From bd8976c6209c07776a966fb4a0677b3ed864f2c8 Mon Sep 17 00:00:00 2001 From: purian23 Date: Sun, 28 Sep 2025 23:55:59 -0400 Subject: [PATCH] feat: Docks refactor - Top/Bottom options --- Common/SettingsData.qml | 50 +++++- Modules/DankBar/DankBar.qml | 76 ++++----- Modules/Dock/Dock.qml | 248 ++++++++++++++++++----------- Modules/Dock/DockApps.qml | 2 +- Modules/Dock/DockContextMenu.qml | 18 ++- Modules/Settings/DockTab.qml | 264 ++++++++++++++++++++++--------- shell.qml | 46 ++++-- 7 files changed, 479 insertions(+), 225 deletions(-) diff --git a/Common/SettingsData.qml b/Common/SettingsData.qml index ff1ee0b6..33e529bb 100644 --- a/Common/SettingsData.qml +++ b/Common/SettingsData.qml @@ -12,6 +12,13 @@ import qs.Services Singleton { id: root + enum Position { + Top, + Bottom, + Left, + Right + } + // Theme settings property string currentThemeName: "blue" property string customThemeFile: "" @@ -119,6 +126,9 @@ Singleton { property bool dockAutoHide: false property bool dockGroupByApp: false property bool dockOpenOnOverview: false + property int dockPosition: SettingsData.Position.Bottom + property real dockSpacing: 4 + property real dockBottomGap: 0 property real cornerRadius: 12 property bool notificationOverlayEnabled: false property bool dankBarAutoHide: false @@ -146,6 +156,7 @@ Singleton { readonly property string _configDir: Paths.strip(_configUrl) signal forceDankBarLayoutRefresh + signal forceDockLayoutRefresh signal widgetDataChanged signal workspaceIconsUpdated @@ -312,6 +323,9 @@ Singleton { showDock = settings.showDock !== undefined ? settings.showDock : false dockAutoHide = settings.dockAutoHide !== undefined ? settings.dockAutoHide : false dockGroupByApp = settings.dockGroupByApp !== undefined ? settings.dockGroupByApp : false + dockPosition = settings.dockPosition !== undefined ? settings.dockPosition : SettingsData.Position.Bottom + dockSpacing = settings.dockSpacing !== undefined ? settings.dockSpacing : 4 + dockBottomGap = settings.dockBottomGap !== undefined ? settings.dockBottomGap : 0 cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12 notificationOverlayEnabled = settings.notificationOverlayEnabled !== undefined ? settings.notificationOverlayEnabled : false dankBarAutoHide = settings.dankBarAutoHide !== undefined ? settings.dankBarAutoHide : (settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false) @@ -428,6 +442,9 @@ Singleton { "dockAutoHide": dockAutoHide, "dockGroupByApp": dockGroupByApp, "dockOpenOnOverview": dockOpenOnOverview, + "dockPosition": dockPosition, + "dockSpacing": dockSpacing, + "dockBottomGap": dockBottomGap, "cornerRadius": cornerRadius, "notificationOverlayEnabled": notificationOverlayEnabled, "dankBarAutoHide": dankBarAutoHide, @@ -959,7 +976,7 @@ Singleton { function setShowDock(enabled) { showDock = enabled - if (enabled && dankBarAtBottom) { + if (enabled && dankBarAtBottom && dockPosition === SettingsData.Position.Bottom) { setDankBarAtBottom(false) } saveSettings() @@ -1057,9 +1074,36 @@ Singleton { function setDankBarAtBottom(enabled) { dankBarAtBottom = enabled - if (enabled && showDock) { - setShowDock(false) + if (enabled && showDock && dockPosition === SettingsData.Position.Bottom) { + setDockPosition(SettingsData.Position.Top) } + if (!enabled && showDock && dockPosition === SettingsData.Position.Top) { + setDockPosition(SettingsData.Position.Bottom) + } + saveSettings() + } + + function setDockPosition(position) { + dockPosition = position + if (position === SettingsData.Position.Bottom && dankBarAtBottom && showDock) { + setDankBarAtBottom(false) + } + if (position === SettingsData.Position.Top && !dankBarAtBottom && showDock) { + setDankBarAtBottom(true) + } + saveSettings() + Qt.callLater(() => forceDockLayoutRefresh()) + } + function setDockSpacing(spacing) { + dockSpacing = spacing + saveSettings() + } + function setDockBottomGap(gap) { + dockBottomGap = gap + saveSettings() + } + function setDockOpenOnOverview(enabled) { + dockOpenOnOverview = enabled saveSettings() } diff --git a/Modules/DankBar/DankBar.qml b/Modules/DankBar/DankBar.qml index 797b2d89..388001b2 100644 --- a/Modules/DankBar/DankBar.qml +++ b/Modules/DankBar/DankBar.qml @@ -15,34 +15,40 @@ import qs.Modules.DankBar import qs.Services import qs.Widgets -PanelWindow { - id: root +Variants { + id: dankBarVariants + model: SettingsData.getFilteredScreens("dankBar") - WlrLayershell.namespace: "quickshell:bar" + signal colorPickerRequested() - property var modelData - property var notepadVariants: null + function getNotepadInstanceForScreen() { + if (typeof notepadSlideoutVariants === "undefined" || !notepadSlideoutVariants || !notepadSlideoutVariants.instances) { + return null + } - property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled + for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) { + var slideout = notepadSlideoutVariants.instances[i] + if (slideout.modelData && slideout.modelData.name === root.screen?.name) { + return slideout + } + } + + return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null + } + + delegate: PanelWindow { + id: root + + WlrLayershell.namespace: "quickshell:bar" + + property var modelData: item + + property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled property real wingtipsRadius: Theme.cornerRadius readonly property real _wingR: Math.max(0, wingtipsRadius) readonly property color _bgColor: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency) readonly property real _dpr: (root.screen && root.screen.devicePixelRatio) ? root.screen.devicePixelRatio : 1 function px(v) { return Math.round(v * _dpr) / _dpr } - - signal colorPickerRequested() - - function getNotepadInstanceForScreen() { - if (!notepadVariants || !notepadVariants.instances) return null - - for (var i = 0; i < notepadVariants.instances.length; i++) { - var slideout = notepadVariants.instances[i] - if (slideout.modelData && slideout.modelData.name === root.screen?.name) { - return slideout - } - } - return null - } property string screenName: modelData.name readonly property int notificationCount: NotificationService.notifications.length readonly property real effectiveBarHeight: Math.max(root.widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) @@ -57,30 +63,9 @@ PanelWindow { ToastService.showError("Please install Material Symbols Rounded and Restart your Shell. See README.md for instructions") } - if (SettingsData.forceStatusBarLayoutRefresh) { - SettingsData.forceStatusBarLayoutRefresh.connect(() => { - Qt.callLater(() => { - leftSection.visible = false - centerSection.visible = false - rightSection.visible = false - Qt.callLater(() => { - leftSection.visible = true - centerSection.visible = true - rightSection.visible = true - }) - }) - }) - } - updateGpuTempConfig() - Qt.callLater(() => Qt.callLater(forceWidgetRefresh)) } - function forceWidgetRefresh() { - const sections = [leftSection, centerSection, rightSection] - sections.forEach(section => section && (section.visible = false)) - Qt.callLater(() => sections.forEach(section => section && (section.visible = true))) - } function updateGpuTempConfig() { const allWidgets = [...(SettingsData.dankBarLeftWidgets || []), ...(SettingsData.dankBarCenterWidgets || []), ...(SettingsData.dankBarRightWidgets || [])] @@ -226,7 +211,7 @@ PanelWindow { } Component.onCompleted: { - notepadInstance = root.getNotepadInstanceForScreen() + notepadInstance = dankBarVariants.getNotepadInstanceForScreen() } Connections { @@ -1284,7 +1269,7 @@ PanelWindow { section: topBarContent.getWidgetSection(parent) || "right" parentScreen: root.screen onColorPickerRequested: { - root.colorPickerRequested() + dankBarVariants.colorPickerRequested() } } } @@ -1313,6 +1298,5 @@ PanelWindow { } } } - - -} + } +} \ No newline at end of file diff --git a/Modules/Dock/Dock.qml b/Modules/Dock/Dock.qml index a966ad81..dd7c2788 100644 --- a/Modules/Dock/Dock.qml +++ b/Modules/Dock/Dock.qml @@ -7,22 +7,46 @@ import qs.Common import qs.Services import qs.Widgets -PanelWindow { - id: dock +pragma ComponentBehavior: Bound - WlrLayershell.namespace: "quickshell:dock" +Variants { + id: dockVariants + model: SettingsData.getFilteredScreens("dock") - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - property var modelData property var contextMenu + + delegate: PanelWindow { + id: dock + + WlrLayershell.namespace: "quickshell:dock" + + anchors { + top: SettingsData.dockPosition === SettingsData.Position.Top + bottom: SettingsData.dockPosition === SettingsData.Position.Bottom + left: true + right: true + } + + property var modelData: item property bool autoHide: SettingsData.dockAutoHide property real backgroundTransparency: SettingsData.dockTransparency property bool groupByApp: SettingsData.dockGroupByApp - property bool contextMenuOpen: (contextMenu && contextMenu.visible && contextMenu.screen === modelData) + readonly property bool isDockAtTop: SettingsData.dockPosition === SettingsData.Position.Top + readonly property bool isDankBarAtTop: !SettingsData.dankBarAtBottom + readonly property bool isDankBarVisible: SettingsData.dankBarVisible + readonly property bool needsBarSpacing: isDankBarVisible && (isDockAtTop === isDankBarAtTop) + readonly property real widgetHeight: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6) + readonly property real effectiveBarHeight: Math.max(widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + readonly property real barSpacing: needsBarSpacing ? (SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap) : 0 + + readonly property real dockMargin: SettingsData.dockSpacing + readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1 + function px(v) { return Math.round(v * _dpr) / _dpr } + + + property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData) property bool windowIsFullscreen: { if (!ToplevelManager.activeToplevel) { return false @@ -31,11 +55,27 @@ PanelWindow { const fullscreenApps = ["vlc", "mpv", "kodi", "steam", "lutris", "wine", "dosbox"] return fullscreenApps.some(app => activeWindow.appId && activeWindow.appId.toLowerCase().includes(app)) } + property bool revealSticky: false + + Timer { + id: revealHold + interval: 250 + repeat: false + onTriggered: dock.revealSticky = false + } + property bool reveal: { if (CompositorService.isNiri && NiriService.inOverview) { return SettingsData.dockOpenOnOverview } - return (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen) && !windowIsFullscreen + return (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky) && !windowIsFullscreen + } + + onContextMenuOpenChanged: { + if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) { + revealSticky = true + revealHold.restart() + } } Connections { @@ -49,102 +89,124 @@ PanelWindow { visible: SettingsData.showDock color: "transparent" - anchors { - bottom: true - left: true - right: true - } - margins { - left: 0 - right: 0 + exclusiveZone: { + if (!SettingsData.showDock || autoHide) return -1 + if (needsBarSpacing) return -1 + return px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) } - implicitHeight: 100 - exclusiveZone: autoHide ? -1 : 65 - 16 - mask: Region { item: dockMouseArea } - MouseArea { - id: dockMouseArea - property real currentScreen: modelData ? modelData : dock.screen - property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920 - property real maxDockWidth: Math.min(screenWidth * 0.8, 1200) + Item { + id: dockCore + anchors.fill: parent - height: dock.reveal ? 65 : 20 - width: dock.reveal ? Math.min(dockBackground.width + 32, maxDockWidth) : Math.min(Math.max(dockBackground.width + 64, 200), screenWidth * 0.5) - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - } - hoverEnabled: true - - Behavior on height { - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - - Item { - id: dockContainer - anchors.fill: parent - - transform: Translate { - id: dockSlide - y: dock.reveal ? 0 : 60 - - Behavior on y { - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic + Connections { + target: dockMouseArea + function onContainsMouseChanged() { + if (dockMouseArea.containsMouse) { + dock.revealSticky = true + revealHold.stop() + } else { + if (dock.autoHide && !dock.contextMenuOpen) { + revealHold.restart() } } } + } - Rectangle { - id: dockBackground - objectName: "dockBackground" - anchors { - top: parent.top - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - } + MouseArea { + id: dockMouseArea + property real currentScreen: modelData ? modelData : dock.screen + property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920 + property real maxDockWidth: Math.min(screenWidth * 0.8, 1200) - width: dockApps.implicitWidth + 12 - height: parent.height - 8 + height: dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1 + width: dock.reveal ? Math.min(dockBackground.implicitWidth + 32, maxDockWidth) : Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5) + anchors { + top: SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top + bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined + horizontalCenter: parent.horizontalCenter + } + hoverEnabled: true + acceptedButtons: Qt.NoButton - anchors.topMargin: 4 - anchors.bottomMargin: 1 - - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency) - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - layer.enabled: true - - Rectangle { - anchors.fill: parent - color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04) - radius: parent.radius - } - - DockApps { - id: dockApps - - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: 4 - anchors.bottomMargin: 4 - - contextMenu: dock.contextMenu - groupByApp: dock.groupByApp + Behavior on height { + NumberAnimation { + duration: 200 + easing.type: Easing.OutCubic } } + + Item { + id: dockContainer + anchors.fill: parent + + transform: Translate { + id: dockSlide + y: { + if (dock.reveal) return 0 + if (SettingsData.dockPosition === SettingsData.Position.Bottom) { + return 60 + } else { + return -60 + } + } + + Behavior on y { + NumberAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + } + + Rectangle { + id: dockBackground + objectName: "dockBackground" + anchors { + top: SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top + bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined + horizontalCenter: parent.horizontalCenter + } + anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? 0 : barSpacing + 4 + anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + 1 : 0 + + implicitWidth: dockApps.implicitWidth + SettingsData.dockSpacing * 2 + implicitHeight: dockApps.implicitHeight + SettingsData.dockSpacing * 2 + width: implicitWidth + height: implicitHeight + + color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency) + radius: Theme.cornerRadius + border.width: 1 + border.color: Theme.outlineMedium + layer.enabled: true + + Rectangle { + anchors.fill: parent + color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04) + radius: parent.radius + } + + DockApps { + id: dockApps + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: SettingsData.dockSpacing + anchors.bottomMargin: SettingsData.dockSpacing + + contextMenu: dockVariants.contextMenu + groupByApp: dock.groupByApp + } + } + Rectangle { id: appTooltip @@ -176,15 +238,15 @@ PanelWindow { property string tooltipText: hoveredButton ? hoveredButton.tooltipText : "" visible: hoveredButton !== null && tooltipText !== "" - width: tooltipLabel.implicitWidth + 24 - height: tooltipLabel.implicitHeight + 12 + width: px(tooltipLabel.implicitWidth + 24) + height: px(tooltipLabel.implicitHeight + 12) color: Theme.surfaceContainer radius: Theme.cornerRadius border.width: 1 border.color: Theme.outlineMedium - y: -height - 8 + y: SettingsData.dockPosition === SettingsData.Position.Bottom ? -height - Theme.spacingS : parent.height + Theme.spacingS x: hoveredButton ? hoveredButton.mapToItem(dockContainer, hoveredButton.width / 2, 0).x - width / 2 : 0 StyledText { @@ -196,5 +258,7 @@ PanelWindow { } } } + } + } } } diff --git a/Modules/Dock/DockApps.qml b/Modules/Dock/DockApps.qml index 09c15f13..1c9fa0ec 100644 --- a/Modules/Dock/DockApps.qml +++ b/Modules/Dock/DockApps.qml @@ -35,7 +35,7 @@ Item { Row { id: row - spacing: 2 + spacing: 8 anchors.centerIn: parent height: 40 diff --git a/Modules/Dock/DockContextMenu.qml b/Modules/Dock/DockContextMenu.qml index b592abca..2acf6ea8 100644 --- a/Modules/Dock/DockContextMenu.qml +++ b/Modules/Dock/DockContextMenu.qml @@ -96,8 +96,15 @@ PanelWindow { actualDockHeight = dockBackground.height } + const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom const dockBottomMargin = 16 - const buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20 + let buttonScreenY + + if (isDockAtBottom) { + buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20 + } else { + buttonScreenY = actualDockHeight + dockBottomMargin + 20 + } const dockContentWidth = dockWindow.width const screenWidth = root.screen.width @@ -119,7 +126,14 @@ PanelWindow { const want = root.anchorPos.x - width / 2 return Math.max(left, Math.min(right, want)) } - y: Math.max(10, root.anchorPos.y - height + 30) + y: { + const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom + if (isDockAtBottom) { + return Math.max(10, root.anchorPos.y - height + 30) + } else { + return Math.min(root.height - height - 10, root.anchorPos.y - 30) + } + } color: Theme.popupBackground() radius: Theme.cornerRadius border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) diff --git a/Modules/Settings/DockTab.qml b/Modules/Settings/DockTab.qml index 53324d34..fe9265b9 100644 --- a/Modules/Settings/DockTab.qml +++ b/Modules/Settings/DockTab.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Controls import Quickshell.Widgets import qs.Common +import qs.Services import qs.Widgets Item { @@ -19,10 +20,10 @@ Item { width: parent.width spacing: Theme.spacingXL - // Enable Dock + // Dock Position StyledRect { width: parent.width - height: enableDockSection.implicitHeight + Theme.spacingL * 2 + height: dockPositionSection.implicitHeight + Theme.spacingL * 2 radius: Theme.cornerRadius color: Theme.surfaceContainerHigh border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, @@ -30,7 +31,7 @@ Item { border.width: 0 Column { - id: enableDockSection + id: dockPositionSection anchors.fill: parent anchors.margins: Theme.spacingL @@ -41,61 +42,53 @@ Item { spacing: Theme.spacingM DankIcon { - name: "dock_to_bottom" + name: "swap_vert" size: Theme.iconSize color: Theme.primary anchors.verticalCenter: parent.verticalCenter } - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - - enableToggle.width - Theme.spacingM - spacing: Theme.spacingXS + StyledText { + id: positionText + text: "Dock Position" + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: "Show Dock" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: "Display a dock at the bottom of the screen with pinned and running applications" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } } - DankToggle { - id: enableToggle - + Item { + width: parent.width - Theme.iconSize - Theme.spacingM - positionText.width - positionButtonGroup.width - Theme.spacingM * 2 anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.showDock - onToggled: checked => { - SettingsData.setShowDock(checked) - } + } + + DankButtonGroup { + id: positionButtonGroup + anchors.verticalCenter: parent.verticalCenter + model: ["Top", "Bottom"] + currentIndex: SettingsData.dockPosition === SettingsData.Position.Bottom ? 1 : 0 + onSelectionChanged: (index, selected) => { + if (selected) { + SettingsData.setDockPosition(index === 1 ? SettingsData.Position.Bottom : SettingsData.Position.Top) + } + } } } } } - // Auto-hide Dock + // Dock Visibility Section StyledRect { width: parent.width - height: autoHideSection.implicitHeight + Theme.spacingL * 2 + height: dockVisibilitySection.implicitHeight + Theme.spacingL * 2 radius: Theme.cornerRadius color: Theme.surfaceContainerHigh border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.width: 0 - visible: SettingsData.showDock - opacity: visible ? 1 : 0 Column { - id: autoHideSection + id: dockVisibilitySection anchors.fill: parent anchors.margins: Theme.spacingL @@ -126,7 +119,7 @@ Item { } StyledText { - text: "Hide the dock when not in use and reveal it when hovering near the bottom of the screen" + text: "Hide the dock when not in use and reveal it when hovering near the dock area" font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceVariantText wrapMode: Text.WordWrap @@ -144,41 +137,73 @@ Item { } } } - } - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.2 } - } - } - - // Show Dock in Overview - StyledRect { - width: parent.width - height: overviewSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, - Theme.outline.b, 0.2) - border.width: 0 - visible: SettingsData.showDock - opacity: visible ? 1 : 0 - - Column { - id: overviewSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM Row { width: parent.width spacing: Theme.spacingM DankIcon { - name: "visibility_off" + name: "dock_to_bottom" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - Theme.spacingM + - enableToggle.width - Theme.spacingM + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: "Show Dock" + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + } + + StyledText { + text: "Display a dock with pinned and running applications that can be positioned at the top or bottom of the screen" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + wrapMode: Text.WordWrap + width: parent.width + } + } + + DankToggle { + id: enableToggle + + anchors.verticalCenter: parent.verticalCenter + checked: SettingsData.showDock + onToggled: checked => { + SettingsData.setShowDock(checked) + } + } + } + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.2 + visible: CompositorService.isNiri + } + + Row { + width: parent.width + spacing: Theme.spacingM + visible: CompositorService.isNiri + + DankIcon { + name: "fullscreen" size: Theme.iconSize color: Theme.primary anchors.verticalCenter: parent.verticalCenter @@ -212,18 +237,11 @@ Item { anchors.verticalCenter: parent.verticalCenter checked: SettingsData.dockOpenOnOverview onToggled: checked => { - SettingsData.setdockOpenOnOverview(checked) + SettingsData.setDockOpenOnOverview(checked) } } } } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } } // Group by App @@ -298,6 +316,110 @@ Item { } } + // Dock Spacing Section + StyledRect { + width: parent.width + height: dockSpacingSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Theme.surfaceContainerHigh + border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, + Theme.outline.b, 0.2) + border.width: 0 + visible: SettingsData.showDock + opacity: visible ? 1 : 0 + + Column { + id: dockSpacingSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: "space_bar" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: "Spacing" + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + Column { + width: parent.width + spacing: Theme.spacingS + + StyledText { + text: "Padding" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + } + + DankSlider { + width: parent.width + height: 24 + value: SettingsData.dockSpacing + minimum: 0 + maximum: 32 + unit: "" + showValue: true + wheelEnabled: false + thumbOutlineColor: Theme.surfaceContainerHigh + onSliderValueChanged: newValue => { + SettingsData.setDockSpacing( + newValue) + } + } + } + + Column { + width: parent.width + spacing: Theme.spacingS + + StyledText { + text: "Height to Edge Gap (Exclusive Zone)" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + } + + DankSlider { + width: parent.width + height: 24 + value: SettingsData.dockBottomGap + minimum: -100 + maximum: 100 + unit: "" + showValue: true + wheelEnabled: false + thumbOutlineColor: Theme.surfaceContainerHigh + onSliderValueChanged: newValue => { + SettingsData.setDockBottomGap( + newValue) + } + } + } + } + + Behavior on opacity { + NumberAnimation { + duration: Theme.mediumDuration + easing.type: Theme.emphasizedEasing + } + } + } + // Dock Transparency Section StyledRect { width: parent.width diff --git a/shell.qml b/shell.qml index 711764a6..c31aab9e 100644 --- a/shell.qml +++ b/shell.qml @@ -46,26 +46,52 @@ ShellRoot { anchors.fill: parent } - Variants { - model: SettingsData.getFilteredScreens("dankBar") + Loader { + id: dankBarLoader + active: true + asynchronous: false - delegate: DankBar { - modelData: item - notepadVariants: notepadSlideoutVariants + property var currentPosition: SettingsData.dankBarAtBottom + + sourceComponent: DankBar { onColorPickerRequested: colorPickerModal.show() } + + onCurrentPositionChanged: { + console.log("DEBUG: DankBar position changed to:", currentPosition, "- recreating bar") + const comp = sourceComponent + sourceComponent = null + Qt.callLater(() => { + sourceComponent = comp + }) + } } - Variants { - model: SettingsData.getFilteredScreens("dock") + Loader { + id: dockLoader + active: true + asynchronous: false - delegate: Dock { - modelData: item + property var currentPosition: SettingsData.dockPosition + + sourceComponent: Dock { contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null - Component.onCompleted: { + } + + onLoaded: { + if (item) { dockContextMenuLoader.active = true } } + + onCurrentPositionChanged: { + console.log("DEBUG: Dock position changed to:", currentPosition, "- recreating dock") + const comp = sourceComponent + sourceComponent = null + Qt.callLater(() => { + sourceComponent = comp + }) + } } Loader {