diff --git a/qt6/src/qml/TitleBar.qml b/qt6/src/qml/TitleBar.qml index 48902a9d5..68bbf07b4 100644 --- a/qt6/src/qml/TitleBar.qml +++ b/qt6/src/qml/TitleBar.qml @@ -28,6 +28,7 @@ Item { // visibility access property bool fullScreenButtonVisible: true + property bool splitScreenEnabled: true signal toggleWindowState() property alias windowButtonGroup: windowButtonsLoader.sourceComponent @@ -179,6 +180,7 @@ Item { embedMode: control.embedMode textColor: control.textColor fullScreenButtonVisible: control.fullScreenButtonVisible + splitScreenEnabled: control.splitScreenEnabled Component.onCompleted: { control.toggleWindowState.connect(maxOrWinded) } diff --git a/qt6/src/qml/WindowButtonGroup.qml b/qt6/src/qml/WindowButtonGroup.qml index a86a9de13..8d1cdd346 100644 --- a/qt6/src/qml/WindowButtonGroup.qml +++ b/qt6/src/qml/WindowButtonGroup.qml @@ -14,6 +14,7 @@ RowLayout { property D.Palette textColor: DS.Style.button.text property bool fullScreenButtonVisible: true + property bool splitScreenEnabled: true property bool embedMode: false signal maxOrWinded() @@ -76,6 +77,7 @@ RowLayout { WindowButton { id: maxOrWindedBtn; objectName: "maxOrWindedBtn" + hoverEnabled: true property bool hasWindowFlag/*: (Window.window.flags & Qt.WindowMaximizeButtonHint)*/ Component.onCompleted: hasWindowFlag = (Window.window.flags & Qt.WindowMaximizeButtonHint) @@ -86,7 +88,82 @@ RowLayout { property bool isMaximized: Window.window.visibility === Window.Maximized icon.name: isMaximized ? "window_restore" : "window_maximize" textColor: control.textColor - onClicked: maxOrWinded() + property bool __longPressed: false + property bool __menuRequested: false + + function showSplitMenu() { + if (!control.splitScreenEnabled || !visible || !enabled) + return false + if (!__menuRequested) + __menuRequested = control.__dwindow.showSplitMenu(maxOrWindedBtn) + return __menuRequested + } + + function hideSplitMenu(delay) { + hoverTimer.stop() + holdTimer.stop() + control.__dwindow.hideSplitMenu(delay) + __menuRequested = false + } + + onHoveredChanged: { + if (hovered && !pressed) + hoverTimer.restart() + else if (!hovered) { + hoverTimer.stop() + if (pressed) + holdTimer.stop() + else + hideSplitMenu(true) + } + } + onPressed: { + __longPressed = false + hoverTimer.stop() + holdTimer.restart() + } + onReleased: { + holdTimer.stop() + if (!__longPressed) + hideSplitMenu(false) + else + __menuRequested = false + } + onCanceled: { + hideSplitMenu(true) + __longPressed = false + } + onClicked: { + if (!__longPressed) + control.maxOrWinded() + __longPressed = false + } + onVisibleChanged: { + if (!visible) { + hoverTimer.stop() + holdTimer.stop() + __menuRequested = false + } + } + onEnabledChanged: if (!enabled) hideSplitMenu(false) + + Timer { + id: hoverTimer + interval: 700 + onTriggered: maxOrWindedBtn.showSplitMenu() + } + Timer { + id: holdTimer + interval: 300 + onTriggered: maxOrWindedBtn.__longPressed = maxOrWindedBtn.showSplitMenu() + } + Connections { + target: control + function onSplitScreenEnabledChanged() { + if (!control.splitScreenEnabled) + maxOrWindedBtn.hideSplitMenu(false) + } + } visible: (hasWindowFlag && !__forceHind && __canResize && __sizeResizable) enabled: (__canMaximize && __canResize) diff --git a/src/dquickwindow.cpp b/src/dquickwindow.cpp index 4988bc1dd..8b5b863bc 100644 --- a/src/dquickwindow.cpp +++ b/src/dquickwindow.cpp @@ -15,6 +15,8 @@ #include #include +#include +#include DQUICK_BEGIN_NAMESPACE @@ -1010,6 +1012,45 @@ void DQuickWindowAttached::popupSystemWindowMenu() DWindowManagerHelper::popupSystemWindowMenu(window()); } +// Platform split-menu functions take a Qt window id and a global logical rectangle. +bool DQuickWindowAttached::showSplitMenu(QQuickItem *button) +{ + D_D(DQuickWindowAttached); + auto *w = window(); + if (!w || !w->isVisible() || !w->handle() || !button || button->window() != w + || !button->isVisible() || !button->isEnabled()) + return false; + + const auto support = reinterpret_cast( + QGuiApplication::platformFunction("_d_supportSplitMenu")); + const auto show = reinterpret_cast( + QGuiApplication::platformFunction("_d_showSplitMenu")); + const auto hide = QGuiApplication::platformFunction("_d_hideSplitMenu"); + const WId wid = w->winId(); + if (!support || !show || !hide || !support(wid)) + return false; + + const QRect rect = button->mapRectToScene(button->boundingRect()).toAlignedRect(); + if (!rect.isValid()) + return false; + show(wid, QRect(w->mapToGlobal(rect.topLeft()), rect.size())); + d->splitMenuWindowId = wid; + return true; +} + +void DQuickWindowAttached::hideSplitMenu(bool delay) +{ + D_D(DQuickWindowAttached); + if (!d->splitMenuWindowId) + return; + const auto hide = reinterpret_cast( + QGuiApplication::platformFunction("_d_hideSplitMenu")); + if (hide) + hide(d->splitMenuWindowId, delay); + if (!delay) + d->splitMenuWindowId = 0; +} + bool DQuickWindowAttached::setWindowBlurAreaByWM(const QVector &area) { D_D(DQuickWindowAttached); diff --git a/src/dquickwindow.h b/src/dquickwindow.h index db67525b4..bf74fad1f 100644 --- a/src/dquickwindow.h +++ b/src/dquickwindow.h @@ -148,6 +148,9 @@ public Q_SLOTS: void popupSystemWindowMenu(); + bool showSplitMenu(QQuickItem *button); + void hideSplitMenu(bool delay = true); + bool setWindowBlurAreaByWM(const QVector &area); bool setWindowBlurAreaByWM(const QList &area); diff --git a/src/private/dquickwindow_p.h b/src/private/dquickwindow_p.h index 801279e78..07efd715e 100644 --- a/src/private/dquickwindow_p.h +++ b/src/private/dquickwindow_p.h @@ -56,6 +56,7 @@ class DQuickWindowAttachedPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate #endif QPointer window = nullptr; + WId splitMenuWindowId = 0; DPlatformHandle *handle = nullptr; BoolOptional explicitEnable {Invalid}; BoolOptional explicitTranslucentBackground {Invalid};