add basic code.
This commit is contained in:
parent
b23259fad4
commit
521c40cbd5
@ -21,12 +21,20 @@ qt6_add_qml_module(Fluent
|
||||
Icons.h
|
||||
Rectangle.h Rectangle.cpp
|
||||
Theme.h Theme.cpp
|
||||
Utilities.h Utilities.cpp
|
||||
QML_FILES
|
||||
qml/Acrylic.qml
|
||||
qml/AppBar.qml
|
||||
qml/Icon.qml
|
||||
qml/IconButton.qml
|
||||
qml/InfoBar.qml
|
||||
qml/Object.qml
|
||||
qml/Router.qml
|
||||
qml/Shadow.qml
|
||||
qml/Text.qml
|
||||
qml/Window.qml
|
||||
RESOURCES
|
||||
resources/noise.png
|
||||
)
|
||||
|
||||
target_include_directories(Fluent
|
||||
|
@ -1,6 +1,39 @@
|
||||
#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} {
|
||||
m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater();
|
||||
}
|
||||
|
||||
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 {
|
||||
return m_fixSize;
|
||||
}
|
||||
@ -69,8 +124,370 @@ void Frameless::onDestruction() {
|
||||
}
|
||||
|
||||
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) {
|
||||
#ifdef Q_OS_WIN
|
||||
if ((eventType != "windows_generic_MSG") || !message) {
|
||||
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
|
||||
Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged)
|
||||
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 topmost READ topmost WRITE setTopmost NOTIFY topmostChanged)
|
||||
Q_PROPERTY(bool disabled READ disabled WRITE setDisabled NOTIFY disabledChanged)
|
||||
@ -21,6 +24,12 @@ public:
|
||||
QQuickItem *maximizeButton() const;
|
||||
void setMaximizeButton(QQuickItem *button);
|
||||
|
||||
QQuickItem *minimizedButton() const;
|
||||
void setMinimizedButton(QQuickItem *button);
|
||||
|
||||
QQuickItem *closeButton() const;
|
||||
void setCloseButton(QQuickItem *button);
|
||||
|
||||
bool fixSize() const;
|
||||
void setFixSize(bool fix);
|
||||
|
||||
@ -39,17 +48,35 @@ public:
|
||||
signals:
|
||||
void appBarChanged();
|
||||
void maximizeButtonChanged();
|
||||
void minimizedButtonChanged();
|
||||
void closeButtonChanged();
|
||||
void fixSizeChanged();
|
||||
void topmostChanged();
|
||||
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:
|
||||
quint64 m_current = 0;
|
||||
QQuickItem *m_appBar = nullptr;
|
||||
QQuickItem *m_maximizeButton = nullptr;
|
||||
QQuickItem *m_minimizedButton = nullptr;
|
||||
QQuickItem *m_closeButton = nullptr;
|
||||
bool m_fixSize = false;
|
||||
bool m_topmost = false;
|
||||
bool m_disabled = false;
|
||||
int m_margins = 8;
|
||||
QList<QPointer<QQuickItem>> m_hitTestList;
|
||||
bool m_isWindows11OrGreater = false;
|
||||
};
|
||||
|
||||
#endif // FRAMELESS_H
|
||||
|
@ -24,3 +24,58 @@ void Theme::setItemNormalColor(const QColor &color) {
|
||||
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
|
||||
Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged)
|
||||
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:
|
||||
Theme(QObject *parent = nullptr);
|
||||
@ -21,13 +31,39 @@ public:
|
||||
QColor itemNormalColor() const;
|
||||
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:
|
||||
void fontPrimaryColorChanged();
|
||||
void itemNormalColorChanged();
|
||||
void windowBackgroundColorChanged();
|
||||
void windowActiveBackgroundColorChanged();
|
||||
void desktopImagePathChanged();
|
||||
void blurBehindWindowEnabledChanged();
|
||||
void itemHoverColorChanged();
|
||||
|
||||
private:
|
||||
QColor m_fontPrimaryColor;
|
||||
QColor m_itemNormalColor;
|
||||
QColor m_itemHoverColor;
|
||||
QColor m_windowBackgroundColor;
|
||||
QColor m_windowActiveBackgroundColor;
|
||||
|
||||
QString m_desktopImagePath;
|
||||
bool m_blurBehindWindowEnabled;
|
||||
};
|
||||
|
||||
#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 Quick.color textColor: Theme.fontPrimaryColor
|
||||
property Quick.color maximizeNormalColor: Theme.itemNormalColor
|
||||
property Quick.color maximizeHoverColor: Theme.itemHoverColor
|
||||
property bool isMac: Utilities.isMacos()
|
||||
property alias buttonMaximize: btn_maximize
|
||||
property alias layoutMacosButtons: layout_macos_buttons
|
||||
property alias layoutStandardbuttons: layout_standard_buttons
|
||||
|
||||
Quick.Item{
|
||||
id:d
|
||||
@ -40,6 +44,11 @@ Quick.Rectangle {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id:layout_standard_buttons
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
IconButton{
|
||||
id:btn_maximize
|
||||
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 fixSize: 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 {
|
||||
title: root.title
|
||||
height: 30
|
||||
@ -39,4 +47,140 @@ Quick.Window {
|
||||
Quick.Component.onCompleted: {
|
||||
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