diff --git a/example/AboutPage.qml b/example/AboutPage.qml index 739f0374..3f6f2c0f 100644 --- a/example/AboutPage.qml +++ b/example/AboutPage.qml @@ -6,8 +6,11 @@ FluWindow { width: 500 height: 600 - minimumWidth: 300 - minimumHeight: 400 + minimumWidth: 500 + minimumHeight: 600 + maximumWidth: 500 + maximumHeight: 600 + title:"关于" FluAppBar{ diff --git a/example/MainPage.qml b/example/MainPage.qml index 3637d4d8..6f89eed3 100644 --- a/example/MainPage.qml +++ b/example/MainPage.qml @@ -18,7 +18,6 @@ FluWindow { id:appbar title: "FluentUI" showDark: true - showFps: true } ListModel{ diff --git a/example/T_Buttons.qml b/example/T_Buttons.qml index bdc0f7e5..5733f28b 100644 --- a/example/T_Buttons.qml +++ b/example/T_Buttons.qml @@ -127,6 +127,30 @@ Item { text:"Disabled" } } + FluDivider{ + Layout.fillWidth: true ; height:1 + } + RowLayout{ + Layout.topMargin: 20 + width: parent.width + FluCheckBox{ + disabled:icon_button_check.checked + } + Item{ + height: 1 + Layout.fillWidth: true + } + FluToggleSwitch{ + id:icon_button_check + Layout.alignment: Qt.AlignRight + } + FluText{ + text:"Disabled" + } + } + FluDivider{ + Layout.fillWidth: true ; height:1 + } } } } diff --git a/example/T_Theme.qml b/example/T_Theme.qml index 0ff23f73..970c051d 100644 --- a/example/T_Theme.qml +++ b/example/T_Theme.qml @@ -59,6 +59,17 @@ Item { FluTheme.isDark = !FluTheme.isDark } } + FluText{ + text:"无边框" + fontStyle: FluText.Subtitle + Layout.topMargin: 20 + } + FluToggleSwitch{ + checked: FluTheme.isFrameless + onClickFunc:function(){ + FluTheme.isFrameless = !FluTheme.isFrameless + } + } } } } diff --git a/src/FluTheme.cpp b/src/FluTheme.cpp index 7f455b46..d290eadd 100644 --- a/src/FluTheme.cpp +++ b/src/FluTheme.cpp @@ -16,5 +16,6 @@ FluTheme::FluTheme(QObject *parent) : QObject{parent} { primaryColor(FluColors::getInstance()->Blue()); + isFrameless(true); isDark(false); } diff --git a/src/FluTheme.h b/src/FluTheme.h index 6fb21505..0b88a7f2 100644 --- a/src/FluTheme.h +++ b/src/FluTheme.h @@ -9,6 +9,7 @@ class FluTheme : public QObject { Q_OBJECT Q_PROPERTY_AUTO(FluColorSet*,primaryColor) + Q_PROPERTY_AUTO(bool,isFrameless); Q_PROPERTY_AUTO(bool,isDark); public: explicit FluTheme(QObject *parent = nullptr); diff --git a/src/FluentUI.pro b/src/FluentUI.pro index 9b84e074..9476f93f 100644 --- a/src/FluentUI.pro +++ b/src/FluentUI.pro @@ -38,13 +38,8 @@ win32 { SOURCES += \ FramelessView_win.cpp } else { - macos { - SOURCES += \ - FramelessView_mac.cpp - }else{ SOURCES += \ FramelessView_unix.cpp - } } DEFINES += VERSION_IN=\\\"1.0.0\\\" diff --git a/src/FramelessView.h b/src/FramelessView.h index f129e2fa..a120307d 100644 --- a/src/FramelessView.h +++ b/src/FramelessView.h @@ -21,6 +21,7 @@ public: void closeDeleteLater(); bool isMax() const; bool isFull() const; + void refreshWindow(); QQuickItem *titleItem() const; static QMap *windowCache; @@ -38,6 +39,7 @@ signals: protected: void showEvent(QShowEvent *e) override; void resizeEvent(QResizeEvent *e) override; + bool event(QEvent *ev) override; # if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override; # else diff --git a/src/FramelessView_mac.cpp b/src/FramelessView_mac.cpp deleted file mode 100644 index c35d418f..00000000 --- a/src/FramelessView_mac.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "FramelessView.h" -#include -#include -#include -#include - -class FramelessViewPrivate -{ -public: - bool m_isMax = false; - bool m_isFull = false; - bool m_deleteLater = false; - QQuickItem *m_titleItem = nullptr; -}; -FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) -{ -// setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - setResizeMode(SizeRootObjectToView); - setIsMax(windowState() == Qt::WindowMaximized); - setIsFull(windowState() == Qt::WindowFullScreen); - connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) { - (void)state; - setIsMax(windowState() == Qt::WindowMaximized); - setIsFull(windowState() == Qt::WindowFullScreen); - }); -} -FramelessView::~FramelessView() -{ - delete d; -} -void FramelessView::showEvent(QShowEvent *e) -{ - Super::showEvent(e); -} -QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) -{ - int w = normalSize.width(); - int h = normalSize.height(); - int x = screenGeo.x() + (screenGeo.width() - w) / 2; - int y = screenGeo.y() + (screenGeo.height() - h) / 2; - if (screenGeo.width() < w) { - x = screenGeo.x(); - w = screenGeo.width(); - } - if (screenGeo.height() < h) { - y = screenGeo.y(); - h = screenGeo.height(); - } - - return { x, y, w, h }; -} -void FramelessView::moveToScreenCenter() -{ - auto geo = calcCenterGeo(screen()->availableGeometry(), size()); - if (minimumWidth() > geo.width() || minimumHeight() > geo.height()) { - setMinimumSize(geo.size()); - } - setGeometry(geo); - update(); -} -void FramelessView::closeDeleteLater(){ - d->m_deleteLater = true; -} - -bool FramelessView::isMax() const -{ - return d->m_isMax; -} -bool FramelessView::isFull() const -{ - return d->m_isFull; -} -QQuickItem *FramelessView::titleItem() const -{ - return d->m_titleItem; -} -void FramelessView::setIsMax(bool isMax) -{ - if (d->m_isMax == isMax) - return; - - d->m_isMax = isMax; - emit isMaxChanged(d->m_isMax); -} -void FramelessView::setIsFull(bool isFull) -{ - if(d->m_isFull == isFull) - return; - - d->m_isFull = isFull; - emit isFullChanged(d->m_isFull); -} -void FramelessView::setTitleItem(QQuickItem *item) -{ - d->m_titleItem = item; -} -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) -#else -bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result) -#endif -{ - return Super::nativeEvent(eventType, message, result); -} - -void FramelessView::resizeEvent(QResizeEvent *e) -{ - Super::resizeEvent(e); -} diff --git a/src/FramelessView_unix.cpp b/src/FramelessView_unix.cpp index e0a22f6d..d19067cd 100644 --- a/src/FramelessView_unix.cpp +++ b/src/FramelessView_unix.cpp @@ -3,6 +3,7 @@ #include #include #include +#include class FramelessViewPrivate { @@ -12,10 +13,10 @@ public: bool m_deleteLater = false; QQuickItem *m_titleItem = nullptr; }; + FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) { -// setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - setResizeMode(SizeRootObjectToView); + refreshWindow(); setIsMax(windowState() == Qt::WindowMaximized); setIsFull(windowState() == Qt::WindowFullScreen); connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) { @@ -23,15 +24,31 @@ FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessVi setIsMax(windowState() == Qt::WindowMaximized); setIsFull(windowState() == Qt::WindowFullScreen); }); + connect(FluTheme::getInstance(),&FluTheme::isFramelessChanged,this,[=](){ + refreshWindow(); + }); } + +void FramelessView::refreshWindow(){ + if(FluTheme::getInstance()->isFrameless()){ + setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + }else{ + setFlags(Qt::Window); + } + setResizeMode(SizeViewToRootObject); + setResizeMode(SizeRootObjectToView); +} + FramelessView::~FramelessView() { delete d; } + void FramelessView::showEvent(QShowEvent *e) { Super::showEvent(e); } + QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) { int w = normalSize.width(); @@ -46,9 +63,9 @@ QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSi y = screenGeo.y(); h = screenGeo.height(); } - return { x, y, w, h }; } + void FramelessView::moveToScreenCenter() { auto geo = calcCenterGeo(screen()->availableGeometry(), size()); @@ -58,6 +75,7 @@ void FramelessView::moveToScreenCenter() setGeometry(geo); update(); } + void FramelessView::closeDeleteLater(){ d->m_deleteLater = true; } @@ -66,14 +84,17 @@ bool FramelessView::isMax() const { return d->m_isMax; } + bool FramelessView::isFull() const { return d->m_isFull; } + QQuickItem *FramelessView::titleItem() const { return d->m_titleItem; } + void FramelessView::setIsMax(bool isMax) { if (d->m_isMax == isMax) @@ -82,6 +103,7 @@ void FramelessView::setIsMax(bool isMax) d->m_isMax = isMax; emit isMaxChanged(d->m_isMax); } + void FramelessView::setIsFull(bool isFull) { if(d->m_isFull == isFull) @@ -90,6 +112,7 @@ void FramelessView::setIsFull(bool isFull) d->m_isFull = isFull; emit isFullChanged(d->m_isFull); } + void FramelessView::setTitleItem(QQuickItem *item) { d->m_titleItem = item; @@ -107,3 +130,15 @@ void FramelessView::resizeEvent(QResizeEvent *e) { Super::resizeEvent(e); } + +bool FramelessView::event(QEvent *ev) +{ + if (ev->type() == QEvent::Close) { + if(d->m_deleteLater){ + deleteLater(); + ev->setAccepted(false); + } + } + return QQuickWindow::event(ev); +} + diff --git a/src/FramelessView_win.cpp b/src/FramelessView_win.cpp index ae53d3e2..d19067cd 100644 --- a/src/FramelessView_win.cpp +++ b/src/FramelessView_win.cpp @@ -3,27 +3,7 @@ #include #include #include - -#include -#include -#include -#include // Fixes error C2504: 'IUnknown' : base class undefined -#include -#include -#include -#pragma comment(lib, "Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved -#pragma comment(lib, "User32.lib") -#pragma comment(lib, "Gdi32.lib") - -static bool isMaxWin(QWindow* win) -{ - return win->windowState() == Qt::WindowMaximized; -} -static bool isFullWin(QQuickView* win) -{ - return win->windowState() == Qt::WindowFullScreen; -} - +#include class FramelessViewPrivate { @@ -33,10 +13,10 @@ public: bool m_deleteLater = false; QQuickItem *m_titleItem = nullptr; }; + FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) { - setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - setResizeMode(SizeRootObjectToView); + refreshWindow(); setIsMax(windowState() == Qt::WindowMaximized); setIsFull(windowState() == Qt::WindowFullScreen); connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) { @@ -44,15 +24,31 @@ FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessVi setIsMax(windowState() == Qt::WindowMaximized); setIsFull(windowState() == Qt::WindowFullScreen); }); + connect(FluTheme::getInstance(),&FluTheme::isFramelessChanged,this,[=](){ + refreshWindow(); + }); } + +void FramelessView::refreshWindow(){ + if(FluTheme::getInstance()->isFrameless()){ + setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + }else{ + setFlags(Qt::Window); + } + setResizeMode(SizeViewToRootObject); + setResizeMode(SizeRootObjectToView); +} + FramelessView::~FramelessView() { delete d; } + void FramelessView::showEvent(QShowEvent *e) { Super::showEvent(e); } + QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) { int w = normalSize.width(); @@ -67,9 +63,9 @@ QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSi y = screenGeo.y(); h = screenGeo.height(); } - return { x, y, w, h }; } + void FramelessView::moveToScreenCenter() { auto geo = calcCenterGeo(screen()->availableGeometry(), size()); @@ -79,6 +75,7 @@ void FramelessView::moveToScreenCenter() setGeometry(geo); update(); } + void FramelessView::closeDeleteLater(){ d->m_deleteLater = true; } @@ -87,14 +84,17 @@ bool FramelessView::isMax() const { return d->m_isMax; } + bool FramelessView::isFull() const { return d->m_isFull; } + QQuickItem *FramelessView::titleItem() const { return d->m_titleItem; } + void FramelessView::setIsMax(bool isMax) { if (d->m_isMax == isMax) @@ -103,6 +103,7 @@ void FramelessView::setIsMax(bool isMax) d->m_isMax = isMax; emit isMaxChanged(d->m_isMax); } + void FramelessView::setIsFull(bool isFull) { if(d->m_isFull == isFull) @@ -111,6 +112,7 @@ void FramelessView::setIsFull(bool isFull) d->m_isFull = isFull; emit isFullChanged(d->m_isFull); } + void FramelessView::setTitleItem(QQuickItem *item) { d->m_titleItem = item; @@ -121,44 +123,6 @@ bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qint bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result) #endif { -#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1)) - // Work-around a bug caused by typo which only exists in Qt 5.11.1 - const auto msg = *reinterpret_cast(message); -#else - const auto msg = static_cast(message); -#endif - if (!msg || !msg->hwnd) - { - return false; - } - switch (msg->message) - { - case WM_NCCALCSIZE: { - const auto mode = static_cast(msg->wParam); - const auto clientRect = mode ? &(reinterpret_cast(msg->lParam)->rgrc[0]) : reinterpret_cast(msg->lParam); - if (mode == TRUE) - { - *result = WVR_REDRAW; - //规避 拖动border进行resize时界面闪烁 - if (!isMaxWin(this) && !isFullWin(this)) - { - if (clientRect->top != 0) - { - clientRect->top -= 0.1; - } - } - else - { - if (clientRect->top != 0) - { - clientRect->top += 0.1; - } - } - return true; - } - break; - } - } return Super::nativeEvent(eventType, message, result); } @@ -166,3 +130,15 @@ void FramelessView::resizeEvent(QResizeEvent *e) { Super::resizeEvent(e); } + +bool FramelessView::event(QEvent *ev) +{ + if (ev->type() == QEvent::Close) { + if(d->m_deleteLater){ + deleteLater(); + ev->setAccepted(false); + } + } + return QQuickWindow::event(ev); +} + diff --git a/src/controls/FluAppBar.qml b/src/controls/FluAppBar.qml index f7616629..6e140e5b 100644 --- a/src/controls/FluAppBar.qml +++ b/src/controls/FluAppBar.qml @@ -13,8 +13,8 @@ Rectangle{ return borerlessColor return Window.window.active ? borerlessColor : Qt.lighter(borerlessColor,1.1) } - property bool isMacos: Qt.platform.os === "osx" - height: isMacos ? 0 : 50 + visible: FluTheme.isFrameless + height: visible ? 50 : 0 width: { if(parent==null) return 200 diff --git a/src/controls/FluButton.qml b/src/controls/FluButton.qml index 27249654..41b82c4d 100644 --- a/src/controls/FluButton.qml +++ b/src/controls/FluButton.qml @@ -62,9 +62,8 @@ Rectangle { id:button_mouse anchors.fill: parent hoverEnabled: true + enabled: !disabled onClicked: { - if(disabled) - return button.clicked() } } diff --git a/src/controls/FluCheckBox.qml b/src/controls/FluCheckBox.qml index 38b2fb33..4e6fecc0 100644 --- a/src/controls/FluCheckBox.qml +++ b/src/controls/FluCheckBox.qml @@ -9,9 +9,23 @@ Item { property string text: "Check Box" property var checkClicked property bool hovered: mouse_area.containsMouse + + property bool disabled: false + width: childrenRect.width height: childrenRect.height + property color borderNormalColor: FluTheme.isDark ? Qt.rgba(160/255,160/255,160/255,1) : Qt.rgba(136/255,136/255,136/255,1) + property color borderCheckedColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + property color borderHoverColor: FluTheme.isDark ? Qt.rgba(167/255,167/255,167/255,1) : Qt.rgba(135/255,135/255,135/255,1) + + + property color normalColor: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(247/255,247/255,247/255,1) + property color checkedColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + property color hoverColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(244/255,244/255,244/255,1) + + property color checkedHoverColor: FluTheme.isDark ? Qt.darker(checkedColor,1.1) : Qt.lighter(checkedColor,1.1) + RowLayout{ spacing: 4 Rectangle{ @@ -19,46 +33,26 @@ Item { height: 22 radius: 4 border.color: { - if(FluTheme.isDark){ - if(checked){ - return FluTheme.primaryColor.lighter - } - return Qt.rgba(160/255,160/255,160/255,1) - }else{ - if(checked){ - if(mouse_area.containsMouse){ - return Qt.rgba(25/255,117/255,187/255,1) - } - return FluTheme.primaryColor.dark - } - return Qt.rgba(136/255,136/255,136/255,1) + if(checked){ + return borderCheckedColor } + if(hovered){ + return borderHoverColor + } + return borderNormalColor } border.width: 1 color: { - if(FluTheme.isDark){ - if(checked){ - if(mouse_area.containsMouse){ - return Qt.rgba(74/255,149/255,207/255,1) - } - return FluTheme.primaryColor.lighter + if(checked){ + if(hovered){ + return checkedHoverColor } - if(mouse_area.containsMouse){ - return Qt.rgba(62/255,62/255,62/255,1) - } - return Qt.rgba(45/255,45/255,45/255,1) - }else{ - if(checked){ - if(mouse_area.containsMouse){ - return Qt.rgba(25/255,117/255,187/255,1) - } - return FluTheme.primaryColor.dark - } - if(mouse_area.containsMouse){ - return Qt.rgba(244/255,244/255,244/255,1) - } - return Qt.rgba(247/255,247/255,247/255,1) + return checkedColor } + if(hovered){ + return hoverColor + } + return normalColor } FluIcon { @@ -79,6 +73,7 @@ Item { id:mouse_area anchors.fill: parent hoverEnabled: true + enabled: !disabled onClicked: { if(checkClicked){ checkClicked() diff --git a/src/controls/FluWindow.qml b/src/controls/FluWindow.qml index 69840e90..15cda4db 100644 --- a/src/controls/FluWindow.qml +++ b/src/controls/FluWindow.qml @@ -21,10 +21,8 @@ Item { property int minimumHeight property int maximumHeight - property bool isMacos: Qt.platform.os === "osx" - property int borderless:{ - if(isMacos){ + if(!FluTheme.isFrameless){ return 0 } if(window === null) @@ -34,6 +32,7 @@ Item { } return 4 } + default property alias content: container.data FluWindowResize{ @@ -51,7 +50,7 @@ Item { color: { if(window === null) return borerlessColor - return window.active ? borerlessColor : Qt.lighter(borerlessColor,1.1) + return window.active ? borerlessColor : Qt.lighter(borerlessColor,1.1) } border.width: 1 anchors.fill: parent