From 7faed137f2431f2cfd9af7606dd28f085b9c0fc2 Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 18 Sep 2026 17:25:45 -0400 Subject: [PATCH] dash/controlCenter: keep the panel size in edit mode and move the resize ring outside --- dank-qml-common | 2 +- flake.lock | 6 +- quickshell/Common/PopoutMetrics.qml | 1 - .../ControlCenter/ControlCenterContent.qml | 11 +- .../ControlCenter/ControlCenterPopout.qml | 5 +- .../Modules/DankDash/DankDashPopout.qml | 357 +++++++++--------- .../Activities/ControlCenterExpanded.qml | 1 + .../DankIsland/Activities/DashTabFace.qml | 1 - quickshell/Widgets/ClockContent.qml | 2 +- quickshell/Widgets/DankGridEditChrome.qml | 39 +- quickshell/Widgets/DankPopout.qml | 1 + quickshell/Widgets/DankPopoutHost.qml | 22 +- quickshell/tests/qml/dash-panel-resize.qml | 20 +- 13 files changed, 222 insertions(+), 246 deletions(-) diff --git a/dank-qml-common b/dank-qml-common index ff99ec8a9..4e0ec3a1c 160000 --- a/dank-qml-common +++ b/dank-qml-common @@ -1 +1 @@ -Subproject commit ff99ec8a93c4a52d792e7020575540582f249ea9 +Subproject commit 4e0ec3a1cf91b6a33723ad5e3e59b437b1374316 diff --git a/flake.lock b/flake.lock index 22f5e1882..d31b9a321 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "dank-qml-common": { "flake": false, "locked": { - "lastModified": 1789755182, - "narHash": "sha256-47BBqvpzKSKo65gRnGirwulJ/c6N3Dg+vEfErwXTu58=", + "lastModified": 1789765673, + "narHash": "sha256-+EyHDMnyAPP+7wOWfVbqz3PJl9H0QRWURYCKnxUhj/c=", "owner": "AvengeMedia", "repo": "dank-qml-common", - "rev": "ff99ec8a93c4a52d792e7020575540582f249ea9", + "rev": "4e0ec3a1cf91b6a33723ad5e3e59b437b1374316", "type": "github" }, "original": { diff --git a/quickshell/Common/PopoutMetrics.qml b/quickshell/Common/PopoutMetrics.qml index 32fd4c17f..d9a5b2bb4 100644 --- a/quickshell/Common/PopoutMetrics.qml +++ b/quickshell/Common/PopoutMetrics.qml @@ -9,6 +9,5 @@ Singleton { readonly property real chromeButtonSize: Theme.iconSizeLarge readonly property real chromeIconSize: Theme.iconSizeSmall readonly property real panelChromeInset: Theme.spacingS - readonly property real panelResizeBand: Theme.spacingL readonly property real editOverflow: Math.max(Theme.minimumTouchTargetSize, chromeButtonSize) / 2 } diff --git a/quickshell/Modules/ControlCenter/ControlCenterContent.qml b/quickshell/Modules/ControlCenter/ControlCenterContent.qml index fc9de69eb..233fd64cc 100644 --- a/quickshell/Modules/ControlCenter/ControlCenterContent.qml +++ b/quickshell/Modules/ControlCenter/ControlCenterContent.qml @@ -28,10 +28,10 @@ FocusScope { property var pageHistory: [] readonly property bool panelResizing: panelResizer.resizing readonly property real sheetContentWidth: host.sheetContentWidth ?? CcMetrics.sheetWidthFor(gridColumns) - readonly property int gridColumnCap: host.gridColumnCap ?? CcMetrics.columnCapFor((host.triggerScreen?.width ?? CcMetrics.sheetWidthDefault + PopoutMetrics.editOverflow * 2 + Theme.spacingL * 2) - PopoutMetrics.editOverflow * 2 - Theme.spacingL * 2) + readonly property int gridColumnCap: host.gridColumnCap ?? CcMetrics.columnCapFor((host.triggerScreen?.width ?? CcMetrics.sheetWidthDefault + Theme.spacingL * 2) - Theme.spacingL * 2) readonly property int gridColumns: host.gridColumns ?? Math.min(CcMetrics.gridColumns, gridColumnCap) readonly property real availableGridHeight: (host.availableHeight ?? (host.triggerScreen?.height ?? CcMetrics.fallbackScreenHeight) - CcMetrics.maxHeightInset) - CcMetrics.sheetPadding * 2 - CcMetrics.headerHeight - Theme.spacingS * 2 - editControls.height - readonly property real editGutter: host.editMode ? PopoutMetrics.editOverflow : 0 + readonly property real editGutter: host.editGutter ?? 0 readonly property DankPanelResizer panelResizer: DankPanelResizer { popout: root.host gutter: root.editGutter @@ -159,14 +159,13 @@ FocusScope { id: panelChrome anchors.fill: parent - anchors.margins: PopoutMetrics.panelChromeInset - contentInset + anchors.margins: -(contentInset + Theme.spacingS) z: 1 visible: root.host.editMode edgeResize: true horizontalResize: true removable: false - edgeBandWidth: PopoutMetrics.panelResizeBand - cornerRadius: Math.max(0, Theme.windowRadius - PopoutMetrics.panelChromeInset) + cornerRadius: Theme.windowRadius + Theme.spacingS buttonSize: Theme.iconSize iconSize: PopoutMetrics.chromeIconSize resizing: root.panelResizing @@ -205,7 +204,7 @@ FocusScope { id: contentFlickable anchors.fill: parent - clip: true + clip: contentHeight > height contentWidth: width contentHeight: Math.max(height, mainColumn.implicitHeight + CcMetrics.sheetPadding * 2) interactive: contentHeight > height diff --git a/quickshell/Modules/ControlCenter/ControlCenterPopout.qml b/quickshell/Modules/ControlCenter/ControlCenterPopout.qml index c663bd84b..7e1b7b344 100644 --- a/quickshell/Modules/ControlCenter/ControlCenterPopout.qml +++ b/quickshell/Modules/ControlCenter/ControlCenterPopout.qml @@ -14,12 +14,13 @@ DankPopout { resizeMotion: true resizing: contentLoader.item?.panelResizing ?? false surfaceFillsScreen: editMode + inputMargin: editMode ? PopoutMetrics.editOverflow * 2 : 0 property string expandedSection: "" property string pendingSection: "" property var triggerScreen: null property bool editMode: false - readonly property int gridColumnCap: CcMetrics.columnCapFor((triggerScreen?.width ?? CcMetrics.sheetWidthDefault + PopoutMetrics.editOverflow * 2 + Theme.spacingL * 2) - PopoutMetrics.editOverflow * 2 - Theme.spacingL * 2) + readonly property int gridColumnCap: CcMetrics.columnCapFor((triggerScreen?.width ?? CcMetrics.sheetWidthDefault + Theme.spacingL * 2) - Theme.spacingL * 2) readonly property int gridColumns: Math.min(CcMetrics.gridColumns, gridColumnCap) readonly property real sheetContentWidth: CcMetrics.sheetWidthFor(gridColumns) readonly property real availableHeight: _maxPopupHeight() @@ -88,7 +89,7 @@ DankPopout { expandedSection = ""; } - popupWidth: sheetContentWidth + (editMode ? PopoutMetrics.editOverflow * 2 : 0) + popupWidth: sheetContentWidth popupHeight: Math.min(_maxPopupHeight(), Math.max(CcMetrics.minHeight, contentLoader.item?.targetImplicitHeight ?? CcMetrics.minHeight)) triggerWidth: CcMetrics.triggerWidth positioning: "" diff --git a/quickshell/Modules/DankDash/DankDashPopout.qml b/quickshell/Modules/DankDash/DankDashPopout.qml index 74b1c3e1c..0535583bc 100644 --- a/quickshell/Modules/DankDash/DankDashPopout.qml +++ b/quickshell/Modules/DankDash/DankDashPopout.qml @@ -21,6 +21,8 @@ DankPopout { resizeMotion: true resizing: contentLoader.item?.panelResizing ?? false surfaceFillsScreen: editMode + inputMargin: editGutter * 2 + hoverDismissSuspended: editMode onOpened: contentFocusTimer.restart() Timer { @@ -62,7 +64,7 @@ DankPopout { readonly property int columnCap: DashMetrics.columnCapFor(screen?.width, SettingsData.showWeekNumber) readonly property real editGutter: editMode ? PopoutMetrics.editOverflow : 0 - popupWidth: DashMetrics.widthFor(SettingsData.showWeekNumber, screen?.width, DashMetrics.panelColumnsFor(activeTabId)) + editGutter * 2 + popupWidth: DashMetrics.widthFor(SettingsData.showWeekNumber, screen?.width, DashMetrics.panelColumnsFor(activeTabId)) minimumSurfaceWidth: DashMetrics.widthFor(SettingsData.showWeekNumber, screen?.width, DashRegistry.widestPanelColumns) popupHeight: contentLoader.item?.implicitHeight ?? (DashMetrics.tabMinHeight + DashMetrics.tabBarBlockHeight + DashMetrics.contentGap + DashMetrics.contentPadding * 2) triggerWidth: DashMetrics.triggerWidth @@ -226,10 +228,9 @@ DankPopout { LayoutMirroring.childrenInherit: true implicitWidth: root.popupWidth - implicitHeight: headerRow.height + DashMetrics.contentGap + pages.implicitHeight + DashMetrics.contentPadding * 2 + root.editGutter + implicitHeight: headerRow.height + DashMetrics.contentGap + pages.implicitHeight + DashMetrics.contentPadding * 2 readonly property bool ready: pages.ready focus: true - clip: width < Theme.px(implicitWidth, root.dpr) || height < Theme.px(implicitHeight, root.dpr) readonly property bool panelResizing: panelResizer.resizing readonly property bool cardResizing: pages.currentItem?.cardResizing ?? false @@ -249,7 +250,6 @@ DankPopout { readonly property bool panelAtDefault: panelColumns === DashMetrics.defaultGridColumns && DashMetrics.panelFloorRowsFor(root.activeTabId) <= contentRows readonly property DankPanelResizer panelResizer: DankPanelResizer { popout: root - gutter: root.editGutter stepWidth: DashMetrics.preferredColumnWidth + DashMetrics.gridGap widthFor: columns => DashMetrics.widthFor(SettingsData.showWeekNumber, root.screen?.width, columns) currentStep: () => mainContainer.panelColumns @@ -260,10 +260,10 @@ DankPopout { minRows: mainContainer.contentRows maxRows: Math.min(pages.rowBudget, DashMetrics.maximumGridRows) onPreview: (columns, rows) => DashMetrics.panelPreview = { - "id": root.activeTabId, - "columns": columns, - "rows": rows - } + "id": root.activeTabId, + "columns": columns, + "rows": rows + } onCommitted: (columns, rows, columnsChanged, rowsChanged) => { const values = {}; if (columnsChanged) @@ -524,13 +524,13 @@ DankPopout { id: panelChrome anchors.fill: parent - anchors.margins: PopoutMetrics.panelChromeInset - contentInset + anchors.margins: -(contentInset + Theme.spacingS) z: 2 visible: root.editMode edgeResize: true removable: false - edgeBandWidth: PopoutMetrics.panelResizeBand - cornerRadius: Math.max(0, Theme.windowRadius - PopoutMetrics.panelChromeInset) + cornerRadius: Theme.windowRadius + Theme.spacingS + handleOverhang: contentInset + Theme.spacingL buttonSize: PopoutMetrics.chromeButtonSize iconSize: PopoutMetrics.chromeIconSize resizing: mainContainer.panelResizing || mainContainer.panelShifted @@ -558,193 +558,200 @@ DankPopout { } Item { - id: contentColumn + id: contentClip - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.topMargin: DashMetrics.contentPadding - anchors.leftMargin: DashMetrics.contentPadding + root.editGutter - anchors.bottomMargin: DashMetrics.contentPadding + root.editGutter - width: root.popupWidth - (DashMetrics.contentPadding + root.editGutter) * 2 + anchors.fill: parent + clip: mainContainer.width < Theme.px(mainContainer.implicitWidth, root.dpr) || mainContainer.height < Theme.px(mainContainer.implicitHeight, root.dpr) Item { - id: headerRow + id: contentColumn - readonly property real stripCenter: (tabBar.y + tabBar.height - Theme.dividerWidth - DashMetrics.contentPadding) / 2 - - width: parent.width - height: root.showTabs ? Math.max(DashMetrics.tabBarBlockHeight, tabBar.y + tabBar.height) : 0 - visible: root.showTabs - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: -DashMetrics.contentPadding - anchors.rightMargin: -DashMetrics.contentPadding - y: tabBar.y + tabBar.height - height - height: Theme.dividerWidth - color: Theme.outlineVariant - visible: tabBar.visible - } - - DankTabBar { - id: tabBar - - anchors.left: parent.left - anchors.right: menuButton.left - anchors.rightMargin: Theme.spacingS - y: -DashMetrics.tabBarLift - visible: !root.editMode && root.detailTabId === "" - tabHeight: DashMetrics.tabHeight - showDivider: false - currentIndex: root.currentTabIndex - spacing: Theme.spacingS - equalWidthTabs: true - enableArrowNavigation: false - cycleOnTab: true - nextFocusTarget: pages.focusTarget - previousFocusTarget: pages.currentItem?.previousFocusTarget ?? pages.focusTarget - model: DashRegistry.tabBarModel - - onTabClicked: function (index) { - const id = root.orderedTabIds[index]; - if (id !== undefined) - root.currentTabId = id; - } - } - - DashEditControls { - id: editControls - anchors.left: parent.left - anchors.right: parent.right - y: Math.round(headerRow.stripCenter - height / 2) - visible: root.editMode - canAdd: (pages.currentItem?.addable?.length ?? 0) > 0 - hasWidgets: mainContainer.hasWidgets - title: mainContainer.hasWidgets ? I18n.tr("Widgets") : (DashRegistry.entry(root.activeTabId)?.text ?? "") - onAddRequested: anchor => pages.currentItem?.openAddMenu(anchor) - onMenuRequested: anchor => headerMenu.openAt(anchor) - onFinished: root.editMode = false - } + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: DashMetrics.contentPadding + anchors.leftMargin: DashMetrics.contentPadding + anchors.bottomMargin: DashMetrics.contentPadding + width: root.popupWidth - DashMetrics.contentPadding * 2 Item { - id: detailHeader + id: headerRow - anchors.left: parent.left - anchors.right: parent.right - y: Math.round(headerRow.stripCenter - height / 2) - height: DashMetrics.headerActionSize - visible: root.detailTabId !== "" && !root.editMode + readonly property real stripCenter: (tabBar.y + tabBar.height - Theme.dividerWidth - DashMetrics.contentPadding) / 2 + + width: parent.width + height: root.showTabs ? Math.max(DashMetrics.tabBarBlockHeight, tabBar.y + tabBar.height) : 0 + visible: root.showTabs + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: -DashMetrics.contentPadding + anchors.rightMargin: -DashMetrics.contentPadding + y: tabBar.y + tabBar.height - height + height: Theme.dividerWidth + color: Theme.outlineVariant + visible: tabBar.visible + } + + DankTabBar { + id: tabBar + + anchors.left: parent.left + anchors.right: menuButton.left + anchors.rightMargin: Theme.spacingS + y: -DashMetrics.tabBarLift + visible: !root.editMode && root.detailTabId === "" + tabHeight: DashMetrics.tabHeight + showDivider: false + currentIndex: root.currentTabIndex + spacing: Theme.spacingS + equalWidthTabs: true + enableArrowNavigation: false + cycleOnTab: true + nextFocusTarget: pages.focusTarget + previousFocusTarget: pages.currentItem?.previousFocusTarget ?? pages.focusTarget + model: DashRegistry.tabBarModel + + onTabClicked: function (index) { + const id = root.orderedTabIds[index]; + if (id !== undefined) + root.currentTabId = id; + } + } + + DashEditControls { + id: editControls + anchors.left: parent.left + anchors.right: parent.right + y: Math.round(headerRow.stripCenter - height / 2) + visible: root.editMode + canAdd: (pages.currentItem?.addable?.length ?? 0) > 0 + hasWidgets: mainContainer.hasWidgets + title: mainContainer.hasWidgets ? I18n.tr("Widgets") : (DashRegistry.entry(root.activeTabId)?.text ?? "") + onAddRequested: anchor => pages.currentItem?.openAddMenu(anchor) + onMenuRequested: anchor => headerMenu.openAt(anchor) + onFinished: root.editMode = false + } + + Item { + id: detailHeader + + anchors.left: parent.left + anchors.right: parent.right + y: Math.round(headerRow.stripCenter - height / 2) + height: DashMetrics.headerActionSize + visible: root.detailTabId !== "" && !root.editMode + + DankActionButton { + id: backButton + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + buttonSize: DashMetrics.headerActionSize + iconName: I18n.isRtl ? "arrow_forward" : "arrow_back" + Accessible.name: I18n.tr("Back") + KeyNavigation.tab: pages.focusTarget + KeyNavigation.backtab: pages.focusTarget + onClicked: root.closeDetail() + } + + StyledText { + anchors.left: backButton.right + anchors.right: parent.right + anchors.leftMargin: Theme.spacingS + anchors.rightMargin: DashMetrics.headerActionSize + Theme.spacingS + anchors.verticalCenter: parent.verticalCenter + text: root.detailEntry?.text ?? "" + font.pixelSize: Theme.fontSizeLarge + font.weight: Theme.fontWeightMedium + color: Theme.surfaceText + elide: Text.ElideRight + } + } DankActionButton { - id: backButton - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - buttonSize: DashMetrics.headerActionSize - iconName: I18n.isRtl ? "arrow_forward" : "arrow_back" - Accessible.name: I18n.tr("Back") - KeyNavigation.tab: pages.focusTarget - KeyNavigation.backtab: pages.focusTarget - onClicked: root.closeDetail() - } + id: menuButton - StyledText { - anchors.left: backButton.right anchors.right: parent.right - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: DashMetrics.headerActionSize + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: root.detailEntry?.text ?? "" - font.pixelSize: Theme.fontSizeLarge - font.weight: Theme.fontWeightMedium - color: Theme.surfaceText - elide: Text.ElideRight + y: Math.round(headerRow.stripCenter - height / 2) + buttonSize: DashMetrics.headerActionSize + iconName: "more_vert" + iconColor: headerMenu.open ? Theme.primary : Theme.onSurfaceVariant + backgroundColor: headerMenu.open ? Theme.withAlpha(Theme.primary, Theme.stateLayerFocus) : "transparent" + Accessible.name: I18n.tr("Options") + visible: !root.editMode + KeyNavigation.tab: pages.focusTarget + KeyNavigation.backtab: root.detailTabId !== "" ? backButton : tabBar + onClicked: headerMenu.openAt(menuButton) } } - DankActionButton { - id: menuButton + DankFlickable { + id: pages - anchors.right: parent.right - y: Math.round(headerRow.stripCenter - height / 2) - buttonSize: DashMetrics.headerActionSize - iconName: "more_vert" - iconColor: headerMenu.open ? Theme.primary : Theme.onSurfaceVariant - backgroundColor: headerMenu.open ? Theme.withAlpha(Theme.primary, Theme.stateLayerFocus) : "transparent" - Accessible.name: I18n.tr("Options") - visible: !root.editMode - KeyNavigation.tab: pages.focusTarget - KeyNavigation.backtab: root.detailTabId !== "" ? backButton : tabBar - onClicked: headerMenu.openAt(menuButton) - } - } + property var currentHost: null + property real settledHeight: DashMetrics.tabMinHeight + readonly property var currentItem: currentHost?.item ?? null + readonly property Item focusTarget: currentHost?.focusTarget ?? null + readonly property bool currentSettled: !!currentHost && (!!currentHost.item || currentHost.failed) + readonly property real currentHostImplicitHeight: currentHost?.implicitHeight ?? 0 + readonly property real targetHeight: currentSettled && currentHost.isCurrent ? DashMetrics.panelHeightFor(root.activeTabId, currentHostImplicitHeight) : -1 + readonly property real bodyHeight: Math.max(settledHeight, currentHostImplicitHeight) + readonly property bool ready: targetHeight >= 0 && settledHeight === targetHeight + readonly property real availableHeight: root.screen ? root.screen.height - headerRow.height - DashMetrics.contentGap - DashMetrics.contentPadding * 2 - Theme.barHeight - Theme.spacingL * 2 : contentHeight + readonly property int rowBudget: DashMetrics.rowCapFor(availableHeight) - DankFlickable { - id: pages + x: -root.editGutter + y: (headerRow.visible ? headerRow.height + DashMetrics.contentGap : 0) - root.editGutter + width: parent.width + root.editGutter * 2 + height: Math.max(0, mainContainer.height - headerRow.height - DashMetrics.contentGap - DashMetrics.contentPadding * 2) + root.editGutter * 2 + implicitHeight: Math.min(settledHeight, Math.max(DashMetrics.gridRowUnit, availableHeight)) + contentWidth: width + contentHeight: bodyHeight + root.editGutter * 2 + clip: contentHeight > height - property var currentHost: null - property real settledHeight: DashMetrics.tabMinHeight - readonly property var currentItem: currentHost?.item ?? null - readonly property Item focusTarget: currentHost?.focusTarget ?? null - readonly property bool currentSettled: !!currentHost && (!!currentHost.item || currentHost.failed) - readonly property real currentHostImplicitHeight: currentHost?.implicitHeight ?? 0 - readonly property real targetHeight: currentSettled && currentHost.isCurrent ? DashMetrics.panelHeightFor(root.activeTabId, currentHostImplicitHeight) : -1 - readonly property real bodyHeight: Math.max(settledHeight, currentHostImplicitHeight) - readonly property bool ready: targetHeight >= 0 && settledHeight === targetHeight - readonly property real availableHeight: root.screen ? root.screen.height - headerRow.height - DashMetrics.contentGap - DashMetrics.contentPadding * 2 - Theme.barHeight - Theme.spacingL * 2 : contentHeight - readonly property int rowBudget: DashMetrics.rowCapFor(availableHeight) - - x: -root.editGutter - y: (headerRow.visible ? headerRow.height + DashMetrics.contentGap : 0) - root.editGutter - width: parent.width + root.editGutter * 2 - height: Math.max(0, mainContainer.height - headerRow.height - DashMetrics.contentGap - DashMetrics.contentPadding * 2) + root.editGutter - implicitHeight: Math.min(settledHeight, Math.max(DashMetrics.gridRowUnit, availableHeight)) - contentWidth: width - contentHeight: bodyHeight + root.editGutter * 2 - clip: contentHeight > height - - function updateContentHeight() { - if (targetHeight < 0) - return; - settledHeight = targetHeight; - } - - onTargetHeightChanged: Qt.callLater(updateContentHeight) - - Repeater { - model: ScriptModel { - values: DashRegistry.tabIds + function updateContentHeight() { + if (targetHeight < 0) + return; + settledHeight = targetHeight; } - DashTabHost { - id: host + onTargetHeightChanged: Qt.callLater(updateContentHeight) - required property string modelData - - width: pages.width - height: pages.height + Math.max(0, pages.bodyHeight - pages.implicitHeight) - contentPadding: root.editGutter - entry: DashRegistry.entry(modelData) - dashHost: root - rowBudget: pages.rowBudget - keyForwardTarget: mainContainer - contentViewport: pages - isCurrent: root.activeTabId === modelData - - onIsCurrentChanged: { - if (isCurrent) - pages.currentHost = host; + Repeater { + model: ScriptModel { + values: DashRegistry.tabIds } - Component.onCompleted: { - if (isCurrent) - pages.currentHost = host; - } + DashTabHost { + id: host - Component.onDestruction: { - if (pages.currentHost === host) - pages.currentHost = null; + required property string modelData + + width: pages.width + height: pages.height + Math.max(0, pages.bodyHeight - pages.implicitHeight) + contentPadding: root.editGutter + entry: DashRegistry.entry(modelData) + dashHost: root + rowBudget: pages.rowBudget + keyForwardTarget: mainContainer + contentViewport: pages + isCurrent: root.activeTabId === modelData + + onIsCurrentChanged: { + if (isCurrent) + pages.currentHost = host; + } + + Component.onCompleted: { + if (isCurrent) + pages.currentHost = host; + } + + Component.onDestruction: { + if (pages.currentHost === host) + pages.currentHost = null; + } } } } diff --git a/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml b/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml index 05cd98501..66f595fa5 100644 --- a/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml +++ b/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml @@ -56,6 +56,7 @@ FocusScope { onEditModeChanged: root.controller.setEditing("controlcenter", editMode) + readonly property real editGutter: editMode ? PopoutMetrics.editOverflow : 0 readonly property int gridColumnCap: root.controller.controlCenterColumnCap readonly property int gridColumns: root.controller.controlCenterColumns readonly property real availableHeight: root.controller.controlCenterMaxHeight - Theme.spacingXS - root.bottomInset diff --git a/quickshell/Modules/DankIsland/Activities/DashTabFace.qml b/quickshell/Modules/DankIsland/Activities/DashTabFace.qml index 012bca001..bdf2eb2e7 100644 --- a/quickshell/Modules/DankIsland/Activities/DashTabFace.qml +++ b/quickshell/Modules/DankIsland/Activities/DashTabFace.qml @@ -206,7 +206,6 @@ FocusScope { visible: root.editMode edgeResize: true removable: false - edgeBandWidth: PopoutMetrics.panelResizeBand cornerRadius: Math.max(0, Theme.windowRadius - PopoutMetrics.panelChromeInset) buttonSize: PopoutMetrics.chromeButtonSize iconSize: PopoutMetrics.chromeIconSize diff --git a/quickshell/Widgets/ClockContent.qml b/quickshell/Widgets/ClockContent.qml index 84f734600..90a8b1fae 100644 --- a/quickshell/Widgets/ClockContent.qml +++ b/quickshell/Widgets/ClockContent.qml @@ -80,7 +80,7 @@ Item { id: layout anchors.centerIn: parent - columns: root.vertical ? 1 : 3 + columns: root.vertical ? 1 : Math.max(1, layout.visibleChildren.length) spacing: root.vertical ? 0 : Theme.spacingS Loader { diff --git a/quickshell/Widgets/DankGridEditChrome.qml b/quickshell/Widgets/DankGridEditChrome.qml index 0105429d5..ad6fa57e0 100644 --- a/quickshell/Widgets/DankGridEditChrome.qml +++ b/quickshell/Widgets/DankGridEditChrome.qml @@ -19,7 +19,6 @@ Item { property real cornerRadius: Theme.cornerRadiusXL property real buttonSize: Theme.iconSizeLarge property real iconSize: Theme.iconSizeSmall - property real edgeBandWidth: Theme.spacingL readonly property real touchTargetSize: Math.max(Theme.minimumTouchTargetSize, buttonSize) readonly property real contentInset: touchTargetSize / 2 readonly property bool showOptionsButton: hasOptions && width - contentInset * 2 >= touchTargetSize * (horizontalResize ? 3 : 2) @@ -114,13 +113,11 @@ Item { } readonly property real gripRadius: Math.max(0, Math.min(cornerRadius, width / 2 - contentInset, height / 2 - contentInset) - Theme.outlineWidthFocused / 2) - readonly property real handleOverhang: edgeResize || Math.min(width, height) - contentInset * 2 < touchTargetSize * 2 ? contentInset : Theme.spacingS / 2 + property real handleOverhang: edgeResize || Math.min(width, height) - contentInset * 2 < touchTargetSize * 2 ? contentInset : Theme.spacingS / 2 readonly property real gripInset: handleOverhang - Theme.spacingS / 2 component ResizeBand: MouseArea { property int signX: 1 - property bool lockX: false - property bool lockY: false property real startX: 0 property real startY: 0 @@ -138,7 +135,7 @@ Item { if (!pressed) return; const p = mapToItem(root, mouse.x, mouse.y); - root.resizeMoved(lockX ? startX : p.x - root.contentInset, lockY ? startY : p.y - root.contentInset); + root.resizeMoved(p.x - root.contentInset, p.y - root.contentInset); } onReleased: root.resizeEnded() onCanceled: root.resizeCanceled() @@ -191,38 +188,6 @@ Item { active: root.edgeResize && root.visible sourceComponent: Item { - ResizeBand { - anchors.right: parent.right - anchors.rightMargin: root.contentInset - root.edgeBandWidth / 2 - y: root.contentInset - root.edgeBandWidth / 2 - width: root.edgeBandWidth - height: root.height - root.contentInset * 2 + root.edgeBandWidth - lockY: true - cursorShape: Qt.SizeHorCursor - } - - ResizeBand { - anchors.left: parent.left - anchors.leftMargin: root.contentInset - root.edgeBandWidth / 2 - y: root.contentInset - root.edgeBandWidth / 2 - width: root.edgeBandWidth - height: root.height - root.contentInset * 2 + root.edgeBandWidth - signX: -1 - lockY: true - cursorShape: Qt.SizeHorCursor - } - - ResizeBand { - anchors.left: parent.left - anchors.leftMargin: root.contentInset - root.edgeBandWidth / 2 - y: root.height - root.contentInset - root.edgeBandWidth / 2 - width: root.width - root.contentInset * 2 + root.edgeBandWidth - height: root.edgeBandWidth - visible: !root.horizontalResize - lockX: true - cursorShape: Qt.SizeVerCursor - } - Handle { anchors.left: parent.left anchors.leftMargin: root.contentInset - (root.horizontalResize ? width / 2 : root.handleOverhang) diff --git a/quickshell/Widgets/DankPopout.qml b/quickshell/Widgets/DankPopout.qml index 0efac6700..263f46a85 100644 --- a/quickshell/Widgets/DankPopout.qml +++ b/quickshell/Widgets/DankPopout.qml @@ -26,6 +26,7 @@ Item { property bool resizeMotion: false property bool resizing: false property bool surfaceFillsScreen: false + property real inputMargin: 0 property bool suspendShadowWhileResizing: false property bool shouldBeVisible: false property bool hoverDismissEnabled: false diff --git a/quickshell/Widgets/DankPopoutHost.qml b/quickshell/Widgets/DankPopoutHost.qml index e10f928b8..047e56fbe 100644 --- a/quickshell/Widgets/DankPopoutHost.qml +++ b/quickshell/Widgets/DankPopoutHost.qml @@ -31,6 +31,7 @@ Item { property bool resizeMotion: popoutHandle.resizeMotion property bool resizing: popoutHandle.resizing property bool surfaceFillsScreen: popoutHandle.surfaceFillsScreen + property real inputMargin: popoutHandle.inputMargin readonly property bool _screenSurface: connected || surfaceFillsScreen property real triggerX: popoutHandle.triggerX property real triggerY: popoutHandle.triggerY @@ -388,7 +389,11 @@ Item { on_ScreenSurfaceChanged: { if (!_screenSurface) _setAnimatedSurfaceEnvelope(); + _surfaceSwitching = contentWindow.visible && Math.abs(contentWindow.width - (_screenSurface ? screenWidth : _surfaceW)) > 1; } + property bool _surfaceSwitching: false + readonly property real _contentWindowWidth: contentWindow.width + on_ContentWindowWidthChanged: _surfaceSwitching = false onResizingChanged: { if (!resizing) backgroundLayer.item?.surfaceMoved(); @@ -1327,10 +1332,10 @@ Item { id: contentHoleRect visible: false color: "transparent" - x: background.dismissRequired ? root.renderedAlignedX : 0 - y: background.dismissRequired ? root._surfaceBodyY : 0 - width: (background.dismissRequired && root.shouldBeVisible) ? root.renderedAlignedWidth : 0 - height: (background.dismissRequired && root.shouldBeVisible) ? root._surfaceBodyH : 0 + x: background.dismissRequired ? root.renderedAlignedX - root.inputMargin : 0 + y: background.dismissRequired ? root._surfaceBodyY - root.inputMargin : 0 + width: (background.dismissRequired && root.shouldBeVisible) ? root.renderedAlignedWidth + root.inputMargin * 2 : 0 + height: (background.dismissRequired && root.shouldBeVisible) ? root._surfaceBodyH + root.inputMargin * 2 : 0 } MouseArea { @@ -1428,10 +1433,10 @@ Item { Item { id: contentMaskRect visible: false - x: contentContainer.x - contentContainer.horizontalConnectorExtent - y: contentContainer.y - contentContainer.verticalConnectorExtent - width: root.connected || contentWindow.closeVisualActive ? root.renderedAlignedWidth + contentContainer.horizontalConnectorExtent * 2 : 0 - height: root.connected || contentWindow.closeVisualActive ? root.renderedAlignedHeight + contentContainer.verticalConnectorExtent * 2 : 0 + x: contentContainer.x - contentContainer.horizontalConnectorExtent - root.inputMargin + y: contentContainer.y - contentContainer.verticalConnectorExtent - root.inputMargin + width: root.connected || contentWindow.closeVisualActive ? root.renderedAlignedWidth + contentContainer.horizontalConnectorExtent * 2 + root.inputMargin * 2 : 0 + height: root.connected || contentWindow.closeVisualActive ? root.renderedAlignedHeight + contentContainer.verticalConnectorExtent * 2 + root.inputMargin * 2 : 0 } Loader { @@ -1679,6 +1684,7 @@ Item { Item { id: directionalClipMask + visible: !root._surfaceSwitching readonly property bool shouldClip: Theme.isDirectionalEffect || root.usesConnectedSurfaceChrome readonly property real clipOversize: 1000 readonly property real connectedClipAllowance: { diff --git a/quickshell/tests/qml/dash-panel-resize.qml b/quickshell/tests/qml/dash-panel-resize.qml index ac4e08ce8..ec07d1119 100644 --- a/quickshell/tests/qml/dash-panel-resize.qml +++ b/quickshell/tests/qml/dash-panel-resize.qml @@ -55,13 +55,11 @@ ShellRoot { } function columnGain() { - const gutter = PopoutMetrics.editOverflow * 2; - return edgeGain(root.popout, widthFor(DashMetrics.defaultGridColumns) + gutter, widthFor(DashMetrics.defaultGridColumns + 1) + gutter); + return edgeGain(root.popout, widthFor(DashMetrics.defaultGridColumns), widthFor(DashMetrics.defaultGridColumns + 1)); } function ccGain() { - const gutter = PopoutMetrics.editOverflow * 2; - return edgeGain(root.cc, CcMetrics.sheetWidthFor(CcMetrics.defaultColumns) + gutter, CcMetrics.sheetWidthFor(CcMetrics.defaultColumns + 1) + gutter); + return edgeGain(root.cc, CcMetrics.sheetWidthFor(CcMetrics.defaultColumns), CcMetrics.sheetWidthFor(CcMetrics.defaultColumns + 1)); } property real dragOriginX: 0 @@ -124,14 +122,14 @@ ShellRoot { check(root.baseRows >= DashMetrics.minimumTabRows && DashMetrics.storedPanelRows("overview") === 0, "unset rows fit the cards: " + root.baseRows); check(!root.popout.contentWindow.anchors.right, "surface hugs the body outside edit mode"); root.popout.editMode = true; - check(root.popout.popupWidth === widthFor(DashMetrics.defaultGridColumns) + PopoutMetrics.editOverflow * 2, "edit mode adds the handle gutter"); + check(root.popout.popupWidth === widthFor(DashMetrics.defaultGridColumns), "edit mode keeps the panel width"); check(root.popout.contentWindow.anchors.right, "edit mode anchors the surface to both sides"); beginDrag(root.popout, c); dragTo(root.popout, c, 2 * columnGain(), 0); check(DashMetrics.panelPreview?.columns === 8, "preview snaps two columns wider: " + JSON.stringify(DashMetrics.panelPreview)); check(snapped(root.popout), "drag snaps the body"); check(c.panelColumns === 8 && DashMetrics.gridColumns === 8, "overview grid follows the preview"); - check(root.popout.popupWidth === widthFor(8) + PopoutMetrics.editOverflow * 2, "popout width follows the preview"); + check(root.popout.popupWidth === widthFor(8), "popout width follows the preview"); dragTo(root.popout, c, 2 * columnGain(), root.rowStep); root.requestedRows = DashMetrics.panelPreview.rows; check(root.requestedRows === root.baseRows + 1 && c.panelRows === root.requestedRows, "pill shows the requested rows: " + JSON.stringify([c.panelRows, root.requestedRows])); @@ -144,7 +142,7 @@ ShellRoot { check(SettingsData.dashOptions?.overview?.panelRows === root.requestedRows, "requested rows stored: " + JSON.stringify(SettingsData.dashOptions)); check(c.panelRows === root.requestedRows, "panel keeps the dragged rows after commit"); root.popout.editMode = false; - check(root.popout.popupWidth === widthFor(8), "gutter goes away with edit mode"); + check(root.popout.popupWidth === widthFor(8), "width holds when edit mode ends"); check(!root.popout.contentWindow.anchors.right, "leaving edit mode releases the surface"); root.popout.requestTab("media"); check(root.popout.animationDuration <= 0 || root.popout.renderedAlignedX !== root.popout.alignedX, "tab switch glides the body"); @@ -159,7 +157,7 @@ ShellRoot { check(DashMetrics.gridColumns === 8, "overview columns untouched by media preview"); c.panelResizer.end(); check(SettingsData.dashOptions?.media?.panelColumns === 5 && SettingsData.dashOptions?.media?.panelRows === undefined, "media columns stored without rows: " + JSON.stringify(SettingsData.dashOptions?.media)); - check(root.popout.popupWidth === widthFor(5) + PopoutMetrics.editOverflow * 2, "media width committed"); + check(root.popout.popupWidth === widthFor(5), "media width committed"); beginDrag(root.popout, c); dragTo(root.popout, c, columnGain(), 0); root.popout.editMode = false; @@ -207,7 +205,7 @@ ShellRoot { slot.resizeTo((targetW - cell.cols) * step, 0); check(DashMetrics.panelPreview?.columns === base + 1 && DashMetrics.gridColumns === base + 1, "card dragged past the edge widens the panel: " + JSON.stringify([DashMetrics.panelPreview, cell, targetW])); check(grid.sizePreview?.changes.w === targetW && grid.slotLayout.slots[index].col === cell.col, "card grows in place: " + JSON.stringify([grid.sizePreview, grid.slotLayout.slots[index], cell])); - check(root.popout.popupWidth === widthFor(base + 1) + PopoutMetrics.editOverflow * 2, "popout follows the card-driven preview: " + root.popout.popupWidth); + check(root.popout.popupWidth === widthFor(base + 1), "popout follows the card-driven preview: " + root.popout.popupWidth); check(c.panelShifted && c.cardResizeColumns === base, "panel pill shows the card-driven column shift: " + JSON.stringify([c.panelShifted, c.panelColumns, c.cardResizeColumns])); slot.finishResize(); check(!c.panelShifted, "panel pill hides after release"); @@ -310,13 +308,13 @@ ShellRoot { check(root.cc.shouldBeVisible && ccContent, "control center open"); check(root.cc.popupWidth === CcMetrics.sheetWidthDefault, "control center default width"); root.cc.editMode = true; - check(root.cc.popupWidth === CcMetrics.sheetWidthDefault + PopoutMetrics.editOverflow * 2, "control center edit mode adds the handle gutter"); + check(root.cc.popupWidth === CcMetrics.sheetWidthDefault, "control center edit mode keeps the sheet width"); check(root.cc.contentWindow.anchors.right, "control center edit mode anchors the surface to both sides"); beginDrag(root.cc, ccContent); dragTo(root.cc, ccContent, 1.4 * ccGain(), 0); check(CcMetrics.gridColumns === CcMetrics.defaultColumns + 1 && CcMetrics.sheetWidth === CcMetrics.sheetWidthFor(CcMetrics.defaultColumns + 1), "control center preview snaps to a column: " + CcMetrics.sheetWidth); check(snapped(root.cc), "control center drag snaps the body"); - check(root.cc.popupWidth === CcMetrics.sheetWidthFor(CcMetrics.defaultColumns + 1) + PopoutMetrics.editOverflow * 2, "control center popout follows the preview"); + check(root.cc.popupWidth === CcMetrics.sheetWidthFor(CcMetrics.defaultColumns + 1), "control center popout follows the preview"); ccContent.panelResizer.end(); check(SettingsData.controlCenterColumns === CcMetrics.defaultColumns + 1, "control center columns stored: " + SettingsData.controlCenterColumns); check(CcMetrics.columnPreview === 0, "control center preview cleared");