diff --git a/EXAMPLE.md b/EXAMPLE.md index 2a3c2a6..c3bddb5 100644 --- a/EXAMPLE.md +++ b/EXAMPLE.md @@ -48,11 +48,13 @@ Path: `~/.config/overzicht/settings.json` "previewMode": "live", "includeInactiveMonitorPreviews": true, "previewRecaptureDelayMs": 60, + "emptyWorkspaceWallpaper": "", "effects": { "enableBackdrop": false, "backdropOpacity": 0.28, "panelOpacity": 0.92, "workspaceOpacity": 0.86, + "emptyWorkspaceWallpaperOverlayOpacity": 0.18, "windowOverlayOpacity": 0.22 }, "workspaceSpacing": 5, diff --git a/README.md b/README.md index 63f0bcc..fa66869 100644 --- a/README.md +++ b/README.md @@ -80,16 +80,24 @@ Additional optional settings: - `overview.previewMode` - `overview.includeInactiveMonitorPreviews` - `overview.previewRecaptureDelayMs` +- `overview.emptyWorkspaceWallpaper` - `overview.effects.enableBackdrop` - `overview.effects.backdropOpacity` - `overview.effects.panelOpacity` - `overview.effects.workspaceOpacity` +- `overview.effects.emptyWorkspaceWallpaperOverlayOpacity` - `overview.effects.windowOverlayOpacity` - `hacks.hyprlandEventDebounceMs` Visual effects notes: - `enableBackdrop` adds a dimmed full-screen backdrop behind the overview. +Visual effects notes: + +- `enableBackdrop` adds a dimmed full-screen backdrop behind the overview. +- `emptyWorkspaceWallpaperOverlayOpacity` controls the tint applied over wallpaper-backed tiles. +- `emptyWorkspaceWallpaper` sets a background image for normal workspace tiles. +- `emptyWorkspaceWallpaperOverlayOpacity` controls the tint applied over wallpaper-backed tiles. For full JSON examples of both runtime files, see [`EXAMPLE.md`](EXAMPLE.md). diff --git a/common/Config.qml b/common/Config.qml index 8f934b9..540ce03 100644 --- a/common/Config.qml +++ b/common/Config.qml @@ -99,6 +99,7 @@ Singleton { property string previewMode: root.optionValue(["overview", "previewMode"], "live") property bool includeInactiveMonitorPreviews: root.optionValue(["overview", "includeInactiveMonitorPreviews"], true) property int previewRecaptureDelayMs: root.optionValue(["overview", "previewRecaptureDelayMs"], 60) + property string emptyWorkspaceWallpaper: root.optionValue(["overview", "emptyWorkspaceWallpaper"], "") property real workspaceSpacing: root.optionValue(["overview", "workspaceSpacing"], 5) property real backgroundPadding: root.optionValue(["overview", "backgroundPadding"], 10) property real workspaceNumberBaseSize: root.optionValue(["overview", "workspaceNumberBaseSize"], 250) @@ -107,6 +108,7 @@ Singleton { property real backdropOpacity: root.optionValue(["overview", "effects", "backdropOpacity"], 0.28) property real panelOpacity: root.optionValue(["overview", "effects", "panelOpacity"], 0.92) property real workspaceOpacity: root.optionValue(["overview", "effects", "workspaceOpacity"], 0.86) + property real emptyWorkspaceWallpaperOverlayOpacity: root.optionValue(["overview", "effects", "emptyWorkspaceWallpaperOverlayOpacity"], 0.18) property real windowOverlayOpacity: root.optionValue(["overview", "effects", "windowOverlayOpacity"], 0.22) } } diff --git a/modules/overview/OverviewWidget.qml b/modules/overview/OverviewWidget.qml index c9d4d3d..a8c6c07 100644 --- a/modules/overview/OverviewWidget.qml +++ b/modules/overview/OverviewWidget.qml @@ -37,12 +37,15 @@ Item { property int windowZ: 1 property int windowDraggingZ: 99999 property real workspaceSpacing: Config.options.overview.workspaceSpacing + property string emptyWorkspaceWallpaperPath: Config.options.overview.emptyWorkspaceWallpaper property real panelOpacity: Math.max(0, Math.min(1, Config.options.overview.effects.panelOpacity)) property real workspaceOpacity: Math.max(0, Math.min(1, Config.options.overview.effects.workspaceOpacity)) + property real emptyWorkspaceWallpaperOverlayOpacity: Math.max(0, Math.min(1, Config.options.overview.effects.emptyWorkspaceWallpaperOverlayOpacity)) property int draggingFromWorkspace: -1 property int draggingTargetWorkspace: -1 property bool hideEmptyRows: Config.options.overview.hideEmptyRows + readonly property bool hasEmptyWorkspaceWallpaper: `${emptyWorkspaceWallpaperPath ?? ""}`.trim().length > 0 function getWorkspaceRow(workspaceId) { if (!Number.isFinite(workspaceId)) @@ -68,6 +71,17 @@ Item { return workspaceGroup * workspacesShown + mappedRow * Config.options.overview.columns + mappedCol + 1 + workspaceOffset; } + function wallpaperSource(path) { + const trimmed = `${path ?? ""}`.trim(); + if (trimmed.length === 0) + return ""; + if (trimmed.startsWith("file:/") || trimmed.startsWith("qrc:/") || trimmed.startsWith("image://") || trimmed.startsWith("http://") || trimmed.startsWith("https://")) + return trimmed; + if (trimmed.startsWith("/")) + return `file://${trimmed}`; + return trimmed; + } + property var rowsWithContent: { if (!root.hideEmptyRows) return null; @@ -114,7 +128,7 @@ Item { StyledRectangularShadow { target: overviewBackground } - Rectangle { // Background + Rectangle { id: overviewBackground property real padding: Config.options.overview.backgroundPadding anchors.fill: parent @@ -128,7 +142,7 @@ Item { border.width: 1 border.color: ColorUtils.applyAlpha(Appearance.colors.colLayer0Border, root.panelOpacity) - ColumnLayout { // Workspaces + ColumnLayout { id: workspaceColumnLayout z: root.workspaceZ @@ -145,10 +159,11 @@ Item { Repeater { model: Config.options.overview.columns - Rectangle { // Workspace + Rectangle { id: workspace property int colIndex: index property int workspaceValue: root.getWorkspaceInCell(rowIndex, colIndex) + property bool showWallpaper: root.hasEmptyWorkspaceWallpaper property color defaultWorkspaceColor: Appearance.colors.colLayer1 property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1) property color hoveredBorderColor: Appearance.colors.colLayer2Hover @@ -156,13 +171,36 @@ Item { implicitWidth: root.workspaceImplicitWidth implicitHeight: root.workspaceImplicitHeight - color: ColorUtils.applyAlpha(hoveredWhileDragging ? hoveredWorkspaceColor : defaultWorkspaceColor, root.workspaceOpacity) + clip: showWallpaper + color: showWallpaper ? "transparent" : ColorUtils.applyAlpha(hoveredWhileDragging ? hoveredWorkspaceColor : defaultWorkspaceColor, root.workspaceOpacity) radius: 0 border.width: 2 border.color: hoveredWhileDragging ? hoveredBorderColor : "transparent" + Image { + visible: workspace.showWallpaper + anchors.fill: parent + source: root.wallpaperSource(root.emptyWorkspaceWallpaperPath) + fillMode: Image.PreserveAspectCrop + asynchronous: true + cache: true + smooth: true + mipmap: true + } + + Rectangle { + visible: workspace.showWallpaper + anchors.fill: parent + radius: parent.radius + color: ColorUtils.applyAlpha( + workspace.hoveredWhileDragging ? workspace.hoveredWorkspaceColor : workspace.defaultWorkspaceColor, + workspace.hoveredWhileDragging ? Math.min(0.28, root.emptyWorkspaceWallpaperOverlayOpacity + 0.08) : root.emptyWorkspaceWallpaperOverlayOpacity + ) + } + StyledText { anchors.centerIn: parent + visible: !workspace.showWallpaper text: workspaceValue font { pixelSize: root.workspaceNumberSize * root.scale @@ -206,7 +244,7 @@ Item { } } - Item { // Windows & focused workspace indicator + Item { id: windowSpace anchors.centerIn: parent implicitWidth: workspaceColumnLayout.implicitWidth @@ -330,7 +368,7 @@ Item { } } - Rectangle { // Focused workspace indicator + Rectangle { id: focusedWorkspaceIndicator property int activeWorkspaceRowIndex: root.getWorkspaceRow(root.effectiveActiveWorkspaceId) property int activeWorkspaceColIndex: root.getWorkspaceColumn(root.effectiveActiveWorkspaceId)