widgets: PIMPL refactor

This commit is contained in:
Yuhang Zhao 2023-08-25 17:50:22 +08:00
parent e6a4849f81
commit f7368d0a08
18 changed files with 759 additions and 1300 deletions

View File

@ -97,12 +97,11 @@ void Dialog::setupUi()
connect(moreButton, &QPushButton::toggled, extension, &QWidget::setVisible); connect(moreButton, &QPushButton::toggled, extension, &QWidget::setVisible);
QVBoxLayout *extensionLayout = new QVBoxLayout; QVBoxLayout *extensionLayout = new QVBoxLayout(extension);
extensionLayout->setContentsMargins(0, 0, 0, 0); extensionLayout->setContentsMargins(0, 0, 0, 0);
extensionLayout->addWidget(wholeWordsCheckBox); extensionLayout->addWidget(wholeWordsCheckBox);
extensionLayout->addWidget(backwardCheckBox); extensionLayout->addWidget(backwardCheckBox);
extensionLayout->addWidget(searchSelectionCheckBox); extensionLayout->addWidget(searchSelectionCheckBox);
extension->setLayout(extensionLayout);
QHBoxLayout *topLeftLayout = new QHBoxLayout; QHBoxLayout *topLeftLayout = new QHBoxLayout;
topLeftLayout->addWidget(label); topLeftLayout->addWidget(label);
@ -120,14 +119,12 @@ void Dialog::setupUi()
controlsLayout->addWidget(extension, 1, 0, 1, 2); controlsLayout->addWidget(extension, 1, 0, 1, 2);
controlsLayout->setRowStretch(2, 1); controlsLayout->setRowStretch(2, 1);
QVBoxLayout *mainLayout = new QVBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSizeConstraint(QLayout::SetFixedSize); mainLayout->setSizeConstraint(QLayout::SetFixedSize);
mainLayout->addWidget(titleBar); mainLayout->addWidget(titleBar);
mainLayout->addLayout(controlsLayout); mainLayout->addLayout(controlsLayout);
setLayout(mainLayout);
extension->hide(); extension->hide();
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);

View File

@ -73,7 +73,6 @@ void MainWindow::initialize()
mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addWidget(m_titleBar); mainLayout->addWidget(m_titleBar);
mainLayout->addWidget(m_glWidget); mainLayout->addWidget(m_glWidget);
setLayout(mainLayout);
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
helper->setTitleBarWidget(m_titleBar); helper->setTitleBarWidget(m_titleBar);

View File

@ -102,7 +102,6 @@ void Widget::initialize()
mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addWidget(m_titleBar); mainLayout->addWidget(m_titleBar);
mainLayout->addLayout(contentLayout); mainLayout->addLayout(contentLayout);
setLayout(mainLayout);
updateStyleSheet(); updateStyleSheet();
m_cancelShortcut = new QShortcut(this); m_cancelShortcut = new QShortcut(this);

View File

@ -44,14 +44,8 @@ public:
Q_NODISCARD static FramelessDialogPrivate *get(FramelessDialog *pub); Q_NODISCARD static FramelessDialogPrivate *get(FramelessDialog *pub);
Q_NODISCARD static const FramelessDialogPrivate *get(const FramelessDialog *pub); Q_NODISCARD static const FramelessDialogPrivate *get(const FramelessDialog *pub);
Q_NODISCARD WidgetsSharedHelper *widgetsSharedHelper() const;
private:
void initialize();
private:
FramelessDialog *q_ptr = nullptr; FramelessDialog *q_ptr = nullptr;
WidgetsSharedHelper *m_sharedHelper = nullptr; WidgetsSharedHelper *sharedHelper = nullptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -44,21 +44,9 @@ public:
Q_NODISCARD static FramelessMainWindowPrivate *get(FramelessMainWindow *pub); Q_NODISCARD static FramelessMainWindowPrivate *get(FramelessMainWindow *pub);
Q_NODISCARD static const FramelessMainWindowPrivate *get(const FramelessMainWindow *pub); Q_NODISCARD static const FramelessMainWindowPrivate *get(const FramelessMainWindow *pub);
Q_NODISCARD bool isNormal() const;
Q_NODISCARD bool isZoomed() const;
void toggleMaximized();
void toggleFullScreen();
Q_NODISCARD WidgetsSharedHelper *widgetsSharedHelper() const;
private:
void initialize();
private:
FramelessMainWindow *q_ptr = nullptr; FramelessMainWindow *q_ptr = nullptr;
Qt::WindowState m_savedWindowState = Qt::WindowNoState; Qt::WindowState savedWindowState = Qt::WindowNoState;
WidgetsSharedHelper *m_sharedHelper = nullptr; WidgetsSharedHelper *sharedHelper = nullptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -44,21 +44,9 @@ public:
Q_NODISCARD static FramelessWidgetPrivate *get(FramelessWidget *pub); Q_NODISCARD static FramelessWidgetPrivate *get(FramelessWidget *pub);
Q_NODISCARD static const FramelessWidgetPrivate *get(const FramelessWidget *pub); Q_NODISCARD static const FramelessWidgetPrivate *get(const FramelessWidget *pub);
Q_NODISCARD bool isNormal() const;
Q_NODISCARD bool isZoomed() const;
void toggleMaximized();
void toggleFullScreen();
Q_NODISCARD WidgetsSharedHelper *widgetsSharedHelper() const;
private:
void initialize();
private:
FramelessWidget *q_ptr = nullptr; FramelessWidget *q_ptr = nullptr;
Qt::WindowState m_savedWindowState = Qt::WindowNoState; Qt::WindowState savedWindowState = Qt::WindowNoState;
WidgetsSharedHelper *m_sharedHelper = nullptr; WidgetsSharedHelper *sharedHelper = nullptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -49,53 +49,25 @@ public:
Q_NODISCARD static FramelessWidgetsHelperPrivate *get(FramelessWidgetsHelper *pub); Q_NODISCARD static FramelessWidgetsHelperPrivate *get(FramelessWidgetsHelper *pub);
Q_NODISCARD static const FramelessWidgetsHelperPrivate *get(const FramelessWidgetsHelper *pub); Q_NODISCARD static const FramelessWidgetsHelperPrivate *get(const FramelessWidgetsHelper *pub);
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
void extendsContentIntoTitleBar(const bool value);
Q_NODISCARD QWidget *getTitleBarWidget() const;
void setTitleBarWidget(QWidget *widget);
void attach(); void attach();
void detach(); void detach();
void setSystemButton(QWidget *widget, const Global::SystemButtonType buttonType);
void setHitTestVisible(QWidget *widget, const bool visible = true);
void setHitTestVisible(const QRect &rect, const bool visible = true);
void setHitTestVisible(QObject *object, const bool visible = true);
void showSystemMenu(const QPoint &pos);
void windowStartSystemMove2(const QPoint &pos);
void windowStartSystemResize2(const Qt::Edges edges, const QPoint &pos);
void moveWindowToDesktopCenter();
void bringWindowToFront();
Q_NODISCARD bool isWindowFixedSize() const;
void setWindowFixedSize(const bool value);
void emitSignalForAllInstances(const char *signal); void emitSignalForAllInstances(const char *signal);
Q_NODISCARD bool isBlurBehindWindowEnabled() const;
void setBlurBehindWindowEnabled(const bool enable, const QColor &color);
void setProperty(const char *name, const QVariant &value); void setProperty(const char *name, const QVariant &value);
Q_NODISCARD QVariant getProperty(const char *name, const QVariant &defaultValue = {}); Q_NODISCARD QVariant getProperty(const char *name, const QVariant &defaultValue = {});
Q_NODISCARD QWidget *window() const;
Q_NODISCARD MicaMaterial *getMicaMaterialIfAny() const; Q_NODISCARD MicaMaterial *getMicaMaterialIfAny() const;
Q_NODISCARD WindowBorderPainter *getWindowBorderIfAny() const; Q_NODISCARD WindowBorderPainter *getWindowBorderIfAny() const;
Q_NODISCARD static WidgetsSharedHelper *findOrCreateSharedHelper(QWidget *window); Q_NODISCARD static WidgetsSharedHelper *findOrCreateSharedHelper(QWidget *window);
Q_NODISCARD static FramelessWidgetsHelper *findOrCreateFramelessHelper(QObject *object); Q_NODISCARD static FramelessWidgetsHelper *findOrCreateFramelessHelper(QObject *object);
Q_NODISCARD bool isReady() const;
void waitForReady();
void repaintAllChildren(const quint32 delay = 0) const; void repaintAllChildren(const quint32 delay = 0) const;
Q_NODISCARD quint32 readyWaitTime() const; Q_NODISCARD quint32 readyWaitTime() const;
void setReadyWaitTime(const quint32 time); void setReadyWaitTime(const quint32 time);
private:
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const; Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const; Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
@ -105,15 +77,13 @@ private:
Q_NODISCARD const FramelessWidgetsHelperData *getWindowData() const; Q_NODISCARD const FramelessWidgetsHelperData *getWindowData() const;
Q_NODISCARD FramelessWidgetsHelperData *getWindowDataMutable() const; Q_NODISCARD FramelessWidgetsHelperData *getWindowDataMutable() const;
private:
FramelessWidgetsHelper *q_ptr = nullptr; FramelessWidgetsHelper *q_ptr = nullptr;
QColor m_savedWindowBackgroundColor = {}; QColor savedWindowBackgroundColor = {};
bool m_blurBehindWindowEnabled = false; bool blurBehindWindowEnabled = false;
QPointer<QWidget> m_window = nullptr; QPointer<QWidget> window = nullptr;
bool m_destroying = false; bool qpaReady = false;
bool m_qpaReady = false; QSizePolicy savedSizePolicy = {};
QSizePolicy m_savedSizePolicy = {}; quint32 qpaWaitTime = 0;
quint32 m_qpaWaitTime = 0;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -27,11 +27,6 @@
#include <FramelessHelper/Widgets/framelesshelperwidgets_global.h> #include <FramelessHelper/Widgets/framelesshelperwidgets_global.h>
#include <optional> #include <optional>
QT_BEGIN_NAMESPACE
class QEnterEvent;
class QPaintEvent;
QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardSystemButton; class StandardSystemButton;
@ -49,46 +44,18 @@ public:
Q_NODISCARD static StandardSystemButtonPrivate *get(StandardSystemButton *pub); Q_NODISCARD static StandardSystemButtonPrivate *get(StandardSystemButton *pub);
Q_NODISCARD static const StandardSystemButtonPrivate *get(const StandardSystemButton *pub); Q_NODISCARD static const StandardSystemButtonPrivate *get(const StandardSystemButton *pub);
Q_NODISCARD QString getGlyph() const; Q_NODISCARD static QSize getRecommendedButtonSize();
void setGlyph(const QString &value);
Q_NODISCARD Global::SystemButtonType getButtonType() const;
void setButtonType(const Global::SystemButtonType type);
Q_NODISCARD QSize getRecommendedButtonSize() const;
Q_NODISCARD QColor getHoverColor() const;
Q_NODISCARD QColor getPressColor() const;
Q_NODISCARD QColor getNormalColor() const;
Q_NODISCARD QColor getActiveForegroundColor() const;
Q_NODISCARD QColor getInactiveForegroundColor() const;
Q_NODISCARD bool isActive() const;
Q_NODISCARD int glyphSize() const;
void setHoverColor(const QColor &value);
void setPressColor(const QColor &value);
void setNormalColor(const QColor &value);
void setActiveForegroundColor(const QColor &value);
void setInactiveForegroundColor(const QColor &value);
void setActive(const bool value);
void setGlyphSize(const int value);
void paintEventHandler(QPaintEvent *event);
private:
void initialize();
private:
StandardSystemButton *q_ptr = nullptr; StandardSystemButton *q_ptr = nullptr;
Global::SystemButtonType m_buttonType = Global::SystemButtonType::Unknown; Global::SystemButtonType buttonType = Global::SystemButtonType::Unknown;
QString m_glyph = {}; QString glyph = {};
QColor m_hoverColor = {}; QColor hoverColor = {};
QColor m_pressColor = {}; QColor pressColor = {};
QColor m_normalColor = {}; QColor normalColor = {};
QColor m_activeForegroundColor = {}; QColor activeForegroundColor = {};
QColor m_inactiveForegroundColor = {}; QColor inactiveForegroundColor = {};
bool m_active = false; bool active = false;
std::optional<int> m_glyphSize = std::nullopt; std::optional<int> glyphSize = std::nullopt;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -29,7 +29,6 @@
#include <optional> #include <optional>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QPaintEvent;
class QMouseEvent; class QMouseEvent;
QT_END_NAMESPACE QT_END_NAMESPACE
@ -59,33 +58,6 @@ public:
Q_NODISCARD static StandardTitleBarPrivate *get(StandardTitleBar *pub); Q_NODISCARD static StandardTitleBarPrivate *get(StandardTitleBar *pub);
Q_NODISCARD static const StandardTitleBarPrivate *get(const StandardTitleBar *pub); Q_NODISCARD static const StandardTitleBarPrivate *get(const StandardTitleBar *pub);
Q_NODISCARD Qt::Alignment titleLabelAlignment() const;
void setTitleLabelAlignment(const Qt::Alignment value);
Q_NODISCARD bool isExtended() const;
void setExtended(const bool value);
Q_NODISCARD bool isHideWhenClose() const;
void setHideWhenClose(const bool value);
Q_NODISCARD ChromePalette *chromePalette() const;
void paintTitleBar(QPaintEvent *event);
Q_NODISCARD bool titleLabelVisible() const;
void setTitleLabelVisible(const bool value);
Q_NODISCARD QSize windowIconSize() const;
void setWindowIconSize(const QSize &value);
Q_NODISCARD bool windowIconVisible() const;
void setWindowIconVisible(const bool value);
Q_NODISCARD QFont titleFont() const;
void setTitleFont(const QFont &value);
Q_NODISCARD bool mouseEventHandler(QMouseEvent *event);
Q_NODISCARD QRect windowIconRect() const; Q_NODISCARD QRect windowIconRect() const;
Q_NODISCARD bool windowIconVisible_real() const; Q_NODISCARD bool windowIconVisible_real() const;
Q_NODISCARD bool isInTitleBarIconArea(const QPoint &pos) const; Q_NODISCARD bool isInTitleBarIconArea(const QPoint &pos) const;
@ -93,35 +65,34 @@ public:
Q_NODISCARD QFont defaultFont() const; Q_NODISCARD QFont defaultFont() const;
Q_NODISCARD FontMetrics titleLabelSize() const; Q_NODISCARD FontMetrics titleLabelSize() const;
public Q_SLOTS: Q_SLOT void updateMaximizeButton();
void updateMaximizeButton(); Q_SLOT void updateTitleBarColor();
void updateTitleBarColor(); Q_SLOT void updateChromeButtonColor();
void updateChromeButtonColor(); Q_SLOT void retranslateUi();
void retranslateUi();
protected: Q_NODISCARD bool mouseEventHandler(QMouseEvent *event);
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
private:
void initialize(); void initialize();
private:
StandardTitleBar *q_ptr = nullptr; StandardTitleBar *q_ptr = nullptr;
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
StandardSystemButton *m_minimizeButton = nullptr; StandardSystemButton *minimizeButton = nullptr;
StandardSystemButton *m_maximizeButton = nullptr; StandardSystemButton *maximizeButton = nullptr;
StandardSystemButton *m_closeButton = nullptr; StandardSystemButton *closeButton = nullptr;
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
QPointer<QWidget> m_window = nullptr; QPointer<QWidget> window = nullptr;
bool m_extended = false; bool extended = false;
Qt::Alignment m_labelAlignment = {}; Qt::Alignment labelAlignment = {};
bool m_hideWhenClose = false; bool hideWhenClose = false;
ChromePalette *m_chromePalette = nullptr; ChromePalette *chromePalette = nullptr;
bool m_titleLabelVisible = true; bool titleLabelVisible = true;
std::optional<QSize> m_windowIconSize = std::nullopt; std::optional<QSize> windowIconSize = std::nullopt;
bool m_windowIconVisible = false; bool windowIconVisible = false;
std::optional<QFont> m_titleFont = std::nullopt; std::optional<QFont> titleFont = std::nullopt;
bool m_closeTriggered = false; bool closeTriggered = false;
protected:
bool eventFilter(QObject *object, QEvent *event) override;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -52,7 +52,7 @@ public:
~StandardSystemButton() override; ~StandardSystemButton() override;
Q_NODISCARD QSize sizeHint() const override; Q_NODISCARD QSize sizeHint() const override;
Q_NODISCARD Global::SystemButtonType buttonType(); Q_NODISCARD Global::SystemButtonType buttonType() const;
Q_NODISCARD QString glyph() const; Q_NODISCARD QString glyph() const;
Q_NODISCARD QColor hoverColor() const; Q_NODISCARD QColor hoverColor() const;
Q_NODISCARD QColor pressColor() const; Q_NODISCARD QColor pressColor() const;

