aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/appearance/StepsWindow.qml
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-17 10:16:40 +0200
committerDanilo M. <danix@danix.xyz>2026-10-17 10:16:40 +0200
commit70bbc970c75221c902c515efd124c47fd702e3b7 (patch)
treed35f6b1ffbb506b65430af7fc1eca2c432879a22 /desktop/modules/appearance/StepsWindow.qml
parente5399f3e8d8572f1db7c4391a7c571d4845500f1 (diff)
downloadquickshell-70bbc970c75221c902c515efd124c47fd702e3b7.tar.gz
quickshell-70bbc970c75221c902c515efd124c47fd702e3b7.zip
appearance moves into the settings window
The appearance shell existed because a wallpaper picker needed more room than the 600px drawer, so it ran as its own process with a full-screen overlay. The settings window now gives it that room, and its five tabs become five settings pages in the desktop process: Wallpaper, Theme, Icons & cursor, Sunset and Idle. appearance/ is gone, and with it a process, a keepalive window and a layer blur rule. The files move to desktop/modules/appearance/ unchanged in what they do. Each tab gets a small *Module.qml; the window's refresh-on-open calls the singletons' refresh(), which the panel's show() used to. The two tabs that were inline Components in AppearancePanel become ThemeTab and WallpaperTab, owning the notices the panel printed. Sunset, Idle and Icons drop their own Flickable so the page scrolls them and search can reveal a row; the wallpaper list virtualises its rows and scrolls itself, so it takes the page's new viewHeight instead. Search finds a colour scheme and an icon or cursor theme by name. The appearance IPC target moves to desktop/shell.qml with the same verbs, so udt-steps and any keybind change only the path. Git now follows the appearance pages and autostart in the sidebar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules/appearance/StepsWindow.qml')
-rw-r--r--desktop/modules/appearance/StepsWindow.qml198
1 files changed, 198 insertions, 0 deletions
diff --git a/desktop/modules/appearance/StepsWindow.qml b/desktop/modules/appearance/StepsWindow.qml
new file mode 100644
index 0000000..7349fcd
--- /dev/null
+++ b/desktop/modules/appearance/StepsWindow.qml
@@ -0,0 +1,198 @@
+// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+import Quickshell
+import Quickshell.Wayland
+import QtQuick
+import "../.."
+
+// One tab per consumer with manual steps pending. Centred on the vertical
+// screen and kept open on purpose: the commands are pasted into a root shell
+// elsewhere, so the window takes keyboard focus only when clicked and stays
+// until closed. Done deletes a tab's file; the producer also clears it once
+// the consumer is up to date.
+Scope {
+ id: root
+
+ property string monitor: "DP-3"
+ property bool open: false
+ property string tab: ""
+
+ readonly property var screenObj:
+ Quickshell.screens.find(s => s.name === root.monitor) ?? Quickshell.screens[0]
+ readonly property var current: Steps.tabs.find(t => t.name === root.tab) ?? Steps.tabs[0] ?? null
+
+ // A poke from udt-steps: reload, and open when something is pending.
+ // Also what a keybind calls to bring the window back after closing it.
+ function poke() {
+ root.opening = true;
+ Steps.refresh();
+ }
+ property bool opening: false
+
+ Connections {
+ target: Steps
+ function onLoaded() {
+ if (Steps.tabs.length === 0) root.open = false;
+ else if (root.opening) root.open = true;
+ root.opening = false;
+ }
+ }
+
+ LazyLoader {
+ active: root.open
+
+ PanelWindow {
+ id: win
+ screen: root.screenObj
+ // No anchors: a layer surface anchored nowhere is centred.
+ implicitWidth: 960
+ implicitHeight: body.implicitHeight + 40
+ color: "transparent"
+ exclusionMode: ExclusionMode.Ignore
+ WlrLayershell.layer: WlrLayer.Top
+ WlrLayershell.namespace: "quickshell-steps"
+ WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
+
+ Rectangle {
+ anchors.fill: parent
+ radius: 14
+ color: Qt.alpha(Theme.base, 0.92)
+ border.width: 1
+ border.color: Qt.alpha(Theme.text, 0.12)
+
+ Item {
+ anchors.fill: parent
+ focus: true
+ Keys.onEscapePressed: root.open = false
+ }
+
+ Column {
+ id: body
+ anchors { top: parent.top; left: parent.left; right: parent.right; margins: 20 }
+ spacing: 16
+
+ Item {
+ width: parent.width
+ height: tabBar.implicitHeight
+
+ Row {
+ id: tabBar
+ spacing: 8
+ Repeater {
+ model: Steps.tabs
+ Tab {
+ required property var modelData
+ text: modelData.label
+ selected: root.current !== null && root.current.name === modelData.name
+ onClicked: root.tab = modelData.name
+ }
+ }
+ }
+
+ Tab {
+ anchors.right: parent.right
+ text: "Close"
+ onClicked: root.open = false
+ }
+ }
+
+ Flickable {
+ width: parent.width
+ // Sized from the screen, never from the window: the
+ // window's height comes from this, and a binding back
+ // to it collapsed the whole thing to its margins.
+ height: Math.min(content.implicitHeight,
+ win.screen.height - 240 - tabBar.implicitHeight - actions.implicitHeight - 32)
+ contentHeight: content.implicitHeight
+ clip: true
+
+ Column {
+ id: content
+ width: parent.width
+ spacing: 12
+
+ Repeater {
+ model: root.current ? root.current.blocks : []
+
+ Loader {
+ required property var modelData
+ width: content.width
+ sourceComponent: modelData.cmd ? cmdBlock : prose
+ property var block: modelData
+ }
+ }
+ }
+ }
+
+ Row {
+ id: actions
+ spacing: 8
+ anchors.right: parent.right
+ Tab {
+ text: "Copy all commands"
+ enabled: root.current !== null && Steps.commands(root.current) !== ""
+ onClicked: Steps.copy(Steps.commands(root.current))
+ }
+ Tab {
+ text: "Done"
+ enabled: root.current !== null
+ onClicked: Steps.dismiss(root.current.name)
+ }
+ }
+ }
+ }
+
+ Component {
+ id: prose
+ Text {
+ text: block.text
+ wrapMode: Text.Wrap
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1 }
+ color: Theme.text
+ }
+ }
+
+ Component {
+ id: cmdBlock
+ Rectangle {
+ implicitHeight: Math.max(code.implicitHeight, copyBtn.implicitHeight) + 24
+ radius: 8
+ color: Qt.alpha(Theme.crust, 0.8)
+ border.width: 1
+ border.color: Qt.alpha(Theme.accent, 0.3)
+
+ // Selectable as well as copyable: sometimes one line of a
+ // block is what is wanted.
+ TextEdit {
+ id: code
+ anchors { left: parent.left; right: copyBtn.left; verticalCenter: parent.verticalCenter; margins: 12 }
+ text: block.text
+ readOnly: true
+ selectByMouse: true
+ wrapMode: TextEdit.WrapAnywhere
+ font { family: "Inconsolata Nerd Font Mono"; pixelSize: Theme.fontSize - 1 }
+ color: Theme.text
+ selectionColor: Qt.alpha(Theme.accent, 0.4)
+ selectedTextColor: Theme.text
+ }
+
+ Tab {
+ id: copyBtn
+ anchors { right: parent.right; rightMargin: 8; verticalCenter: parent.verticalCenter }
+ text: "Copy"
+ onClicked: Steps.copy(block.text)
+ }
+ }
+ }
+ }
+ }
+}