From a2b195580b5577e24c7ec5c07640e7ea2639ad61 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 17 Nov 2023 13:19:00 +0200 Subject: [PATCH] EffectMaker: Fix popup geometry Effect Maker preview and node combo box popups will now stay within the screen boundaries of the screen the parent combo box belongs to. Fixes: QDS-10512 Change-Id: Ibbfb706499c4b17e27ff5ae471fef8bb9f7384cb Reviewed-by: Mahmoud Badri --- .../EffectNodesComboBox.qml | 52 +++++++++++++------ .../PreviewImagesComboBox.qml | 52 +++++++++++++------ .../effectmakernew/effectmakerwidget.cpp | 14 +++++ .../effectmakernew/effectmakerwidget.h | 2 + 4 files changed, 86 insertions(+), 34 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml index 0827b20c1e3..0aca7a89089 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml @@ -23,18 +23,48 @@ StudioControls.ComboBox { required property Item mainRoot + readonly property int popupHeight: Math.min(800, row.height + 2) + + function calculateWindowGeometry() { + var globalPos = EffectMakerBackend.rootView.globalPos(mainRoot.mapFromItem(root, 0, 0)) + var screenRect = EffectMakerBackend.rootView.screenRect(); + + window.width = row.width + 2 // 2: scrollView left and right 1px margins + + var newX = globalPos.x + root.width - window.width + if (newX < screenRect.x) + newX = globalPos.x + + var newY = Math.min(screenRect.y + screenRect.height, + Math.max(screenRect.y, globalPos.y + root.height - 1)) + + // Check if we have more space above or below the control, and put control on that side, + // unless we have enough room for maximum size popup under the control + var newHeight + var screenY = newY - screenRect.y + if (screenRect.height - screenY > screenY || screenRect.height - screenY > root.popupHeight) { + newHeight = Math.min(root.popupHeight, screenRect.height - screenY) + } else { + newHeight = Math.min(root.popupHeight, screenY - root.height) + newY = newY - newHeight - root.height + 1 + } + + window.height = newHeight + window.x = newX + window.y = newY + } + Connections { target: root.popup function onAboutToShow() { - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - window.width - window.y = a.y + b.y + root.height - 1 + root.calculateWindowGeometry() window.show() window.requestActivate() + + // Geometry can get corrupted by first show after screen change, so recalc it + root.calculateWindowGeometry() } function onAboutToHide() { @@ -45,8 +75,6 @@ StudioControls.ComboBox { Window { id: window - width: row.width + 2 // 2: scrollView left and right 1px margins - height: Math.min(800, Math.min(row.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint onActiveFocusItemChanged: { @@ -67,16 +95,6 @@ StudioControls.ComboBox { Row { id: row - onWidthChanged: { - // Needed to update on first window showing, as row.width only gets - // correct value after the window is shown, so first showing is off - - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - row.width - } - padding: 10 spacing: 10 diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml index bcf4efbd4d9..02e43ea10c7 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml @@ -30,18 +30,48 @@ StudioControls.ComboBox { "images/preview4.png"] property string selectedImage: images[0] + readonly property int popupHeight: Math.min(800, col.height + 2) + + function calculateWindowGeometry() { + var globalPos = EffectMakerBackend.rootView.globalPos(mainRoot.mapFromItem(root, 0, 0)) + var screenRect = EffectMakerBackend.rootView.screenRect(); + + window.width = col.width + 2 // 2: scrollView left and right 1px margins + + var newX = globalPos.x + root.width - window.width + if (newX < screenRect.x) + newX = globalPos.x + + var newY = Math.min(screenRect.y + screenRect.height, + Math.max(screenRect.y, globalPos.y + root.height - 1)) + + // Check if we have more space above or below the control, and put control on that side, + // unless we have enough room for maximum size popup under the control + var newHeight + var screenY = newY - screenRect.y + if (screenRect.height - screenY > screenY || screenRect.height - screenY > root.popupHeight) { + newHeight = Math.min(root.popupHeight, screenRect.height - screenY) + } else { + newHeight = Math.min(root.popupHeight, screenY - root.height) + newY = newY - newHeight - root.height + 1 + } + + window.height = newHeight + window.x = newX + window.y = newY + } + Connections { target: root.popup function onAboutToShow() { - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - window.width - window.y = a.y + b.y + root.height - 1 + root.calculateWindowGeometry() window.show() window.requestActivate() + + // Geometry can get corrupted by first show after screen change, so recalc it + root.calculateWindowGeometry() } function onAboutToHide() { @@ -65,8 +95,6 @@ StudioControls.ComboBox { Window { id: window - width: col.width + 2 // 2: scrollView left and right 1px margins - height: Math.min(800, Math.min(col.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint onActiveFocusItemChanged: { @@ -88,16 +116,6 @@ StudioControls.ComboBox { Column { id: col - onWidthChanged: { - // Needed to update on first window showing, as row.width only gets - // correct value after the window is shown, so first showing is off - - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - col.width - } - padding: 10 spacing: 10 diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index 738c0a00168..724ab04f892 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -119,6 +119,20 @@ void EffectMakerWidget::focusSection(int section) Q_UNUSED(section) } +QRect EffectMakerWidget::screenRect() const +{ + if (m_quickWidget && m_quickWidget->screen()) + return m_quickWidget->screen()->availableGeometry(); + return {}; +} + +QPoint EffectMakerWidget::globalPos(const QPoint &point) const +{ + if (m_quickWidget) + return m_quickWidget->mapToGlobal(point); + return point; +} + QSize EffectMakerWidget::sizeHint() const { return {420, 420}; diff --git a/src/plugins/effectmakernew/effectmakerwidget.h b/src/plugins/effectmakernew/effectmakerwidget.h index 24efac7b586..3c43d732e40 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.h +++ b/src/plugins/effectmakernew/effectmakerwidget.h @@ -41,6 +41,8 @@ public: Q_INVOKABLE void addEffectNode(const QString &nodeQenPath); Q_INVOKABLE void focusSection(int section); + Q_INVOKABLE QRect screenRect() const; + Q_INVOKABLE QPoint globalPos(const QPoint &point) const; QSize sizeHint() const override;