From 464e2af51550686d35f3ec81d2bc9cd9e28958b2 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Wed, 6 Jul 2022 14:24:41 +0800 Subject: [PATCH] finish the chrome palette implementation And with some other minor tweaks that improve user experience. Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- examples/mainwindow/mainwindow.cpp | 19 +++ include/FramelessHelper/Core/chromepalette.h | 21 +++ .../Core/framelesshelper_windows.h | 14 +- .../Core/private/chromepalette_p.h | 11 +- .../FramelessHelper/Quick/QuickChromePalette | 1 + .../Quick/framelesshelperquick_global.h | 14 -- .../Quick/private/quickstandardtitlebar_p.h | 1 + .../Quick/quickchromepalette.h | 48 +++++++ .../Widgets/private/standardtitlebar_p.h | 5 - .../Widgets/standardtitlebar.h | 3 - src/core/chromepalette.cpp | 129 +++++++++++++++++- src/core/utils_win.cpp | 8 +- src/quick/CMakeLists.txt | 2 + src/quick/framelessquickmodule.cpp | 7 +- src/quick/quickchromepalette.cpp | 35 +++++ src/quick/quickchromepalette.h | 1 + src/quick/quickstandardtitlebar.cpp | 7 +- src/widgets/standardtitlebar.cpp | 120 ++++++++-------- 18 files changed, 339 insertions(+), 107 deletions(-) create mode 100644 include/FramelessHelper/Quick/QuickChromePalette create mode 100644 include/FramelessHelper/Quick/quickchromepalette.h create mode 100644 src/quick/quickchromepalette.cpp create mode 100644 src/quick/quickchromepalette.h diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 9b98b0b..c720ae3 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -68,10 +68,29 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::initialize() { m_titleBar.reset(new StandardTitleBar(this)); + m_titleBar->setTitleLabelAlignment(Qt::AlignCenter); m_mainWindow.reset(new Ui::MainWindow); m_mainWindow->setupUi(this); QMenuBar * const mb = menuBar(); + mb->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + mb->setStyleSheet(FRAMELESSHELPER_STRING_LITERAL(R"( +QMenuBar { + background-color: transparent; +} + +QMenuBar::item { + background: transparent; +} + +QMenuBar::item:selected { + background: #a8a8a8; +} + +QMenuBar::item:pressed { + background: #888888; +} + )")); const auto titleBarLayout = static_cast(m_titleBar->layout()); titleBarLayout->insertWidget(0, mb); diff --git a/include/FramelessHelper/Core/chromepalette.h b/include/FramelessHelper/Core/chromepalette.h index fcc64d4..e88ba6f 100644 --- a/include/FramelessHelper/Core/chromepalette.h +++ b/include/FramelessHelper/Core/chromepalette.h @@ -58,6 +58,15 @@ class FRAMELESSHELPER_CORE_API ChromePalette : public QObject Q_PROPERTY(QColor chromeButtonPressColor READ chromeButtonPressColor WRITE setChromeButtonPressColor RESET resetChromeButtonPressColor NOTIFY chromeButtonPressColorChanged FINAL) + Q_PROPERTY(QColor closeButtonNormalColor READ closeButtonNormalColor + WRITE setCloseButtonNormalColor RESET resetCloseButtonNormalColor + NOTIFY closeButtonNormalColorChanged FINAL) + Q_PROPERTY(QColor closeButtonHoverColor READ closeButtonHoverColor + WRITE setCloseButtonHoverColor RESET resetCloseButtonHoverColor + NOTIFY closeButtonHoverColorChanged FINAL) + Q_PROPERTY(QColor closeButtonPressColor READ closeButtonPressColor + WRITE setCloseButtonPressColor RESET resetCloseButtonPressColor + NOTIFY closeButtonPressColorChanged FINAL) public: explicit ChromePalette(QObject *parent = nullptr); @@ -70,6 +79,9 @@ public: Q_NODISCARD QColor chromeButtonNormalColor() const; Q_NODISCARD QColor chromeButtonHoverColor() const; Q_NODISCARD QColor chromeButtonPressColor() const; + Q_NODISCARD QColor closeButtonNormalColor() const; + Q_NODISCARD QColor closeButtonHoverColor() const; + Q_NODISCARD QColor closeButtonPressColor() const; public Q_SLOTS: void setTitleBarActiveBackgroundColor(const QColor &value); @@ -86,6 +98,12 @@ public Q_SLOTS: void resetChromeButtonHoverColor(); void setChromeButtonPressColor(const QColor &value); void resetChromeButtonPressColor(); + void setCloseButtonNormalColor(const QColor &value); + void resetCloseButtonNormalColor(); + void setCloseButtonHoverColor(const QColor &value); + void resetCloseButtonHoverColor(); + void setCloseButtonPressColor(const QColor &value); + void resetCloseButtonPressColor(); Q_SIGNALS: void titleBarActiveBackgroundColorChanged(); @@ -95,6 +113,9 @@ Q_SIGNALS: void chromeButtonNormalColorChanged(); void chromeButtonHoverColorChanged(); void chromeButtonPressColorChanged(); + void closeButtonNormalColorChanged(); + void closeButtonHoverColorChanged(); + void closeButtonPressColorChanged(); void titleBarColorChanged(); void chromeButtonColorChanged(); diff --git a/include/FramelessHelper/Core/framelesshelper_windows.h b/include/FramelessHelper/Core/framelesshelper_windows.h index fc945c4..62ed8e4 100644 --- a/include/FramelessHelper/Core/framelesshelper_windows.h +++ b/include/FramelessHelper/Core/framelesshelper_windows.h @@ -188,12 +188,12 @@ using MONITOR_DPI_TYPE = enum MONITOR_DPI_TYPE using _DWMWINDOWATTRIBUTE = enum _DWMWINDOWATTRIBUTE { - _DWMWA_USE_HOSTBACKDROPBRUSH = 17, + _DWMWA_USE_HOSTBACKDROPBRUSH = 17, // [set] BOOL, Allows the use of host backdrop brushes for the window. _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, // Undocumented - _DWMWA_USE_IMMERSIVE_DARK_MODE = 20, - _DWMWA_WINDOW_CORNER_PREFERENCE = 33, - _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37, - _DWMWA_SYSTEMBACKDROP_TYPE = 38, + _DWMWA_USE_IMMERSIVE_DARK_MODE = 20, // [set] BOOL, Allows a window to either use the accent color, or dark, according to the user Color Mode preferences. + _DWMWA_WINDOW_CORNER_PREFERENCE = 33, // [set] WINDOW_CORNER_PREFERENCE, Controls the policy that rounds top-level window corners + _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37, // [get] UINT, width of the visible border around a thick frame window + _DWMWA_SYSTEMBACKDROP_TYPE = 38, // [get, set] SYSTEMBACKDROP_TYPE, Controls the system-drawn backdrop material of a window, including behind the non-client area. _DWMWA_MICA_EFFECT = 1029 // Undocumented }; @@ -254,10 +254,10 @@ using ACCENT_STATE = enum ACCENT_STATE ACCENT_DISABLED = 0, ACCENT_ENABLE_GRADIENT = 1, ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_ENABLE_BLURBEHIND = 3, // Traditional DWM blur ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 ACCENT_USE_HOST_BACKDROP = 5, // RS5 1809 - ACCENT_INVALID_STATE = 6 + ACCENT_INVALID_STATE = 6 // Using this value will remove the window background }; using ACCENT_POLICY = struct ACCENT_POLICY diff --git a/include/FramelessHelper/Core/private/chromepalette_p.h b/include/FramelessHelper/Core/private/chromepalette_p.h index a9c8394..439c0ab 100644 --- a/include/FramelessHelper/Core/private/chromepalette_p.h +++ b/include/FramelessHelper/Core/private/chromepalette_p.h @@ -47,7 +47,10 @@ public: TitleBarInactiveForegroundColor = 0x00000008, ChromeButtonNormalColor = 0x00000010, ChromeButtonHoverColor = 0x00000020, - ChromeButtonPressColor = 0x00000040 + ChromeButtonPressColor = 0x00000040, + CloseButtonNormalColor = 0x00000080, + CloseButtonHoverColor = 0x00000100, + CloseButtonPressColor = 0x00000200 }; Q_ENUM(MaskFlag) Q_DECLARE_FLAGS(Mask, MaskFlag) @@ -73,6 +76,9 @@ private: QColor chromeButtonNormalColor_sys = {}; QColor chromeButtonHoverColor_sys = {}; QColor chromeButtonPressColor_sys = {}; + QColor closeButtonNormalColor_sys = {}; + QColor closeButtonHoverColor_sys = {}; + QColor closeButtonPressColor_sys = {}; // User-defined ones: QColor titleBarActiveBackgroundColor = {}; QColor titleBarInactiveBackgroundColor = {}; @@ -81,6 +87,9 @@ private: QColor chromeButtonNormalColor = {}; QColor chromeButtonHoverColor = {}; QColor chromeButtonPressColor = {}; + QColor closeButtonNormalColor = {}; + QColor closeButtonHoverColor = {}; + QColor closeButtonPressColor = {}; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ChromePalettePrivate::Mask) diff --git a/include/FramelessHelper/Quick/QuickChromePalette b/include/FramelessHelper/Quick/QuickChromePalette new file mode 100644 index 0000000..1bafea7 --- /dev/null +++ b/include/FramelessHelper/Quick/QuickChromePalette @@ -0,0 +1 @@ +#include diff --git a/include/FramelessHelper/Quick/framelesshelperquick_global.h b/include/FramelessHelper/Quick/framelesshelperquick_global.h index d6b7841..d1ef98f 100644 --- a/include/FramelessHelper/Quick/framelesshelperquick_global.h +++ b/include/FramelessHelper/Quick/framelesshelperquick_global.h @@ -25,7 +25,6 @@ #pragma once #include -#include #if __has_include() # include #else @@ -191,17 +190,4 @@ private: #endif }; -class FRAMELESSHELPER_QUICK_API QuickChromePalette : public ChromePalette -{ - Q_OBJECT -#ifdef QML_ANONYMOUS - QML_ANONYMOUS -#endif - Q_DISABLE_COPY_MOVE(QuickChromePalette) - -public: - explicit QuickChromePalette(QObject *parent = nullptr); - ~QuickChromePalette() override; -}; - FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/private/quickstandardtitlebar_p.h b/include/FramelessHelper/Quick/private/quickstandardtitlebar_p.h index db71205..bc97372 100644 --- a/include/FramelessHelper/Quick/private/quickstandardtitlebar_p.h +++ b/include/FramelessHelper/Quick/private/quickstandardtitlebar_p.h @@ -26,6 +26,7 @@ #include "framelesshelperquick_global.h" #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +#include "quickchromepalette.h" #include #include diff --git a/include/FramelessHelper/Quick/quickchromepalette.h b/include/FramelessHelper/Quick/quickchromepalette.h new file mode 100644 index 0000000..f34e8b6 --- /dev/null +++ b/include/FramelessHelper/Quick/quickchromepalette.h @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include "framelesshelperquick_global.h" +#include +#include + +FRAMELESSHELPER_BEGIN_NAMESPACE + +class FRAMELESSHELPER_QUICK_API QuickChromePalette : public ChromePalette +{ + Q_OBJECT +#ifdef QML_ANONYMOUS + QML_ANONYMOUS +#endif + Q_DISABLE_COPY_MOVE(QuickChromePalette) + +public: + explicit QuickChromePalette(QObject *parent = nullptr); + ~QuickChromePalette() override; +}; + +FRAMELESSHELPER_END_NAMESPACE + +QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickChromePalette)) diff --git a/include/FramelessHelper/Widgets/private/standardtitlebar_p.h b/include/FramelessHelper/Widgets/private/standardtitlebar_p.h index d408983..f753432 100644 --- a/include/FramelessHelper/Widgets/private/standardtitlebar_p.h +++ b/include/FramelessHelper/Widgets/private/standardtitlebar_p.h @@ -29,8 +29,6 @@ #include QT_BEGIN_NAMESPACE -class QLabel; -class QSpacerItem; class QPaintEvent; QT_END_NAMESPACE @@ -80,15 +78,12 @@ private: private: QPointer q_ptr = nullptr; - QScopedPointer m_windowTitleLabel; QScopedPointer m_minimizeButton; QScopedPointer m_maximizeButton; QScopedPointer m_closeButton; QPointer m_window = nullptr; bool m_extended = false; Qt::Alignment m_labelAlignment = {}; - QSpacerItem *m_labelLeftStretch = nullptr; - QSpacerItem *m_labelRightStretch = nullptr; bool m_hideWhenClose = false; QScopedPointer m_chromePalette; }; diff --git a/include/FramelessHelper/Widgets/standardtitlebar.h b/include/FramelessHelper/Widgets/standardtitlebar.h index 6bd3b4b..48b4750 100644 --- a/include/FramelessHelper/Widgets/standardtitlebar.h +++ b/include/FramelessHelper/Widgets/standardtitlebar.h @@ -27,7 +27,6 @@ #include "framelesshelperwidgets_global.h" #include #include -#include FRAMELESSHELPER_BEGIN_NAMESPACE @@ -40,7 +39,6 @@ class FRAMELESSHELPER_WIDGETS_API StandardTitleBar : public QWidget Q_DECLARE_PRIVATE(StandardTitleBar) Q_DISABLE_COPY_MOVE(StandardTitleBar) Q_PROPERTY(Qt::Alignment titleLabelAlignment READ titleLabelAlignment WRITE setTitleLabelAlignment NOTIFY titleLabelAlignmentChanged FINAL) - Q_PROPERTY(QLabel* titleLabel READ titleLabel CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* minimizeButton READ minimizeButton CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* maximizeButton READ maximizeButton CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* closeButton READ closeButton CONSTANT FINAL) @@ -55,7 +53,6 @@ public: Q_NODISCARD Qt::Alignment titleLabelAlignment() const; void setTitleLabelAlignment(const Qt::Alignment value); - Q_NODISCARD QLabel *titleLabel() const; Q_NODISCARD StandardSystemButton *minimizeButton() const; Q_NODISCARD StandardSystemButton *maximizeButton() const; Q_NODISCARD StandardSystemButton *closeButton() const; diff --git a/src/core/chromepalette.cpp b/src/core/chromepalette.cpp index 1d17a61..226f0fc 100644 --- a/src/core/chromepalette.cpp +++ b/src/core/chromepalette.cpp @@ -83,14 +83,31 @@ void ChromePalettePrivate::refresh() } }(); titleBarInactiveBackgroundColor_sys = (dark ? kDefaultSystemDarkColor : kDefaultWhiteColor); - // ### TODO: Use dark/light color if background color is light/dark. - titleBarActiveForegroundColor_sys = ((dark || colorized) ? kDefaultWhiteColor : kDefaultBlackColor); + titleBarActiveForegroundColor_sys = [this, dark, colorized]() -> QColor { + if (dark || colorized) { + // Calculate the most appropriate foreground color, based on the + // current background color. + const qreal grayF = ( + (0.299 * titleBarActiveBackgroundColor_sys.redF()) + + (0.587 * titleBarActiveBackgroundColor_sys.greenF()) + + (0.114 * titleBarActiveBackgroundColor_sys.blueF())); + if (grayF <= 0.5) { + return kDefaultWhiteColor; + } + } + return kDefaultBlackColor; + }(); titleBarInactiveForegroundColor_sys = kDefaultDarkGrayColor; chromeButtonNormalColor_sys = kDefaultTransparentColor; chromeButtonHoverColor_sys = Utils::calculateSystemButtonBackgroundColor(SystemButtonType::Minimize, ButtonState::Hovered); chromeButtonPressColor_sys = Utils::calculateSystemButtonBackgroundColor(SystemButtonType::Minimize, ButtonState::Pressed); + closeButtonNormalColor_sys = kDefaultTransparentColor; + closeButtonHoverColor_sys = + Utils::calculateSystemButtonBackgroundColor(SystemButtonType::Close, ButtonState::Hovered); + closeButtonPressColor_sys = + Utils::calculateSystemButtonBackgroundColor(SystemButtonType::Close, ButtonState::Pressed); Q_Q(ChromePalette); Q_EMIT q->titleBarActiveBackgroundColorChanged(); Q_EMIT q->titleBarInactiveBackgroundColorChanged(); @@ -99,11 +116,15 @@ void ChromePalettePrivate::refresh() Q_EMIT q->chromeButtonNormalColorChanged(); Q_EMIT q->chromeButtonHoverColorChanged(); Q_EMIT q->chromeButtonPressColorChanged(); + Q_EMIT q->closeButtonNormalColorChanged(); + Q_EMIT q->closeButtonHoverColorChanged(); + Q_EMIT q->closeButtonPressColorChanged(); Q_EMIT q->titleBarColorChanged(); Q_EMIT q->chromeButtonColorChanged(); } -ChromePalette::ChromePalette(QObject *parent) : QObject(parent), d_ptr(new ChromePalettePrivate(this)) +ChromePalette::ChromePalette(QObject *parent) : + QObject(parent), d_ptr(new ChromePalettePrivate(this)) { } @@ -172,6 +193,33 @@ QColor ChromePalette::chromeButtonPressColor() const return d->chromeButtonPressColor_sys; } +QColor ChromePalette::closeButtonNormalColor() const +{ + Q_D(const ChromePalette); + if (d->mask & ChromePalettePrivate::MaskFlag::CloseButtonNormalColor) { + return d->closeButtonNormalColor; + } + return d->closeButtonNormalColor_sys; +} + +QColor ChromePalette::closeButtonHoverColor() const +{ + Q_D(const ChromePalette); + if (d->mask & ChromePalettePrivate::MaskFlag::CloseButtonHoverColor) { + return d->closeButtonHoverColor; + } + return d->closeButtonHoverColor_sys; +} + +QColor ChromePalette::closeButtonPressColor() const +{ + Q_D(const ChromePalette); + if (d->mask & ChromePalettePrivate::MaskFlag::CloseButtonPressColor) { + return d->closeButtonPressColor; + } + return d->closeButtonPressColor_sys; +} + void ChromePalette::setTitleBarActiveBackgroundColor(const QColor &value) { Q_ASSERT(value.isValid()); @@ -347,4 +395,79 @@ void ChromePalette::resetChromeButtonPressColor() Q_EMIT chromeButtonColorChanged(); } +void ChromePalette::setCloseButtonNormalColor(const QColor &value) +{ + Q_ASSERT(value.isValid()); + if (!value.isValid()) { + return; + } + Q_D(ChromePalette); + if (d->closeButtonNormalColor == value) { + return; + } + d->closeButtonNormalColor = value; + d->mask |= ChromePalettePrivate::MaskFlag::CloseButtonNormalColor; + Q_EMIT closeButtonNormalColorChanged(); + Q_EMIT chromeButtonColorChanged(); +} + +void ChromePalette::resetCloseButtonNormalColor() +{ + Q_D(ChromePalette); + d->closeButtonNormalColor = {}; + d->mask &= ~ChromePalettePrivate::Mask(ChromePalettePrivate::MaskFlag::CloseButtonNormalColor); + Q_EMIT closeButtonNormalColorChanged(); + Q_EMIT chromeButtonColorChanged(); +} + +void ChromePalette::setCloseButtonHoverColor(const QColor &value) +{ + Q_ASSERT(value.isValid()); + if (!value.isValid()) { + return; + } + Q_D(ChromePalette); + if (d->closeButtonHoverColor == value) { + return; + } + d->closeButtonHoverColor = value; + d->mask |= ChromePalettePrivate::MaskFlag::CloseButtonHoverColor; + Q_EMIT closeButtonHoverColorChanged(); + Q_EMIT chromeButtonColorChanged(); +} + +void ChromePalette::resetCloseButtonHoverColor() +{ + Q_D(ChromePalette); + d->closeButtonHoverColor = {}; + d->mask &= ~ChromePalettePrivate::Mask(ChromePalettePrivate::MaskFlag::CloseButtonHoverColor); + Q_EMIT closeButtonHoverColorChanged(); + Q_EMIT chromeButtonColorChanged(); +} + +void ChromePalette::setCloseButtonPressColor(const QColor &value) +{ + Q_ASSERT(value.isValid()); + if (!value.isValid()) { + return; + } + Q_D(ChromePalette); + if (d->closeButtonPressColor == value) { + return; + } + d->closeButtonPressColor = value; + d->mask |= ChromePalettePrivate::MaskFlag::CloseButtonPressColor; + Q_EMIT closeButtonPressColorChanged(); + Q_EMIT chromeButtonColorChanged(); +} + +void ChromePalette::resetCloseButtonPressColor() +{ + Q_D(ChromePalette); + d->closeButtonPressColor = {}; + d->mask &= ~ChromePalettePrivate::Mask(ChromePalettePrivate::MaskFlag::CloseButtonPressColor); + Q_EMIT closeButtonPressColorChanged(); + Q_EMIT chromeButtonColorChanged(); +} + FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 72ee83c..ab582d2 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -1324,8 +1324,12 @@ void Utils::tryToEnableHighestDpiAwarenessLevel() return; } } - if (SetProcessDPIAware() == FALSE) { - qWarning() << getSystemErrorMessage(kSetProcessDPIAware); + // Some really old MinGW SDK may lack this function, we workaround this + // issue by always load it dynamically at runtime. + if (API_USER_AVAILABLE(SetProcessDPIAware)) { + if (API_CALL_FUNCTION(SetProcessDPIAware) == FALSE) { + qWarning() << getSystemErrorMessage(kSetProcessDPIAware); + } } } diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt index 00236eb..eceb16e 100644 --- a/src/quick/CMakeLists.txt +++ b/src/quick/CMakeLists.txt @@ -35,6 +35,7 @@ set(SOURCES ${INCLUDE_PREFIX}/framelessquickmodule.h ${INCLUDE_PREFIX}/framelessquickhelper.h ${INCLUDE_PREFIX}/framelessquickutils.h + ${INCLUDE_PREFIX}/quickchromepalette.h ${INCLUDE_PREFIX}/private/quickstandardsystembutton_p.h ${INCLUDE_PREFIX}/private/quickstandardtitlebar_p.h ${INCLUDE_PREFIX}/private/framelessquickhelper_p.h @@ -46,6 +47,7 @@ set(SOURCES framelessquickmodule.cpp framelessquickwindow.cpp framelessquickhelper.cpp + quickchromepalette.cpp ) if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC) diff --git a/src/quick/framelessquickmodule.cpp b/src/quick/framelessquickmodule.cpp index c1378d9..b79e761 100644 --- a/src/quick/framelessquickmodule.cpp +++ b/src/quick/framelessquickmodule.cpp @@ -25,6 +25,7 @@ #include "framelessquickmodule.h" #include "framelessquickhelper.h" #include "framelessquickutils.h" +#include "quickchromepalette.h" #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) # include "quickstandardsystembutton_p.h" # include "quickstandardtitlebar_p.h" @@ -89,10 +90,4 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine) qmlRegisterModule(QUICK_URI_FULL); } -QuickChromePalette::QuickChromePalette(QObject *parent) : ChromePalette(parent) -{ -} - -QuickChromePalette::~QuickChromePalette() = default; - FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/quickchromepalette.cpp b/src/quick/quickchromepalette.cpp new file mode 100644 index 0000000..ce51bb7 --- /dev/null +++ b/src/quick/quickchromepalette.cpp @@ -0,0 +1,35 @@ +/* + * MIT License + * + * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "quickchromepalette.h" + +FRAMELESSHELPER_BEGIN_NAMESPACE + +QuickChromePalette::QuickChromePalette(QObject *parent) : ChromePalette(parent) +{ +} + +QuickChromePalette::~QuickChromePalette() = default; + +FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/quickchromepalette.h b/src/quick/quickchromepalette.h new file mode 100644 index 0000000..a1d5ba7 --- /dev/null +++ b/src/quick/quickchromepalette.h @@ -0,0 +1 @@ +#include "../../include/FramelessHelper/Quick/quickchromepalette.h" diff --git a/src/quick/quickstandardtitlebar.cpp b/src/quick/quickstandardtitlebar.cpp index 8e4e5e3..95dbad7 100644 --- a/src/quick/quickstandardtitlebar.cpp +++ b/src/quick/quickstandardtitlebar.cpp @@ -205,9 +205,10 @@ void QuickStandardTitleBar::updateChromeButtonColor() m_maximizeButton->setHoverColor(hover); m_maximizeButton->setPressColor(press); m_closeButton->setColor(color); - m_closeButton->setNormalColor(normal); - m_closeButton->setHoverColor(hover); - m_closeButton->setPressColor(press); + // The close button is special. + m_closeButton->setNormalColor(m_chromePalette->closeButtonNormalColor()); + m_closeButton->setHoverColor(m_chromePalette->closeButtonHoverColor()); + m_closeButton->setPressColor(m_chromePalette->closeButtonPressColor()); } void QuickStandardTitleBar::clickMinimizeButton() diff --git a/src/widgets/standardtitlebar.cpp b/src/widgets/standardtitlebar.cpp index e85d22b..409b245 100644 --- a/src/widgets/standardtitlebar.cpp +++ b/src/widgets/standardtitlebar.cpp @@ -26,7 +26,6 @@ #include "standardtitlebar_p.h" #include "standardsystembutton.h" #include -#include #include #include #include @@ -35,9 +34,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -FRAMELESSHELPER_STRING_CONSTANT2(StyleSheetColorTemplate, "color: rgba(%1, %2, %3, %4);") -FRAMELESSHELPER_STRING_CONSTANT2(StyleSheetBackgroundColorTemplate, "background-color: rgba(%1, %2, %3, %4);") - StandardTitleBarPrivate::StandardTitleBarPrivate(StandardTitleBar *q) : QObject(q) { Q_ASSERT(q); @@ -79,28 +75,8 @@ void StandardTitleBarPrivate::setTitleLabelAlignment(const Qt::Alignment value) return; } m_labelAlignment = value; - bool needsInvalidate = false; - if (m_labelAlignment & Qt::AlignLeft) { - m_labelLeftStretch->changeSize(kDefaultTitleBarContentsMargin, 0, QSizePolicy::Fixed); - m_labelRightStretch->changeSize(0, 0, QSizePolicy::Expanding); - needsInvalidate = true; - } - if (m_labelAlignment & Qt::AlignRight) { - m_labelLeftStretch->changeSize(0, 0, QSizePolicy::Expanding); - m_labelRightStretch->changeSize(kDefaultTitleBarContentsMargin, 0, QSizePolicy::Fixed); - needsInvalidate = true; - } - if (m_labelAlignment & Qt::AlignHCenter) { - m_labelLeftStretch->changeSize(0, 0, QSizePolicy::Expanding); - m_labelRightStretch->changeSize(0, 0, QSizePolicy::Expanding); - needsInvalidate = true; - } Q_Q(StandardTitleBar); - if (needsInvalidate) { - // Tell the layout manager that we have changed the layout item's size - // manually to let it refresh the layout immediately. - q->layout()->invalidate(); - } + q->update(); Q_EMIT q->titleLabelAlignmentChanged(); } @@ -144,6 +120,7 @@ void StandardTitleBarPrivate::paintTitleBar(QPaintEvent *event) { Q_UNUSED(event); Q_Q(StandardTitleBar); +#if 0 // This block of code ensures that our widget can still apply the stylesheet correctly. // Enabling the "Qt::WA_StyledBackground" attribute can also achieve the same // effect, but since it's documented as only for internal uses, we use the @@ -152,6 +129,51 @@ void StandardTitleBarPrivate::paintTitleBar(QPaintEvent *event) option.initFrom(q); QStylePainter painter(q); painter.drawPrimitive(QStyle::PE_Widget, option); +#else + if (!m_window || m_chromePalette.isNull()) { + return; + } + const bool active = m_window->isActiveWindow(); + const QColor backgroundColor = (active ? + m_chromePalette->titleBarActiveBackgroundColor() : + m_chromePalette->titleBarInactiveBackgroundColor()); + const QColor foregroundColor = (active ? + m_chromePalette->titleBarActiveForegroundColor() : + m_chromePalette->titleBarInactiveForegroundColor()); + QPainter painter(q); + painter.save(); + painter.setRenderHints(QPainter::Antialiasing | + QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); + painter.fillRect(QRect(QPoint(0, 0), q->size()), backgroundColor); + const QString text = m_window->windowTitle(); + if (!text.isEmpty()) { + const QFont font = [q]() -> QFont { + QFont f = q->font(); + f.setPointSize(kDefaultTitleBarFontPointSize); + return f; + }(); + painter.setPen(foregroundColor); + painter.setFont(font); + const QRect rect = [this, q]() -> QRect { + const int w = q->width(); + int leftMargin = 0; + int rightMargin = 0; + if (m_labelAlignment & Qt::AlignLeft) { + leftMargin = kDefaultTitleBarContentsMargin; + } + if (m_labelAlignment & Qt::AlignRight) { + rightMargin = (w - m_minimizeButton->x() + kDefaultTitleBarContentsMargin); + } + const int x = leftMargin; + const int y = 0; + const int width = (w - leftMargin - rightMargin); + const int height = q->height(); + return {QPoint(x, y), QSize(width, height)}; + }(); + painter.drawText(rect, m_labelAlignment, text); + } + painter.restore(); +#endif } void StandardTitleBarPrivate::updateMaximizeButton() @@ -163,20 +185,8 @@ void StandardTitleBarPrivate::updateMaximizeButton() void StandardTitleBarPrivate::updateTitleBarColor() { - const bool active = m_window->isActiveWindow(); - const QColor backgroundColor = (active ? - m_chromePalette->titleBarActiveBackgroundColor() : - m_chromePalette->titleBarInactiveBackgroundColor()); - const QColor foregroundColor = (active ? - m_chromePalette->titleBarActiveForegroundColor() : - m_chromePalette->titleBarInactiveForegroundColor()); - m_windowTitleLabel->setStyleSheet(kStyleSheetColorTemplate.arg( - QString::number(foregroundColor.red()), QString::number(foregroundColor.green()), - QString::number(foregroundColor.blue()), QString::number(foregroundColor.alpha()))); Q_Q(StandardTitleBar); - q->setStyleSheet(kStyleSheetBackgroundColorTemplate.arg( - QString::number(backgroundColor.red()), QString::number(backgroundColor.green()), - QString::number(backgroundColor.blue()), QString::number(backgroundColor.alpha()))); + q->update(); } void StandardTitleBarPrivate::updateChromeButtonColor() @@ -197,9 +207,10 @@ void StandardTitleBarPrivate::updateChromeButtonColor() m_maximizeButton->setHoverColor(hover); m_maximizeButton->setPressColor(press); m_closeButton->setColor(color); - m_closeButton->setNormalColor(normal); - m_closeButton->setHoverColor(hover); - m_closeButton->setPressColor(press); + // The close button is special. + m_closeButton->setNormalColor(m_chromePalette->closeButtonNormalColor()); + m_closeButton->setHoverColor(m_chromePalette->closeButtonHoverColor()); + m_closeButton->setPressColor(m_chromePalette->closeButtonPressColor()); } void StandardTitleBarPrivate::retranslateUi() @@ -251,13 +262,10 @@ void StandardTitleBarPrivate::initialize() this, &StandardTitleBarPrivate::updateChromeButtonColor); q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); q->setFixedHeight(kDefaultTitleBarHeight); - m_windowTitleLabel.reset(new QLabel(q)); - m_windowTitleLabel->setFrameShape(QFrame::NoFrame); - QFont windowTitleFont = q->font(); - windowTitleFont.setPointSize(kDefaultTitleBarFontPointSize); - m_windowTitleLabel->setFont(windowTitleFont); - m_windowTitleLabel->setText(m_window->windowTitle()); - connect(m_window, &QWidget::windowTitleChanged, m_windowTitleLabel.data(), &QLabel::setText); + connect(m_window, &QWidget::windowTitleChanged, this, [q](const QString &title){ + Q_UNUSED(title); + q->update(); + }); m_minimizeButton.reset(new StandardSystemButton(SystemButtonType::Minimize, q)); connect(m_minimizeButton.data(), &StandardSystemButton::clicked, m_window, &QWidget::showMinimized); m_maximizeButton.reset(new StandardSystemButton(SystemButtonType::Maximize, q)); @@ -277,14 +285,6 @@ void StandardTitleBarPrivate::initialize() m_window->close(); } }); - m_labelLeftStretch = new QSpacerItem(0, 0); - m_labelRightStretch = new QSpacerItem(0, 0); - const auto titleLabelLayout = new QHBoxLayout; - titleLabelLayout->setSpacing(0); - titleLabelLayout->setContentsMargins(0, 0, 0, 0); - titleLabelLayout->addSpacerItem(m_labelLeftStretch); - titleLabelLayout->addWidget(m_windowTitleLabel.data()); - titleLabelLayout->addSpacerItem(m_labelRightStretch); // According to the title bar design guidance, the system buttons should always be // placed on the top-right corner of the window, so we need the following additional // layouts to ensure this. @@ -302,7 +302,7 @@ void StandardTitleBarPrivate::initialize() const auto titleBarLayout = new QHBoxLayout(q); titleBarLayout->setSpacing(0); titleBarLayout->setContentsMargins(0, 0, 0, 0); - titleBarLayout->addLayout(titleLabelLayout); + titleBarLayout->addStretch(); titleBarLayout->addLayout(systemButtonsOuterLayout); q->setLayout(titleBarLayout); setTitleLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter); @@ -331,12 +331,6 @@ void StandardTitleBar::setTitleLabelAlignment(const Qt::Alignment value) d->setTitleLabelAlignment(value); } -QLabel *StandardTitleBar::titleLabel() const -{ - Q_D(const StandardTitleBar); - return d->m_windowTitleLabel.data(); -} - StandardSystemButton *StandardTitleBar::minimizeButton() const { Q_D(const StandardTitleBar);