From 56db321846c8bf12e2aa3f3e0ea98fa864d53d69 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Sat, 20 Sep 2025 12:23:43 +0200 Subject: [PATCH] fix: disable panel dragging during text input and dialog interaction NPanel: disable DragHandler when popups open, block drag over text inputs BarWidgetSettingsDialog: notify panel of open/close state BarSectionEditor: pass panel reference to dialog --- .../SettingsPanel/Bar/BarSectionEditor.qml | 14 +- .../Bar/BarWidgetSettingsDialog.qml | 16 +++ Widgets/NPanel.qml | 123 +++++++++++++++++- 3 files changed, 150 insertions(+), 3 deletions(-) diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml index aa006544..6f2adf7c 100644 --- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml +++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml @@ -23,6 +23,9 @@ NBox { signal dragPotentialStarted signal dragPotentialEnded + property bool hasOpenDialog: false + property bool hasOpenPopup: false + color: Color.mSurface Layout.fillWidth: true Layout.minimumHeight: { @@ -189,11 +192,15 @@ NBox { onClicked: { var component = Qt.createComponent(Qt.resolvedUrl("BarWidgetSettingsDialog.qml")) function instantiateAndOpen() { + // Find the settings panel + var settingsPanel = findSettingsPanel() + var dialog = component.createObject(root, { "widgetIndex": index, "widgetData": modelData, "widgetId": modelData.id, - "parent": Overlay.overlay + "parent": Overlay.overlay, + "settingsPanel": settingsPanel }) if (dialog) { dialog.open() @@ -201,6 +208,11 @@ NBox { Logger.error("BarSectionEditor", "Failed to create settings dialog instance") } } + + function findSettingsPanel() { + var panel = PanelService.getPanel("settingsPanel") + return panel + } if (component.status === Component.Ready) { instantiateAndOpen() } else if (component.status === Component.Error) { diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml index fe65650f..ba6f9c61 100644 --- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml +++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml @@ -14,6 +14,7 @@ Popup { property int widgetIndex: -1 property var widgetData: null property string widgetId: "" + property var settingsPanel: null // Center popup in parent x: (parent.width - width) * 0.5 @@ -23,6 +24,7 @@ Popup { height: content.implicitHeight + padding * 2 padding: Style.marginXL * scaling modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside background: Rectangle { id: bgRect @@ -37,6 +39,20 @@ Popup { if (widgetData && widgetId) { loadWidgetSettings() } + notifySettingsPanel(true) + } + + onClosed: { + notifySettingsPanel(false) + } + + function notifySettingsPanel(isOpen) { + if (settingsPanel && settingsPanel.hasOwnProperty('hasOpenPopup')) { + settingsPanel.hasOpenPopup = isOpen + Logger.log("BarWidgetSettingsDialog", "Notified settings panel popup state:", isOpen, "Panel:", settingsPanel.objectName || "unnamed") + } else { + Logger.warn("BarWidgetSettingsDialog", "No settings panel reference available to notify popup state:", isOpen) + } } function loadWidgetSettings() { diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index 26ad0b8b..b0ffff13 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -33,6 +33,7 @@ Loader { property bool panelKeyboardFocus: false property bool backgroundClickEnabled: true + property bool hasOpenPopup: false // Animation properties readonly property real originalScale: 0.7 @@ -155,6 +156,70 @@ Loader { dimmingOpacity = Style.opacityHeavy } + // Function to check if any popups are open + function checkForOpenPopups() { + // Check if this panel has an open popup + if (root.hasOpenPopup) { + return true + } + + var contentItem = panelContentLoader.item + if (!contentItem) + return false + + // Check for BarSectionEditor dialogs + if (hasOpenDialogInContent(contentItem)) { + return true + } + + return hasOpenPopupRecursive(contentItem) + } + + function hasOpenDialogInContent(item) { + if (!item) + return false + + // Check if this item is a BarSectionEditor with an open dialog + if (item.hasOwnProperty('hasOpenDialog') && item.hasOpenDialog) { + return true + } + + // Check children recursively + if (item.children) { + for (var i = 0; i < item.children.length; i++) { + var child = item.children[i] + if (child && hasOpenDialogInContent(child)) { + return true + } + } + } + + return false + } + + function hasOpenPopupRecursive(item) { + if (!item) + return false + + // Check if this item is a popup and is open + if (item.hasOwnProperty('opened') && item.opened) + return true + if (item.hasOwnProperty('visible') && item.visible && item.toString().includes("Popup")) + return true + + // Check children recursively + if (item.children) { + for (var i = 0; i < item.children.length; i++) { + var child = item.children[i] + if (child && hasOpenPopupRecursive(child)) { + return true + } + } + } + + return false + } + Connections { target: ScalingService function onScaleChanged(screenName, scale) { @@ -413,15 +478,64 @@ Loader { sourceComponent: root.panelContent } - // Handle drag move on the whole panel area + // FIXED: Handle drag move with text input exclusion DragHandler { id: dragHandler target: null - enabled: panelBackground.draggable + enabled: panelBackground.draggable && !panelWindow.checkForOpenPopups() + + // Add grab permissions to be more selective + grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType + property real dragStartX: 0 property real dragStartY: 0 + + // Helper function to check if an item is a text input + function isTextInputItem(item) { + if (!item) + return false + + var itemString = item.toString() + return (itemString.indexOf("TextField") >= 0 || itemString.indexOf("TextInput") >= 0 || itemString.indexOf("TextEdit") >= 0 || (item.objectName && (item.objectName.indexOf("textField") >= 0 || item.objectName.indexOf("textInput") >= 0 || item.objectName.indexOf("input") >= 0))) + } + + // Helper function to check if we're over a text input (walks up parent chain) + function isOverTextInput(x, y) { + var item = panelContentLoader.childAt(x, y) + var maxDepth = 10 // Prevent infinite loops + var depth = 0 + + while (item && depth < maxDepth) { + if (isTextInputItem(item)) { + return true + } + + // Check if this item has text input children + for (var i = 0; i < item.children.length; i++) { + if (isTextInputItem(item.children[i])) { + // Check if the point is within this child + var childPos = item.children[i].mapToItem(panelBackground, 0, 0) + if (x >= childPos.x && x <= childPos.x + item.children[i].width && y >= childPos.y && y <= childPos.y + item.children[i].height) { + return true + } + } + } + + item = item.parent + depth++ + } + return false + } + onActiveChanged: { if (active) { + // Check if we're starting drag over a text input + var localPos = mapToItem(panelBackground, centroid.position) + if (isOverTextInput(localPos.x, localPos.y)) { + // Cancel drag by returning early + return + } + // Capture current position into manual coordinates BEFORE toggling isDragged panelBackground.manualX = panelBackground.x panelBackground.manualY = panelBackground.y @@ -436,7 +550,12 @@ Loader { root.enableBackgroundClick() } } + onTranslationChanged: { + // Only process if we're actually dragging (not cancelled) + if (!panelBackground.isDragged) + return + // Proposed new coordinates from fixed drag origin var nx = dragStartX + translation.x var ny = dragStartY + translation.y