add basic code.
This commit is contained in:
parent
b23259fad4
commit
521c40cbd5
@ -21,12 +21,20 @@ qt6_add_qml_module(Fluent
|
|||||||
Icons.h
|
Icons.h
|
||||||
Rectangle.h Rectangle.cpp
|
Rectangle.h Rectangle.cpp
|
||||||
Theme.h Theme.cpp
|
Theme.h Theme.cpp
|
||||||
|
Utilities.h Utilities.cpp
|
||||||
QML_FILES
|
QML_FILES
|
||||||
|
qml/Acrylic.qml
|
||||||
qml/AppBar.qml
|
qml/AppBar.qml
|
||||||
|
qml/Icon.qml
|
||||||
qml/IconButton.qml
|
qml/IconButton.qml
|
||||||
|
qml/InfoBar.qml
|
||||||
|
qml/Object.qml
|
||||||
qml/Router.qml
|
qml/Router.qml
|
||||||
|
qml/Shadow.qml
|
||||||
qml/Text.qml
|
qml/Text.qml
|
||||||
qml/Window.qml
|
qml/Window.qml
|
||||||
|
RESOURCES
|
||||||
|
resources/noise.png
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(Fluent
|
target_include_directories(Fluent
|
||||||
|
@ -1,6 +1,39 @@
|
|||||||
#include "Frameless.h"
|
#include "Frameless.h"
|
||||||
|
#include "Utilities.h"
|
||||||
|
#include <QQuickWindow>
|
||||||
|
#include <dwmapi.h>
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
static inline void setShadow(HWND hwnd) {
|
||||||
|
const MARGINS shadow = {1, 0, 0, 0};
|
||||||
|
typedef HRESULT(WINAPI * DwmExtendFrameIntoClientAreaPtr)(HWND hWnd, const MARGINS *pMarInset);
|
||||||
|
HMODULE module = LoadLibrary(L"dwmapi.dll");
|
||||||
|
if (module) {
|
||||||
|
DwmExtendFrameIntoClientAreaPtr dwm_extendframe_into_client_area_;
|
||||||
|
dwm_extendframe_into_client_area_ =
|
||||||
|
reinterpret_cast<DwmExtendFrameIntoClientAreaPtr>(GetProcAddress(module, "DwmExtendFrameIntoClientArea"));
|
||||||
|
if (dwm_extendframe_into_client_area_) {
|
||||||
|
dwm_extendframe_into_client_area_(hwnd, &shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool containsCursorToItem(QQuickItem *item) {
|
||||||
|
auto window = item->window();
|
||||||
|
if ((window == nullptr) || !item || !item->isVisible()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto point = window->mapFromGlobal(QCursor::pos());
|
||||||
|
auto rect = QRectF(item->mapToItem(window->contentItem(), QPointF(0, 0)), item->size());
|
||||||
|
if (rect.contains(point)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Frameless::Frameless(QQuickItem *parent) : QQuickItem{parent} {
|
Frameless::Frameless(QQuickItem *parent) : QQuickItem{parent} {
|
||||||
|
m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater();
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickItem *Frameless::appBar() const {
|
QQuickItem *Frameless::appBar() const {
|
||||||
@ -25,6 +58,28 @@ void Frameless::setMaximizeButton(QQuickItem *button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QQuickItem *Frameless::minimizedButton() const {
|
||||||
|
return m_minimizedButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::setMinimizedButton(QQuickItem *button) {
|
||||||
|
if (m_minimizedButton != button) {
|
||||||
|
m_minimizedButton = button;
|
||||||
|
emit minimizedButtonChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QQuickItem *Frameless::closeButton() const {
|
||||||
|
return m_closeButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::setCloseButton(QQuickItem *button) {
|
||||||
|
if (m_closeButton != button) {
|
||||||
|
m_closeButton = button;
|
||||||
|
emit closeButtonChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Frameless::fixSize() const {
|
bool Frameless::fixSize() const {
|
||||||
return m_fixSize;
|
return m_fixSize;
|
||||||
}
|
}
|
||||||
@ -69,8 +124,370 @@ void Frameless::onDestruction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Frameless::componentComplete() {
|
void Frameless::componentComplete() {
|
||||||
|
if (m_disabled) return;
|
||||||
|
int w = window()->width();
|
||||||
|
int h = window()->height();
|
||||||
|
m_current = window()->winId();
|
||||||
|
window()->setFlags((window()->flags()) | Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint |
|
||||||
|
Qt::WindowCloseButtonHint);
|
||||||
|
if (!m_fixSize) {
|
||||||
|
window()->setFlag(Qt::WindowMaximizeButtonHint);
|
||||||
|
}
|
||||||
|
window()->installEventFilter(this);
|
||||||
|
QGuiApplication::instance()->installNativeEventFilter(this);
|
||||||
|
if (m_maximizeButton) {
|
||||||
|
setHitTestVisible(m_maximizeButton);
|
||||||
|
}
|
||||||
|
if (m_minimizedButton) {
|
||||||
|
setHitTestVisible(m_minimizedButton);
|
||||||
|
}
|
||||||
|
if (m_closeButton) {
|
||||||
|
setHitTestVisible(m_closeButton);
|
||||||
|
}
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#if (QT_VERSION == QT_VERSION_CHECK(6, 5, 3))
|
||||||
|
qWarning() << "Qt's own frameless bug, currently only exist in 6.5.3, please use other versions";
|
||||||
|
#endif
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
|
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||||
|
if (m_fixSize) {
|
||||||
|
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
|
||||||
|
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
|
||||||
|
connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
|
||||||
|
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
||||||
|
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
|
||||||
|
}
|
||||||
|
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
||||||
|
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
||||||
|
connect(window(), &QQuickWindow::screenChanged, this, [hwnd] {
|
||||||
|
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
||||||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
|
||||||
|
::RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
|
||||||
|
});
|
||||||
|
if (!window()->property("_hideShadow").toBool()) {
|
||||||
|
setShadow(hwnd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
auto appBarHeight = m_appBar->height();
|
||||||
|
h = qRound(h + appBarHeight);
|
||||||
|
if (m_fixSize) {
|
||||||
|
window()->setMaximumSize(QSize(w, h));
|
||||||
|
window()->setMinimumSize(QSize(w, h));
|
||||||
|
} else {
|
||||||
|
window()->setMinimumHeight(window()->minimumHeight() + appBarHeight);
|
||||||
|
window()->setMaximumHeight(window()->maximumHeight() + appBarHeight);
|
||||||
|
}
|
||||||
|
window()->resize(QSize(w, h));
|
||||||
|
connect(this, &Frameless::topmostChanged, this, [this] { setWindowTopmost(topmost()); });
|
||||||
|
setWindowTopmost(topmost());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frameless::eventFilter(QObject *obj, QEvent *event) {
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
switch (ev->type()) {
|
||||||
|
case QEvent::MouseButtonPress:
|
||||||
|
if (_edges != 0) {
|
||||||
|
QMouseEvent *event = static_cast<QMouseEvent *>(ev);
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
_updateCursor(_edges);
|
||||||
|
window()->startSystemResize(Qt::Edges(_edges));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_hitAppBar()) {
|
||||||
|
qint64 clickTimer = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
qint64 offset = clickTimer - this->_clickTimer;
|
||||||
|
this->_clickTimer = clickTimer;
|
||||||
|
if (offset < 300) {
|
||||||
|
if (_isMaximized()) {
|
||||||
|
showNormal();
|
||||||
|
} else {
|
||||||
|
showMaximized();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window()->startSystemMove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QEvent::MouseButtonRelease:
|
||||||
|
_edges = 0;
|
||||||
|
break;
|
||||||
|
case QEvent::MouseMove: {
|
||||||
|
if (_isMaximized() || _isFullScreen()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (_fixSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QMouseEvent *event = static_cast<QMouseEvent *>(ev);
|
||||||
|
QPoint p =
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
event->pos();
|
||||||
|
#else
|
||||||
|
event->position().toPoint();
|
||||||
|
#endif
|
||||||
|
if (p.x() >= _margins && p.x() <= (window()->width() - _margins) && p.y() >= _margins &&
|
||||||
|
p.y() <= (window()->height() - _margins)) {
|
||||||
|
if (_edges != 0) {
|
||||||
|
_edges = 0;
|
||||||
|
_updateCursor(_edges);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_edges = 0;
|
||||||
|
if (p.x() < _margins) {
|
||||||
|
_edges |= Qt::LeftEdge;
|
||||||
|
}
|
||||||
|
if (p.x() > (window()->width() - _margins)) {
|
||||||
|
_edges |= Qt::RightEdge;
|
||||||
|
}
|
||||||
|
if (p.y() < _margins) {
|
||||||
|
_edges |= Qt::TopEdge;
|
||||||
|
}
|
||||||
|
if (p.y() > (window()->height() - _margins)) {
|
||||||
|
_edges |= Qt::BottomEdge;
|
||||||
|
}
|
||||||
|
_updateCursor(_edges);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Frameless::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) {
|
bool Frameless::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if ((eventType != "windows_generic_MSG") || !message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const auto msg = static_cast<const MSG *>(message);
|
||||||
|
auto hwnd = msg->hwnd;
|
||||||
|
if (!hwnd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const quint64 wid = reinterpret_cast<qint64>(hwnd);
|
||||||
|
if (wid != m_current) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto uMsg = msg->message;
|
||||||
|
const auto wParam = msg->wParam;
|
||||||
|
const auto lParam = msg->lParam;
|
||||||
|
if (uMsg == WM_WINDOWPOSCHANGING) {
|
||||||
|
auto *wp = reinterpret_cast<WINDOWPOS *>(lParam);
|
||||||
|
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) {
|
||||||
|
wp->flags |= SWP_NOCOPYBITS;
|
||||||
|
*result = static_cast<qintptr>(::DefWindowProcW(hwnd, uMsg, wParam, lParam));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (uMsg == WM_NCCALCSIZE && wParam == TRUE) {
|
||||||
|
bool isMaximum = ::IsZoomed(hwnd);
|
||||||
|
if (isMaximum) {
|
||||||
|
window()->setProperty("__margins", 7);
|
||||||
|
} else {
|
||||||
|
window()->setProperty("__margins", 0);
|
||||||
|
}
|
||||||
|
setMaximizeHovered(false);
|
||||||
|
*result = WVR_REDRAW;
|
||||||
|
return true;
|
||||||
|
} else if (uMsg == WM_NCHITTEST) {
|
||||||
|
if (m_isWindows11OrGreater) {
|
||||||
|
if (hitMaximizeButton()) {
|
||||||
|
if (*result == HTNOWHERE) {
|
||||||
|
*result = HTZOOM;
|
||||||
|
}
|
||||||
|
setMaximizeHovered(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
setMaximizeHovered(false);
|
||||||
|
setMaximizePressed(false);
|
||||||
|
}
|
||||||
|
*result = 0;
|
||||||
|
POINT nativeGlobalPos{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||||
|
POINT nativeLocalPos = nativeGlobalPos;
|
||||||
|
::ScreenToClient(hwnd, &nativeLocalPos);
|
||||||
|
RECT clientRect{0, 0, 0, 0};
|
||||||
|
::GetClientRect(hwnd, &clientRect);
|
||||||
|
auto clientWidth = clientRect.right - clientRect.left;
|
||||||
|
auto clientHeight = clientRect.bottom - clientRect.top;
|
||||||
|
bool left = nativeLocalPos.x < m_margins;
|
||||||
|
bool right = nativeLocalPos.x > clientWidth - m_margins;
|
||||||
|
bool top = nativeLocalPos.y < m_margins;
|
||||||
|
bool bottom = nativeLocalPos.y > clientHeight - m_margins;
|
||||||
|
*result = 0;
|
||||||
|
if (!m_fixSize && !isFullScreen() && !isMaximized()) {
|
||||||
|
if (left && top) {
|
||||||
|
*result = HTTOPLEFT;
|
||||||
|
} else if (left && bottom) {
|
||||||
|
*result = HTBOTTOMLEFT;
|
||||||
|
} else if (right && top) {
|
||||||
|
*result = HTTOPRIGHT;
|
||||||
|
} else if (right && bottom) {
|
||||||
|
*result = HTBOTTOMRIGHT;
|
||||||
|
} else if (left) {
|
||||||
|
*result = HTLEFT;
|
||||||
|
} else if (right) {
|
||||||
|
*result = HTRIGHT;
|
||||||
|
} else if (top) {
|
||||||
|
*result = HTTOP;
|
||||||
|
} else if (bottom) {
|
||||||
|
*result = HTBOTTOM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (0 != *result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (hitAppBar()) {
|
||||||
|
*result = HTCAPTION;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*result = HTCLIENT;
|
||||||
|
return true;
|
||||||
|
} else if (uMsg == WM_NCPAINT) {
|
||||||
|
*result = FALSE;
|
||||||
|
return false;
|
||||||
|
} else if (uMsg == WM_NCACTIVATE) {
|
||||||
|
*result = TRUE;
|
||||||
|
return true;
|
||||||
|
} else if (m_isWindows11OrGreater && (uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN)) {
|
||||||
|
if (hitMaximizeButton()) {
|
||||||
|
QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::LeftButton,
|
||||||
|
Qt::LeftButton, Qt::NoModifier);
|
||||||
|
QGuiApplication::sendEvent(m_maximizeButton, &event);
|
||||||
|
setMaximizePressed(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (m_isWindows11OrGreater && (uMsg == WM_NCLBUTTONUP || uMsg == WM_NCRBUTTONUP)) {
|
||||||
|
if (hitMaximizeButton()) {
|
||||||
|
QMouseEvent event = QMouseEvent(QEvent::MouseButtonRelease, QPoint(), QPoint(), Qt::LeftButton,
|
||||||
|
Qt::LeftButton, Qt::NoModifier);
|
||||||
|
QGuiApplication::sendEvent(m_maximizeButton, &event);
|
||||||
|
setMaximizePressed(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (uMsg == WM_NCRBUTTONDOWN) {
|
||||||
|
if (wParam == HTCAPTION) {
|
||||||
|
auto pos = window()->position();
|
||||||
|
auto offset = window()->mapFromGlobal(QCursor::pos());
|
||||||
|
showSystemMenu(QPoint(pos.x() + offset.x(), pos.y() + offset.y()));
|
||||||
|
}
|
||||||
|
} else if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN) {
|
||||||
|
const bool altPressed = ((wParam == VK_MENU) || (::GetKeyState(VK_MENU) < 0));
|
||||||
|
const bool spacePressed = ((wParam == VK_SPACE) || (::GetKeyState(VK_SPACE) < 0));
|
||||||
|
if (altPressed && spacePressed) {
|
||||||
|
auto pos = window()->position();
|
||||||
|
showSystemMenu(QPoint(pos.x(), qRound(pos.y() + m_appBar->height())));
|
||||||
|
}
|
||||||
|
} else if (uMsg == WM_SYSCOMMAND) {
|
||||||
|
if (wParam == SC_MINIMIZE) {
|
||||||
|
if (window()->transientParent()) {
|
||||||
|
auto _hwnd = reinterpret_cast<HWND>(window()->transientParent()->winId());
|
||||||
|
::ShowWindow(_hwnd, 2);
|
||||||
|
} else {
|
||||||
|
auto _hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
|
::ShowWindow(_hwnd, 2);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frameless::isFullScreen() {
|
||||||
|
return window()->visibility() == QWindow::FullScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frameless::isMaximized() {
|
||||||
|
return window()->visibility() == QWindow::Maximized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::setMaximizeHovered(bool val) {
|
||||||
|
if (m_maximizeButton) {
|
||||||
|
m_maximizeButton->setProperty("hover", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::setMaximizePressed(bool val) {
|
||||||
|
if (m_maximizeButton) {
|
||||||
|
m_maximizeButton->setProperty("down", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::setWindowTopmost(bool topmost) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
|
if (topmost) {
|
||||||
|
::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||||
|
} else {
|
||||||
|
::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
window()->setFlag(Qt::WindowStaysOnTopHint, topmost);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frameless::hitMaximizeButton() {
|
||||||
|
if (containsCursorToItem(m_maximizeButton)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Frameless::hitAppBar() {
|
||||||
|
for (int i = 0; i <= m_hitTestList.size() - 1; ++i) {
|
||||||
|
auto item = m_hitTestList.at(i);
|
||||||
|
if (containsCursorToItem(item)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((m_appBar != nullptr) && containsCursorToItem(m_appBar)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::showSystemMenu(QPoint point) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QScreen *screen = window()->screen();
|
||||||
|
if (!screen) {
|
||||||
|
screen = QGuiApplication::primaryScreen();
|
||||||
|
}
|
||||||
|
if (!screen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QPoint origin = screen->geometry().topLeft();
|
||||||
|
auto nativePos = QPointF(QPointF(point - origin) * window()->devicePixelRatio()).toPoint() + origin;
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
|
auto hMenu = ::GetSystemMenu(hwnd, FALSE);
|
||||||
|
if (isMaximized() || isFullScreen()) {
|
||||||
|
::EnableMenuItem(hMenu, SC_MOVE, MFS_DISABLED);
|
||||||
|
::EnableMenuItem(hMenu, SC_RESTORE, MFS_ENABLED);
|
||||||
|
} else {
|
||||||
|
::EnableMenuItem(hMenu, SC_MOVE, MFS_ENABLED);
|
||||||
|
::EnableMenuItem(hMenu, SC_RESTORE, MFS_DISABLED);
|
||||||
|
}
|
||||||
|
if (!m_fixSize && !isMaximized() && !isFullScreen()) {
|
||||||
|
::EnableMenuItem(hMenu, SC_SIZE, MFS_ENABLED);
|
||||||
|
::EnableMenuItem(hMenu, SC_MAXIMIZE, MFS_ENABLED);
|
||||||
|
} else {
|
||||||
|
::EnableMenuItem(hMenu, SC_SIZE, MFS_DISABLED);
|
||||||
|
::EnableMenuItem(hMenu, SC_MAXIMIZE, MFS_DISABLED);
|
||||||
|
}
|
||||||
|
const int result =
|
||||||
|
::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
|
||||||
|
nativePos.x(), nativePos.y(), 0, hwnd, nullptr);
|
||||||
|
if (result) {
|
||||||
|
::PostMessageW(hwnd, WM_SYSCOMMAND, result, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -9,6 +9,9 @@ class Frameless : public QQuickItem, QAbstractNativeEventFilter {
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged)
|
Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged)
|
||||||
Q_PROPERTY(QQuickItem *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged)
|
Q_PROPERTY(QQuickItem *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged)
|
||||||
|
Q_PROPERTY(QQuickItem *minimizedButton READ minimizedButton WRITE setMinimizedButton NOTIFY minimizedButtonChanged)
|
||||||
|
Q_PROPERTY(QQuickItem *closeButton READ closeButton WRITE setCloseButton NOTIFY closeButtonChanged)
|
||||||
|
|
||||||
Q_PROPERTY(bool fixSize READ fixSize WRITE setFixSize NOTIFY fixSizeChanged)
|
Q_PROPERTY(bool fixSize READ fixSize WRITE setFixSize NOTIFY fixSizeChanged)
|
||||||
Q_PROPERTY(bool topmost READ topmost WRITE setTopmost NOTIFY topmostChanged)
|
Q_PROPERTY(bool topmost READ topmost WRITE setTopmost NOTIFY topmostChanged)
|
||||||
Q_PROPERTY(bool disabled READ disabled WRITE setDisabled NOTIFY disabledChanged)
|
Q_PROPERTY(bool disabled READ disabled WRITE setDisabled NOTIFY disabledChanged)
|
||||||
@ -21,6 +24,12 @@ public:
|
|||||||
QQuickItem *maximizeButton() const;
|
QQuickItem *maximizeButton() const;
|
||||||
void setMaximizeButton(QQuickItem *button);
|
void setMaximizeButton(QQuickItem *button);
|
||||||
|
|
||||||
|
QQuickItem *minimizedButton() const;
|
||||||
|
void setMinimizedButton(QQuickItem *button);
|
||||||
|
|
||||||
|
QQuickItem *closeButton() const;
|
||||||
|
void setCloseButton(QQuickItem *button);
|
||||||
|
|
||||||
bool fixSize() const;
|
bool fixSize() const;
|
||||||
void setFixSize(bool fix);
|
void setFixSize(bool fix);
|
||||||
|
|
||||||
@ -39,17 +48,35 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void appBarChanged();
|
void appBarChanged();
|
||||||
void maximizeButtonChanged();
|
void maximizeButtonChanged();
|
||||||
|
void minimizedButtonChanged();
|
||||||
|
void closeButtonChanged();
|
||||||
void fixSizeChanged();
|
void fixSizeChanged();
|
||||||
void topmostChanged();
|
void topmostChanged();
|
||||||
void disabledChanged();
|
void disabledChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool isFullScreen();
|
||||||
|
bool isMaximized();
|
||||||
|
void setMaximizeHovered(bool val);
|
||||||
|
void setMaximizePressed(bool val);
|
||||||
|
void setWindowTopmost(bool topmost);
|
||||||
|
bool hitMaximizeButton();
|
||||||
|
bool hitAppBar();
|
||||||
|
void showSystemMenu(QPoint point);
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
quint64 m_current = 0;
|
||||||
QQuickItem *m_appBar = nullptr;
|
QQuickItem *m_appBar = nullptr;
|
||||||
QQuickItem *m_maximizeButton = nullptr;
|
QQuickItem *m_maximizeButton = nullptr;
|
||||||
|
QQuickItem *m_minimizedButton = nullptr;
|
||||||
|
QQuickItem *m_closeButton = nullptr;
|
||||||
bool m_fixSize = false;
|
bool m_fixSize = false;
|
||||||
bool m_topmost = false;
|
bool m_topmost = false;
|
||||||
bool m_disabled = false;
|
bool m_disabled = false;
|
||||||
|
int m_margins = 8;
|
||||||
QList<QPointer<QQuickItem>> m_hitTestList;
|
QList<QPointer<QQuickItem>> m_hitTestList;
|
||||||
|
bool m_isWindows11OrGreater = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FRAMELESS_H
|
#endif // FRAMELESS_H
|
||||||
|
@ -24,3 +24,58 @@ void Theme::setItemNormalColor(const QColor &color) {
|
|||||||
emit itemNormalColorChanged();
|
emit itemNormalColorChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QColor Theme::itemHoverColor() const {
|
||||||
|
return m_itemHoverColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::setItemHoverColor(const QColor &color) {
|
||||||
|
if (m_itemHoverColor != color) {
|
||||||
|
m_itemHoverColor = color;
|
||||||
|
emit itemHoverColorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Theme::windowBackgroundColor() const {
|
||||||
|
return m_windowBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::setWindowBackgroundColor(const QColor &color) {
|
||||||
|
if (m_windowBackgroundColor != color) {
|
||||||
|
m_windowBackgroundColor = color;
|
||||||
|
emit windowBackgroundColorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Theme::windowActiveBackgroundColor() const {
|
||||||
|
return m_windowActiveBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::setWindowActiveBackgroundColor(const QColor &color) {
|
||||||
|
if (m_windowActiveBackgroundColor != color) {
|
||||||
|
m_windowActiveBackgroundColor = color;
|
||||||
|
emit windowActiveBackgroundColorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Theme::desktopImagePath() const {
|
||||||
|
return m_desktopImagePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::setDesktopImagePath(const QString &path) {
|
||||||
|
if (m_desktopImagePath != path) {
|
||||||
|
m_desktopImagePath = path;
|
||||||
|
emit desktopImagePathChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Theme::blurBehindWindowEnabled() const {
|
||||||
|
return m_blurBehindWindowEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::setBlurBehindWindowEnabled(bool enabled) {
|
||||||
|
if (m_blurBehindWindowEnabled != enabled) {
|
||||||
|
m_blurBehindWindowEnabled = enabled;
|
||||||
|
emit blurBehindWindowEnabledChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,6 +11,16 @@ class Theme : public QObject {
|
|||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged)
|
Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged)
|
||||||
Q_PROPERTY(QColor itemNormalColor READ itemNormalColor WRITE setItemNormalColor NOTIFY itemNormalColorChanged)
|
Q_PROPERTY(QColor itemNormalColor READ itemNormalColor WRITE setItemNormalColor NOTIFY itemNormalColorChanged)
|
||||||
|
Q_PROPERTY(QColor itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QColor windowBackgroundColor READ windowBackgroundColor WRITE setWindowBackgroundColor NOTIFY
|
||||||
|
windowBackgroundColorChanged)
|
||||||
|
Q_PROPERTY(QColor windowActiveBackgroundColor READ windowActiveBackgroundColor WRITE setWindowActiveBackgroundColor
|
||||||
|
NOTIFY windowActiveBackgroundColorChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QString desktopImagePath READ desktopImagePath WRITE setDesktopImagePath NOTIFY desktopImagePathChanged)
|
||||||
|
Q_PROPERTY(bool blurBehindWindowEnabled READ blurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY
|
||||||
|
blurBehindWindowEnabledChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Theme(QObject *parent = nullptr);
|
Theme(QObject *parent = nullptr);
|
||||||
@ -21,13 +31,39 @@ public:
|
|||||||
QColor itemNormalColor() const;
|
QColor itemNormalColor() const;
|
||||||
void setItemNormalColor(const QColor &color);
|
void setItemNormalColor(const QColor &color);
|
||||||
|
|
||||||
|
QColor itemHoverColor() const;
|
||||||
|
void setItemHoverColor(const QColor &color);
|
||||||
|
|
||||||
|
QColor windowBackgroundColor() const;
|
||||||
|
void setWindowBackgroundColor(const QColor &color);
|
||||||
|
|
||||||
|
QColor windowActiveBackgroundColor() const;
|
||||||
|
void setWindowActiveBackgroundColor(const QColor &color);
|
||||||
|
|
||||||
|
QString desktopImagePath() const;
|
||||||
|
void setDesktopImagePath(const QString &path);
|
||||||
|
|
||||||
|
bool blurBehindWindowEnabled() const;
|
||||||
|
void setBlurBehindWindowEnabled(bool enabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void fontPrimaryColorChanged();
|
void fontPrimaryColorChanged();
|
||||||
void itemNormalColorChanged();
|
void itemNormalColorChanged();
|
||||||
|
void windowBackgroundColorChanged();
|
||||||
|
void windowActiveBackgroundColorChanged();
|
||||||
|
void desktopImagePathChanged();
|
||||||
|
void blurBehindWindowEnabledChanged();
|
||||||
|
void itemHoverColorChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QColor m_fontPrimaryColor;
|
QColor m_fontPrimaryColor;
|
||||||
QColor m_itemNormalColor;
|
QColor m_itemNormalColor;
|
||||||
|
QColor m_itemHoverColor;
|
||||||
|
QColor m_windowBackgroundColor;
|
||||||
|
QColor m_windowActiveBackgroundColor;
|
||||||
|
|
||||||
|
QString m_desktopImagePath;
|
||||||
|
bool m_blurBehindWindowEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // THEME_H
|
#endif // THEME_H
|
||||||
|
72
Fluent/Utilities.cpp
Normal file
72
Fluent/Utilities.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "Utilities.h"
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
Utilities *Utilities::instance() {
|
||||||
|
static Utilities *self = nullptr;
|
||||||
|
if (self == nullptr) {
|
||||||
|
self = new Utilities();
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utilities *Utilities::create(QQmlEngine *, QJSEngine *) {
|
||||||
|
auto ret = instance();
|
||||||
|
QJSEngine::setObjectOwnership(ret, QJSEngine::CppOwnership);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utilities::Utilities(QObject *parent) : QObject{parent} {
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect Utilities::desktopAvailableGeometry(QQuickWindow *window) {
|
||||||
|
return window->screen()->availableGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl Utilities::getUrlByFilePath(const QString &path) {
|
||||||
|
return QUrl::fromLocalFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utilities::isMacos() {
|
||||||
|
#if defined(Q_OS_MACOS)
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utilities::isWin() {
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int Utilities::windowBuildNumber() {
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
QSettings regKey{QString::fromUtf8(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion)"),
|
||||||
|
QSettings::NativeFormat};
|
||||||
|
if (regKey.contains(QString::fromUtf8("CurrentBuildNumber"))) {
|
||||||
|
auto buildNumber = regKey.value(QString::fromUtf8("CurrentBuildNumber")).toInt();
|
||||||
|
return buildNumber;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utilities::isWindows11OrGreater() {
|
||||||
|
static QVariant var;
|
||||||
|
if (var.isNull()) {
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
auto buildNumber = windowBuildNumber();
|
||||||
|
if (buildNumber >= 22000) {
|
||||||
|
var = QVariant::fromValue(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
var = QVariant::fromValue(false);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return var.toBool();
|
||||||
|
}
|
||||||
|
}
|
26
Fluent/Utilities.h
Normal file
26
Fluent/Utilities.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef UTILITIES_H
|
||||||
|
#define UTILITIES_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
class Utilities : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_SINGLETON
|
||||||
|
public:
|
||||||
|
static Utilities *instance();
|
||||||
|
static Utilities *create(QQmlEngine *, QJSEngine *);
|
||||||
|
Q_INVOKABLE int windowBuildNumber();
|
||||||
|
Q_INVOKABLE bool isWindows11OrGreater();
|
||||||
|
Q_INVOKABLE bool isWin();
|
||||||
|
Q_INVOKABLE bool isMacos();
|
||||||
|
Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window);
|
||||||
|
Q_INVOKABLE QUrl getUrlByFilePath(const QString &path);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Utilities(QObject *parent = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // UTILITIES_H
|
33
Fluent/qml/Acrylic.qml
Normal file
33
Fluent/qml/Acrylic.qml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: control
|
||||||
|
property color tintColor: Qt.rgba(1, 1, 1, 1)
|
||||||
|
property real tintOpacity: 0.65
|
||||||
|
property real luminosity: 0.01
|
||||||
|
property real noiseOpacity: 0.02
|
||||||
|
property var target
|
||||||
|
property int blurRadius: 32
|
||||||
|
property rect targetRect: Qt.rect(control.x, control.y, control.width,control.height)
|
||||||
|
ShaderEffectSource {
|
||||||
|
id: effect_source
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: false
|
||||||
|
sourceRect: control.targetRect
|
||||||
|
sourceItem: control.target
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Qt.rgba(1, 1, 1, luminosity)
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Qt.rgba(tintColor.r, tintColor.g, tintColor.b, tintOpacity)
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: "qrc:/qt/qml/Fluent/resources/noise.png"
|
||||||
|
fillMode: Image.Tile
|
||||||
|
opacity: control.noiseOpacity
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,11 @@ Quick.Rectangle {
|
|||||||
property string maximizeText : qsTr("Maximize")
|
property string maximizeText : qsTr("Maximize")
|
||||||
property Quick.color textColor: Theme.fontPrimaryColor
|
property Quick.color textColor: Theme.fontPrimaryColor
|
||||||
property Quick.color maximizeNormalColor: Theme.itemNormalColor
|
property Quick.color maximizeNormalColor: Theme.itemNormalColor
|
||||||
|
property Quick.color maximizeHoverColor: Theme.itemHoverColor
|
||||||
|
property bool isMac: Utilities.isMacos()
|
||||||
property alias buttonMaximize: btn_maximize
|
property alias buttonMaximize: btn_maximize
|
||||||
|
property alias layoutMacosButtons: layout_macos_buttons
|
||||||
|
property alias layoutStandardbuttons: layout_standard_buttons
|
||||||
|
|
||||||
Quick.Item{
|
Quick.Item{
|
||||||
id:d
|
id:d
|
||||||
@ -40,6 +44,11 @@ Quick.Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
id:layout_standard_buttons
|
||||||
|
height: parent.height
|
||||||
|
anchors.right: parent.right
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
IconButton{
|
IconButton{
|
||||||
id:btn_maximize
|
id:btn_maximize
|
||||||
property bool hover: btn_maximize.hovered
|
property bool hover: btn_maximize.hovered
|
||||||
@ -65,5 +74,14 @@ Quick.Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quick.Loader{
|
||||||
|
id:layout_macos_buttons
|
||||||
|
anchors{
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 10
|
||||||
|
}
|
||||||
|
sourceComponent: isMac ? com_macos_buttons : undefined
|
||||||
|
Quick.Component.onDestruction: sourceComponent = undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
19
Fluent/qml/Icon.qml
Normal file
19
Fluent/qml/Icon.qml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Text {
|
||||||
|
property int iconSource
|
||||||
|
property int iconSize: 20
|
||||||
|
property color iconColor: FluTheme.dark ? "#FFFFFF" : "#000000"
|
||||||
|
id:control
|
||||||
|
font.family: font_loader.name
|
||||||
|
font.pixelSize: iconSize
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
color: iconColor
|
||||||
|
text: (String.fromCharCode(iconSource).toString(16))
|
||||||
|
opacity: iconSource>0
|
||||||
|
FontLoader{
|
||||||
|
id: font_loader
|
||||||
|
source: "qrc:/qt/qml/FluentUI/Font/FluentIcons.ttf"
|
||||||
|
}
|
||||||
|
}
|
245
Fluent/qml/InfoBar.qml
Normal file
245
Fluent/qml/InfoBar.qml
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
import QtQuick as Quick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Fluent
|
||||||
|
|
||||||
|
Object {
|
||||||
|
property var root
|
||||||
|
property int layoutY: 75
|
||||||
|
id:control
|
||||||
|
Object{
|
||||||
|
id:mcontrol
|
||||||
|
property string const_success: "success"
|
||||||
|
property string const_info: "info"
|
||||||
|
property string const_warning: "warning"
|
||||||
|
property string const_error: "error"
|
||||||
|
property int maxWidth: 300
|
||||||
|
property var screenLayout: null
|
||||||
|
function create(type,text,duration,moremsg){
|
||||||
|
if(screenLayout){
|
||||||
|
var last = screenLayout.getLastloader()
|
||||||
|
if(last.type === type && last.text === text && moremsg === last.moremsg){
|
||||||
|
last.duration = duration
|
||||||
|
if (duration > 0) last.restart()
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initScreenLayout()
|
||||||
|
return contentComponent.createObject(screenLayout,{type:type,text:text,duration:duration,moremsg:moremsg,})
|
||||||
|
}
|
||||||
|
function createCustom(itemcomponent,duration){
|
||||||
|
initScreenLayout()
|
||||||
|
if(itemcomponent){
|
||||||
|
return contentComponent.createObject(screenLayout,{itemcomponent:itemcomponent,duration:duration})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function initScreenLayout(){
|
||||||
|
if(screenLayout == null){
|
||||||
|
screenLayout = screenlayoutComponent.createObject(root)
|
||||||
|
screenLayout.y = control.layoutY
|
||||||
|
screenLayout.z = 100000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Component {
|
||||||
|
id:screenlayoutComponent
|
||||||
|
Quick.Column{
|
||||||
|
parent: Overlay.overlay
|
||||||
|
z:999
|
||||||
|
spacing: 20
|
||||||
|
width: root.width
|
||||||
|
move: Quick.Transition {
|
||||||
|
Quick.NumberAnimation {
|
||||||
|
properties: "y"
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
duration: FluTheme.animationEnabled ? 333 : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onChildrenChanged: if(children.length === 0) destroy()
|
||||||
|
function getLastloader(){
|
||||||
|
if(children.length > 0){
|
||||||
|
return children[children.length - 1]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Component{
|
||||||
|
id:contentComponent
|
||||||
|
Quick.Item{
|
||||||
|
id:content
|
||||||
|
property int duration: 1500
|
||||||
|
property var itemcomponent
|
||||||
|
property string type
|
||||||
|
property string text
|
||||||
|
property string moremsg
|
||||||
|
width: parent.width
|
||||||
|
height: loader.height
|
||||||
|
function close(){
|
||||||
|
content.destroy()
|
||||||
|
}
|
||||||
|
function restart(){
|
||||||
|
delayTimer.restart()
|
||||||
|
}
|
||||||
|
Quick.Timer {
|
||||||
|
id:delayTimer
|
||||||
|
interval: duration
|
||||||
|
running: duration > 0
|
||||||
|
repeat: duration > 0
|
||||||
|
onTriggered: content.close()
|
||||||
|
}
|
||||||
|
Quick.Loader{
|
||||||
|
id:loader
|
||||||
|
x:(parent.width - width) / 2
|
||||||
|
property var _super: content
|
||||||
|
scale: item ? 1 : 0
|
||||||
|
asynchronous: true
|
||||||
|
Quick.Behavior on scale {
|
||||||
|
enabled: FluTheme.animationEnabled
|
||||||
|
Quick.NumberAnimation {
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
duration: 167
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle
|
||||||
|
Quick.Component.onDestruction: sourceComponent = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property Quick.Component fluent_sytle: Quick.Rectangle{
|
||||||
|
width: rowlayout.width + (btn_close.visible ? 30 : 48)
|
||||||
|
height: rowlayout.height + 20
|
||||||
|
color: {
|
||||||
|
if(FluTheme.dark){
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return Qt.rgba(57/255,61/255,27/255,1)
|
||||||
|
case mcontrol.const_warning: return Qt.rgba(67/255,53/255,25/255,1)
|
||||||
|
case mcontrol.const_info: return Qt.rgba(39/255,39/255,39/255,1)
|
||||||
|
case mcontrol.const_error: return Qt.rgba(68/255,39/255,38/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(1,1,1,1)
|
||||||
|
}else{
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return Qt.rgba(223/255,246/255,221/255,1)
|
||||||
|
case mcontrol.const_warning: return Qt.rgba(255/255,244/255,206/255,1)
|
||||||
|
case mcontrol.const_info: return Qt.rgba(244/255,244/255,244/255,1)
|
||||||
|
case mcontrol.const_error: return Qt.rgba(253/255,231/255,233/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(1,1,1,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Shadow {
|
||||||
|
radius: 4
|
||||||
|
}
|
||||||
|
radius: 4
|
||||||
|
border.width: 1
|
||||||
|
border.color: {
|
||||||
|
if(FluTheme.dark){
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return Qt.rgba(56/255,61/255,27/255,1)
|
||||||
|
case mcontrol.const_warning: return Qt.rgba(66/255,53/255,25/255,1)
|
||||||
|
case mcontrol.const_info: return Qt.rgba(38/255,39/255,39/255,1)
|
||||||
|
case mcontrol.const_error: return Qt.rgba(67/255,39/255,38/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(1,1,1,1)
|
||||||
|
}else{
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return Qt.rgba(210/255,232/255,208/255,1)
|
||||||
|
case mcontrol.const_warning: return Qt.rgba(240/255,230/255,194/255,1)
|
||||||
|
case mcontrol.const_info: return Qt.rgba(230/255,230/255,230/255,1)
|
||||||
|
case mcontrol.const_error: return Qt.rgba(238/255,217/255,219/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(1,1,1,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Row{
|
||||||
|
id:rowlayout
|
||||||
|
x:20
|
||||||
|
y:(parent.height - height) / 2
|
||||||
|
spacing: 10
|
||||||
|
Icon{
|
||||||
|
iconSource:{
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return FluentIcons.CompletedSolid
|
||||||
|
case mcontrol.const_warning: return FluentIcons.InfoSolid
|
||||||
|
case mcontrol.const_info: return FluentIcons.InfoSolid
|
||||||
|
case mcontrol.const_error: return FluentIcons.StatusErrorFull
|
||||||
|
}FluentIcons.StatusErrorFull
|
||||||
|
return FluentIcons.FA_info_circle
|
||||||
|
}
|
||||||
|
iconSize:20
|
||||||
|
iconColor: {
|
||||||
|
if(FluTheme.dark){
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return Qt.rgba(108/255,203/255,95/255,1)
|
||||||
|
case mcontrol.const_warning: return Qt.rgba(252/255,225/255,0/255,1)
|
||||||
|
case mcontrol.const_info: return FluTheme.primaryColor
|
||||||
|
case mcontrol.const_error: return Qt.rgba(255/255,153/255,164/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(1,1,1,1)
|
||||||
|
}else{
|
||||||
|
switch(_super.type){
|
||||||
|
case mcontrol.const_success: return Qt.rgba(15/255,123/255,15/255,1)
|
||||||
|
case mcontrol.const_warning: return Qt.rgba(157/255,93/255,0/255,1)
|
||||||
|
case mcontrol.const_info: return Qt.rgba(0/255,102/255,180/255,1)
|
||||||
|
case mcontrol.const_error: return Qt.rgba(196/255,43/255,28/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(1,1,1,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Quick.Column{
|
||||||
|
spacing: 5
|
||||||
|
Text{
|
||||||
|
text:_super.text
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
width: Math.min(implicitWidth,mcontrol.maxWidth)
|
||||||
|
}
|
||||||
|
Text{
|
||||||
|
text: _super.moremsg
|
||||||
|
visible: _super.moremsg
|
||||||
|
wrapMode : Text.WrapAnywhere
|
||||||
|
textColor: FluColors.Grey120
|
||||||
|
width: Math.min(implicitWidth,mcontrol.maxWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton{
|
||||||
|
id:btn_close
|
||||||
|
iconSource: FluentIcons.ChromeClose
|
||||||
|
iconSize: 10
|
||||||
|
verticalPadding: 0
|
||||||
|
horizontalPadding: 0
|
||||||
|
width: 30
|
||||||
|
height: 20
|
||||||
|
visible: _super.duration<=0
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
iconColor: FluTheme.dark ? Qt.rgba(222/255,222/255,222/255,1) : Qt.rgba(97/255,97/255,97/255,1)
|
||||||
|
onClicked: _super.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function showSuccess(text,duration=1000,moremsg){
|
||||||
|
return mcontrol.create(mcontrol.const_success,text,duration,moremsg ? moremsg : "")
|
||||||
|
}
|
||||||
|
function showInfo(text,duration=1000,moremsg){
|
||||||
|
return mcontrol.create(mcontrol.const_info,text,duration,moremsg ? moremsg : "")
|
||||||
|
}
|
||||||
|
function showWarning(text,duration=1000,moremsg){
|
||||||
|
return mcontrol.create(mcontrol.const_warning,text,duration,moremsg ? moremsg : "")
|
||||||
|
}
|
||||||
|
function showError(text,duration=1000,moremsg){
|
||||||
|
return mcontrol.create(mcontrol.const_error,text,duration,moremsg ? moremsg : "")
|
||||||
|
}
|
||||||
|
function showCustom(itemcomponent,duration=1000){
|
||||||
|
return mcontrol.createCustom(itemcomponent,duration)
|
||||||
|
}
|
||||||
|
function clearAllInfo(){
|
||||||
|
if(mcontrol.screenLayout != null) {
|
||||||
|
mcontrol.screenLayout.destroy()
|
||||||
|
mcontrol.screenLayout = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
7
Fluent/qml/Object.qml
Normal file
7
Fluent/qml/Object.qml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id:root
|
||||||
|
default property list<QtObject> children
|
||||||
|
|
||||||
|
}
|
21
Fluent/qml/Shadow.qml
Normal file
21
Fluent/qml/Shadow.qml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property color color: FluTheme.dark ? "#000000" : "#999999"
|
||||||
|
property int elevation: 5
|
||||||
|
property int radius: 4
|
||||||
|
id:control
|
||||||
|
anchors.fill: parent
|
||||||
|
Repeater{
|
||||||
|
model: elevation
|
||||||
|
Rectangle{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#00000000"
|
||||||
|
opacity: 0.01 * (elevation-index+1)
|
||||||
|
anchors.margins: -index
|
||||||
|
radius: control.radius+index
|
||||||
|
border.width: index
|
||||||
|
border.color: control.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,11 @@
|
|||||||
import QtQuick
|
import QtQuick as Quick
|
||||||
|
|
||||||
Item {
|
import Fluent
|
||||||
|
|
||||||
|
Quick.Text {
|
||||||
|
property Quick.color textColor: FluTheme.fontPrimaryColor
|
||||||
|
id:text
|
||||||
|
color: textColor
|
||||||
|
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering
|
||||||
|
font: FluTextStyle.Body
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,14 @@ Quick.Window {
|
|||||||
property bool showDark: false
|
property bool showDark: false
|
||||||
property bool fixSize: false
|
property bool fixSize: false
|
||||||
property bool stayTop: false
|
property bool stayTop: false
|
||||||
|
property int __margins: 0
|
||||||
|
property var background : com_background
|
||||||
|
property Quick.color backgroundColor: {
|
||||||
|
if(active){
|
||||||
|
return Theme.windowActiveBackgroundColor
|
||||||
|
}
|
||||||
|
return Theme.windowBackgroundColor
|
||||||
|
}
|
||||||
property Quick.Item appBar: AppBar {
|
property Quick.Item appBar: AppBar {
|
||||||
title: root.title
|
title: root.title
|
||||||
height: 30
|
height: 30
|
||||||
@ -39,4 +47,140 @@ Quick.Window {
|
|||||||
Quick.Component.onCompleted: {
|
Quick.Component.onCompleted: {
|
||||||
Router.addWindow(root)
|
Router.addWindow(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quick.Component {
|
||||||
|
id:com_app_bar
|
||||||
|
Quick.Item{
|
||||||
|
data: root.appBar
|
||||||
|
Quick.Component.onCompleted: {
|
||||||
|
root.appBar.width = Qt.binding(function(){
|
||||||
|
return this.parent.width
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Quick.Item{
|
||||||
|
id: layout_container
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: root.__margins
|
||||||
|
Quick.Loader{
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: background
|
||||||
|
Quick.Component.onDestruction: sourceComponent = undefined
|
||||||
|
}
|
||||||
|
Quick.Loader{
|
||||||
|
id:loader_app_bar
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
height: {
|
||||||
|
if(root.useSystemAppBar){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return root.fitsAppBarWindows ? 0 : root.appBar.height
|
||||||
|
}
|
||||||
|
sourceComponent: root.useSystemAppBar ? undefined : com_app_bar
|
||||||
|
Quick.Component.onDestruction: sourceComponent = undefined
|
||||||
|
}
|
||||||
|
Quick.Item{
|
||||||
|
id:layout_content
|
||||||
|
anchors{
|
||||||
|
top: loader_app_bar.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
Quick.Loader{
|
||||||
|
property string loadingText
|
||||||
|
property bool cancel: false
|
||||||
|
id:loader_loading
|
||||||
|
anchors.fill: parent
|
||||||
|
Quick.Component.onDestruction: sourceComponent = undefined
|
||||||
|
}
|
||||||
|
InfoBar{
|
||||||
|
id:info_bar
|
||||||
|
root: layout_container
|
||||||
|
}
|
||||||
|
|
||||||
|
Quick.Loader{
|
||||||
|
id:loader_border
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: {
|
||||||
|
if(root.useSystemAppBar || Utilities.isWin() || root.visibility === Window.Maximized || root.visibility === Window.FullScreen){
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return com_border
|
||||||
|
}
|
||||||
|
Quick.Component.onDestruction: sourceComponent = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Quick.Component {
|
||||||
|
id:com_background
|
||||||
|
Quick.Item{
|
||||||
|
Rectangle{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: root.backgroundColor
|
||||||
|
}
|
||||||
|
Quick.Image{
|
||||||
|
id:img_back
|
||||||
|
visible: false
|
||||||
|
cache: false
|
||||||
|
fillMode: Quick.Image.PreserveAspectCrop
|
||||||
|
asynchronous: true
|
||||||
|
Quick.Component.onCompleted: {
|
||||||
|
img_back.updateLayout()
|
||||||
|
source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
|
||||||
|
}
|
||||||
|
Quick.Connections{
|
||||||
|
target: root
|
||||||
|
function onScreenChanged(){
|
||||||
|
img_back.updateLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function updateLayout(){
|
||||||
|
var geometry = Utilities.desktopAvailableGeometry(root)
|
||||||
|
img_back.width = geometry.width
|
||||||
|
img_back.height = geometry.height
|
||||||
|
img_back.sourceSize = Qt.size(img_back.width,img_back.height)
|
||||||
|
}
|
||||||
|
Quick.Connections{
|
||||||
|
target: Theme
|
||||||
|
function onDesktopImagePathChanged(){
|
||||||
|
timer_update_image.restart()
|
||||||
|
}
|
||||||
|
function onBlurBehindWindowEnabledChanged(){
|
||||||
|
if(Theme.blurBehindWindowEnabled){
|
||||||
|
img_back.source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
|
||||||
|
}else{
|
||||||
|
img_back.source = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Timer{
|
||||||
|
id:timer_update_image
|
||||||
|
interval: 150
|
||||||
|
onTriggered: {
|
||||||
|
img_back.source = ""
|
||||||
|
img_back.source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Acrylic{
|
||||||
|
anchors.fill: parent
|
||||||
|
target: img_back
|
||||||
|
tintOpacity: Theme.dark ? 0.80 : 0.75
|
||||||
|
blurRadius: 64
|
||||||
|
visible: root.active && Theme.blurBehindWindowEnabled
|
||||||
|
tintColor: Theme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1)
|
||||||
|
targetRect: Qt.rect(root.x-root.screen.virtualX,root.y-root.screen.virtualY,root.width,root.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
Fluent/resources/noise.png
Normal file
BIN
Fluent/resources/noise.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 266 KiB |
Loading…
Reference in New Issue
Block a user