View File

@ -988,6 +988,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
#endif #endif
case WM_NCMOUSEHOVER: case WM_NCMOUSEHOVER:
case WM_NCMOUSELEAVE: { case WM_NCMOUSELEAVE: {
// For future code readers:
// The following code is not workaround anything, it's just try to emulate the original
// behavior of a native Win32 window.
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE)); const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE));
const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)); const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK));
const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam); const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam);

View File

@ -237,7 +237,8 @@ void FramelessQuickHelperPrivate::setProperty(const char *name, const QVariant &
Q_ASSERT(name); Q_ASSERT(name);
Q_ASSERT(*name != '\0'); Q_ASSERT(*name != '\0');
Q_ASSERT(value.isValid()); Q_ASSERT(value.isValid());
if (!name || (*name == '\0') || !value.isValid()) { Q_ASSERT(!value.isNull());
if (!name || (*name == '\0') || !value.isValid() || value.isNull()) {
return; return;
} }
Q_Q(FramelessQuickHelper); Q_Q(FramelessQuickHelper);
@ -261,7 +262,7 @@ QVariant FramelessQuickHelperPrivate::getProperty(const char *name, const QVaria
return {}; return {};
} }
const QVariant value = window->property(name); const QVariant value = window->property(name);
return (value.isValid() ? value : defaultValue); return ((value.isValid() && !value.isNull()) ? value : defaultValue);
} }
QuickMicaMaterial *FramelessQuickHelperPrivate::findOrCreateMicaMaterial() const QuickMicaMaterial *FramelessQuickHelperPrivate::findOrCreateMicaMaterial() const

View File

@ -26,7 +26,6 @@
#include "framelessdialog_p.h" #include "framelessdialog_p.h"
#include "framelesswidgetshelper.h" #include "framelesswidgetshelper.h"
#include "widgetssharedhelper_p.h" #include "widgetssharedhelper_p.h"
#include <FramelessHelper/Core/utils.h>
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -54,7 +53,6 @@ FramelessDialogPrivate::FramelessDialogPrivate(FramelessDialog *q) : QObject(q)
return; return;
} }
q_ptr = q; q_ptr = q;
initialize();
} }
FramelessDialogPrivate::~FramelessDialogPrivate() = default; FramelessDialogPrivate::~FramelessDialogPrivate() = default;
@ -77,22 +75,13 @@ const FramelessDialogPrivate *FramelessDialogPrivate::get(const FramelessDialog
return pub->d_func(); return pub->d_func();
} }
void FramelessDialogPrivate::initialize()
{
Q_Q(FramelessDialog);
FramelessWidgetsHelper::get(q)->extendsContentIntoTitleBar();
m_sharedHelper = new WidgetsSharedHelper(this);
m_sharedHelper->setup(q);
}
WidgetsSharedHelper *FramelessDialogPrivate::widgetsSharedHelper() const
{
return m_sharedHelper;
}
FramelessDialog::FramelessDialog(QWidget *parent) FramelessDialog::FramelessDialog(QWidget *parent)
: QDialog(parent), d_ptr(new FramelessDialogPrivate(this)) : QDialog(parent), d_ptr(new FramelessDialogPrivate(this))
{ {
FramelessWidgetsHelper::get(this)->extendsContentIntoTitleBar();
Q_D(FramelessDialog);
d->sharedHelper = new WidgetsSharedHelper(d);
d->sharedHelper->setup(this);
} }
FramelessDialog::~FramelessDialog() = default; FramelessDialog::~FramelessDialog() = default;

View File

