diff options
Diffstat (limited to 'appearance')
| -rw-r--r-- | appearance/AppearancePanel.qml | 35 | ||||
| -rw-r--r-- | appearance/Field.qml | 50 | ||||
| -rw-r--r-- | appearance/SunsetTab.qml | 169 | ||||
| -rw-r--r-- | appearance/Toggle.qml | 56 | ||||
| -rw-r--r-- | appearance/shell.qml | 3 |
5 files changed, 302 insertions, 11 deletions
diff --git a/appearance/AppearancePanel.qml b/appearance/AppearancePanel.qml index 708682c..a4c12b6 100644 --- a/appearance/AppearancePanel.qml +++ b/appearance/AppearancePanel.qml @@ -21,6 +21,12 @@ Scope { property string tab: "wallpaper" property string notice: "" + readonly property var tabs: ["wallpaper", "theme", "sunset", "idle", "icons"] + readonly property var tabLabels: ({ + wallpaper: "Wallpaper", theme: "Theme", sunset: "Sunset", + idle: "Idle", icons: "Icons", + }) + // What the mock screens show. Hovering a thumbnail previews it on the // targeted screen; the other keeps whatever is currently set. property string hovering: "" @@ -35,6 +41,7 @@ Scope { // started, which for an autostarted one is the whole session. Udt.refresh(); Wallpapers.refresh(); + Hyprsunset.refresh(); root.open = true; } function close() { root.open = false; } @@ -99,7 +106,8 @@ Scope { Keys.onEscapePressed: root.close() Keys.onPressed: event => { if (event.key === Qt.Key_Tab) { - root.tab = root.tab === "theme" ? "wallpaper" : "theme"; + const i = root.tabs.indexOf(root.tab); + root.tab = root.tabs[(i + 1) % root.tabs.length]; event.accepted = true; } } @@ -123,15 +131,14 @@ Scope { Row { spacing: 8 - Tab { - text: "Wallpaper" - selected: root.tab === "wallpaper" - onClicked: root.tab = "wallpaper" - } - Tab { - text: "Theme" - selected: root.tab === "theme" - onClicked: root.tab = "theme" + Repeater { + model: root.tabs + Tab { + required property var modelData + text: root.tabLabels[modelData] + selected: root.tab === modelData + onClicked: root.tab = modelData + } } Item { width: 12; height: 1 } Text { @@ -154,7 +161,13 @@ Scope { Loader { width: parent.width height: parent.height - y - sourceComponent: root.tab === "theme" ? themeTab : wallpaperTab + // Existing tabs are inline Components; the new ones are + // files. sourceComponent wins when it is non-null. + sourceComponent: root.tab === "theme" ? themeTab + : root.tab === "wallpaper" ? wallpaperTab : null + source: root.tab === "sunset" ? Qt.resolvedUrl("SunsetTab.qml") + : root.tab === "idle" ? Qt.resolvedUrl("IdleTab.qml") + : root.tab === "icons" ? Qt.resolvedUrl("IconsTab.qml") : "" } } } diff --git a/appearance/Field.qml b/appearance/Field.qml new file mode 100644 index 0000000..004bda6 --- /dev/null +++ b/appearance/Field.qml @@ -0,0 +1,50 @@ +// 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 QtQuick + +Rectangle { + id: field + property alias value: input.text + property string placeholder: "" + signal edited + + implicitWidth: 70 + height: 24 + radius: 5 + color: Qt.alpha(Theme.surface, 0.5) + border.width: 1 + border.color: input.activeFocus ? Qt.alpha(Theme.accent, 0.6) : Qt.alpha(Theme.text, 0.12) + + Text { + anchors.fill: parent + anchors.leftMargin: 6 + anchors.rightMargin: 6 + verticalAlignment: Text.AlignVCenter + visible: input.text === "" + text: field.placeholder + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + color: Theme.overlay + } + + TextInput { + id: input + anchors.fill: parent + anchors.leftMargin: 6 + anchors.rightMargin: 6 + verticalAlignment: TextInput.AlignVCenter + clip: true + selectByMouse: true + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + color: Theme.text + onEditingFinished: field.edited() + } +} diff --git a/appearance/SunsetTab.qml b/appearance/SunsetTab.qml new file mode 100644 index 0000000..50f6ad6 --- /dev/null +++ b/appearance/SunsetTab.qml @@ -0,0 +1,169 @@ +// 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 QtQuick + +Flickable { + contentHeight: col.implicitHeight + clip: true + + Column { + id: col + width: parent.width + spacing: 12 + + Row { + spacing: 8 + Text { + anchors.verticalCenter: parent.verticalCenter + text: "Lat" + color: Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + } + Field { width: 90; value: Hyprsunset.lat; onEdited: Hyprsunset.lat = value; placeholder: "lat" } + Text { + anchors.verticalCenter: parent.verticalCenter + text: "Lon" + color: Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + } + Field { width: 90; value: Hyprsunset.lon; onEdited: Hyprsunset.lon = value; placeholder: "lon" } + Toggle { + anchors.verticalCenter: parent.verticalCenter + checked: Hyprsunset.autoDetect + label: "auto" + onToggled: Hyprsunset.autoDetect = checked + } + Tab { text: "Detect"; onClicked: Hyprsunset.detect() } + Tab { text: Hyprsunset.busy ? "fetching…" : "Fetch sun times"; onClicked: Hyprsunset.fetchSun() } + Text { + anchors.verticalCenter: parent.verticalCenter + text: Hyprsunset.sunSummary + color: Theme.overlay + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } + } + + Repeater { + model: Hyprsunset.profiles + Rectangle { + required property var modelData + required property int index + width: col.width + implicitHeight: 40 + radius: 8 + color: Qt.alpha(Theme.surface, 0.35) + + Row { + anchors.fill: parent + anchors.margins: 8 + spacing: 8 + + Text { + anchors.verticalCenter: parent.verticalCenter + text: index === Hyprsunset.dayIndex(Hyprsunset.profiles) ? "day" + : index === Hyprsunset.nightIndex(Hyprsunset.profiles) ? "night" : "profile" + color: Theme.subtext + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + } + Field { + anchors.verticalCenter: parent.verticalCenter + width: 60 + value: modelData.time + placeholder: "HH:MM" + onEdited: Hyprsunset.profiles = Hyprsunset.profiles.map( + (p, i) => i === index ? Object.assign({}, p, { time: value }) : p) + } + Toggle { + anchors.verticalCenter: parent.verticalCenter + checked: modelData.identity + label: "identity" + onToggled: Hyprsunset.profiles = Hyprsunset.profiles.map( + (p, i) => i === index ? Object.assign({}, p, { identity: checked }) : p) + } + Toggle { + anchors.verticalCenter: parent.verticalCenter + checked: modelData.temperature !== null && modelData.temperature !== undefined + label: "temp" + onToggled: Hyprsunset.profiles = Hyprsunset.profiles.map( + (p, i) => i === index ? Object.assign({}, p, + { temperature: checked ? (p.temperature ?? 5500) : null }) : p) + } + Field { + anchors.verticalCenter: parent.verticalCenter + width: 70 + value: modelData.temperature === null || modelData.temperature === undefined + ? "" : String(modelData.temperature) + placeholder: "5500" + onEdited: Hyprsunset.profiles = Hyprsunset.profiles.map( + (p, i) => i === index ? Object.assign({}, p, + { temperature: value === "" ? null : parseInt(value, 10) }) : p) + } + Toggle { + anchors.verticalCenter: parent.verticalCenter + checked: modelData.gamma !== null && modelData.gamma !== undefined + label: "gamma" + onToggled: Hyprsunset.profiles = Hyprsunset.profiles.map( + (p, i) => i === index ? Object.assign({}, p, + { gamma: checked ? (p.gamma ?? 1.0) : null }) : p) + } + Field { + anchors.verticalCenter: parent.verticalCenter + width: 60 + value: modelData.gamma === null || modelData.gamma === undefined + ? "" : String(modelData.gamma) + placeholder: "0.8" + onEdited: Hyprsunset.profiles = Hyprsunset.profiles.map( + (p, i) => i === index ? Object.assign({}, p, + { gamma: value === "" ? null : parseFloat(value) }) : p) + } + Item { width: 8; height: 1 } + Tab { + anchors.verticalCenter: parent.verticalCenter + text: "✕" + onClicked: Hyprsunset.profiles = + Hyprsunset.profiles.filter((p, i) => i !== index) + } + // The Row is pinned to the card width, so parent.width is + // real, but bound it anyway: a narrow enough panel would + // make the subtraction negative and put the Row in a + // negative-width state. + Item { width: Math.max(0, parent.width - 640); height: 1 } + } + } + } + + Row { + spacing: 8 + Tab { + text: "+ Add profile" + onClicked: Hyprsunset.profiles = + Hyprsunset.profiles.concat([{ time: "0:00", identity: false, + temperature: null, gamma: null }]) + } + Tab { text: "Live preview"; onClicked: Hyprsunset.preview() } + Tab { + text: "Save + Restart" + selected: true + onClicked: Hyprsunset.save() + } + } + + Text { + width: parent.width + wrapMode: Text.Wrap + visible: Hyprsunset.notice !== "" + text: Hyprsunset.notice + color: Hyprsunset.notice.indexOf("invalid") === 0 ? Theme.red : Theme.green + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + } + } +} diff --git a/appearance/Toggle.qml b/appearance/Toggle.qml new file mode 100644 index 0000000..2bb56a2 --- /dev/null +++ b/appearance/Toggle.qml @@ -0,0 +1,56 @@ +// 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 QtQuick + +Rectangle { + id: toggle + property bool checked: false + property string label: "" + signal toggled + + implicitWidth: row.implicitWidth + implicitHeight: 22 + color: "transparent" + + Row { + id: row + anchors.verticalCenter: parent.verticalCenter + spacing: 6 + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 16; height: 16; radius: 4 + color: toggle.checked ? Qt.alpha(Theme.accent, 0.7) : Qt.alpha(Theme.surface, 0.5) + border.width: 1 + border.color: toggle.checked ? Qt.alpha(Theme.accent, 0.9) : Qt.alpha(Theme.text, 0.2) + Text { + anchors.centerIn: parent + visible: toggle.checked + text: "✓" + font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 6; bold: true } + color: Theme.base + } + } + Text { + anchors.verticalCenter: parent.verticalCenter + visible: toggle.label !== "" + text: toggle.label + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + color: Theme.subtext + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { toggle.checked = !toggle.checked; toggle.toggled(); } + } +} diff --git a/appearance/shell.qml b/appearance/shell.qml index c0356a8..ea87fc3 100644 --- a/appearance/shell.qml +++ b/appearance/shell.qml @@ -20,6 +20,9 @@ ShellRoot { function toggle() { panel.toggle(""); } function wallpaper() { panel.toggle("wallpaper"); } function theme() { panel.toggle("theme"); } + function sunset() { panel.toggle("sunset"); } + function idle() { panel.toggle("idle"); } + function icons() { panel.toggle("icons"); } function selftest(): string { return Hyprsunset.selftest() + "\n" + Hypridle.selftest() + "\n" + Icons.selftest(); } |
