From a04fd53a38edd94e6d24a86d68976636d7b55359 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Wed, 1 Jun 2022 11:16:34 +0800 Subject: [PATCH] general improvements 1. replace raw char array with QByteArray 2. Register QWindow for Quick module 3. Account for hidden and disable state when hovering controls 4. fix quick title bar label alignment Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- .../Quick/private/framelessquickhelper_p.h | 2 +- .../private/framelesswidgetshelper_p.h | 2 +- src/core/framelessconfig.cpp | 29 +++++++---- src/quick/framelessquickhelper.cpp | 50 +++++++++++++------ src/quick/framelessquickmodule.cpp | 1 + src/quick/quickstandardtitlebar.cpp | 15 ++++-- src/widgets/framelesswidgetshelper.cpp | 47 +++++++++++------ 7 files changed, 98 insertions(+), 48 deletions(-) diff --git a/include/FramelessHelper/Quick/private/framelessquickhelper_p.h b/include/FramelessHelper/Quick/private/framelessquickhelper_p.h index 8bb00e5..bb82381 100644 --- a/include/FramelessHelper/Quick/private/framelessquickhelper_p.h +++ b/include/FramelessHelper/Quick/private/framelessquickhelper_p.h @@ -65,7 +65,7 @@ public: Q_NODISCARD bool isWindowFixedSize() const; void setWindowFixedSize(const bool value); - void emitSignalForAllInstances(const char *signal); + void emitSignalForAllInstances(const QByteArray &signal); private: Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const; diff --git a/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h b/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h index f1d69f4..555f058 100644 --- a/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h +++ b/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h @@ -61,7 +61,7 @@ public: Q_NODISCARD bool isWindowFixedSize() const; void setWindowFixedSize(const bool value); - void emitSignalForAllInstances(const char *signal); + void emitSignalForAllInstances(const QByteArray &signal); private: Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const; diff --git a/src/core/framelessconfig.cpp b/src/core/framelessconfig.cpp index 91dbfb9..b60780d 100644 --- a/src/core/framelessconfig.cpp +++ b/src/core/framelessconfig.cpp @@ -34,17 +34,23 @@ using namespace Global; FRAMELESSHELPER_STRING_CONSTANT2(ConfigFileName, ".framelesshelper.ini") -static constexpr const struct +static const struct { - const char *env = nullptr; - const char *ini = nullptr; + const QByteArray env = {}; + const QByteArray cfg = {}; } OptionsTable[] = { - {"FRAMELESSHELPER_USE_CROSS_PLATFORM_QT_IMPLEMENTATION", "Options/UseCrossPlatformQtImplementation"}, - {"FRAMELESSHELPER_FORCE_HIDE_WINDOW_FRAME_BORDER", "Options/ForceHideWindowFrameBorder"}, - {"FRAMELESSHELPER_FORCE_SHOW_WINDOW_FRAME_BORDER", "Options/ForceShowWindowFrameBorder"}, - {"FRAMELESSHELPER_DISABLE_WINDOWS_SNAP_LAYOUTS", "Options/DisableWindowsSnapLayouts"}, - {"FRAMELESSHELPER_WINDOW_USE_ROUND_CORNERS", "Options/WindowUseRoundCorners"}, - {"FRAMELESSHELPER_CENTER_WINDOW_BEFORE_SHOW", "Options/CenterWindowBeforeShow"} + {FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_USE_CROSS_PLATFORM_QT_IMPLEMENTATION"), + FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/UseCrossPlatformQtImplementation")}, + {FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_FORCE_HIDE_WINDOW_FRAME_BORDER"), + FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/ForceHideWindowFrameBorder")}, + {FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_FORCE_SHOW_WINDOW_FRAME_BORDER"), + FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/ForceShowWindowFrameBorder")}, + {FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_DISABLE_WINDOWS_SNAP_LAYOUTS"), + FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/DisableWindowsSnapLayouts")}, + {FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_WINDOW_USE_ROUND_CORNERS"), + FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/WindowUseRoundCorners")}, + {FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_CENTER_WINDOW_BEFORE_SHOW"), + FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/CenterWindowBeforeShow")} }; static constexpr const auto OptionCount = std::size(OptionsTable); @@ -86,8 +92,9 @@ void FramelessConfig::reload(const bool force) return new QSettings(appDir.filePath(kConfigFileName), QSettings::IniFormat); }()); for (int i = 0; i != OptionCount; ++i) { - const bool on = (qEnvironmentVariableIsSet(OptionsTable[i].env) && (qEnvironmentVariableIntValue(OptionsTable[i].env) > 0)) - || (!configFile.isNull() && configFile->value(QUtf8String(OptionsTable[i].ini), false).toBool()); + const bool on = (qEnvironmentVariableIsSet(OptionsTable[i].env.constData()) + && (qEnvironmentVariableIntValue(OptionsTable[i].env.constData()) > 0)) + || (!configFile.isNull() && configFile->value(QUtf8String(OptionsTable[i].cfg), false).toBool()); g_data()->options[i] = on; } g_data()->loaded = true; diff --git a/src/quick/framelessquickhelper.cpp b/src/quick/framelessquickhelper.cpp index abdd4c0..516265f 100644 --- a/src/quick/framelessquickhelper.cpp +++ b/src/quick/framelessquickhelper.cpp @@ -111,7 +111,7 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value) return; } data->titleBarItem = value; - emitSignalForAllInstances("titleBarItemChanged"); + emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("titleBarItemChanged")); } void FramelessQuickHelperPrivate::attachToWindow() @@ -184,7 +184,7 @@ void FramelessQuickHelperPrivate::attachToWindow() if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) { moveWindowToDesktopCenter(); } - emitSignalForAllInstances("ready"); + emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("ready")); }); } @@ -305,7 +305,7 @@ void FramelessQuickHelperPrivate::bringWindowToFront() window->show(); } if (window->visibility() == QQuickWindow::Minimized) { - window->showNormal(); // ### FIXME + window->showNormal(); // ### FIXME: we should not show normal, we should restore the previous state. } window->raise(); window->requestActivate(); @@ -353,10 +353,10 @@ void FramelessQuickHelperPrivate::setWindowFixedSize(const bool value) Q_EMIT q->windowFixedSizeChanged(); } -void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal) +void FramelessQuickHelperPrivate::emitSignalForAllInstances(const QByteArray &signal) { - Q_ASSERT(signal); - if (!signal) { + Q_ASSERT(!signal.isEmpty()); + if (signal.isEmpty()) { return; } Q_Q(FramelessQuickHelper); @@ -370,7 +370,7 @@ void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal) return; } for (auto &&instance : qAsConst(instances)) { - QMetaObject::invokeMethod(instance, signal); + QMetaObject::invokeMethod(instance, signal.constData()); } } @@ -397,31 +397,31 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob } *button = QuickGlobal::SystemButtonType::Unknown; const QuickHelperData data = getWindowData(); - if (data.windowIconButton) { + if (data.windowIconButton && data.windowIconButton->isVisible() && data.windowIconButton->isEnabled()) { if (mapItemGeometryToScene(data.windowIconButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::WindowIcon; return true; } } - if (data.contextHelpButton) { + if (data.contextHelpButton && data.contextHelpButton->isVisible() && data.contextHelpButton->isEnabled()) { if (mapItemGeometryToScene(data.contextHelpButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Help; return true; } } - if (data.minimizeButton) { + if (data.minimizeButton && data.minimizeButton->isVisible() && data.minimizeButton->isEnabled()) { if (mapItemGeometryToScene(data.minimizeButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Minimize; return true; } } - if (data.maximizeButton) { + if (data.maximizeButton && data.maximizeButton->isVisible() && data.maximizeButton->isEnabled()) { if (mapItemGeometryToScene(data.maximizeButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Maximize; return true; } } - if (data.closeButton) { + if (data.closeButton && data.closeButton->isVisible() && data.closeButton->isEnabled()) { if (mapItemGeometryToScene(data.closeButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Close; return true; @@ -434,20 +434,38 @@ bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) c { const QuickHelperData data = getWindowData(); if (!data.titleBarItem) { + // There's no title bar at all, the mouse will always be in the client area. return false; } - QRegion region = mapItemGeometryToScene(data.titleBarItem); + if (!data.titleBarItem->isVisible() || !data.titleBarItem->isEnabled()) { + // The title bar is hidden or disabled for some reason, treat it as there's no title bar. + return false; + } + Q_Q(const FramelessQuickHelper); + const QQuickWindow * const window = q->window(); + if (!window) { + // The FramelessQuickHelper item has not been attached to a specific window yet, + // so we assume there's no title bar. + return false; + } + const QRect windowRect = {QPoint(0, 0), window->size()}; + const QRect titleBarRect = mapItemGeometryToScene(data.titleBarItem); + if (!titleBarRect.intersects(windowRect)) { + // The title bar is totally outside of the window for some reason, + // also treat it as there's no title bar. + return false; + } + QRegion region = titleBarRect; const auto systemButtons = {data.windowIconButton, data.contextHelpButton, data.minimizeButton, data.maximizeButton, data.closeButton}; for (auto &&button : qAsConst(systemButtons)) { - if (button) { + if (button && button->isVisible() && button->isEnabled()) { region -= mapItemGeometryToScene(button); } } if (!data.hitTestVisibleItems.isEmpty()) { for (auto &&item : qAsConst(data.hitTestVisibleItems)) { - Q_ASSERT(item); - if (item) { + if (item && item->isVisible() && item->isEnabled()) { region -= mapItemGeometryToScene(item); } } diff --git a/src/quick/framelessquickmodule.cpp b/src/quick/framelessquickmodule.cpp index 648b2d8..887191d 100644 --- a/src/quick/framelessquickmodule.cpp +++ b/src/quick/framelessquickmodule.cpp @@ -69,6 +69,7 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine) Q_UNUSED(scriptEngine); return new FramelessQuickUtils; }); + qmlRegisterRevision(QUICK_URI_FULL); qmlRegisterRevision(QUICK_URI_FULL); qmlRegisterRevision(QUICK_URI_FULL); qmlRegisterType(QUICK_URI_EXPAND("FramelessHelper")); diff --git a/src/quick/quickstandardtitlebar.cpp b/src/quick/quickstandardtitlebar.cpp index 5e81bb6..ccc5826 100644 --- a/src/quick/quickstandardtitlebar.cpp +++ b/src/quick/quickstandardtitlebar.cpp @@ -57,6 +57,13 @@ void QuickStandardTitleBar::setTitleLabelAlignment(const Qt::Alignment value) } m_labelAlignment = value; QQuickAnchors * const labelAnchors = QQuickItemPrivate::get(m_windowTitleLabel.data())->anchors(); + //labelAnchors->setMargins(0); + labelAnchors->resetFill(); + labelAnchors->resetCenterIn(); + labelAnchors->resetTop(); + labelAnchors->resetBottom(); + labelAnchors->resetLeft(); + labelAnchors->resetRight(); const QQuickItemPrivate * const titleBarPriv = QQuickItemPrivate::get(this); if (m_labelAlignment & Qt::AlignTop) { labelAnchors->setTop(titleBarPriv->top()); @@ -75,13 +82,13 @@ void QuickStandardTitleBar::setTitleLabelAlignment(const Qt::Alignment value) labelAnchors->setRightMargin(kDefaultTitleBarContentsMargin); } if (m_labelAlignment & Qt::AlignVCenter) { - labelAnchors->setTopMargin(0); - labelAnchors->setBottomMargin(0); + //labelAnchors->setTopMargin(0); + //labelAnchors->setBottomMargin(0); labelAnchors->setVerticalCenter(titleBarPriv->verticalCenter()); } if (m_labelAlignment & Qt::AlignHCenter) { - labelAnchors->setLeftMargin(0); - labelAnchors->setRightMargin(0); + //labelAnchors->setLeftMargin(0); + //labelAnchors->setRightMargin(0); labelAnchors->setHorizontalCenter(titleBarPriv->horizontalCenter()); } Q_EMIT titleLabelAlignmentChanged(); diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index ec21af9..d87fbaa 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -130,10 +130,10 @@ void FramelessWidgetsHelperPrivate::setWindowFixedSize(const bool value) Q_EMIT q->windowFixedSizeChanged(); } -void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal) +void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const QByteArray &signal) { - Q_ASSERT(signal); - if (!signal) { + Q_ASSERT(!signal.isEmpty()); + if (signal.isEmpty()) { return; } const QWidget * const window = getWindow(); @@ -145,7 +145,7 @@ void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal return; } for (auto &&instance : qAsConst(instances)) { - QMetaObject::invokeMethod(instance, signal); + QMetaObject::invokeMethod(instance, signal.constData()); } } @@ -164,7 +164,7 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget) return; } data->titleBarWidget = widget; - emitSignalForAllInstances("titleBarWidgetChanged"); + emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("titleBarWidgetChanged")); } QWidget *FramelessWidgetsHelperPrivate::getTitleBarWidget() const @@ -268,7 +268,7 @@ void FramelessWidgetsHelperPrivate::attachToWindow() if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) { moveWindowToDesktopCenter(); } - emitSignalForAllInstances("ready"); + emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("ready")); }); } @@ -338,31 +338,31 @@ bool FramelessWidgetsHelperPrivate::isInSystemButtons(const QPoint &pos, SystemB } *button = SystemButtonType::Unknown; const WidgetsHelperData data = getWindowData(); - if (data.windowIconButton) { + if (data.windowIconButton && data.windowIconButton->isVisible() && data.windowIconButton->isEnabled()) { if (data.windowIconButton->geometry().contains(pos)) { *button = SystemButtonType::WindowIcon; return true; } } - if (data.contextHelpButton) { + if (data.contextHelpButton && data.contextHelpButton->isVisible() && data.contextHelpButton->isEnabled()) { if (data.contextHelpButton->geometry().contains(pos)) { *button = SystemButtonType::Help; return true; } } - if (data.minimizeButton) { + if (data.minimizeButton && data.minimizeButton->isVisible() && data.minimizeButton->isEnabled()) { if (data.minimizeButton->geometry().contains(pos)) { *button = SystemButtonType::Minimize; return true; } } - if (data.maximizeButton) { + if (data.maximizeButton && data.maximizeButton->isVisible() && data.maximizeButton->isEnabled()) { if (data.maximizeButton->geometry().contains(pos)) { *button = SystemButtonType::Maximize; return true; } } - if (data.closeButton) { + if (data.closeButton && data.closeButton->isVisible() && data.closeButton->isEnabled()) { if (data.closeButton->geometry().contains(pos)) { *button = SystemButtonType::Close; return true; @@ -375,20 +375,37 @@ bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) { const WidgetsHelperData data = getWindowData(); if (!data.titleBarWidget) { + // There's no title bar at all, the mouse will always be in the client area. return false; } - QRegion region = mapWidgetGeometryToScene(data.titleBarWidget); + if (!data.titleBarWidget->isVisible() || !data.titleBarWidget->isEnabled()) { + // The title bar is hidden or disabled for some reason, treat it as there's no title bar. + return false; + } + const QWidget * const window = getWindow(); + if (!window) { + // The FramelessWidgetsHelper object has not been attached to a specific window yet, + // so we assume there's no title bar. + return false; + } + const QRect windowRect = {QPoint(0, 0), window->size()}; + const QRect titleBarRect = mapWidgetGeometryToScene(data.titleBarWidget); + if (!titleBarRect.intersects(windowRect)) { + // The title bar is totally outside of the window for some reason, + // also treat it as there's no title bar. + return false; + } + QRegion region = titleBarRect; const auto systemButtons = {data.windowIconButton, data.contextHelpButton, data.minimizeButton, data.maximizeButton, data.closeButton}; for (auto &&button : qAsConst(systemButtons)) { - if (button) { + if (button && button->isVisible() && button->isEnabled()) { region -= mapWidgetGeometryToScene(button); } } if (!data.hitTestVisibleWidgets.isEmpty()) { for (auto &&widget : qAsConst(data.hitTestVisibleWidgets)) { - Q_ASSERT(widget); - if (widget) { + if (widget && widget->isVisible() && widget->isEnabled()) { region -= mapWidgetGeometryToScene(widget); } }