@ -54,7 +54,6 @@ FramelessMainWindowPrivate::FramelessMainWindowPrivate(FramelessMainWindow *q) :
return; return;
} }
q_ptr = q; q_ptr = q;
initialize();
} }
FramelessMainWindowPrivate::~FramelessMainWindowPrivate() = default; FramelessMainWindowPrivate::~FramelessMainWindowPrivate() = default;
@ -77,81 +76,45 @@ const FramelessMainWindowPrivate *FramelessMainWindowPrivate::get(const Frameles
return pub->d_func(); return pub->d_func();
} }
void FramelessMainWindowPrivate::initialize()
{
Q_Q(FramelessMainWindow);
FramelessWidgetsHelper::get(q)->extendsContentIntoTitleBar();
m_sharedHelper = new WidgetsSharedHelper(this);
m_sharedHelper->setup(q);
}
bool FramelessMainWindowPrivate::isNormal() const
{
Q_Q(const FramelessMainWindow);
return (Utils::windowStatesToWindowState(q->windowState()) == Qt::WindowNoState);
}
bool FramelessMainWindowPrivate::isZoomed() const
{
Q_Q(const FramelessMainWindow);
return (q->isMaximized() || q->isFullScreen());
}
void FramelessMainWindowPrivate::toggleMaximized()
{
Q_Q(FramelessMainWindow);
if (q->isMaximized()) {
q->showNormal();
} else {
q->showMaximized();
}
}
void FramelessMainWindowPrivate::toggleFullScreen()
{
Q_Q(FramelessMainWindow);
if (q->isFullScreen()) {
q->setWindowState(m_savedWindowState);
} else {
m_savedWindowState = Utils::windowStatesToWindowState(q->windowState());
q->showFullScreen();
}
}
WidgetsSharedHelper *FramelessMainWindowPrivate::widgetsSharedHelper() const
{
return m_sharedHelper;
}
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags) FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags)
: QMainWindow(parent, flags), d_ptr(new FramelessMainWindowPrivate(this)) : QMainWindow(parent, flags), d_ptr(new FramelessMainWindowPrivate(this))
{ {
FramelessWidgetsHelper::get(this)->extendsContentIntoTitleBar();
Q_D(FramelessMainWindow);
d->sharedHelper = new WidgetsSharedHelper(d);
d->sharedHelper->setup(this);
} }
FramelessMainWindow::~FramelessMainWindow() = default; FramelessMainWindow::~FramelessMainWindow() = default;
bool FramelessMainWindow::isNormal() const bool FramelessMainWindow::isNormal() const
{ {
Q_D(const FramelessMainWindow); return (Utils::windowStatesToWindowState(windowState()) == Qt::WindowNoState);
return d->isNormal();
} }
bool FramelessMainWindow::isZoomed() const bool FramelessMainWindow::isZoomed() const
{ {
Q_D(const FramelessMainWindow); return (isMaximized() || isFullScreen());
return d->isZoomed();
} }
void FramelessMainWindow::toggleMaximized() void FramelessMainWindow::toggleMaximized()
{ {
Q_D(FramelessMainWindow); if (isMaximized()) {
d->toggleMaximized(); showNormal();
} else {
showMaximized();
}
} }
void FramelessMainWindow::toggleFullScreen() void FramelessMainWindow::toggleFullScreen()
{ {
Q_D(FramelessMainWindow); Q_D(FramelessMainWindow);
d->toggleFullScreen(); if (isFullScreen()) {
setWindowState(d->savedWindowState);
} else {
d->savedWindowState = Utils::windowStatesToWindowState(windowState());
showFullScreen();
}
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -54,7 +54,6 @@ FramelessWidgetPrivate::FramelessWidgetPrivate(FramelessWidget *q) : QObject(q)
return; return;
} }
q_ptr = q; q_ptr = q;
initialize();
} }
FramelessWidgetPrivate::~FramelessWidgetPrivate() = default; FramelessWidgetPrivate::~FramelessWidgetPrivate() = default;
@ -77,81 +76,45 @@ const FramelessWidgetPrivate *FramelessWidgetPrivate::get(const FramelessWidget
return pub->d_func(); return pub->d_func();
} }
void FramelessWidgetPrivate::initialize()
{
Q_Q(FramelessWidget);
FramelessWidgetsHelper::get(q)->extendsContentIntoTitleBar();
m_sharedHelper = new WidgetsSharedHelper(this);
m_sharedHelper->setup(q);
}
bool FramelessWidgetPrivate::isNormal() const
{
Q_Q(const FramelessWidget);
return (Utils::windowStatesToWindowState(q->windowState()) == Qt::WindowNoState);
}
bool FramelessWidgetPrivate::isZoomed() const
{
Q_Q(const FramelessWidget);
return (q->isMaximized() || q->isFullScreen());
}
void FramelessWidgetPrivate::toggleMaximized()
{
Q_Q(FramelessWidget);
if (q->isMaximized()) {
q->showNormal();
} else {
q->showMaximized();
}
}
void FramelessWidgetPrivate::toggleFullScreen()
{
Q_Q(FramelessWidget);
if (q->isFullScreen()) {
q->setWindowState(m_savedWindowState);
} else {
m_savedWindowState = Utils::windowStatesToWindowState(q->windowState());
q->showFullScreen();
}
}
WidgetsSharedHelper *FramelessWidgetPrivate::widgetsSharedHelper() const
{
return m_sharedHelper;
}
FramelessWidget::FramelessWidget(QWidget *parent) FramelessWidget::FramelessWidget(QWidget *parent)
: QWidget(parent, Qt::Window), d_ptr(new FramelessWidgetPrivate(this)) : QWidget(parent, Qt::Window), d_ptr(new FramelessWidgetPrivate(this))
{ {
FramelessWidgetsHelper::get(this)->extendsContentIntoTitleBar();
Q_D(FramelessWidget);
d->sharedHelper = new WidgetsSharedHelper(d);
d->sharedHelper->setup(this);
} }
FramelessWidget::~FramelessWidget() = default; FramelessWidget::~FramelessWidget() = default;
bool FramelessWidget::isNormal() const bool FramelessWidget::isNormal() const
{ {
Q_D(const FramelessWidget); return (Utils::windowStatesToWindowState(windowState()) == Qt::WindowNoState);
return d->isNormal();
} }
bool FramelessWidget::isZoomed() const bool FramelessWidget::isZoomed() const
{ {
Q_D(const FramelessWidget); return (isMaximized() || isFullScreen());
return d->isZoomed();
} }
void FramelessWidget::toggleMaximized() void FramelessWidget::toggleMaximized()
{ {
Q_D(FramelessWidget); if (isMaximized()) {
d->toggleMaximized(); showNormal();
} else {
showMaximized();
}
} }
void FramelessWidget::toggleFullScreen() void FramelessWidget::toggleFullScreen()
{ {
Q_D(FramelessWidget); Q_D(FramelessWidget);
d->toggleFullScreen(); if (isFullScreen()) {
setWindowState(d->savedWindowState);
} else {
d->savedWindowState = Utils::windowStatesToWindowState(windowState());
showFullScreen();
}
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -169,11 +169,7 @@ FramelessWidgetsHelperPrivate::FramelessWidgetsHelperPrivate(FramelessWidgetsHel
q_ptr = q; q_ptr = q;
} }
FramelessWidgetsHelperPrivate::~FramelessWidgetsHelperPrivate() FramelessWidgetsHelperPrivate::~FramelessWidgetsHelperPrivate() = default;
{
m_destroying = true;
extendsContentIntoTitleBar(false);
}
FramelessWidgetsHelperPrivate *FramelessWidgetsHelperPrivate::get(FramelessWidgetsHelper *pub) FramelessWidgetsHelperPrivate *FramelessWidgetsHelperPrivate::get(FramelessWidgetsHelper *pub)
{ {
@ -193,37 +189,6 @@ const FramelessWidgetsHelperPrivate *FramelessWidgetsHelperPrivate::get(const Fr
return pub->d_func(); return pub->d_func();
} }
bool FramelessWidgetsHelperPrivate::isWindowFixedSize() const
{
if (!m_window) {
return false;
}
return isWidgetFixedSize(m_window);
}
void FramelessWidgetsHelperPrivate::setWindowFixedSize(const bool value)
{
if (!m_window) {
return;
}
if (isWindowFixedSize() == value) {
return;
}
if (value) {
m_savedSizePolicy = m_window->sizePolicy();
m_window->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_window->setFixedSize(m_window->size());
} else {
m_window->setSizePolicy(m_savedSizePolicy);
m_window->setMinimumSize(kDefaultWindowSize);
m_window->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
}
#ifdef Q_OS_WINDOWS
std::ignore = Utils::setAeroSnappingEnabled(m_window->winId(), !value);
#endif
emitSignalForAllInstances("windowFixedSizeChanged");
}
void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal) void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal)
{ {
Q_ASSERT(signal); Q_ASSERT(signal);
@ -231,10 +196,10 @@ void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal
if (!signal || (*signal == '\0')) { if (!signal || (*signal == '\0')) {
return; return;
} }
if (!m_window) { if (!window) {
return; return;
} }
const auto instances = m_window->findChildren<FramelessWidgetsHelper *>(); const auto instances = window->findChildren<FramelessWidgetsHelper *>();
if (instances.isEmpty()) { if (instances.isEmpty()) {
return; return;
} }
@ -243,57 +208,20 @@ void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal
} }
} }
bool FramelessWidgetsHelperPrivate::isBlurBehindWindowEnabled() const
{
return m_blurBehindWindowEnabled;
}
void FramelessWidgetsHelperPrivate::setBlurBehindWindowEnabled(const bool enable, const QColor &color)
{
if (!m_window) {
return;
}
if (m_blurBehindWindowEnabled == enable) {
return;
}
if (Utils::isBlurBehindWindowSupported()) {
QPalette palette = m_window->palette();
if (enable) {
m_savedWindowBackgroundColor = palette.color(QPalette::Window);
}
palette.setColor(QPalette::Window, (enable ? kDefaultTransparentColor : m_savedWindowBackgroundColor));
m_window->setPalette(palette);
if (Utils::setBlurBehindWindowEnabled(m_window->winId(),
(enable ? BlurMode::Default : BlurMode::Disable), color)) {
m_blurBehindWindowEnabled = enable;
emitSignalForAllInstances("blurBehindWindowEnabledChanged");
} else {
WARNING << "Failed to enable/disable blur behind window.";
}
} else {
if (WidgetsSharedHelper * const helper = findOrCreateSharedHelper(m_window)) {
m_blurBehindWindowEnabled = enable;
helper->setMicaEnabled(m_blurBehindWindowEnabled);
emitSignalForAllInstances("blurBehindWindowEnabledChanged");
} else {
DEBUG << "Blur behind window is not supported on current platform.";
}
}
}
void FramelessWidgetsHelperPrivate::setProperty(const char *name, const QVariant &value) void FramelessWidgetsHelperPrivate::setProperty(const char *name, const QVariant &value)
{ {
Q_ASSERT(name); Q_ASSERT(name);
Q_ASSERT(*name != '\0'); Q_ASSERT(*name != '\0');
Q_ASSERT(value.isValid()); Q_ASSERT(value.isValid());
if (!name || (*name == '\0') || !value.isValid()) { Q_ASSERT(!value.isNull());
if (!name || (*name == '\0') || !value.isValid() || value.isNull()) {
return; return;
} }
Q_ASSERT(m_window); Q_ASSERT(window);
if (!m_window) { if (!window) {
return; return;
} }
m_window->setProperty(name, value); window->setProperty(name, value);
} }
QVariant FramelessWidgetsHelperPrivate::getProperty(const char *name, const QVariant &defaultValue) QVariant FramelessWidgetsHelperPrivate::getProperty(const char *name, const QVariant &defaultValue)
@ -303,25 +231,20 @@ QVariant FramelessWidgetsHelperPrivate::getProperty(const char *name, const QVar
if (!name || (*name == '\0')) { if (!name || (*name == '\0')) {
return {}; return {};
} }
Q_ASSERT(m_window); Q_ASSERT(window);
if (!m_window) { if (!window) {
return {}; return {};
} }
const QVariant value = m_window->property(name); const QVariant value = window->property(name);
return (value.isValid() ? value : defaultValue); return ((value.isValid() && !value.isNull()) ? value : defaultValue);
}
QWidget *FramelessWidgetsHelperPrivate::window() const
{
return m_window;
} }
MicaMaterial *FramelessWidgetsHelperPrivate::getMicaMaterialIfAny() const MicaMaterial *FramelessWidgetsHelperPrivate::getMicaMaterialIfAny() const
{ {
if (!m_window) { if (!window) {
return nullptr; return nullptr;
} }
if (const WidgetsSharedHelper * const helper = findOrCreateSharedHelper(m_window)) { if (const WidgetsSharedHelper * const helper = findOrCreateSharedHelper(window)) {
return helper->rawMicaMaterial(); return helper->rawMicaMaterial();
} }
return nullptr; return nullptr;
@ -329,10 +252,10 @@ MicaMaterial *FramelessWidgetsHelperPrivate::getMicaMaterialIfAny() const
WindowBorderPainter *FramelessWidgetsHelperPrivate::getWindowBorderIfAny() const WindowBorderPainter *FramelessWidgetsHelperPrivate::getWindowBorderIfAny() const
{ {
if (!m_window) { if (!window) {
return nullptr; return nullptr;
} }
if (const WidgetsSharedHelper * const helper = findOrCreateSharedHelper(m_window)) { if (const WidgetsSharedHelper * const helper = findOrCreateSharedHelper(window)) {
return helper->rawWindowBorder(); return helper->rawWindowBorder();
} }
return nullptr; return nullptr;
@ -346,17 +269,17 @@ WidgetsSharedHelper *FramelessWidgetsHelperPrivate::findOrCreateSharedHelper(QWi
} }
if (const auto widget = qobject_cast<FramelessWidget *>(window)) { if (const auto widget = qobject_cast<FramelessWidget *>(window)) {
if (const auto widgetPriv = FramelessWidgetPrivate::get(widget)) { if (const auto widgetPriv = FramelessWidgetPrivate::get(widget)) {
return widgetPriv->widgetsSharedHelper(); return widgetPriv->sharedHelper;
} }
} }
if (const auto mainWindow = qobject_cast<FramelessMainWindow *>(window)) { if (const auto mainWindow = qobject_cast<FramelessMainWindow *>(window)) {
if (const auto mainWindowPriv = FramelessMainWindowPrivate::get(mainWindow)) { if (const auto mainWindowPriv = FramelessMainWindowPrivate::get(mainWindow)) {
return mainWindowPriv->widgetsSharedHelper(); return mainWindowPriv->sharedHelper;
} }
} }
if (const auto dialog = qobject_cast<FramelessDialog *>(window)) { if (const auto dialog = qobject_cast<FramelessDialog *>(window)) {
if (const auto dialogPriv = FramelessDialogPrivate::get(dialog)) { if (const auto dialogPriv = FramelessDialogPrivate::get(dialog)) {
return dialogPriv->widgetsSharedHelper(); return dialogPriv->sharedHelper;
} }
} }
QWidget * const topLevelWindow = window->window(); QWidget * const topLevelWindow = window->window();
@ -391,38 +314,14 @@ FramelessWidgetsHelper *FramelessWidgetsHelperPrivate::findOrCreateFramelessHelp
return instance; return instance;
} }
bool FramelessWidgetsHelperPrivate::isReady() const
{
return m_qpaReady;
}
void FramelessWidgetsHelperPrivate::waitForReady()
{
if (m_qpaReady) {
return;
}
#if 1
QEventLoop loop;
Q_Q(FramelessWidgetsHelper);
const QMetaObject::Connection connection = connect(
q, &FramelessWidgetsHelper::ready, &loop, &QEventLoop::quit);
loop.exec();
disconnect(connection);
#else
while (!m_qpaReady) {
QCoreApplication::processEvents();
}
#endif
}
void FramelessWidgetsHelperPrivate::repaintAllChildren(const quint32 delay) const void FramelessWidgetsHelperPrivate::repaintAllChildren(const quint32 delay) const
{ {
if (!m_window) { if (!window) {
return; return;
} }
const auto update = [this]() -> void { const auto update = [this]() -> void {
forceWidgetRepaint(m_window); forceWidgetRepaint(window);
const QList<QWidget *> widgets = m_window->findChildren<QWidget *>(); const QList<QWidget *> widgets = window->findChildren<QWidget *>();
if (widgets.isEmpty()) { if (widgets.isEmpty()) {
return; return;
} }
@ -439,102 +338,28 @@ void FramelessWidgetsHelperPrivate::repaintAllChildren(const quint32 delay) cons
quint32 FramelessWidgetsHelperPrivate::readyWaitTime() const quint32 FramelessWidgetsHelperPrivate::readyWaitTime() const
{ {
return m_qpaWaitTime; return qpaWaitTime;
} }
void FramelessWidgetsHelperPrivate::setReadyWaitTime(const quint32 time) void FramelessWidgetsHelperPrivate::setReadyWaitTime(const quint32 time)
{ {
if (m_qpaWaitTime == time) { if (qpaWaitTime == time) {
return; return;
} }
m_qpaWaitTime = time; qpaWaitTime = time;
}
bool FramelessWidgetsHelperPrivate::isContentExtendedIntoTitleBar() const
{
const FramelessWidgetsHelperData *data = getWindowData();
return (data ? data->ready : false);
}
void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
{
Q_ASSERT(widget);
if (!widget) {
return;
}
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data || (data->titleBarWidget == widget)) {
return;
}
data->titleBarWidget = widget;
emitSignalForAllInstances("titleBarWidgetChanged");
}
QWidget *FramelessWidgetsHelperPrivate::getTitleBarWidget() const
{
const FramelessWidgetsHelperData *data = getWindowData();
return (data ? data->titleBarWidget : nullptr);
}
void FramelessWidgetsHelperPrivate::setHitTestVisible(QWidget *widget, const bool visible)
{
Q_ASSERT(widget);
if (!widget) {
return;
}
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
if (visible) {
data->hitTestVisibleWidgets.append(widget);
} else {
data->hitTestVisibleWidgets.removeAll(widget);
}
}
void FramelessWidgetsHelperPrivate::setHitTestVisible(const QRect &rect, const bool visible)
{
Q_ASSERT(rect.isValid());
if (!rect.isValid()) {
return;
}
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
if (visible) {
data->hitTestVisibleRects.append(rect);
} else {
data->hitTestVisibleRects.removeAll(rect);
}
}
void FramelessWidgetsHelperPrivate::setHitTestVisible(QObject *object, const bool visible)
{
Q_ASSERT(object);
if (!object) {
return;
}
const auto widget = qobject_cast<QWidget *>(object);
Q_ASSERT(widget);
if (!widget) {
return;
}
setHitTestVisible(widget, visible);
} }
void FramelessWidgetsHelperPrivate::attach() void FramelessWidgetsHelperPrivate::attach()
{ {
QWidget * const window = findTopLevelWindow(); QWidget * const tlw = findTopLevelWindow();
Q_ASSERT(window); Q_ASSERT(tlw);
if (!window) { if (!tlw) {
return; return;
} }
if (m_window == window) { if (window == tlw) {
return; return;
} }
m_window = window; window = tlw;
if (!window->testAttribute(Qt::WA_DontCreateNativeAncestors)) { if (!window->testAttribute(Qt::WA_DontCreateNativeAncestors)) {
window->setAttribute(Qt::WA_DontCreateNativeAncestors); window->setAttribute(Qt::WA_DontCreateNativeAncestors);
@ -548,39 +373,41 @@ void FramelessWidgetsHelperPrivate::attach()
return; return;
} }
Q_Q(FramelessWidgetsHelper);
SystemParameters params = {}; SystemParameters params = {};
params.getWindowId = [window]() -> WId { return window->winId(); }; params.getWindowId = [this]() -> WId { return window->winId(); };
params.getWindowFlags = [window]() -> Qt::WindowFlags { return window->windowFlags(); }; params.getWindowFlags = [this]() -> Qt::WindowFlags { return window->windowFlags(); };
params.setWindowFlags = [window](const Qt::WindowFlags flags) -> void { window->setWindowFlags(flags); }; params.setWindowFlags = [this](const Qt::WindowFlags flags) -> void { window->setWindowFlags(flags); };
params.getWindowSize = [window]() -> QSize { return window->size(); }; params.getWindowSize = [this]() -> QSize { return window->size(); };
params.setWindowSize = [window](const QSize &size) -> void { window->resize(size); }; params.setWindowSize = [this](const QSize &size) -> void { window->resize(size); };
params.getWindowPosition = [window]() -> QPoint { return window->pos(); }; params.getWindowPosition = [this]() -> QPoint { return window->pos(); };
params.setWindowPosition = [window](const QPoint &pos) -> void { window->move(pos); }; params.setWindowPosition = [this](const QPoint &pos) -> void { window->move(pos); };
params.getWindowScreen = [window]() -> QScreen * { params.getWindowScreen = [this]() -> QScreen * {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return window->screen(); return window->screen();
#else #else
return window->windowHandle()->screen(); return window->windowHandle()->screen();
#endif #endif
}; };
params.isWindowFixedSize = [this]() -> bool { return isWindowFixedSize(); }; params.isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); };
params.setWindowFixedSize = [this](const bool value) -> void { setWindowFixedSize(value); }; params.setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); };
params.getWindowState = [window]() -> Qt::WindowState { return Utils::windowStatesToWindowState(window->windowState()); }; params.getWindowState = [this]() -> Qt::WindowState { return Utils::windowStatesToWindowState(window->windowState()); };
params.setWindowState = [window](const Qt::WindowState state) -> void { window->setWindowState(state); }; params.setWindowState = [this](const Qt::WindowState state) -> void { window->setWindowState(state); };
params.getWindowHandle = [window]() -> QWindow * { return window->windowHandle(); }; params.getWindowHandle = [this]() -> QWindow * { return window->windowHandle(); };
params.windowToScreen = [window](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); }; params.windowToScreen = [this](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); };
params.screenToWindow = [window](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); }; params.screenToWindow = [this](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); };
params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); }; params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
params.getWindowDevicePixelRatio = [window]() -> qreal { return window->devicePixelRatioF(); }; params.getWindowDevicePixelRatio = [this]() -> qreal { return window->devicePixelRatioF(); };
params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { setSystemButtonState(button, state); }; params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { setSystemButtonState(button, state); };
params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); }; params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); };
params.showSystemMenu = [this](const QPoint &pos) -> void { showSystemMenu(pos); }; params.showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); };
params.setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); }; params.setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); };
params.getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); }; params.getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); };
params.setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); }; params.setCursor = [this](const QCursor &cursor) -> void { window->setCursor(cursor); };
params.unsetCursor = [window]() -> void { window->unsetCursor(); }; params.unsetCursor = [this]() -> void { window->unsetCursor(); };
params.getWidgetHandle = [window]() -> QObject * { return window; }; params.getWidgetHandle = [this]() -> QObject * { return window; };
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); }; params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
params.resetQtGrabbedControl = []() -> void { qt_button_down = nullptr; }; params.resetQtGrabbedControl = []() -> void { qt_button_down = nullptr; };
@ -594,13 +421,13 @@ void FramelessWidgetsHelperPrivate::attach()
// we reach here, and all the modifications from the Qt side will be lost // we reach here, and all the modifications from the Qt side will be lost
// due to QPA will reset the position and size of the window during it's // due to QPA will reset the position and size of the window during it's
// initialization process. // initialization process.
QTimer::singleShot(m_qpaWaitTime, this, [this](){ QTimer::singleShot(qpaWaitTime, this, [this, q](){
m_qpaReady = true; qpaReady = true;
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) { if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
moveWindowToDesktopCenter(); q->moveWindowToDesktopCenter();
} }
if (FramelessConfig::instance()->isSet(Option::EnableBlurBehindWindow)) { if (FramelessConfig::instance()->isSet(Option::EnableBlurBehindWindow)) {
setBlurBehindWindowEnabled(true, {}); q->setBlurBehindWindowEnabled(true);
} }
emitSignalForAllInstances("windowChanged"); emitSignalForAllInstances("windowChanged");
emitSignalForAllInstances("ready"); emitSignalForAllInstances("ready");
@ -609,35 +436,20 @@ void FramelessWidgetsHelperPrivate::attach()
void FramelessWidgetsHelperPrivate::detach() void FramelessWidgetsHelperPrivate::detach()
{ {
if (!m_window) { if (!window) {
return; return;
} }
const WId windowId = m_window->winId(); const WId windowId = window->winId();
const auto it = g_framelessWidgetsHelperData()->constFind(windowId); const auto it = g_framelessWidgetsHelperData()->constFind(windowId);
if (it == g_framelessWidgetsHelperData()->constEnd()) { if (it == g_framelessWidgetsHelperData()->constEnd()) {
return; return;
} }
g_framelessWidgetsHelperData()->erase(it); g_framelessWidgetsHelperData()->erase(it);
FramelessManager::instance()->removeWindow(windowId); FramelessManager::instance()->removeWindow(windowId);
m_window = nullptr; window = nullptr;
emitSignalForAllInstances("windowChanged"); emitSignalForAllInstances("windowChanged");
} }
void FramelessWidgetsHelperPrivate::extendsContentIntoTitleBar(const bool value)
{
if (isContentExtendedIntoTitleBar() == value) {
return;
}
if (value) {
attach();
} else {
detach();
}
if (!m_destroying) {
emitSignalForAllInstances("extendsContentIntoTitleBarChanged");
}
}
QWidget *FramelessWidgetsHelperPrivate::findTopLevelWindow() const QWidget *FramelessWidgetsHelperPrivate::findTopLevelWindow() const
{ {
Q_Q(const FramelessWidgetsHelper); Q_Q(const FramelessWidgetsHelper);
@ -653,11 +465,11 @@ QWidget *FramelessWidgetsHelperPrivate::findTopLevelWindow() const
const FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowData() const const FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowData() const
{ {
//Q_ASSERT(m_window); //Q_ASSERT(window);
if (!m_window) { if (!window) {
return nullptr; return nullptr;
} }
const WId windowId = m_window->winId(); const WId windowId = window->winId();
auto it = g_framelessWidgetsHelperData()->find(windowId); auto it = g_framelessWidgetsHelperData()->find(windowId);
if (it == g_framelessWidgetsHelperData()->end()) { if (it == g_framelessWidgetsHelperData()->end()) {
it = g_framelessWidgetsHelperData()->insert(windowId, {}); it = g_framelessWidgetsHelperData()->insert(windowId, {});
@ -667,11 +479,11 @@ const FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowData()
FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowDataMutable() const FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowDataMutable() const
{ {
//Q_ASSERT(m_window); //Q_ASSERT(window);
if (!m_window) { if (!window) {
return nullptr; return nullptr;
} }
const WId windowId = m_window->winId(); const WId windowId = window->winId();
auto it = g_framelessWidgetsHelperData()->find(windowId); auto it = g_framelessWidgetsHelperData()->find(windowId);
if (it == g_framelessWidgetsHelperData()->end()) { if (it == g_framelessWidgetsHelperData()->end()) {
it = g_framelessWidgetsHelperData()->insert(windowId, {}); it = g_framelessWidgetsHelperData()->insert(windowId, {});
@ -685,10 +497,10 @@ QRect FramelessWidgetsHelperPrivate::mapWidgetGeometryToScene(const QWidget * co
if (!widget) { if (!widget) {
return {}; return {};
} }
if (!m_window) { if (!window) {
return {}; return {};
} }
const QPoint originPoint = widget->mapTo(m_window, QPoint(0, 0)); const QPoint originPoint = widget->mapTo(window, QPoint(0, 0));
const QSize size = widget->size(); const QSize size = widget->size();
return QRect(originPoint, size); return QRect(originPoint, size);
} }
@ -751,12 +563,12 @@ bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos)
// The title bar is hidden or disabled for some reason, treat it as there's no title bar. // The title bar is hidden or disabled for some reason, treat it as there's no title bar.
return false; return false;
} }
if (!m_window) { if (!window) {
// The FramelessWidgetsHelper object has not been attached to a specific window yet, // The FramelessWidgetsHelper object has not been attached to a specific window yet,
// so we assume there's no title bar. // so we assume there's no title bar.
return false; return false;
} }
const QRect windowRect = {QPoint(0, 0), m_window->size()}; const QRect windowRect = {QPoint(0, 0), window->size()};
const QRect titleBarRect = mapWidgetGeometryToScene(data->titleBarWidget); const QRect titleBarRect = mapWidgetGeometryToScene(data->titleBarWidget);
if (!titleBarRect.intersects(windowRect)) { if (!titleBarRect.intersects(windowRect)) {
// The title bar is totally outside of the window for some reason, // The title bar is totally outside of the window for some reason,
@ -793,7 +605,7 @@ bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos)
bool FramelessWidgetsHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) const bool FramelessWidgetsHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) const
{ {
if (!m_window) { if (!window) {
return false; return false;
} }
const auto withinFrameBorder = [this, &pos]() -> bool { const auto withinFrameBorder = [this, &pos]() -> bool {
@ -806,9 +618,9 @@ bool FramelessWidgetsHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) c
} }
#endif #endif
return ((pos.x() < kDefaultResizeBorderThickness) return ((pos.x() < kDefaultResizeBorderThickness)
|| (pos.x() >= (m_window->width() - kDefaultResizeBorderThickness))); || (pos.x() >= (window->width() - kDefaultResizeBorderThickness)));
}(); }();
return ((Utils::windowStatesToWindowState(m_window->windowState()) == Qt::WindowNoState) && withinFrameBorder); return ((Utils::windowStatesToWindowState(window->windowState()) == Qt::WindowNoState) && withinFrameBorder);
} }
void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType button, const ButtonState state) void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType button, const ButtonState state)
@ -817,42 +629,45 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
Q_UNUSED(state); Q_UNUSED(state);
} }
void FramelessWidgetsHelperPrivate::moveWindowToDesktopCenter() void FramelessWidgetsHelper::moveWindowToDesktopCenter()
{ {
if (!m_window) { Q_D(FramelessWidgetsHelper);
if (!d->window) {
return; return;
} }
Utils::moveWindowToDesktopCenter(&getWindowData()->params, true); Utils::moveWindowToDesktopCenter(&d->getWindowData()->params, true);
} }
void FramelessWidgetsHelperPrivate::bringWindowToFront() void FramelessWidgetsHelper::bringWindowToFront()
{ {
if (!m_window) { Q_D(FramelessWidgetsHelper);
if (!d->window) {
return; return;
} }
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
std::ignore = Utils::bringWindowToFront(m_window->winId()); std::ignore = Utils::bringWindowToFront(d->window->winId());
#else #else
if (m_window->isHidden()) { if (d->window->isHidden()) {
m_window->show(); d->window->show();
} }
if (m_window->isMinimized()) { if (d->window->isMinimized()) {
m_window->setWindowState(m_window->windowState() & ~Qt::WindowMinimized); d->window->setWindowState(d->window->windowState() & ~Qt::WindowMinimized);
} }
m_window->raise(); d->window->raise();
m_window->activateWindow(); d->window->activateWindow();
#endif #endif
} }
void FramelessWidgetsHelperPrivate::showSystemMenu(const QPoint &pos) void FramelessWidgetsHelper::showSystemMenu(const QPoint &pos)
{ {
if (!m_window) { Q_D(FramelessWidgetsHelper);
if (!d->window) {
return; return;
} }
const WId windowId = m_window->winId(); const WId windowId = d->window->winId();
const QPoint nativePos = Utils::toNativeGlobalPosition(m_window->windowHandle(), pos); const QPoint nativePos = Utils::toNativeGlobalPosition(d->window->windowHandle(), pos);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
std::ignore = Utils::showSystemMenu(windowId, nativePos, false, &getWindowData()->params); std::ignore = Utils::showSystemMenu(windowId, nativePos, false, &d->getWindowData()->params);
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
Utils::openSystemMenu(windowId, nativePos); Utils::openSystemMenu(windowId, nativePos);
#else #else
@ -861,33 +676,36 @@ void FramelessWidgetsHelperPrivate::showSystemMenu(const QPoint &pos)
#endif #endif
} }
void FramelessWidgetsHelperPrivate::windowStartSystemMove2(const QPoint &pos) void FramelessWidgetsHelper::windowStartSystemMove2(const QPoint &pos)
{ {
if (!m_window) { Q_D(FramelessWidgetsHelper);
if (!d->window) {
return; return;
} }
std::ignore = Utils::startSystemMove(m_window->windowHandle(), pos); std::ignore = Utils::startSystemMove(d->window->windowHandle(), pos);
} }
void FramelessWidgetsHelperPrivate::windowStartSystemResize2(const Qt::Edges edges, const QPoint &pos) void FramelessWidgetsHelper::windowStartSystemResize2(const Qt::Edges edges, const QPoint &pos)
{ {
if (!m_window) { Q_D(FramelessWidgetsHelper);
if (!d->window) {
return; return;
} }
if (edges == Qt::Edges{}) { if (edges == Qt::Edges{}) {
return; return;
} }
std::ignore = Utils::startSystemResize(m_window->windowHandle(), edges, pos); std::ignore = Utils::startSystemResize(d->window->windowHandle(), edges, pos);
} }
void FramelessWidgetsHelperPrivate::setSystemButton(QWidget *widget, const SystemButtonType buttonType) void FramelessWidgetsHelper::setSystemButton(QWidget *widget, const SystemButtonType buttonType)
{ {
Q_ASSERT(widget); Q_ASSERT(widget);
Q_ASSERT(buttonType != SystemButtonType::Unknown); Q_ASSERT(buttonType != SystemButtonType::Unknown);
if (!widget || (buttonType == SystemButtonType::Unknown)) { if (!widget || (buttonType == SystemButtonType::Unknown)) {
return; return;
} }
FramelessWidgetsHelperData *data = getWindowDataMutable(); Q_D(FramelessWidgetsHelper);
FramelessWidgetsHelperData *data = d->getWindowDataMutable();
if (!data) { if (!data) {
return; return;
} }
@ -929,34 +747,10 @@ FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *object)
return FramelessWidgetsHelperPrivate::findOrCreateFramelessHelper(object); return FramelessWidgetsHelperPrivate::findOrCreateFramelessHelper(object);
} }
QWidget *FramelessWidgetsHelper::titleBarWidget() const
{
Q_D(const FramelessWidgetsHelper);
return d->getTitleBarWidget();
}
bool FramelessWidgetsHelper::isWindowFixedSize() const
{
Q_D(const FramelessWidgetsHelper);
return d->isWindowFixedSize();
}
bool FramelessWidgetsHelper::isBlurBehindWindowEnabled() const
{
Q_D(const FramelessWidgetsHelper);
return d->isBlurBehindWindowEnabled();
}
QWidget *FramelessWidgetsHelper::window() const QWidget *FramelessWidgetsHelper::window() const
{ {
Q_D(const FramelessWidgetsHelper); Q_D(const FramelessWidgetsHelper);
return d->window(); return d->window;
}
bool FramelessWidgetsHelper::isContentExtendedIntoTitleBar() const
{
Q_D(const FramelessWidgetsHelper);
return d->isContentExtendedIntoTitleBar();
} }
MicaMaterial *FramelessWidgetsHelper::micaMaterial() const MicaMaterial *FramelessWidgetsHelper::micaMaterial() const
@ -971,22 +765,107 @@ WindowBorderPainter *FramelessWidgetsHelper::windowBorder() const
return d->getWindowBorderIfAny(); return d->getWindowBorderIfAny();
} }
bool FramelessWidgetsHelper::isWindowFixedSize() const
{
Q_D(const FramelessWidgetsHelper);
if (!d->window) {
return false;
}
return isWidgetFixedSize(d->window);
}
void FramelessWidgetsHelper::setWindowFixedSize(const bool value)
{
Q_D(FramelessWidgetsHelper);
if (!d->window) {
return;
}
if (isWindowFixedSize() == value) {
return;
}
if (value) {
d->savedSizePolicy = d->window->sizePolicy();
d->window->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
d->window->setFixedSize(d->window->size());
} else {
d->window->setSizePolicy(d->savedSizePolicy);
d->window->setMinimumSize(kDefaultWindowSize);
d->window->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
}
#ifdef Q_OS_WINDOWS
std::ignore = Utils::setAeroSnappingEnabled(d->window->winId(), !value);
#endif
d->emitSignalForAllInstances("windowFixedSizeChanged");
}
bool FramelessWidgetsHelper::isBlurBehindWindowEnabled() const
{
Q_D(const FramelessWidgetsHelper);
return d->blurBehindWindowEnabled;
}
void FramelessWidgetsHelper::setBlurBehindWindowEnabled(const bool enable)
{
Q_D(FramelessWidgetsHelper);
if (!d->window) {
return;
}
if (d->blurBehindWindowEnabled == enable) {
return;
}
if (Utils::isBlurBehindWindowSupported()) {
QPalette palette = d->window->palette();
if (enable) {
d->savedWindowBackgroundColor = palette.color(QPalette::Window);
}
palette.setColor(QPalette::Window, (enable ? kDefaultTransparentColor : d->savedWindowBackgroundColor));
d->window->setPalette(palette);
if (Utils::setBlurBehindWindowEnabled(d->window->winId(), (enable ? BlurMode::Default : BlurMode::Disable), {})) {
d->blurBehindWindowEnabled = enable;
d->emitSignalForAllInstances("blurBehindWindowEnabledChanged");
} else {
WARNING << "Failed to enable/disable blur behind window.";
}
} else {
if (WidgetsSharedHelper * const helper = d->findOrCreateSharedHelper(d->window)) {
d->blurBehindWindowEnabled = enable;
helper->setMicaEnabled(d->blurBehindWindowEnabled);
d->emitSignalForAllInstances("blurBehindWindowEnabledChanged");
} else {
DEBUG << "Blur behind window is not supported on current platform.";
}
}
}
bool FramelessWidgetsHelper::isReady() const bool FramelessWidgetsHelper::isReady() const
{ {
Q_D(const FramelessWidgetsHelper); Q_D(const FramelessWidgetsHelper);
return d->isReady(); return d->qpaReady;
} }
void FramelessWidgetsHelper::waitForReady() void FramelessWidgetsHelper::waitForReady()
{ {
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
d->waitForReady(); if (d->qpaReady) {
return;
}
#if 1
QEventLoop loop{};
const QMetaObject::Connection connection = connect(this, &FramelessWidgetsHelper::ready, &loop, &QEventLoop::quit);
loop.exec();
disconnect(connection);
#else
while (!d->qpaReady) {
QCoreApplication::processEvents();
}
#endif
} }
void FramelessWidgetsHelper::extendsContentIntoTitleBar(const bool value) bool FramelessWidgetsHelper::isContentExtendedIntoTitleBar() const
{ {
Q_D(FramelessWidgetsHelper); Q_D(const FramelessWidgetsHelper);
d->extendsContentIntoTitleBar(value); const FramelessWidgetsHelperData *data = d->getWindowData();
return (data ? data->ready : false);
} }
void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget) void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
@ -996,18 +875,19 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
d->setTitleBarWidget(widget); FramelessWidgetsHelperData *data = d->getWindowDataMutable();
} if (!data || (data->titleBarWidget == widget)) {
void FramelessWidgetsHelper::setSystemButton(QWidget *widget, const SystemButtonType buttonType)
{
Q_ASSERT(widget);
Q_ASSERT(buttonType != SystemButtonType::Unknown);
if (!widget || (buttonType == SystemButtonType::Unknown)) {
return; return;
} }
Q_D(FramelessWidgetsHelper); data->titleBarWidget = widget;
d->setSystemButton(widget, buttonType); d->emitSignalForAllInstances("titleBarWidgetChanged");
}
QWidget *FramelessWidgetsHelper::titleBarWidget() const
{
Q_D(const FramelessWidgetsHelper);
const FramelessWidgetsHelperData *data = d->getWindowData();
return (data ? data->titleBarWidget : nullptr);
} }
void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visible) void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visible)
@ -1017,7 +897,15 @@ void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visib
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
d->setHitTestVisible(widget, visible); FramelessWidgetsHelperData *data = d->getWindowDataMutable();
if (!data) {
return;
}
if (visible) {
data->hitTestVisibleWidgets.append(widget);
} else {
data->hitTestVisibleWidgets.removeAll(widget);
}
} }
void FramelessWidgetsHelper::setHitTestVisible(const QRect &rect, const bool visible) void FramelessWidgetsHelper::setHitTestVisible(const QRect &rect, const bool visible)
@ -1027,7 +915,15 @@ void FramelessWidgetsHelper::setHitTestVisible(const QRect &rect, const bool vis
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
d->setHitTestVisible(rect, visible); FramelessWidgetsHelperData *data = d->getWindowDataMutable();
if (!data) {
return;
}
if (visible) {
data->hitTestVisibleRects.append(rect);
} else {
data->hitTestVisibleRects.removeAll(rect);
}
} }
void FramelessWidgetsHelper::setHitTestVisible(QObject *object, const bool visible) void FramelessWidgetsHelper::setHitTestVisible(QObject *object, const bool visible)
@ -1036,53 +932,26 @@ void FramelessWidgetsHelper::setHitTestVisible(QObject *object, const bool visib
if (!object) { if (!object) {
return; return;
} }
Q_D(FramelessWidgetsHelper); const auto widget = qobject_cast<QWidget *>(object);
d->setHitTestVisible(object, visible); Q_ASSERT(widget);
if (!widget) {
return;
}
setHitTestVisible(widget, visible);
} }
void FramelessWidgetsHelper::showSystemMenu(const QPoint &pos) void FramelessWidgetsHelper::extendsContentIntoTitleBar(const bool value)
{ {
Q_D(FramelessWidgetsHelper); if (isContentExtendedIntoTitleBar() == value) {
d->showSystemMenu(pos);
}
void FramelessWidgetsHelper::windowStartSystemMove2(const QPoint &pos)
{
Q_D(FramelessWidgetsHelper);
d->windowStartSystemMove2(pos);
}
void FramelessWidgetsHelper::windowStartSystemResize2(const Qt::Edges edges, const QPoint &pos)
{
if (edges == Qt::Edges{}) {
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
d->windowStartSystemResize2(edges, pos); if (value) {
d->attach();
} else {
d->detach();
} }
d->emitSignalForAllInstances("extendsContentIntoTitleBarChanged");
void FramelessWidgetsHelper::moveWindowToDesktopCenter()
{
Q_D(FramelessWidgetsHelper);
d->moveWindowToDesktopCenter();
}
void FramelessWidgetsHelper::bringWindowToFront()
{
Q_D(FramelessWidgetsHelper);
d->bringWindowToFront();
}
void FramelessWidgetsHelper::setWindowFixedSize(const bool value)
{
Q_D(FramelessWidgetsHelper);
d->setWindowFixedSize(value);
}
void FramelessWidgetsHelper::setBlurBehindWindowEnabled(const bool value)
{
Q_D(FramelessWidgetsHelper);
d->setBlurBehindWindowEnabled(value, {});
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -56,7 +56,6 @@ StandardSystemButtonPrivate::StandardSystemButtonPrivate(StandardSystemButton *q
return; return;
} }
q_ptr = q; q_ptr = q;
initialize();
} }
StandardSystemButtonPrivate::~StandardSystemButtonPrivate() = default; StandardSystemButtonPrivate::~StandardSystemButtonPrivate() = default;
@ -79,252 +78,20 @@ const StandardSystemButtonPrivate *StandardSystemButtonPrivate::get(const Standa
return pub->d_func(); return pub->d_func();
} }
QString StandardSystemButtonPrivate::getGlyph() const QSize StandardSystemButtonPrivate::getRecommendedButtonSize()
{
return m_glyph;
}
void StandardSystemButtonPrivate::setGlyph(const QString &value)
{
Q_ASSERT(!value.isEmpty());
if (value.isEmpty()) {
return;
}
if (m_glyph == value) {
return;
}
m_glyph = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->glyphChanged();
}
SystemButtonType StandardSystemButtonPrivate::getButtonType() const
{
return m_buttonType;
}
void StandardSystemButtonPrivate::setButtonType(const SystemButtonType type)
{
Q_ASSERT(type != SystemButtonType::Unknown);
if (type == SystemButtonType::Unknown) {
return;
}
if (m_buttonType == type) {
return;
}
m_buttonType = type;
setGlyph(Utils::getSystemButtonGlyph(m_buttonType));
Q_Q(StandardSystemButton);
q->update();
}
QSize StandardSystemButtonPrivate::getRecommendedButtonSize() const
{ {
return kDefaultSystemButtonSize; return kDefaultSystemButtonSize;
} }
QColor StandardSystemButtonPrivate::getHoverColor() const
{
return m_hoverColor;
}
QColor StandardSystemButtonPrivate::getPressColor() const
{
return m_pressColor;
}
QColor StandardSystemButtonPrivate::getNormalColor() const
{
return m_normalColor;
}
QColor StandardSystemButtonPrivate::getActiveForegroundColor() const
{
return m_activeForegroundColor;
}
QColor StandardSystemButtonPrivate::getInactiveForegroundColor() const
{
return m_inactiveForegroundColor;
}
bool StandardSystemButtonPrivate::isActive() const
{
return m_active;
}
int StandardSystemButtonPrivate::glyphSize() const
{
return m_glyphSize.value_or(FramelessManagerPrivate::getIconFont().pointSize());
}
void StandardSystemButtonPrivate::setHoverColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (m_hoverColor == value) {
return;
}
m_hoverColor = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->hoverColorChanged();
}
void StandardSystemButtonPrivate::setPressColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (m_pressColor == value) {
return;
}
m_pressColor = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->pressColorChanged();
}
void StandardSystemButtonPrivate::setNormalColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (m_normalColor == value) {
return;
}
m_normalColor = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->normalColorChanged();
}
void StandardSystemButtonPrivate::setActiveForegroundColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (m_activeForegroundColor == value) {
return;
}
m_activeForegroundColor = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->activeForegroundColorChanged();
}
void StandardSystemButtonPrivate::setInactiveForegroundColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (m_inactiveForegroundColor == value) {
return;
}
m_inactiveForegroundColor = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->inactiveForegroundColorChanged();
}
void StandardSystemButtonPrivate::setActive(const bool value)
{
if (m_active == value) {
return;
}
m_active = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->activeChanged();
}
void StandardSystemButtonPrivate::setGlyphSize(const int value)
{
Q_ASSERT(value > 0);
if (value <= 0) {
return;
}
if (glyphSize() == value) {
return;
}
m_glyphSize = value;
Q_Q(StandardSystemButton);
q->update();
Q_EMIT q->glyphSizeChanged();
}
void StandardSystemButtonPrivate::paintEventHandler(QPaintEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
Q_Q(StandardSystemButton);
QPainter painter(q);
painter.save();
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing
| QPainter::SmoothPixmapTransform);
const auto backgroundColor = [this, q]() -> QColor {
// The pressed state has higher priority than the hovered state.
if (q->isDown() && m_pressColor.isValid()) {
return m_pressColor;
}
if (q->underMouse() && m_hoverColor.isValid()) {
return m_hoverColor;
}
if (m_normalColor.isValid()) {
return m_normalColor;
}
return {};
}();
const QRect buttonRect = {QPoint(0, 0), q->size()};
if (backgroundColor.isValid()) {
painter.fillRect(buttonRect, backgroundColor);
}
if (!m_glyph.isEmpty()) {
painter.setPen([this, q]() -> QColor {
if (!q->underMouse() && !m_active && m_inactiveForegroundColor.isValid()) {
return m_inactiveForegroundColor;
}
if (m_activeForegroundColor.isValid()) {
return m_activeForegroundColor;
}
return kDefaultBlackColor;
}());
painter.setFont([this]() -> QFont {
QFont font = FramelessManagerPrivate::getIconFont();
if (m_glyphSize.has_value()) {
font.setPointSize(m_glyphSize.value());
}
return font;
}());
painter.drawText(buttonRect, Qt::AlignCenter, m_glyph);
}
painter.restore();
event->accept();
}
void StandardSystemButtonPrivate::initialize()
{
FramelessManagerPrivate::initializeIconFont();
Q_Q(StandardSystemButton);
q->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
q->setFixedSize(getRecommendedButtonSize());
q->setIconSize(kDefaultSystemButtonIconSize);
q->setMouseTracking(true);
q->setAttribute(Qt::WA_Hover);
}
StandardSystemButton::StandardSystemButton(QWidget *parent) StandardSystemButton::StandardSystemButton(QWidget *parent)
: QPushButton(parent), d_ptr(new StandardSystemButtonPrivate(this)) : QPushButton(parent), d_ptr(new StandardSystemButtonPrivate(this))
{ {
FramelessManagerPrivate::initializeIconFont();
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFixedSize(StandardSystemButtonPrivate::getRecommendedButtonSize());
setIconSize(kDefaultSystemButtonIconSize);
setMouseTracking(true);
setAttribute(Qt::WA_Hover);
} }
StandardSystemButton::StandardSystemButton(const SystemButtonType type, QWidget *parent) StandardSystemButton::StandardSystemButton(const SystemButtonType type, QWidget *parent)
@ -337,122 +104,243 @@ StandardSystemButton::~StandardSystemButton() = default;
QSize StandardSystemButton::sizeHint() const QSize StandardSystemButton::sizeHint() const
{ {
Q_D(const StandardSystemButton); return StandardSystemButtonPrivate::getRecommendedButtonSize();
return d->getRecommendedButtonSize();
}
SystemButtonType StandardSystemButton::buttonType()
{
Q_D(const StandardSystemButton);
return d->getButtonType();
} }
QString StandardSystemButton::glyph() const QString StandardSystemButton::glyph() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->getGlyph(); return d->glyph;
} }
void StandardSystemButton::setButtonType(const SystemButtonType value) void StandardSystemButton::setGlyph(const QString &value)
{ {
Q_ASSERT(!value.isEmpty());
if (value.isEmpty()) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setButtonType(value); if (d->glyph == value) {
return;
}
d->glyph = value;
update();
Q_EMIT glyphChanged();
} }
void StandardSystemButton::setGlyph(const QString &glyph) SystemButtonType StandardSystemButton::buttonType() const
{ {
Q_D(const StandardSystemButton);
return d->buttonType;
}
void StandardSystemButton::setButtonType(const SystemButtonType type)
{
Q_ASSERT(type != SystemButtonType::Unknown);
if (type == SystemButtonType::Unknown) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setGlyph(glyph); if (d->buttonType == type) {
return;
}
d->buttonType = type;
setGlyph(Utils::getSystemButtonGlyph(d->buttonType));
update();
} }
QColor StandardSystemButton::hoverColor() const QColor StandardSystemButton::hoverColor() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->getHoverColor(); return d->hoverColor;
}
void StandardSystemButton::setHoverColor(const QColor &value)
{
Q_D(StandardSystemButton);
d->setHoverColor(value);
} }
QColor StandardSystemButton::pressColor() const QColor StandardSystemButton::pressColor() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->getPressColor(); return d->pressColor;
} }
QColor StandardSystemButton::normalColor() const QColor StandardSystemButton::normalColor() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->getNormalColor(); return d->normalColor;
} }
QColor StandardSystemButton::activeForegroundColor() const QColor StandardSystemButton::activeForegroundColor() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->getActiveForegroundColor(); return d->activeForegroundColor;
} }
QColor StandardSystemButton::inactiveForegroundColor() const QColor StandardSystemButton::inactiveForegroundColor() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->getInactiveForegroundColor(); return d->inactiveForegroundColor;
} }
bool StandardSystemButton::isActive() const bool StandardSystemButton::isActive() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->isActive(); return d->active;
} }
int StandardSystemButton::glyphSize() const int StandardSystemButton::glyphSize() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->glyphSize(); return d->glyphSize.value_or(FramelessManagerPrivate::getIconFont().pointSize());
}
void StandardSystemButton::setHoverColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
Q_D(StandardSystemButton);
if (d->hoverColor == value) {
return;
}
d->hoverColor = value;
update();
Q_EMIT hoverColorChanged();
} }
void StandardSystemButton::setPressColor(const QColor &value) void StandardSystemButton::setPressColor(const QColor &value)
{ {
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setPressColor(value); if (d->pressColor == value) {
return;
}
d->pressColor = value;
update();
Q_EMIT pressColorChanged();
} }
void StandardSystemButton::setNormalColor(const QColor &value) void StandardSystemButton::setNormalColor(const QColor &value)
{ {
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setNormalColor(value); if (d->normalColor == value) {
return;
}
d->normalColor = value;
update();
Q_EMIT normalColorChanged();
} }
void StandardSystemButton::setActiveForegroundColor(const QColor &value) void StandardSystemButton::setActiveForegroundColor(const QColor &value)
{ {
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setActiveForegroundColor(value); if (d->activeForegroundColor == value) {
return;
}
d->activeForegroundColor = value;
update();
Q_EMIT activeForegroundColorChanged();
} }
void StandardSystemButton::setInactiveForegroundColor(const QColor &value) void StandardSystemButton::setInactiveForegroundColor(const QColor &value)
{ {
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setInactiveForegroundColor(value); if (d->inactiveForegroundColor == value) {
return;
}
d->inactiveForegroundColor = value;
update();
Q_EMIT inactiveForegroundColorChanged();
} }
void StandardSystemButton::setActive(const bool value) void StandardSystemButton::setActive(const bool value)
{ {
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setActive(value); if (d->active == value) {
return;
}
d->active = value;
update();
Q_EMIT activeChanged();
} }
void StandardSystemButton::setGlyphSize(const int value) void StandardSystemButton::setGlyphSize(const int value)
{ {
Q_ASSERT(value > 0);
if (value <= 0) {
return;
}
if (glyphSize() == value) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setGlyphSize(value); d->glyphSize = value;
update();
Q_EMIT glyphSizeChanged();
} }
void StandardSystemButton::paintEvent(QPaintEvent *event) void StandardSystemButton::paintEvent(QPaintEvent *event)
{ {
Q_ASSERT(event);
if (!event) {
return;
}
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->paintEventHandler(event); QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing
| QPainter::SmoothPixmapTransform);
const auto backgroundColor = [this, d]() -> QColor {
// The pressed state has higher priority than the hovered state.
if (isDown() && d->pressColor.isValid()) {
return d->pressColor;
}
if (underMouse() && d->hoverColor.isValid()) {
return d->hoverColor;
}
if (d->normalColor.isValid()) {
return d->normalColor;
}
return {};
}();
const QRect buttonRect = {QPoint(0, 0), size()};
if (backgroundColor.isValid()) {
painter.fillRect(buttonRect, backgroundColor);
}
if (!d->glyph.isEmpty()) {
painter.setPen([this, d]() -> QColor {
if (!underMouse() && !d->active && d->inactiveForegroundColor.isValid()) {
return d->inactiveForegroundColor;
}
if (d->activeForegroundColor.isValid()) {
return d->activeForegroundColor;
}
return kDefaultBlackColor;
}());
painter.setFont([d]() -> QFont {
QFont font = FramelessManagerPrivate::getIconFont();
if (d->glyphSize.has_value()) {
font.setPointSize(d->glyphSize.value());
}
return font;
}());
painter.drawText(buttonRect, Qt::AlignCenter, d->glyph);
}
painter.restore();
event->accept();
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -83,58 +83,6 @@ const StandardTitleBarPrivate *StandardTitleBarPrivate::get(const StandardTitleB
return pub->d_func(); return pub->d_func();
} }
Qt::Alignment StandardTitleBarPrivate::titleLabelAlignment() const
{
return m_labelAlignment;
}
void StandardTitleBarPrivate::setTitleLabelAlignment(const Qt::Alignment value)
{
if (m_labelAlignment == value) {
return;
}
m_labelAlignment = value;
Q_Q(StandardTitleBar);
q->update();
Q_EMIT q->titleLabelAlignmentChanged();
}
bool StandardTitleBarPrivate::isExtended() const
{
return m_extended;
}
void StandardTitleBarPrivate::setExtended(const bool value)
{
if (m_extended == value) {
return;
}
m_extended = value;
Q_Q(StandardTitleBar);
q->setFixedHeight(m_extended ? kDefaultExtendedTitleBarHeight : kDefaultTitleBarHeight);
Q_EMIT q->extendedChanged();
}
bool StandardTitleBarPrivate::isHideWhenClose() const
{
return m_hideWhenClose;
}
void StandardTitleBarPrivate::setHideWhenClose(const bool value)
{
if (m_hideWhenClose == value) {
return;
}
m_hideWhenClose = value;
Q_Q(StandardTitleBar);
Q_EMIT q->hideWhenCloseChanged();
}
ChromePalette *StandardTitleBarPrivate::chromePalette() const
{
return m_chromePalette;
}
QFont StandardTitleBarPrivate::defaultFont() const QFont StandardTitleBarPrivate::defaultFont() const
{ {
Q_Q(const StandardTitleBar); Q_Q(const StandardTitleBar);
@ -145,14 +93,14 @@ QFont StandardTitleBarPrivate::defaultFont() const
StandardTitleBarPrivate::FontMetrics StandardTitleBarPrivate::titleLabelSize() const StandardTitleBarPrivate::FontMetrics StandardTitleBarPrivate::titleLabelSize() const
{ {
if (!m_window) { if (!window) {
return {}; return {};
} }
const QString text = m_window->windowTitle(); const QString text = window->windowTitle();
if (text.isEmpty()) { if (text.isEmpty()) {
return {}; return {};
} }
const QFont font = m_titleFont.value_or(defaultFont()); const QFont font = titleFont.value_or(defaultFont());
const QFontMetrics fontMetrics(font); const QFontMetrics fontMetrics(font);
return { return {
/* .width */ Utils::horizontalAdvance(fontMetrics, text), /* .width */ Utils::horizontalAdvance(fontMetrics, text),
@ -161,143 +109,6 @@ StandardTitleBarPrivate::FontMetrics StandardTitleBarPrivate::titleLabelSize() c
}; };
} }
void StandardTitleBarPrivate::paintTitleBar(QPaintEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
Q_Q(StandardTitleBar);
if (!m_window || !m_chromePalette) {
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);
if (m_titleLabelVisible) {
const QString text = m_window->windowTitle();
if (!text.isEmpty()) {
painter.setPen(foregroundColor);
painter.setFont(m_titleFont.value_or(defaultFont()));
const auto pos = [this, q]() -> QPoint {
const FontMetrics labelSize = titleLabelSize();
const int titleBarWidth = q->width();
int x = 0;
if (m_labelAlignment & Qt::AlignLeft) {
x = (windowIconRect().right() + kDefaultTitleBarContentsMargin);
} else if (m_labelAlignment & Qt::AlignRight) {
x = (titleBarWidth - kDefaultTitleBarContentsMargin - labelSize.width);
#ifndef Q_OS_MACOS
x -= (titleBarWidth - m_minimizeButton->x());
#endif // Q_OS_MACOS
} else if (m_labelAlignment & Qt::AlignHCenter) {
x = std::round(qreal(titleBarWidth - labelSize.width) / qreal(2));
} else {
WARNING << "The alignment for the title label is not set!";
}
const int y = std::round((qreal(q->height() - labelSize.height) / qreal(2)) + qreal(labelSize.ascent));
return {x, y};
}();
painter.drawText(pos, text);
}
}
if (m_windowIconVisible) {
const QIcon icon = m_window->windowIcon();
if (!icon.isNull()) {
icon.paint(&painter, windowIconRect());
}
}
painter.restore();
event->accept();
}
bool StandardTitleBarPrivate::titleLabelVisible() const
{
return m_titleLabelVisible;
}
void StandardTitleBarPrivate::setTitleLabelVisible(const bool value)
{
if (m_titleLabelVisible == value) {
return;
}
m_titleLabelVisible = value;
Q_Q(StandardTitleBar);
q->update();
Q_EMIT q->titleLabelVisibleChanged();
}
QSize StandardTitleBarPrivate::windowIconSize() const
{
return m_windowIconSize.value_or(kDefaultWindowIconSize);
}
void StandardTitleBarPrivate::setWindowIconSize(const QSize &value)
{
Q_ASSERT(!value.isEmpty());
if (value.isEmpty()) {
return;
}
if (windowIconSize() == value) {
return;
}
m_windowIconSize = value;
Q_Q(StandardTitleBar);
q->update();
Q_EMIT q->windowIconSizeChanged();
}
bool StandardTitleBarPrivate::windowIconVisible() const
{
return m_windowIconVisible;
}
void StandardTitleBarPrivate::setWindowIconVisible(const bool value)
{
if (m_windowIconVisible == value) {
return;
}
m_windowIconVisible = value;
Q_Q(StandardTitleBar);
q->update();
Q_EMIT q->windowIconVisibleChanged();
#ifndef Q_OS_MACOS
// Ideally we should use FramelessWidgetsHelper::get(this) everywhere, but sadly when
// we call it here, it may be too early that FramelessWidgetsHelper has not attached
// to the top level widget yet, and thus it will trigger an assert error (the assert
// should not be suppressed, because it usually indicates there's something really
// wrong). So here we have to use the top level widget directly, as a special case.
// NOTE: In your own code, you should always use FramelessWidgetsHelper::get(this)
// if possible.
FramelessWidgetsHelper::get(m_window)->setHitTestVisible(windowIconRect(), windowIconVisible_real());
#endif // Q_OS_MACOS
}
QFont StandardTitleBarPrivate::titleFont() const
{
return m_titleFont.value_or(QFont());
}
void StandardTitleBarPrivate::setTitleFont(const QFont &value)
{
if (titleFont() == value) {
return;
}
m_titleFont = value;
Q_Q(StandardTitleBar);
q->update();
Q_EMIT q->titleFontChanged();
}
bool StandardTitleBarPrivate::mouseEventHandler(QMouseEvent *event) bool StandardTitleBarPrivate::mouseEventHandler(QMouseEvent *event)
{ {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
@ -319,7 +130,7 @@ bool StandardTitleBarPrivate::mouseEventHandler(QMouseEvent *event)
switch (event->type()) { switch (event->type()) {
case QEvent::MouseButtonRelease: case QEvent::MouseButtonRelease:
// We need a valid top level widget here. // We need a valid top level widget here.
if (m_window && interestArea) { if (window && interestArea) {
// Sadly the mouse release events are always triggered before the // Sadly the mouse release events are always triggered before the
// mouse double click events, and if we intercept the mouse release // mouse double click events, and if we intercept the mouse release
// events here, we'll never get the double click events afterwards, // events here, we'll never get the double click events afterwards,
@ -339,16 +150,16 @@ bool StandardTitleBarPrivate::mouseEventHandler(QMouseEvent *event)
// The close event is already triggered, don't try to show the // The close event is already triggered, don't try to show the
// system menu anymore, otherwise it will prevent our window // system menu anymore, otherwise it will prevent our window
// from closing. // from closing.
if (m_closeTriggered) { if (closeTriggered) {
return; return;
} }
// Please refer to the comments in StandardTitleBarPrivate::setWindowIconVisible(). // Please refer to the comments in StandardTitleBarPrivate::setWindowIconVisible().
FramelessWidgetsHelper::get(m_window)->showSystemMenu([button, q, &scenePos, this]() -> QPoint { FramelessWidgetsHelper::get(window)->showSystemMenu([button, q, &scenePos, this]() -> QPoint {
QPoint pos = scenePos; QPoint pos = scenePos;
if (button == Qt::LeftButton) { if (button == Qt::LeftButton) {
pos = {0, q->height()}; pos = {0, q->height()};
} }
return m_window->mapToGlobal(pos); return window->mapToGlobal(pos);
}()); }());
}); });
// Don't eat this event, we have not handled it yet. // Don't eat this event, we have not handled it yet.
@ -356,9 +167,9 @@ bool StandardTitleBarPrivate::mouseEventHandler(QMouseEvent *event)
break; break;
case QEvent::MouseButtonDblClick: case QEvent::MouseButtonDblClick:
// We need a valid top level widget here. // We need a valid top level widget here.
if (m_window && (button == Qt::LeftButton) && interestArea) { if (window && (button == Qt::LeftButton) && interestArea) {
m_closeTriggered = true; closeTriggered = true;
m_window->close(); window->close();
// Eat this event, we have handled it here. // Eat this event, we have handled it here.
event->accept(); event->accept();
return true; return true;
@ -377,21 +188,21 @@ QRect StandardTitleBarPrivate::windowIconRect() const
if (!windowIconVisible_real()) { if (!windowIconVisible_real()) {
return {}; return {};
} }
const QSize size = windowIconSize(); const QSize size = q->windowIconSize();
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
const auto x = [this, q, &size]() -> int { const auto x = [this, q, &size]() -> int {
if (m_labelAlignment & Qt::AlignLeft) { if (labelAlignment & Qt::AlignLeft) {
return (kMacOSChromeButtonAreaWidth + kDefaultTitleBarContentsMargin); return (kMacOSChromeButtonAreaWidth + kDefaultTitleBarContentsMargin);
} }
const int titleBarWidth = q->width(); const int titleBarWidth = q->width();
const int labelWidth = titleLabelSize().width; const int labelWidth = titleLabelSize().width;
if (m_labelAlignment & Qt::AlignRight) { if (labelAlignment & Qt::AlignRight) {
// We need two spacer here, one is on the right edge of the title bar, // We need two spacer here, one is on the right edge of the title bar,
// the other one is between the window icon and the window label. // the other one is between the window icon and the window label.
return (titleBarWidth - kDefaultTitleBarContentsMargin return (titleBarWidth - kDefaultTitleBarContentsMargin
- labelWidth - kDefaultTitleBarContentsMargin - size.width()); - labelWidth - kDefaultTitleBarContentsMargin - size.width());
} }
if (m_labelAlignment & Qt::AlignHCenter) { if (labelAlignment & Qt::AlignHCenter) {
const int centeredX = std::round(qreal(titleBarWidth - labelWidth) / qreal(2)); const int centeredX = std::round(qreal(titleBarWidth - labelWidth) / qreal(2));
return (centeredX - kDefaultTitleBarContentsMargin - size.width()); return (centeredX - kDefaultTitleBarContentsMargin - size.width());
} }
@ -407,7 +218,7 @@ QRect StandardTitleBarPrivate::windowIconRect() const
bool StandardTitleBarPrivate::windowIconVisible_real() const bool StandardTitleBarPrivate::windowIconVisible_real() const
{ {
return (m_windowIconVisible && !m_window->windowIcon().isNull()); return (windowIconVisible && !window->windowIcon().isNull());
} }
bool StandardTitleBarPrivate::isInTitleBarIconArea(const QPoint &pos) const bool StandardTitleBarPrivate::isInTitleBarIconArea(const QPoint &pos) const
@ -421,9 +232,9 @@ bool StandardTitleBarPrivate::isInTitleBarIconArea(const QPoint &pos) const
void StandardTitleBarPrivate::updateMaximizeButton() void StandardTitleBarPrivate::updateMaximizeButton()
{ {
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
const bool max = m_window->isMaximized(); const bool max = window->isMaximized();
m_maximizeButton->setButtonType(max ? SystemButtonType::Restore : SystemButtonType::Maximize); maximizeButton->setButtonType(max ? SystemButtonType::Restore : SystemButtonType::Maximize);
m_maximizeButton->setToolTip(max ? tr("Restore") : tr("Maximize")); maximizeButton->setToolTip(max ? tr("Restore") : tr("Maximize"));
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
} }
@ -436,39 +247,39 @@ void StandardTitleBarPrivate::updateTitleBarColor()
void StandardTitleBarPrivate::updateChromeButtonColor() void StandardTitleBarPrivate::updateChromeButtonColor()
{ {
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
const bool active = m_window->isActiveWindow(); const bool active = window->isActiveWindow();
const QColor activeForeground = m_chromePalette->titleBarActiveForegroundColor(); const QColor activeForeground = chromePalette->titleBarActiveForegroundColor();
const QColor inactiveForeground = m_chromePalette->titleBarInactiveForegroundColor(); const QColor inactiveForeground = chromePalette->titleBarInactiveForegroundColor();
const QColor normal = m_chromePalette->chromeButtonNormalColor(); const QColor normal = chromePalette->chromeButtonNormalColor();
const QColor hover = m_chromePalette->chromeButtonHoverColor(); const QColor hover = chromePalette->chromeButtonHoverColor();
const QColor press = m_chromePalette->chromeButtonPressColor(); const QColor press = chromePalette->chromeButtonPressColor();
m_minimizeButton->setActiveForegroundColor(activeForeground); minimizeButton->setActiveForegroundColor(activeForeground);
m_minimizeButton->setInactiveForegroundColor(inactiveForeground); minimizeButton->setInactiveForegroundColor(inactiveForeground);
m_minimizeButton->setNormalColor(normal); minimizeButton->setNormalColor(normal);
m_minimizeButton->setHoverColor(hover); minimizeButton->setHoverColor(hover);
m_minimizeButton->setPressColor(press); minimizeButton->setPressColor(press);
m_minimizeButton->setActive(active); minimizeButton->setActive(active);
m_maximizeButton->setActiveForegroundColor(activeForeground); maximizeButton->setActiveForegroundColor(activeForeground);
m_maximizeButton->setInactiveForegroundColor(inactiveForeground); maximizeButton->setInactiveForegroundColor(inactiveForeground);
m_maximizeButton->setNormalColor(normal); maximizeButton->setNormalColor(normal);
m_maximizeButton->setHoverColor(hover); maximizeButton->setHoverColor(hover);
m_maximizeButton->setPressColor(press); maximizeButton->setPressColor(press);
m_maximizeButton->setActive(active); maximizeButton->setActive(active);
m_closeButton->setActiveForegroundColor(activeForeground); closeButton->setActiveForegroundColor(activeForeground);
m_closeButton->setInactiveForegroundColor(inactiveForeground); closeButton->setInactiveForegroundColor(inactiveForeground);
m_closeButton->setNormalColor(m_chromePalette->closeButtonNormalColor()); closeButton->setNormalColor(chromePalette->closeButtonNormalColor());
m_closeButton->setHoverColor(m_chromePalette->closeButtonHoverColor()); closeButton->setHoverColor(chromePalette->closeButtonHoverColor());
m_closeButton->setPressColor(m_chromePalette->closeButtonPressColor()); closeButton->setPressColor(chromePalette->closeButtonPressColor());
m_closeButton->setActive(active); closeButton->setActive(active);
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
} }
void StandardTitleBarPrivate::retranslateUi() void StandardTitleBarPrivate::retranslateUi()
{ {
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
m_minimizeButton->setToolTip(tr("Minimize")); minimizeButton->setToolTip(tr("Minimize"));
m_maximizeButton->setToolTip(m_window->isMaximized() ? tr("Restore") : tr("Maximize")); maximizeButton->setToolTip(window->isMaximized() ? tr("Restore") : tr("Maximize"));
m_closeButton->setToolTip(tr("Close")); closeButton->setToolTip(tr("Close"));
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
} }
@ -483,17 +294,17 @@ bool StandardTitleBarPrivate::eventFilter(QObject *object, QEvent *event)
return QObject::eventFilter(object, event); return QObject::eventFilter(object, event);
} }
const auto widget = qobject_cast<QWidget *>(object); const auto widget = qobject_cast<QWidget *>(object);
if (!widget->isWindow() || (widget != m_window)) { if (!widget->isWindow() || (widget != window)) {
return QObject::eventFilter(object, event); return QObject::eventFilter(object, event);
} }
switch (event->type()) { switch (event->type()) {
case QEvent::WindowStateChange: case QEvent::WindowStateChange:
updateMaximizeButton(); updateMaximizeButton();
break; break;
case QEvent::ActivationChange: case QEvent::ActivationChange: {
updateTitleBarColor(); updateTitleBarColor();
updateChromeButtonColor(); updateChromeButtonColor();
break; } break;
case QEvent::LanguageChange: case QEvent::LanguageChange:
retranslateUi(); retranslateUi();
break; break;
@ -506,19 +317,19 @@ bool StandardTitleBarPrivate::eventFilter(QObject *object, QEvent *event)
void StandardTitleBarPrivate::initialize() void StandardTitleBarPrivate::initialize()
{ {
Q_Q(StandardTitleBar); Q_Q(StandardTitleBar);
m_window = q->window(); window = q->window();
m_chromePalette = new ChromePalette(this); chromePalette = new ChromePalette(this);
connect(m_chromePalette, &ChromePalette::titleBarColorChanged, connect(chromePalette, &ChromePalette::titleBarColorChanged,
this, &StandardTitleBarPrivate::updateTitleBarColor); this, &StandardTitleBarPrivate::updateTitleBarColor);
connect(m_chromePalette, &ChromePalette::chromeButtonColorChanged, connect(chromePalette, &ChromePalette::chromeButtonColorChanged,
this, &StandardTitleBarPrivate::updateChromeButtonColor); this, &StandardTitleBarPrivate::updateChromeButtonColor);
q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
q->setFixedHeight(kDefaultTitleBarHeight); q->setFixedHeight(kDefaultTitleBarHeight);
connect(m_window, &QWidget::windowIconChanged, this, [q](const QIcon &icon){ connect(window, &QWidget::windowIconChanged, this, [q](const QIcon &icon){
Q_UNUSED(icon); Q_UNUSED(icon);
q->update(); q->update();
}); });
connect(m_window, &QWidget::windowTitleChanged, this, [q](const QString &title){ connect(window, &QWidget::windowTitleChanged, this, [q](const QString &title){
Q_UNUSED(title); Q_UNUSED(title);
q->update(); q->update();
}); });
@ -526,26 +337,25 @@ void StandardTitleBarPrivate::initialize()
const auto titleBarLayout = new QHBoxLayout(q); const auto titleBarLayout = new QHBoxLayout(q);
titleBarLayout->setSpacing(0); titleBarLayout->setSpacing(0);
titleBarLayout->setContentsMargins(0, 0, 0, 0); titleBarLayout->setContentsMargins(0, 0, 0, 0);
q->setLayout(titleBarLayout); q->setTitleLabelAlignment(Qt::AlignCenter);
setTitleLabelAlignment(Qt::AlignCenter);
#else // !Q_OS_MACOS #else // !Q_OS_MACOS
m_minimizeButton = new StandardSystemButton(SystemButtonType::Minimize, q); minimizeButton = new StandardSystemButton(SystemButtonType::Minimize, q);
connect(m_minimizeButton, &StandardSystemButton::clicked, m_window, &QWidget::showMinimized); connect(minimizeButton, &StandardSystemButton::clicked, window, &QWidget::showMinimized);
m_maximizeButton = new StandardSystemButton(SystemButtonType::Maximize, q); maximizeButton = new StandardSystemButton(SystemButtonType::Maximize, q);
updateMaximizeButton(); updateMaximizeButton();
connect(m_maximizeButton, &StandardSystemButton::clicked, this, [this](){ connect(maximizeButton, &StandardSystemButton::clicked, this, [this](){
if (m_window->isMaximized()) { if (window->isMaximized()) {
m_window->showNormal(); window->showNormal();
} else { } else {
m_window->showMaximized(); window->showMaximized();
} }
}); });
m_closeButton = new StandardSystemButton(SystemButtonType::Close, q); closeButton = new StandardSystemButton(SystemButtonType::Close, q);
connect(m_closeButton, &StandardSystemButton::clicked, this, [this](){ connect(closeButton, &StandardSystemButton::clicked, this, [this](){
if (m_hideWhenClose) { if (hideWhenClose) {
m_window->hide(); window->hide();
} else { } else {
m_window->close(); window->close();
} }
}); });
// According to the title bar design guidance, the system buttons should always be // According to the title bar design guidance, the system buttons should always be
@ -554,9 +364,9 @@ void StandardTitleBarPrivate::initialize()
const auto systemButtonsInnerLayout = new QHBoxLayout; const auto systemButtonsInnerLayout = new QHBoxLayout;
systemButtonsInnerLayout->setSpacing(0); systemButtonsInnerLayout->setSpacing(0);
systemButtonsInnerLayout->setContentsMargins(0, 0, 0, 0); systemButtonsInnerLayout->setContentsMargins(0, 0, 0, 0);
systemButtonsInnerLayout->addWidget(m_minimizeButton); systemButtonsInnerLayout->addWidget(minimizeButton);
systemButtonsInnerLayout->addWidget(m_maximizeButton); systemButtonsInnerLayout->addWidget(maximizeButton);
systemButtonsInnerLayout->addWidget(m_closeButton); systemButtonsInnerLayout->addWidget(closeButton);
const auto systemButtonsOuterLayout = new QVBoxLayout; const auto systemButtonsOuterLayout = new QVBoxLayout;
systemButtonsOuterLayout->setSpacing(0); systemButtonsOuterLayout->setSpacing(0);
systemButtonsOuterLayout->setContentsMargins(0, 0, 0, 0); systemButtonsOuterLayout->setContentsMargins(0, 0, 0, 0);
@ -567,13 +377,12 @@ void StandardTitleBarPrivate::initialize()
titleBarLayout->setContentsMargins(0, 0, 0, 0); titleBarLayout->setContentsMargins(0, 0, 0, 0);
titleBarLayout->addStretch(); titleBarLayout->addStretch();
titleBarLayout->addLayout(systemButtonsOuterLayout); titleBarLayout->addLayout(systemButtonsOuterLayout);
q->setLayout(titleBarLayout); q->setTitleLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
setTitleLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
retranslateUi(); retranslateUi();
updateTitleBarColor(); updateTitleBarColor();
updateChromeButtonColor(); updateChromeButtonColor();
m_window->installEventFilter(this); window->installEventFilter(this);
} }
StandardTitleBar::StandardTitleBar(QWidget *parent) StandardTitleBar::StandardTitleBar(QWidget *parent)
@ -583,122 +392,26 @@ StandardTitleBar::StandardTitleBar(QWidget *parent)
StandardTitleBar::~StandardTitleBar() = default; StandardTitleBar::~StandardTitleBar() = default;
Qt::Alignment StandardTitleBar::titleLabelAlignment() const
{
Q_D(const StandardTitleBar);
return d->titleLabelAlignment();
}
void StandardTitleBar::setTitleLabelAlignment(const Qt::Alignment value)
{
Q_D(StandardTitleBar);
d->setTitleLabelAlignment(value);
}
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
StandardSystemButton *StandardTitleBar::minimizeButton() const StandardSystemButton *StandardTitleBar::minimizeButton() const
{ {
Q_D(const StandardTitleBar); Q_D(const StandardTitleBar);
return d->m_minimizeButton; return d->minimizeButton;
} }
StandardSystemButton *StandardTitleBar::maximizeButton() const StandardSystemButton *StandardTitleBar::maximizeButton() const
{ {
Q_D(const StandardTitleBar); Q_D(const StandardTitleBar);
return d->m_maximizeButton; return d->maximizeButton;
} }
StandardSystemButton *StandardTitleBar::closeButton() const StandardSystemButton *StandardTitleBar::closeButton() const
{ {
Q_D(const StandardTitleBar); Q_D(const StandardTitleBar);
return d->m_closeButton; return d->closeButton;
} }
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
bool StandardTitleBar::isExtended() const
{
Q_D(const StandardTitleBar);
return d->isExtended();
}
void StandardTitleBar::setExtended(const bool value)
{
Q_D(StandardTitleBar);
d->setExtended(value);
}
bool StandardTitleBar::isHideWhenClose() const
{
Q_D(const StandardTitleBar);
return d->isHideWhenClose();
}
void StandardTitleBar::setHideWhenClose(const bool value)
{
Q_D(StandardTitleBar);
d->setHideWhenClose(value);
}
ChromePalette *StandardTitleBar::chromePalette() const
{
Q_D(const StandardTitleBar);
return d->chromePalette();
}
bool StandardTitleBar::titleLabelVisible() const
{
Q_D(const StandardTitleBar);
return d->titleLabelVisible();
}
void StandardTitleBar::setTitleLabelVisible(const bool value)
{
Q_D(StandardTitleBar);
d->setTitleLabelVisible(value);
}
QSize StandardTitleBar::windowIconSize() const
{
Q_D(const StandardTitleBar);
return d->windowIconSize();
}
void StandardTitleBar::setWindowIconSize(const QSize &value)
{
Q_D(StandardTitleBar);
d->setWindowIconSize(value);
}
bool StandardTitleBar::windowIconVisible() const
{
Q_D(const StandardTitleBar);
return d->windowIconVisible();
}
void StandardTitleBar::setWindowIconVisible(const bool value)
{
Q_D(StandardTitleBar);
d->setWindowIconVisible(value);
}
QFont StandardTitleBar::titleFont() const
{
Q_D(const StandardTitleBar);
return d->titleFont();
}
void StandardTitleBar::setTitleFont(const QFont &value)
{
Q_D(StandardTitleBar);
d->setTitleFont(value);
}
void StandardTitleBar::paintEvent(QPaintEvent *event)
{
Q_D(StandardTitleBar);
d->paintTitleBar(event);
}
void StandardTitleBar::mouseReleaseEvent(QMouseEvent *event) void StandardTitleBar::mouseReleaseEvent(QMouseEvent *event)
{ {
QWidget::mouseReleaseEvent(event); QWidget::mouseReleaseEvent(event);
@ -713,4 +426,201 @@ void StandardTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
std::ignore = d->mouseEventHandler(event); std::ignore = d->mouseEventHandler(event);
} }
Qt::Alignment StandardTitleBar::titleLabelAlignment() const
{
Q_D(const StandardTitleBar);
return d->labelAlignment;
}
void StandardTitleBar::setTitleLabelAlignment(const Qt::Alignment value)
{
Q_D(StandardTitleBar);
if (d->labelAlignment == value) {
return;
}
d->labelAlignment = value;
update();
Q_EMIT titleLabelAlignmentChanged();
}
bool StandardTitleBar::isExtended() const
{
Q_D(const StandardTitleBar);
return d->extended;
}
void StandardTitleBar::setExtended(const bool value)
{
Q_D(StandardTitleBar);
if (d->extended == value) {
return;
}
d->extended = value;
setFixedHeight(d->extended ? kDefaultExtendedTitleBarHeight : kDefaultTitleBarHeight);
Q_EMIT extendedChanged();
}
bool StandardTitleBar::isHideWhenClose() const
{
Q_D(const StandardTitleBar);
return d->hideWhenClose;
}
void StandardTitleBar::setHideWhenClose(const bool value)
{
Q_D(StandardTitleBar);
if (d->hideWhenClose == value) {
return;
}
d->hideWhenClose = value;
Q_EMIT hideWhenCloseChanged();
}
ChromePalette *StandardTitleBar::chromePalette() const
{
Q_D(const StandardTitleBar);
return d->chromePalette;
}
void StandardTitleBar::paintEvent(QPaintEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
Q_D(StandardTitleBar);
if (!d->window) {
return;
}
const bool active = d->window->isActiveWindow();
const QColor backgroundColor = (active ?
d->chromePalette->titleBarActiveBackgroundColor() :
d->chromePalette->titleBarInactiveBackgroundColor());
const QColor foregroundColor = (active ?
d->chromePalette->titleBarActiveForegroundColor() :
d->chromePalette->titleBarInactiveForegroundColor());
QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
painter.fillRect(QRect(QPoint(0, 0), size()), backgroundColor);
if (d->titleLabelVisible) {
const QString text = d->window->windowTitle();
if (!text.isEmpty()) {
painter.setPen(foregroundColor);
painter.setFont(d->titleFont.value_or(d->defaultFont()));
const auto pos = [this, d]() -> QPoint {
const StandardTitleBarPrivate::FontMetrics labelSize = d->titleLabelSize();
const int titleBarWidth = width();
int x = 0;
if (d->labelAlignment & Qt::AlignLeft) {
x = (d->windowIconRect().right() + kDefaultTitleBarContentsMargin);
} else if (d->labelAlignment & Qt::AlignRight) {
x = (titleBarWidth - kDefaultTitleBarContentsMargin - labelSize.width);
#ifndef Q_OS_MACOS
x -= (titleBarWidth - d->minimizeButton->x());
#endif // Q_OS_MACOS
} else if (d->labelAlignment & Qt::AlignHCenter) {
x = std::round(qreal(titleBarWidth - labelSize.width) / qreal(2));
} else {
WARNING << "The alignment for the title label is not set!";
}
const int y = std::round((qreal(height() - labelSize.height) / qreal(2)) + qreal(labelSize.ascent));
return {x, y};
}();
painter.drawText(pos, text);
}
}
if (d->windowIconVisible) {
const QIcon icon = d->window->windowIcon();
if (!icon.isNull()) {
icon.paint(&painter, d->windowIconRect());
}
}
painter.restore();
event->accept();
}
bool StandardTitleBar::titleLabelVisible() const
{
Q_D(const StandardTitleBar);
return d->titleLabelVisible;
}
void StandardTitleBar::setTitleLabelVisible(const bool value)
{
Q_D(StandardTitleBar);
if (d->titleLabelVisible == value) {
return;
}
d->titleLabelVisible = value;
update();
Q_EMIT titleLabelVisibleChanged();
}
QSize StandardTitleBar::windowIconSize() const
{
Q_D(const StandardTitleBar);
return d->windowIconSize.value_or(kDefaultWindowIconSize);
}
void StandardTitleBar::setWindowIconSize(const QSize &value)
{
Q_ASSERT(!value.isEmpty());
if (value.isEmpty()) {
return;
}
if (windowIconSize() == value) {
return;
}
Q_D(StandardTitleBar);
d->windowIconSize = value;
update();
Q_EMIT windowIconSizeChanged();
}
bool StandardTitleBar::windowIconVisible() const
{
Q_D(const StandardTitleBar);
return d->windowIconVisible;
}
void StandardTitleBar::setWindowIconVisible(const bool value)
{
Q_D(StandardTitleBar);
if (d->windowIconVisible == value) {
return;
}
d->windowIconVisible = value;
update();
Q_EMIT windowIconVisibleChanged();
#ifndef Q_OS_MACOS
// Ideally we should use FramelessWidgetsHelper::get(this) everywhere, but sadly when
// we call it here, it may be too early that FramelessWidgetsHelper has not attached
// to the top level widget yet, and thus it will trigger an assert error (the assert
// should not be suppressed, because it usually indicates there's something really
// wrong). So here we have to use the top level widget directly, as a special case.
// NOTE: In your own code, you should always use FramelessWidgetsHelper::get(this)
// if possible.
FramelessWidgetsHelper::get(d->window)->setHitTestVisible(d->windowIconRect(), d->windowIconVisible_real());
#endif // Q_OS_MACOS
}
QFont StandardTitleBar::titleFont() const
{
Q_D(const StandardTitleBar);
return d->titleFont.value_or(QFont());
}
void StandardTitleBar::setTitleFont(const QFont &value)
{
if (titleFont() == value) {
return;
}
Q_D(StandardTitleBar);
d->titleFont = value;
update();
Q_EMIT titleFontChanged();
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE