From a5087735b5f7b1cf1efe7230c1460bd9d4cec0be Mon Sep 17 00:00:00 2001 From: bbedward Date: Sat, 19 Sep 2026 17:07:37 -0400 Subject: [PATCH] theme: add fixed corner radius mode and rescale radius strength --- dank-qml-common | 2 +- quickshell/Common/SettingsData.qml | 4 +- quickshell/Common/Theme.qml | 29 +++++++------- .../Modules/DankDash/DankDashPopout.qml | 8 ++-- quickshell/Modules/DankDash/DashMetrics.qml | 24 +++++++++++- quickshell/Modules/DankDash/DashRegistry.qml | 15 ++++---- .../Modules/DankDash/Media/MediaDeviceRow.qml | 2 +- .../Modules/DankDash/NotificationsTab.qml | 2 +- .../Overview/CalendarOverviewCard.qml | 2 +- quickshell/Modules/DankDash/WallpaperTab.qml | 2 +- .../DankIsland/Activities/DashTabFace.qml | 4 +- .../Modules/DankIsland/IslandController.qml | 2 +- .../Modules/Settings/ThemeSurfacesTab.qml | 30 ++++++++++++++- quickshell/tests/qml/dash-panel-resize.qml | 32 +++++++++++----- quickshell/tests/settings-radius.test.mjs | 2 +- .../translations/settings_search_index.json | 38 +++++++++++++++++++ 16 files changed, 150 insertions(+), 48 deletions(-) diff --git a/dank-qml-common b/dank-qml-common index ccab90ec9..6f75d9065 160000 --- a/dank-qml-common +++ b/dank-qml-common @@ -1 +1 @@ -Subproject commit ccab90ec90e0cdd620eadc2e1ad8b4740363472c +Subproject commit 6f75d9065b2ff708eb1e91eec30ec5008d1ce3ee diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 5c760f11b..319d20d35 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -185,7 +185,9 @@ Singleton { property string controlCenterTileColorMode: Spec.SPEC.controlCenterTileColorMode.def property string buttonColorMode: Spec.SPEC.buttonColorMode.def property int radiusStrength: Spec.SPEC.radiusStrength.def - readonly property real cornerRadius: Shape.radius("m", Shape.scaleForStrength(radiusStrength)) + property string radiusMode: Spec.SPEC.radiusMode.def + property int fixedRadius: Spec.SPEC.fixedRadius.def + readonly property real cornerRadius: Shape.radius("m", Shape.scaleForStrength(radiusStrength), radiusMode === "fixed" ? fixedRadius : -1) property int niriLayoutGapsOverride: Spec.SPEC.niriLayoutGapsOverride.def property int niriLayoutRadiusOverride: Spec.SPEC.niriLayoutRadiusOverride.def property int niriLayoutBorderSize: Spec.SPEC.niriLayoutBorderSize.def diff --git a/quickshell/Common/Theme.qml b/quickshell/Common/Theme.qml index 8ac4fc3fd..97c456ba8 100644 --- a/quickshell/Common/Theme.qml +++ b/quickshell/Common/Theme.qml @@ -1142,18 +1142,19 @@ Singleton { } readonly property real radiusStrength: typeof SettingsData !== "undefined" ? SettingsData.radiusStrength : 50 - readonly property real shapeScale: Shape.scaleForStrength(radiusStrength) + readonly property real fixedRadius: typeof SettingsData !== "undefined" && SettingsData.radiusMode === "fixed" ? SettingsData.fixedRadius : -1 + readonly property real shapeScale: fixedRadius >= 0 ? fixedRadius / Shape.corners.m : Shape.scaleForStrength(radiusStrength) readonly property real cornerRadius: cornerRadiusM - readonly property real cornerRadiusXXS: Shape.radius("xxs", shapeScale) - readonly property real cornerRadiusXS: Shape.radius("xs", shapeScale) - readonly property real cornerRadiusS: Shape.radius("s", shapeScale) - readonly property real cornerRadiusM: Shape.radius("m", shapeScale) - readonly property real cornerRadiusL: Shape.radius("l", shapeScale) - readonly property real cornerRadiusLIncreased: Shape.radius("lIncreased", shapeScale) - readonly property real cornerRadiusXL: Shape.radius("xl", shapeScale) - readonly property real cornerRadiusXLIncreased: Shape.radius("xlIncreased", shapeScale) - readonly property real cornerRadiusXXL: Shape.radius("xxl", shapeScale) - readonly property real cornerRadiusFull: shapeScale > 0 ? 9999 : 0 + readonly property real cornerRadiusXXS: Shape.radius("xxs", shapeScale, fixedRadius) + readonly property real cornerRadiusXS: Shape.radius("xs", shapeScale, fixedRadius) + readonly property real cornerRadiusS: Shape.radius("s", shapeScale, fixedRadius) + readonly property real cornerRadiusM: Shape.radius("m", shapeScale, fixedRadius) + readonly property real cornerRadiusL: Shape.radius("l", shapeScale, fixedRadius) + readonly property real cornerRadiusLIncreased: Shape.radius("lIncreased", shapeScale, fixedRadius) + readonly property real cornerRadiusXL: Shape.radius("xl", shapeScale, fixedRadius) + readonly property real cornerRadiusXLIncreased: Shape.radius("xlIncreased", shapeScale, fixedRadius) + readonly property real cornerRadiusXXL: Shape.radius("xxl", shapeScale, fixedRadius) + readonly property real cornerRadiusFull: fixedRadius >= 0 ? fixedRadius : (shapeScale > 0 ? 9999 : 0) readonly property real cornerRadiusSmall: cornerRadiusS readonly property real cornerRadiusLarge: cornerRadiusL readonly property int compositorRadiusOverride: { @@ -1167,15 +1168,15 @@ Singleton { readonly property real windowRadius: compositorRadiusOverride >= 0 ? compositorRadiusOverride : cornerRadiusL function scaledRadius(radius, limit) { - return Shape.scaledRadius(radius, limit, shapeScale); + return Shape.scaledRadius(radius, limit, shapeScale, fixedRadius); } function fullRadius(width, height) { - return Shape.fullRadius(width, height, shapeScale); + return Shape.fullRadius(width, height, shapeScale, fixedRadius); } function buttonRadius(width, height, sizeHeight, pressed, round) { - return Shape.buttonRadius(width, height, sizeHeight, pressed, round, shapeScale); + return Shape.buttonRadius(width, height, sizeHeight, pressed, round, shapeScale, fixedRadius); } readonly property real groupedListGap: spacingXXS diff --git a/quickshell/Modules/DankDash/DankDashPopout.qml b/quickshell/Modules/DankDash/DankDashPopout.qml index d755dedd3..4b8d074e3 100644 --- a/quickshell/Modules/DankDash/DankDashPopout.qml +++ b/quickshell/Modules/DankDash/DankDashPopout.qml @@ -66,7 +66,7 @@ DankPopout { 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) + popupHeight: contentLoader.item?.implicitHeight ?? (DashMetrics.tabDefaultHeight + DashMetrics.tabBarBlockHeight + DashMetrics.contentGap + DashMetrics.contentPadding * 2) triggerWidth: DashMetrics.triggerWidth screen: triggerScreen @@ -247,7 +247,7 @@ DankPopout { readonly property int panelColumns: DashMetrics.panelColumnsFor(root.activeTabId) readonly property int contentRows: DashMetrics.rowsForHeight(pages.currentHostImplicitHeight) readonly property int panelRows: Math.max(DashMetrics.panelFloorRowsFor(root.activeTabId), contentRows) - readonly property bool panelAtDefault: panelColumns === DashMetrics.defaultGridColumns && DashMetrics.panelFloorRowsFor(root.activeTabId) <= contentRows + readonly property bool panelAtDefault: panelColumns === DashMetrics.defaultGridColumns && panelRows === DashMetrics.defaultPanelRows(root.activeTabId, contentRows) readonly property DankPanelResizer panelResizer: DankPanelResizer { popout: root stepWidth: DashMetrics.preferredColumnWidth + DashMetrics.gridGap @@ -269,7 +269,7 @@ DankPopout { if (columnsChanged) values.panelColumns = columns; if (rowsChanged) - values.panelRows = rows > mainContainer.contentRows ? rows : DashMetrics.minimumTabRows; + values.panelRows = DashMetrics.panelRowsToStore(root.activeTabId, rows, mainContainer.contentRows); DashRegistry.setOptions(root.activeTabId, values); DashMetrics.panelPreview = null; } @@ -691,7 +691,7 @@ DankPopout { id: pages property var currentHost: null - property real settledHeight: DashMetrics.tabMinHeight + property real settledHeight: DashMetrics.tabDefaultHeight readonly property var currentItem: currentHost?.item ?? null readonly property Item focusTarget: currentHost?.focusTarget ?? null readonly property bool currentSettled: !!currentHost && (!!currentHost.item || currentHost.failed) diff --git a/quickshell/Modules/DankDash/DashMetrics.qml b/quickshell/Modules/DankDash/DashMetrics.qml index 5892cfc78..631b596d6 100644 --- a/quickshell/Modules/DankDash/DashMetrics.qml +++ b/quickshell/Modules/DankDash/DashMetrics.qml @@ -48,6 +48,7 @@ Singleton { readonly property int maximumGridRows: 8 readonly property int maximumCardRows: 64 readonly property int minimumTabRows: 4 + readonly property int defaultTabRows: 5 property var panelPreview: null function clampColumns(value) { @@ -77,13 +78,31 @@ Singleton { function panelFloorRowsFor(id) { if (panelPreview?.id === id) return panelPreview.rows; - return storedPanelRows(id) || minimumTabRows; + return storedPanelRows(id) || defaultRowsFor(id); + } + + function defaultRowsForTab(tab) { + return tab?.sizeToContent === true ? minimumTabRows : defaultTabRows; + } + + function defaultRowsFor(id) { + return defaultRowsForTab(DashRegistry.entry(id)?.tab); } function panelRowsFor(id, contentHeight = 0) { return Math.max(panelFloorRowsFor(id), rowsForHeight(contentHeight)); } + function defaultPanelRows(id, contentRows) { + return Math.max(defaultRowsFor(id), contentRows); + } + + function panelRowsToStore(id, rows, contentRows) { + if (rows < defaultRowsFor(id) || rows > defaultPanelRows(id, contentRows)) + return rows; + return defaultRowsFor(id); + } + function panelHeightFor(id, contentHeight = 0) { return heightForRows(panelRowsFor(id, contentHeight)); } @@ -111,7 +130,8 @@ Singleton { readonly property int gridColumns: panelColumnsFor(overviewId) readonly property real gridRowUnit: 96 readonly property real gridGap: Theme.spacingS - readonly property real tabMinHeight: minimumTabRows * gridRowUnit + (minimumTabRows - 1) * gridGap + readonly property real tabMinHeight: heightForRows(minimumTabRows) + readonly property real tabDefaultHeight: heightForRows(defaultTabRows) readonly property real cardRadius: Theme.cornerRadius readonly property real surfaceRadius: Theme.cornerRadiusXL readonly property real mutedAlpha: 0.72 diff --git a/quickshell/Modules/DankDash/DashRegistry.qml b/quickshell/Modules/DankDash/DashRegistry.qml index 1c8c92867..a6cdd5a21 100644 --- a/quickshell/Modules/DankDash/DashRegistry.qml +++ b/quickshell/Modules/DankDash/DashRegistry.qml @@ -69,10 +69,10 @@ Singleton { return choice("tone", I18n.tr("Tone", "noun, dashboard widget color tone option label"), "", toneChoices); } - function panelOptions() { + function panelOptions(tab) { return [Object.assign(number("panelColumns", I18n.tr("Panel width (columns)"), DashMetrics.defaultGridColumns, DashMetrics.minimumGridColumns, DashMetrics.maximumGridColumns), { "settingsOnly": true - }), Object.assign(number("panelRows", I18n.tr("Panel height (rows)"), DashMetrics.minimumTabRows, DashMetrics.minimumTabRows, DashMetrics.maximumGridRows), { + }), Object.assign(number("panelRows", I18n.tr("Panel height (rows)"), DashMetrics.defaultRowsForTab(tab), DashMetrics.minimumTabRows, DashMetrics.maximumGridRows), { "settingsOnly": true })]; } @@ -95,7 +95,8 @@ Singleton { "description": I18n.tr("Now playing and media controls"), "tab": { "component": mediaTab, - "async": true + "async": true, + "sizeToContent": true }, "card": { "component": mediaCard, @@ -143,7 +144,8 @@ Singleton { "available": SettingsData.weatherEnabled, "tab": { "component": weatherTab, - "async": true + "async": true, + "sizeToContent": true }, "card": { "component": weatherCard, @@ -372,7 +374,6 @@ Singleton { } readonly property var entries: { - const panel = panelOptions(); return builtins.map(e => e.card ? Object.assign({}, e, { "card": Object.assign({ "text": e.text, @@ -383,7 +384,7 @@ Singleton { "maxH": DashMetrics.maximumCardRows }, e.card) }) : e).concat(pluginEntries).map(e => e.tab ? Object.assign({}, e, { - "options": (e.options ?? []).concat(panel) + "options": (e.options ?? []).concat(panelOptions(e.tab)) }) : e); } @@ -548,7 +549,7 @@ Singleton { const stored = storedOptions(id); if (!("panelColumns" in stored) && !("panelRows" in stored)) return; - setPanelSize(id, DashMetrics.defaultGridColumns, DashMetrics.minimumTabRows); + setPanelSize(id, DashMetrics.defaultGridColumns, DashMetrics.defaultRowsFor(id)); } function resetOptions(id) { diff --git a/quickshell/Modules/DankDash/Media/MediaDeviceRow.qml b/quickshell/Modules/DankDash/Media/MediaDeviceRow.qml index 3777d9c81..7350ef082 100644 --- a/quickshell/Modules/DankDash/Media/MediaDeviceRow.qml +++ b/quickshell/Modules/DankDash/Media/MediaDeviceRow.qml @@ -38,7 +38,7 @@ SettingsRow { leading: Rectangle { width: Theme.iconButtonSize height: width - radius: Theme.cornerRadiusFull + radius: Theme.fullRadius(width, height) color: root.selected ? Theme.onPrimary : Theme.chipSurface DankIcon { diff --git a/quickshell/Modules/DankDash/NotificationsTab.qml b/quickshell/Modules/DankDash/NotificationsTab.qml index 75d2a488a..fa37ec9a4 100644 --- a/quickshell/Modules/DankDash/NotificationsTab.qml +++ b/quickshell/Modules/DankDash/NotificationsTab.qml @@ -81,7 +81,7 @@ FocusScope { viewport.contentY = Math.max(0, Math.min(point.y, bottom)); } - implicitHeight: NotificationMetrics.centerMaxHeight + implicitHeight: DashMetrics.tabMinHeight enabled: interactive clip: true LayoutMirroring.enabled: I18n.isRtl diff --git a/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml b/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml index ef4052cb8..085f41a8d 100644 --- a/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml +++ b/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml @@ -569,7 +569,7 @@ Card { width: parent ? parent.width : 0 height: Math.max(DashMetrics.eventRowMinHeight, eventContent.implicitHeight + Theme.spacingS * 2) - radius: Theme.cornerRadiusM + radius: Theme.cornerRadiusS color: isDragging ? Theme.withAlpha(Theme.primary, Theme.stateLayerDrag) : Theme.foregroundColor(Theme.chipSurface, Theme.isFloatingWindow(root)) z: isDragging ? 100 : visualIndex activeFocusOnTab: !!modelData && !isEditing && root.interactive diff --git a/quickshell/Modules/DankDash/WallpaperTab.qml b/quickshell/Modules/DankDash/WallpaperTab.qml index 4822c620e..8449d7003 100644 --- a/quickshell/Modules/DankDash/WallpaperTab.qml +++ b/quickshell/Modules/DankDash/WallpaperTab.qml @@ -16,7 +16,7 @@ Item { LayoutMirroring.childrenInherit: true implicitWidth: DashMetrics.contentWidthFor(SettingsData.showWeekNumber, DashMetrics.panelColumnsFor(entryId)) - implicitHeight: DashMetrics.tabMinHeight + DashMetrics.wallpaperFooterHeight + implicitHeight: DashMetrics.tabMinHeight property string wallpaperDir: "" readonly property string searchQuery: wallpaperSearchField.text diff --git a/quickshell/Modules/DankIsland/Activities/DashTabFace.qml b/quickshell/Modules/DankIsland/Activities/DashTabFace.qml index bdf2eb2e7..237550f6b 100644 --- a/quickshell/Modules/DankIsland/Activities/DashTabFace.qml +++ b/quickshell/Modules/DankIsland/Activities/DashTabFace.qml @@ -58,7 +58,7 @@ FocusScope { if (columnsChanged) values.panelColumns = columns; if (rowsChanged) - values.panelRows = rows > root.contentRows ? rows : DashMetrics.minimumTabRows; + values.panelRows = DashMetrics.panelRowsToStore(root.entryId, rows, root.contentRows); DashRegistry.setOptions(root.entryId, values); DashMetrics.panelPreview = null; } @@ -210,7 +210,7 @@ FocusScope { buttonSize: PopoutMetrics.chromeButtonSize iconSize: PopoutMetrics.chromeIconSize resizing: root.panelResizer.resizing - atDefault: root.panelColumns === DashMetrics.defaultGridColumns && DashMetrics.panelFloorRowsFor(root.entryId) <= root.contentRows + atDefault: root.panelColumns === DashMetrics.defaultGridColumns && root.panelRows === DashMetrics.defaultPanelRows(root.entryId, root.contentRows) sizeText: root.panelColumns + "×" + root.panelRows onResizeStarted: (px, py, signX) => root.panelResizer.begin(px, py, signX) onResizeMoved: (px, py) => root.panelResizer.move(px, py) diff --git a/quickshell/Modules/DankIsland/IslandController.qml b/quickshell/Modules/DankIsland/IslandController.qml index d7ca65256..afb06e45d 100644 --- a/quickshell/Modules/DankIsland/IslandController.qml +++ b/quickshell/Modules/DankIsland/IslandController.qml @@ -78,7 +78,7 @@ QtObject { readonly property real dashboardMaxWidth: Math.min(dashboardAvailableWidth, DashMetrics.widthFor(SettingsData.showWeekNumber, undefined, editingActivity !== "" ? dashboardColumnCap : DashRegistry.widestPanelColumns) + PopoutMetrics.editOverflow * 2) property var dashboardContentHeights: ({}) readonly property real dashboardChromeHeight: Theme.buttonHeightXS + Theme.spacingXS * 2 + DashMetrics.contentPadding - readonly property real dashboardHeight: Math.min(dashboardAvailableHeight, Math.max(DashMetrics.tabMinHeight + dashboardChromeHeight, ...Object.values(dashboardContentHeights))) + readonly property real dashboardHeight: Math.min(dashboardAvailableHeight, Math.max(DashMetrics.tabDefaultHeight + dashboardChromeHeight, ...Object.values(dashboardContentHeights))) readonly property int dashboardRowBudget: Math.max(DashMetrics.minimumTabRows, Math.floor((dashboardAvailableHeight - dashboardChromeHeight + DashMetrics.gridGap) / (DashMetrics.gridRowUnit + DashMetrics.gridGap))) readonly property real mediaCompactMaxLength: 360 property real notificationContentLength: 0 diff --git a/quickshell/Modules/Settings/ThemeSurfacesTab.qml b/quickshell/Modules/Settings/ThemeSurfacesTab.qml index aea057d60..8cb07fcb0 100644 --- a/quickshell/Modules/Settings/ThemeSurfacesTab.qml +++ b/quickshell/Modules/Settings/ThemeSurfacesTab.qml @@ -134,10 +134,24 @@ Column { onClicked: root.parentModal?.navigateTo("compositor_layout") } + SettingsButtonGroupRow { + tab: "theme" + tags: ["corner", "radius", "rounded", "square", "fixed", "material", "shape"] + settingKey: "radiusMode" + text: I18n.tr("Corner style") + model: [I18n.tr("Material scale", "corner style: Material shape scale with a strength slider"), I18n.tr("Fixed", "corner style: one radius for every corner")] + currentIndex: SettingsData.radiusMode === "fixed" ? 1 : 0 + onSelectionChanged: (index, selected) => { + if (selected) + SettingsData.set("radiusMode", index === 1 ? "fixed" : "scale"); + } + } + SettingsSliderRow { tab: "theme" - tags: ["corner", "radius", "rounded", "square"] + tags: ["corner", "radius", "rounded", "square", "strength"] settingKey: "radiusStrength" + visible: SettingsData.radiusMode !== "fixed" text: I18n.tr("Radius strength", "global component corner rounding") description: I18n.tr("50 uses Material shapes. Lower values reduce rounding; higher values increase it.", "radius strength slider description") minimumLabel: I18n.tr("Square") @@ -148,6 +162,20 @@ Column { onSliderValueChanged: newValue => SettingsData.set("radiusStrength", newValue) } + SettingsSliderRow { + tab: "theme" + tags: ["corner", "radius", "rounded", "square", "fixed"] + settingKey: "fixedRadius" + visible: SettingsData.radiusMode === "fixed" + text: I18n.tr("Corner radius") + minimumLabel: I18n.tr("Square") + value: SettingsData.fixedRadius + minimum: 0 + maximum: 32 + unit: "px" + onSliderValueChanged: newValue => SettingsData.set("fixedRadius", newValue) + } + SettingsSliderRow { tab: "theme" tags: ["window", "corner", "radius", "rounded", "popout", "menu", "modal", "compositor", "niri", "hyprland", "mango"] diff --git a/quickshell/tests/qml/dash-panel-resize.qml b/quickshell/tests/qml/dash-panel-resize.qml index d68179596..ae81120ce 100644 --- a/quickshell/tests/qml/dash-panel-resize.qml +++ b/quickshell/tests/qml/dash-panel-resize.qml @@ -172,6 +172,13 @@ ShellRoot { beginDrag(root.popout, c); c.panelResizer.end(); check(!DashMetrics.panelPreview && SettingsData.dashOptions?.media === undefined, "release without movement stores nothing"); + check(c.panelRows === DashMetrics.minimumTabRows && c.contentRows === DashMetrics.minimumTabRows && c.panelAtDefault, "media sizes to its content: " + JSON.stringify([c.panelRows, c.contentRows])); + beginDrag(root.popout, c); + dragTo(root.popout, c, 0, root.rowStep); + c.panelResizer.end(); + check(SettingsData.dashOptions?.media?.panelRows === DashMetrics.minimumTabRows + 1 && c.panelRows === DashMetrics.minimumTabRows + 1 && !c.panelAtDefault, "one row above the content is stored for a content-sized tab: " + JSON.stringify([SettingsData.dashOptions?.media, c.panelRows])); + DashRegistry.resetPanelSize("media"); + check(SettingsData.dashOptions?.media === undefined && c.panelRows === DashMetrics.minimumTabRows, "reset returns media to its content rows: " + c.panelRows); root.popout.editMode = false; DashRegistry.setPanelSize("overview", DashMetrics.defaultGridColumns, root.baseRows + 1); root.popout.requestTab("overview"); @@ -270,40 +277,45 @@ ShellRoot { break; case 5: root.wallHeight = root.popout.popupHeight; - check(c.contentRows === DashMetrics.rowsForHeight(DashMetrics.tabMinHeight + DashMetrics.wallpaperFooterHeight) && c.panelRows === c.contentRows, "wallpaper rows cover its content: " + JSON.stringify([c.contentRows, c.panelRows])); - check(DashMetrics.heightForRows(c.contentRows) > DashMetrics.tabMinHeight + DashMetrics.wallpaperFooterHeight, "wallpaper content sits between rows"); - check(c.panelResizer.maxRows > c.contentRows, "screen leaves room for one more row: " + JSON.stringify([c.panelResizer.maxRows, c.contentRows])); + check(c.contentRows === DashMetrics.minimumTabRows && c.panelRows === DashMetrics.defaultTabRows, "wallpaper rests on the shared default rows: " + JSON.stringify([c.contentRows, c.panelRows])); + check(c.panelResizer.maxRows > c.panelRows, "screen leaves room for one more row: " + JSON.stringify([c.panelResizer.maxRows, c.panelRows])); beginDrag(root.popout, c); dragTo(root.popout, c, 0, root.rowStep); - check(DashMetrics.panelPreview?.rows === c.contentRows + 1, "wallpaper preview adds a row: " + JSON.stringify(DashMetrics.panelPreview)); + check(DashMetrics.panelPreview?.rows === DashMetrics.defaultTabRows + 1, "wallpaper preview adds a row: " + JSON.stringify(DashMetrics.panelPreview)); break; case 6: check(root.popout.popupHeight === root.wallHeight + root.rowStep, "one row of drag adds one row of height: " + JSON.stringify([root.popout.popupHeight, root.wallHeight])); dragTo(root.popout, c, 0, 0); - check(DashMetrics.panelPreview?.rows === c.contentRows, "dragging back lands on the content rows"); + check(DashMetrics.panelPreview?.rows === DashMetrics.defaultTabRows, "dragging back lands on the default rows"); break; case 7: - check(root.popout.popupHeight === root.wallHeight, "the content-row preview matches the resting height: " + JSON.stringify([root.popout.popupHeight, root.wallHeight])); + check(root.popout.popupHeight === root.wallHeight, "the default-row preview matches the resting height: " + JSON.stringify([root.popout.popupHeight, root.wallHeight])); c.panelResizer.end(); check(!DashMetrics.panelPreview && SettingsData.dashOptions?.wallpaper === undefined, "release on the start rows stores nothing"); beginDrag(root.popout, c); dragTo(root.popout, c, 0, root.rowStep); c.panelResizer.end(); - check(SettingsData.dashOptions?.wallpaper?.panelRows === c.contentRows + 1, "wallpaper rows stored: " + JSON.stringify(SettingsData.dashOptions?.wallpaper)); + check(SettingsData.dashOptions?.wallpaper?.panelRows === DashMetrics.defaultTabRows + 1, "wallpaper rows stored: " + JSON.stringify(SettingsData.dashOptions?.wallpaper)); break; case 8: check(root.popout.popupHeight === root.wallHeight + root.rowStep, "committed rows keep the preview height: " + JSON.stringify([root.popout.popupHeight, root.wallHeight])); beginDrag(root.popout, c); dragTo(root.popout, c, 0, -root.rowStep); c.panelResizer.end(); - check(SettingsData.dashOptions?.wallpaper === undefined, "dragging back to the content clears the stored rows"); + check(SettingsData.dashOptions?.wallpaper === undefined, "dragging back to the default clears the stored rows"); + beginDrag(root.popout, c); + dragTo(root.popout, c, 0, -root.rowStep); + c.panelResizer.end(); + check(SettingsData.dashOptions?.wallpaper?.panelRows === DashMetrics.minimumTabRows && c.panelRows === DashMetrics.minimumTabRows, "wallpaper shrinks below the default down to its content: " + JSON.stringify([SettingsData.dashOptions?.wallpaper, c.panelRows])); break; case 9: - check(root.popout.popupHeight === root.wallHeight, "cleared rows keep the row-aligned height: " + JSON.stringify([root.popout.popupHeight, root.wallHeight])); + check(root.popout.popupHeight === root.wallHeight - root.rowStep, "stored rows below the default shrink the panel: " + JSON.stringify([root.popout.popupHeight, root.wallHeight])); + DashRegistry.resetPanelSize("wallpaper"); + check(SettingsData.dashOptions?.wallpaper === undefined && c.panelRows === DashMetrics.defaultTabRows, "reset returns wallpaper to the default rows: " + c.panelRows); root.popout.editMode = false; break; case 10: - check(root.popout.popupHeight === root.wallHeightOut, "leaving edit mode keeps the height: " + JSON.stringify([root.popout.popupHeight, root.wallHeightOut])); + check(root.popout.popupHeight === root.wallHeightOut, "reset restores the default height outside edit mode: " + JSON.stringify([root.popout.popupHeight, root.wallHeightOut])); SettingsData.weatherEnabled = true; root.popout.requestTab("weather"); break; diff --git a/quickshell/tests/settings-radius.test.mjs b/quickshell/tests/settings-radius.test.mjs index 103d9579a..3f32350f3 100644 --- a/quickshell/tests/settings-radius.test.mjs +++ b/quickshell/tests/settings-radius.test.mjs @@ -7,7 +7,7 @@ const spec = store.SpecModule; test("legacy migration preserves explicit radii and defaults sparse settings to 50", () => { for (const version of [0, 13, 14, 18, 22]) { - for (const [radius, strength] of [[0, 0], [8, 25], [12, 38], [16, 50], [32, 80], [undefined, 50]]) { + for (const [radius, strength] of [[0, 0], [8, 25], [12, 38], [16, 50], [32, 100], [undefined, 50]]) { const original = { configVersion: version, cornerRadius: radius, niriLayoutRadiusOverride: 17 }; const migrated = store.migrateToVersion(original, 26); assert.equal(migrated.radiusStrength, strength); diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 054a3b882..8940ee746 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -549,6 +549,44 @@ ], "page": "theme_surfaces" }, + { + "section": "fixedRadius", + "label": "Corner radius", + "tabIndex": -1, + "category": "Interface style", + "keywords": [ + "corner", + "corners", + "fixed", + "interface", + "radius", + "round", + "rounded", + "square", + "style" + ], + "page": "theme_surfaces" + }, + { + "section": "radiusMode", + "label": "Corner style", + "tabIndex": -1, + "category": "Interface style", + "keywords": [ + "corner", + "corners", + "fixed", + "interface", + "material", + "radius", + "round", + "rounded", + "shape", + "square", + "style" + ], + "page": "theme_surfaces" + }, { "section": "notificationHistorySaveCritical", "label": "Critical",