From 8f8f6c23ea3594fdf402cd558541480108d85401 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Mon, 22 Sep 2025 21:33:38 -0400 Subject: [PATCH] Bar Editor: added ability to move widget to other sections with right clicking context menu. --- Modules/Settings/Bar/BarSectionEditor.qml | 46 +++++++++ Modules/Settings/Tabs/BarTab.qml | 22 +++++ Widgets/NContextMenu.qml | 113 ++++++++++++++++++++++ shell.qml | 2 +- 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 Widgets/NContextMenu.qml diff --git a/Modules/Settings/Bar/BarSectionEditor.qml b/Modules/Settings/Bar/BarSectionEditor.qml index 777c47d6b..2652eff32 100644 --- a/Modules/Settings/Bar/BarSectionEditor.qml +++ b/Modules/Settings/Bar/BarSectionEditor.qml @@ -20,6 +20,7 @@ NBox { signal removeWidget(string section, int index) signal reorderWidget(string section, int fromIndex, int toIndex) signal updateWidgetSettings(string section, int index, var settings) + signal moveWidget(string fromSection, int index, string toSection) signal dragPotentialStarted signal dragPotentialEnded @@ -125,6 +126,7 @@ NBox { Repeater { model: widgetModel + delegate: Rectangle { id: widgetItem required property int index @@ -158,6 +160,50 @@ NBox { } } + // Context menu for moving widget to other sections + NContextMenu { + id: contextMenu + parent: Overlay.overlay + model: [{ + "label": "Move to Left", + "action": "left", + "icon": "arrow-left", + "visible": root.sectionId !== "left" + }, { + "label": "Move to Center", + "action": "center", + "icon": "arrows-horizontal", + "visible": root.sectionId !== "center" + }, { + "label": "Move to Right", + "action": "right", + "icon": "arrow-right", + "visible": root.sectionId !== "right" + }] + + onTriggered: action => root.moveWidget(root.sectionId, index, action) + } + + // Update the MouseArea to use the new context menu + MouseArea { + id: contextMouseArea + anchors.fill: parent + acceptedButtons: Qt.RightButton + z: -1 // Below the buttons but above background + + onClicked: mouse => { + if (mouse.button === Qt.RightButton) { + // Check if click is not on the buttons area + const localX = mouse.x + const buttonsStartX = parent.width - (parent.buttonsCount * parent.buttonsWidth) + + if (localX < buttonsStartX) { + // Use the helper function to open at mouse position + contextMenu.openAtItem(widgetItem, mouse.x, mouse.y) + } + } + } + } RowLayout { id: widgetContent anchors.centerIn: parent diff --git a/Modules/Settings/Tabs/BarTab.qml b/Modules/Settings/Tabs/BarTab.qml index 3ad303767..2049959c2 100644 --- a/Modules/Settings/Tabs/BarTab.qml +++ b/Modules/Settings/Tabs/BarTab.qml @@ -219,6 +219,7 @@ ColumnLayout { onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex) onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection) onDragPotentialStarted: root.handleDragStart() onDragPotentialEnded: root.handleDragEnd() } @@ -233,6 +234,7 @@ ColumnLayout { onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex) onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection) onDragPotentialStarted: root.handleDragStart() onDragPotentialEnded: root.handleDragEnd() } @@ -247,6 +249,7 @@ ColumnLayout { onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex) onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection) onDragPotentialStarted: root.handleDragStart() onDragPotentialEnded: root.handleDragEnd() } @@ -341,6 +344,25 @@ ColumnLayout { //Logger.log("BarTab", `Updated widget settings for ${settings.id} in ${section} section`) } + function _moveWidgetBetweenSections(fromSection, index, toSection) { + // Get the widget from the source section + if (index >= 0 && index < Settings.data.bar.widgets[fromSection].length) { + var widget = Settings.data.bar.widgets[fromSection][index] + + // Remove from source section + var sourceArray = Settings.data.bar.widgets[fromSection].slice() + sourceArray.splice(index, 1) + Settings.data.bar.widgets[fromSection] = sourceArray + + // Add to target section + var targetArray = Settings.data.bar.widgets[toSection].slice() + targetArray.push(widget) + Settings.data.bar.widgets[toSection] = targetArray + + //Logger.log("BarTab", `Moved widget ${widget.id} from ${fromSection} to ${toSection}`) + } + } + // Base list model for all combo boxes ListModel { id: availableWidgets diff --git a/Widgets/NContextMenu.qml b/Widgets/NContextMenu.qml new file mode 100644 index 000000000..a1b7562c4 --- /dev/null +++ b/Widgets/NContextMenu.qml @@ -0,0 +1,113 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons +import qs.Services + +Popup { + id: root + + property alias model: listView.model + property real itemHeight: 36 * scaling + property real itemPadding: Style.marginM * scaling + + signal triggered(string action) + + width: 180 * scaling + padding: Style.marginS * scaling + + onOpened: PanelService.willOpenPopup(root) + onClosed: PanelService.willClosePopup(root) + + background: Rectangle { + color: Color.mSurfaceVariant + border.color: Color.mOutline + border.width: Math.max(1, Style.borderS * scaling) + radius: Style.radiusM * scaling + } + + contentItem: ListView { + id: listView + implicitHeight: contentHeight + spacing: Style.marginXXS * scaling + interactive: contentHeight > root.height + clip: true + + delegate: ItemDelegate { + id: menuItem + width: listView.width + height: modelData.visible !== false ? root.itemHeight : 0 + visible: modelData.visible !== false + opacity: modelData.enabled !== false ? 1.0 : 0.5 + enabled: modelData.enabled !== false + + // Store reference to the popup + property var popup: root + + background: Rectangle { + color: menuItem.hovered && menuItem.enabled ? Color.mTertiary : Color.transparent + radius: Style.radiusS * scaling + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + + contentItem: RowLayout { + spacing: Style.marginS * scaling + + // Optional icon + NIcon { + visible: modelData.icon !== undefined + icon: modelData.icon || "" + font.pointSize: Style.fontSizeM * scaling + color: menuItem.hovered && menuItem.enabled ? Color.mOnTertiary : Color.mOnSurface + Layout.leftMargin: root.itemPadding + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + + NText { + text: modelData.label || modelData.text || "" + font.pointSize: Style.fontSizeM * scaling + color: menuItem.hovered && menuItem.enabled ? Color.mOnTertiary : Color.mOnSurface + verticalAlignment: Text.AlignVCenter + Layout.fillWidth: true + Layout.leftMargin: modelData.icon === undefined ? root.itemPadding : 0 + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + } + } + + onClicked: { + if (enabled) { + popup.triggered(modelData.action || modelData.key || index.toString()) + popup.close() + } + } + } + } + + // Helper function to open at mouse position + function openAt(x, y) { + root.x = x + root.y = y + root.open() + } + + // Helper function to open at item + function openAtItem(item, mouseX, mouseY) { + var pos = item.mapToItem(root.parent, mouseX || 0, mouseY || 0) + openAt(pos.x, pos.y) + } +} diff --git a/shell.qml b/shell.qml index d801b4010..e7f53d16c 100644 --- a/shell.qml +++ b/shell.qml @@ -118,7 +118,7 @@ ShellRoot { Connections { target: Quickshell function onReloadCompleted() { - Quickshell.inhibitReloadPopup(); + Quickshell.inhibitReloadPopup() } } }