From b2e092d0be17a3c3f92a2652544db369c6effdb5 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 13 Aug 2026 15:41:16 +0200 Subject: [PATCH] changes to config plugin, reduce file amount + code, fix greeter --- Greeter/Center.qml | 17 +- Greeter/Components/AnimatedTabIndexPair.qml | 24 - Greeter/Components/BaseStyledSlider.qml | 166 ------ Greeter/Components/CircularIndicator.qml | 9 +- Greeter/Components/CircularProgress.qml | 128 +++-- Greeter/Components/CollapsibleSection.qml | 136 ----- Greeter/Components/ColorArcPicker.qml | 209 -------- Greeter/Components/ColoredIcon.qml | 34 -- Greeter/Components/Coloriser.qml | 14 - Greeter/Components/CustomAudioSlider.qml | 71 --- Greeter/Components/CustomBusyIndicator.qml | 69 --- Greeter/Components/CustomButton.qml | 33 -- Greeter/Components/CustomCheckbox.qml | 38 -- Greeter/Components/CustomComboBox.qml | 170 ------- Greeter/Components/CustomIcon.qml | 10 - Greeter/Components/CustomRadioButton.qml | 54 -- Greeter/Components/CustomScrollBar.qml | 190 ------- Greeter/Components/CustomShortcut.qml | 5 - Greeter/Components/CustomSlider.qml | 175 ------- Greeter/Components/CustomSpinBox.qml | 169 ------- Greeter/Components/CustomSplitButton.qml | 149 ------ Greeter/Components/CustomSplitButtonRow.qml | 70 --- Greeter/Components/CustomSwitch.qml | 158 ------ Greeter/Components/CustomTextField.qml | 2 +- Greeter/Components/CustomTextInput.qml | 6 +- Greeter/Components/CustomTooltip.qml | 25 - Greeter/Components/CustomTooltipContent.qml | 55 -- Greeter/Components/ExtraIndicator.qml | 44 -- Greeter/Components/FilledSlider.qml | 29 -- Greeter/Components/GradientSlider.qml | 47 -- Greeter/Components/HoverIconButton.qml | 33 -- Greeter/Components/IconButton.qml | 80 --- Greeter/Components/MarqueeText.qml | 224 --------- Greeter/Components/Menu.qml | 176 ------- Greeter/Components/MenuItem.qml | 12 - Greeter/Components/PathMenu.qml | 76 --- Greeter/Components/PathViewMenu.qml | 181 ------- Greeter/Components/Ref.qml | 8 - Greeter/Components/SpinBoxRow.qml | 51 -- Greeter/Components/StateLayer.qml | 1 - Greeter/Components/Toast/ToastItem.qml | 132 ----- Greeter/Components/Toast/Toasts.qml | 142 ------ Greeter/Config/AccentColor.qml | 13 - Greeter/Config/Appearance.qml | 13 - Greeter/Config/AppearanceConf.qml | 114 ----- Greeter/Config/BackgroundConfig.qml | 14 - Greeter/Config/BarConfig.qml | 77 --- Greeter/Config/Colors.qml | 13 - Greeter/Config/Config.qml | 474 ------------------ Greeter/Config/DashboardConfig.qml | 36 -- Greeter/Config/DockConfig.qml | 10 - Greeter/Config/General.qml | 63 --- Greeter/Config/IdleTimeout.qml | 15 - Greeter/Config/Launcher.qml | 109 ---- Greeter/Config/LockConf.qml | 18 - Greeter/Config/MaterialEasing.qml | 26 - Greeter/Config/NotifConfig.qml | 20 - Greeter/Config/Osd.qml | 16 - Greeter/Config/Overview.qml | 8 - Greeter/Config/Screenshot.qml | 13 - Greeter/Config/Services.qml | 22 - Greeter/Config/SidebarConfig.qml | 11 - Greeter/Config/Transparency.qml | 7 - Greeter/Config/UtilConfig.qml | 35 -- Greeter/Config/WorkspaceWidget.qml | 6 - Greeter/Helpers/Brightness.qml | 264 ---------- Greeter/Helpers/Hypr.qml | 8 - Greeter/Helpers/SystemInfo.qml | 83 --- Greeter/InputField.qml | 7 +- .../DynamicColors.qml => Services/Colors.qml} | 63 ++- Greeter/SessionDock.qml | 9 +- Greeter/UserDock.qml | 6 +- Greeter/WeatherInfo.qml | 2 +- Helpers/Players.qml | 2 +- Modules/Bar/Bar.qml | 2 +- Modules/Launcher/Services/Actions.qml | 2 +- Modules/Lock/Fetch.qml | 162 ------ Modules/Settings/Common/ListEditor.qml | 5 +- .../Pages/Panels/Bar/BarStatusIcons.qml | 37 +- Modules/SysTray/StatusIcons.qml | 2 +- Plugins/ZShell/Config/Appearance.cpp | 40 -- Plugins/ZShell/Config/Appearance.hpp | 78 --- Plugins/ZShell/Config/Background.cpp | 7 - Plugins/ZShell/Config/Background.hpp | 14 - Plugins/ZShell/Config/Bar.cpp | 63 --- Plugins/ZShell/Config/Bar.hpp | 52 -- Plugins/ZShell/Config/CMakeLists.txt | 41 +- Plugins/ZShell/Config/Clipboard.cpp | 16 - Plugins/ZShell/Config/Clipboard.hpp | 28 -- Plugins/ZShell/Config/Colors.cpp | 14 - Plugins/ZShell/Config/Colors.hpp | 26 - Plugins/ZShell/Config/Config.hpp | 86 ---- Plugins/ZShell/Config/ConfigSection.cpp | 87 ---- Plugins/ZShell/Config/ConfigSection.hpp | 82 --- Plugins/ZShell/Config/Dashboard.cpp | 39 -- Plugins/ZShell/Config/Dashboard.hpp | 56 --- Plugins/ZShell/Config/Dock.cpp | 15 - Plugins/ZShell/Config/Dock.hpp | 19 - Plugins/ZShell/Config/General.cpp | 77 --- Plugins/ZShell/Config/General.hpp | 82 --- Plugins/ZShell/Config/Launcher.cpp | 71 --- Plugins/ZShell/Config/Launcher.hpp | 55 -- Plugins/ZShell/Config/Lock.cpp | 19 - Plugins/ZShell/Config/Lock.hpp | 31 -- Plugins/ZShell/Config/Notifs.cpp | 22 - Plugins/ZShell/Config/Notifs.hpp | 34 -- Plugins/ZShell/Config/Osd.cpp | 17 - Plugins/ZShell/Config/Osd.hpp | 29 -- Plugins/ZShell/Config/Overview.cpp | 9 - Plugins/ZShell/Config/Overview.hpp | 16 - Plugins/ZShell/Config/Screenshot.cpp | 15 - Plugins/ZShell/Config/Screenshot.hpp | 26 - Plugins/ZShell/Config/Services.cpp | 23 - Plugins/ZShell/Config/Services.hpp | 27 - Plugins/ZShell/Config/Sidebar.cpp | 13 - Plugins/ZShell/Config/Sidebar.hpp | 25 - Plugins/ZShell/Config/Tokens.cpp | 109 ---- Plugins/ZShell/Config/Tokens.hpp | 348 ------------- Plugins/ZShell/Config/Utilities.cpp | 38 -- Plugins/ZShell/Config/Utilities.hpp | 61 --- Plugins/ZShell/Config/appearance.hpp | 83 +++ Plugins/ZShell/Config/background.hpp | 18 + Plugins/ZShell/Config/bar.hpp | 94 ++++ Plugins/ZShell/Config/clipboard.hpp | 33 ++ Plugins/ZShell/Config/colors.hpp | 31 ++ .../ZShell/Config/{Config.cpp => config.cpp} | 101 ++-- Plugins/ZShell/Config/config.hpp | 95 ++++ Plugins/ZShell/Config/configlist.cpp | 305 +++++++++++ Plugins/ZShell/Config/configlist.hpp | 141 ++++++ Plugins/ZShell/Config/confignode.cpp | 89 ++++ Plugins/ZShell/Config/confignode.hpp | 63 +++ Plugins/ZShell/Config/configobject.cpp | 270 ++++++++++ Plugins/ZShell/Config/configobject.hpp | 100 ++++ Plugins/ZShell/Config/dashboard.hpp | 63 +++ Plugins/ZShell/Config/dock.hpp | 29 ++ Plugins/ZShell/Config/general.hpp | 158 ++++++ Plugins/ZShell/Config/launcher.hpp | 177 +++++++ Plugins/ZShell/Config/lock.hpp | 36 ++ Plugins/ZShell/Config/notifs.hpp | 39 ++ Plugins/ZShell/Config/osd.hpp | 34 ++ Plugins/ZShell/Config/screenshot.hpp | 27 + Plugins/ZShell/Config/services.hpp | 54 ++ Plugins/ZShell/Config/sidebar.hpp | 30 ++ Plugins/ZShell/Config/tokens.hpp | 221 ++++++++ Plugins/ZShell/Config/utilities.hpp | 70 +++ 145 files changed, 2531 insertions(+), 6949 deletions(-) delete mode 100644 Greeter/Components/AnimatedTabIndexPair.qml delete mode 100644 Greeter/Components/BaseStyledSlider.qml delete mode 100644 Greeter/Components/CollapsibleSection.qml delete mode 100644 Greeter/Components/ColorArcPicker.qml delete mode 100644 Greeter/Components/ColoredIcon.qml delete mode 100644 Greeter/Components/Coloriser.qml delete mode 100644 Greeter/Components/CustomAudioSlider.qml delete mode 100644 Greeter/Components/CustomBusyIndicator.qml delete mode 100644 Greeter/Components/CustomButton.qml delete mode 100644 Greeter/Components/CustomCheckbox.qml delete mode 100644 Greeter/Components/CustomComboBox.qml delete mode 100644 Greeter/Components/CustomIcon.qml delete mode 100644 Greeter/Components/CustomRadioButton.qml delete mode 100644 Greeter/Components/CustomScrollBar.qml delete mode 100644 Greeter/Components/CustomShortcut.qml delete mode 100644 Greeter/Components/CustomSlider.qml delete mode 100644 Greeter/Components/CustomSpinBox.qml delete mode 100644 Greeter/Components/CustomSplitButton.qml delete mode 100644 Greeter/Components/CustomSplitButtonRow.qml delete mode 100644 Greeter/Components/CustomSwitch.qml delete mode 100644 Greeter/Components/CustomTooltip.qml delete mode 100644 Greeter/Components/CustomTooltipContent.qml delete mode 100644 Greeter/Components/ExtraIndicator.qml delete mode 100644 Greeter/Components/FilledSlider.qml delete mode 100644 Greeter/Components/GradientSlider.qml delete mode 100644 Greeter/Components/HoverIconButton.qml delete mode 100644 Greeter/Components/IconButton.qml delete mode 100644 Greeter/Components/MarqueeText.qml delete mode 100644 Greeter/Components/Menu.qml delete mode 100644 Greeter/Components/MenuItem.qml delete mode 100644 Greeter/Components/PathMenu.qml delete mode 100644 Greeter/Components/PathViewMenu.qml delete mode 100644 Greeter/Components/Ref.qml delete mode 100644 Greeter/Components/SpinBoxRow.qml delete mode 100644 Greeter/Components/Toast/ToastItem.qml delete mode 100644 Greeter/Components/Toast/Toasts.qml delete mode 100644 Greeter/Config/AccentColor.qml delete mode 100644 Greeter/Config/Appearance.qml delete mode 100644 Greeter/Config/AppearanceConf.qml delete mode 100644 Greeter/Config/BackgroundConfig.qml delete mode 100644 Greeter/Config/BarConfig.qml delete mode 100644 Greeter/Config/Colors.qml delete mode 100644 Greeter/Config/Config.qml delete mode 100644 Greeter/Config/DashboardConfig.qml delete mode 100644 Greeter/Config/DockConfig.qml delete mode 100644 Greeter/Config/General.qml delete mode 100644 Greeter/Config/IdleTimeout.qml delete mode 100644 Greeter/Config/Launcher.qml delete mode 100644 Greeter/Config/LockConf.qml delete mode 100644 Greeter/Config/MaterialEasing.qml delete mode 100644 Greeter/Config/NotifConfig.qml delete mode 100644 Greeter/Config/Osd.qml delete mode 100644 Greeter/Config/Overview.qml delete mode 100644 Greeter/Config/Screenshot.qml delete mode 100644 Greeter/Config/Services.qml delete mode 100644 Greeter/Config/SidebarConfig.qml delete mode 100644 Greeter/Config/Transparency.qml delete mode 100644 Greeter/Config/UtilConfig.qml delete mode 100644 Greeter/Config/WorkspaceWidget.qml delete mode 100644 Greeter/Helpers/Brightness.qml delete mode 100644 Greeter/Helpers/SystemInfo.qml rename Greeter/{Config/DynamicColors.qml => Services/Colors.qml} (89%) delete mode 100644 Modules/Lock/Fetch.qml delete mode 100644 Plugins/ZShell/Config/Appearance.cpp delete mode 100644 Plugins/ZShell/Config/Appearance.hpp delete mode 100644 Plugins/ZShell/Config/Background.cpp delete mode 100644 Plugins/ZShell/Config/Background.hpp delete mode 100644 Plugins/ZShell/Config/Bar.cpp delete mode 100644 Plugins/ZShell/Config/Bar.hpp delete mode 100644 Plugins/ZShell/Config/Clipboard.cpp delete mode 100644 Plugins/ZShell/Config/Clipboard.hpp delete mode 100644 Plugins/ZShell/Config/Colors.cpp delete mode 100644 Plugins/ZShell/Config/Colors.hpp delete mode 100644 Plugins/ZShell/Config/Config.hpp delete mode 100644 Plugins/ZShell/Config/ConfigSection.cpp delete mode 100644 Plugins/ZShell/Config/ConfigSection.hpp delete mode 100644 Plugins/ZShell/Config/Dashboard.cpp delete mode 100644 Plugins/ZShell/Config/Dashboard.hpp delete mode 100644 Plugins/ZShell/Config/Dock.cpp delete mode 100644 Plugins/ZShell/Config/Dock.hpp delete mode 100644 Plugins/ZShell/Config/General.cpp delete mode 100644 Plugins/ZShell/Config/General.hpp delete mode 100644 Plugins/ZShell/Config/Launcher.cpp delete mode 100644 Plugins/ZShell/Config/Launcher.hpp delete mode 100644 Plugins/ZShell/Config/Lock.cpp delete mode 100644 Plugins/ZShell/Config/Lock.hpp delete mode 100644 Plugins/ZShell/Config/Notifs.cpp delete mode 100644 Plugins/ZShell/Config/Notifs.hpp delete mode 100644 Plugins/ZShell/Config/Osd.cpp delete mode 100644 Plugins/ZShell/Config/Osd.hpp delete mode 100644 Plugins/ZShell/Config/Overview.cpp delete mode 100644 Plugins/ZShell/Config/Overview.hpp delete mode 100644 Plugins/ZShell/Config/Screenshot.cpp delete mode 100644 Plugins/ZShell/Config/Screenshot.hpp delete mode 100644 Plugins/ZShell/Config/Services.cpp delete mode 100644 Plugins/ZShell/Config/Services.hpp delete mode 100644 Plugins/ZShell/Config/Sidebar.cpp delete mode 100644 Plugins/ZShell/Config/Sidebar.hpp delete mode 100644 Plugins/ZShell/Config/Tokens.cpp delete mode 100644 Plugins/ZShell/Config/Tokens.hpp delete mode 100644 Plugins/ZShell/Config/Utilities.cpp delete mode 100644 Plugins/ZShell/Config/Utilities.hpp create mode 100644 Plugins/ZShell/Config/appearance.hpp create mode 100644 Plugins/ZShell/Config/background.hpp create mode 100644 Plugins/ZShell/Config/bar.hpp create mode 100644 Plugins/ZShell/Config/clipboard.hpp create mode 100644 Plugins/ZShell/Config/colors.hpp rename Plugins/ZShell/Config/{Config.cpp => config.cpp} (52%) create mode 100644 Plugins/ZShell/Config/config.hpp create mode 100644 Plugins/ZShell/Config/configlist.cpp create mode 100644 Plugins/ZShell/Config/configlist.hpp create mode 100644 Plugins/ZShell/Config/confignode.cpp create mode 100644 Plugins/ZShell/Config/confignode.hpp create mode 100644 Plugins/ZShell/Config/configobject.cpp create mode 100644 Plugins/ZShell/Config/configobject.hpp create mode 100644 Plugins/ZShell/Config/dashboard.hpp create mode 100644 Plugins/ZShell/Config/dock.hpp create mode 100644 Plugins/ZShell/Config/general.hpp create mode 100644 Plugins/ZShell/Config/launcher.hpp create mode 100644 Plugins/ZShell/Config/lock.hpp create mode 100644 Plugins/ZShell/Config/notifs.hpp create mode 100644 Plugins/ZShell/Config/osd.hpp create mode 100644 Plugins/ZShell/Config/screenshot.hpp create mode 100644 Plugins/ZShell/Config/services.hpp create mode 100644 Plugins/ZShell/Config/sidebar.hpp create mode 100644 Plugins/ZShell/Config/tokens.hpp create mode 100644 Plugins/ZShell/Config/utilities.hpp diff --git a/Greeter/Center.qml b/Greeter/Center.qml index fb3aa2d..9dafdcd 100644 --- a/Greeter/Center.qml +++ b/Greeter/Center.qml @@ -2,10 +2,9 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts -import qs.Paths +import ZShell.Config import qs.Components import qs.Helpers -import ZShell.Config import qs.Services ColumnLayout { @@ -29,7 +28,7 @@ ColumnLayout { Layout.alignment: Qt.AlignVCenter color: Colors.palette.m3secondary font.bold: true - font.family: Appearance.font.family.clock + font.family: Config.appearance.font.family.clock font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) text: Time.hourStr } @@ -38,7 +37,7 @@ ColumnLayout { Layout.alignment: Qt.AlignVCenter color: Colors.palette.m3primary font.bold: true - font.family: Appearance.font.family.clock + font.family: Config.appearance.font.family.clock font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) text: ":" } @@ -47,7 +46,7 @@ ColumnLayout { Layout.alignment: Qt.AlignVCenter color: Colors.palette.m3secondary font.bold: true - font.family: Appearance.font.family.clock + font.family: Config.appearance.font.family.clock font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) text: Time.minuteStr } @@ -58,7 +57,7 @@ ColumnLayout { Layout.topMargin: -Tokens.padding.large * 2 color: Colors.palette.m3tertiary font.bold: true - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale) text: Time.format("dddd, d MMMM yyyy") } @@ -89,7 +88,7 @@ ColumnLayout { CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3onSurfaceVariant - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.normal font.weight: 600 text: root.greeter.username @@ -238,7 +237,7 @@ ColumnLayout { anchors.right: parent.right animateProp: "opacity" color: Colors.palette.m3onSurfaceVariant - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono horizontalAlignment: Qt.AlignHCenter lineHeight: 1.2 opacity: shouldBeVisible && !message.msg ? 1 : 0 @@ -293,7 +292,7 @@ ColumnLayout { anchors.left: parent.left anchors.right: parent.right color: isError ? Colors.palette.m3error : Colors.palette.m3primary - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.small horizontalAlignment: Qt.AlignHCenter opacity: 0 diff --git a/Greeter/Components/AnimatedTabIndexPair.qml b/Greeter/Components/AnimatedTabIndexPair.qml deleted file mode 100644 index d8fb656..0000000 --- a/Greeter/Components/AnimatedTabIndexPair.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick - -QtObject { - id: root - - property real idx1: index - property int idx1Duration: 100 - property real idx2: index - property int idx2Duration: 300 - required property int index - - Behavior on idx1 { - NumberAnimation { - duration: root.idx1Duration - easing.type: Easing.OutSine - } - } - Behavior on idx2 { - NumberAnimation { - duration: root.idx2Duration - easing.type: Easing.OutSine - } - } -} diff --git a/Greeter/Components/BaseStyledSlider.qml b/Greeter/Components/BaseStyledSlider.qml deleted file mode 100644 index 22a6d3e..0000000 --- a/Greeter/Components/BaseStyledSlider.qml +++ /dev/null @@ -1,166 +0,0 @@ -import QtQuick -import QtQuick.Templates -import ZShell.Config -import qs.Services - -Slider { - id: root - - property color color: Colors.palette.m3secondary - required property string icon - property bool initialized: false - readonly property bool isHorizontal: orientation === Qt.Horizontal - readonly property bool isVertical: orientation === Qt.Vertical - property real multiplier: 100 - property real oldValue - - // Wrapper components can inject their own track visuals here. - property Component trackContent - - // Keep current behavior for existing usages. - orientation: Qt.Vertical - - background: CustomRect { - id: groove - - color: Colors.layer(Colors.palette.m3surfaceContainer, 2) - height: root.availableHeight - radius: Tokens.rounding.full - width: root.availableWidth - x: root.leftPadding - y: root.topPadding - - Loader { - id: trackLoader - - anchors.fill: parent - sourceComponent: root.trackContent - - onLoaded: { - if (!item) - return; - - item.rootSlider = root; - item.groove = groove; - item.handleItem = handle; - } - } - } - handle: Item { - id: handle - - property alias moving: icon.moving - - implicitHeight: Math.min(root.width, root.height) - implicitWidth: Math.min(root.width, root.height) - x: root.isHorizontal ? root.leftPadding + root.visualPosition * (root.availableWidth - width) : root.leftPadding + (root.availableWidth - width) / 2 - y: root.isVertical ? root.topPadding + root.visualPosition * (root.availableHeight - height) : root.topPadding + (root.availableHeight - height) / 2 - - Elevation { - anchors.fill: parent - level: handleInteraction.containsMouse ? 2 : 1 - radius: rect.radius - } - - CustomRect { - id: rect - - anchors.fill: parent - color: Colors.palette.m3inverseSurface - radius: Tokens.rounding.full - - MouseArea { - id: handleInteraction - - acceptedButtons: Qt.NoButton - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - } - - MaterialIcon { - id: icon - - property bool moving - - function update(): void { - animate = !moving; - binding.when = moving; - font.pointSize = moving ? Tokens.font.size.small : Tokens.font.size.larger; - font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; - } - - anchors.centerIn: parent - color: Colors.palette.m3inverseOnSurface - text: root.icon - - onMovingChanged: anim.restart() - - Binding { - id: binding - - property: "text" - target: icon - value: Math.round(root.value * root.multiplier) - when: false - } - - SequentialAnimation { - id: anim - - Anim { - duration: Tokens.anim.durations.normal / 2 - easing.bezierCurve: Tokens.anim.curves.standardAccel - property: "scale" - target: icon - to: 0 - } - - ScriptAction { - script: icon.update() - } - - Anim { - duration: Tokens.anim.durations.normal / 2 - easing.bezierCurve: Tokens.anim.curves.standardDecel - property: "scale" - target: icon - to: 1 - } - } - } - } - } - Behavior on value { - Anim { - duration: Tokens.anim.durations.large - } - } - - onPressedChanged: handle.moving = pressed - onValueChanged: { - if (!initialized) { - initialized = true; - oldValue = value; - return; - } - - if (Math.abs(value - oldValue) < 0.01) - return; - - oldValue = value; - handle.moving = true; - stateChangeDelay.restart(); - } - - Timer { - id: stateChangeDelay - - interval: 500 - - onTriggered: { - if (!root.pressed) - handle.moving = false; - } - } -} diff --git a/Greeter/Components/CircularIndicator.qml b/Greeter/Components/CircularIndicator.qml index b71f439..94112e9 100644 --- a/Greeter/Components/CircularIndicator.qml +++ b/Greeter/Components/CircularIndicator.qml @@ -18,8 +18,8 @@ BusyIndicator { } property int animState - property color bgColour: Colors.palette.m3secondaryContainer - property color fgColour: Colors.palette.m3primary + property color bgColor: Colors.palette.m3secondaryContainer + property color fgColor: Colors.palette.m3primary property real implicitSize: Tokens.font.size.normal * 3 property real internalStrokeWidth: strokeWidth readonly property alias progress: manager.progress @@ -32,8 +32,8 @@ BusyIndicator { contentItem: CircularProgress { anchors.fill: parent - bgColour: root.bgColour - fgColour: root.fgColour + bgColor: root.bgColor + fgColor: root.fgColor padding: root.padding rotation: manager.rotation startAngle: manager.startFraction * 360 @@ -74,7 +74,6 @@ BusyIndicator { CircularIndicatorManager { id: manager - } NumberAnimation { diff --git a/Greeter/Components/CircularProgress.qml b/Greeter/Components/CircularProgress.qml index b52ae53..a463552 100644 --- a/Greeter/Components/CircularProgress.qml +++ b/Greeter/Components/CircularProgress.qml @@ -1,67 +1,117 @@ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Shapes +import ZShell.Components import ZShell.Config import qs.Services -Shape { +Item { id: root - readonly property real arcRadius: (size - padding - strokeWidth) / 2 - property color bgColour: Colors.palette.m3secondaryContainer - property color fgColour: Colors.palette.m3primary + readonly property real arcRadius: (size - padding - strokeWidth * (1 + waveAmplitude * 2)) / 2 + property color bgColor: Colors.palette.m3secondaryContainer + property real clampedVal: Math.max(1 / 360, Math.min(1, isNaN(value) ? 0 : value)) + readonly property real dotAngleRad: (startAngle + sweepAngle - gapAngle * (sweepAngle < 360 ? 0 : 1)) * Math.PI / 180 + property color fgColor: Colors.palette.m3primary readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI) + property alias hasEndIndicator: dot.active + property real implicitSize property int padding: 0 readonly property real size: Math.min(width, height) property int spacing: Tokens.spacing.small property int startAngle: -90 - property int strokeWidth: Tokens.padding.smaller - readonly property real vValue: value || 1 / 360 + property int strokeWidth: Tokens.padding.small + property int sweepAngle: 360 + readonly property real thickness: strokeWidth * (1 + waveAmplitude) * 2 property real value + property alias waveAmplitude: wave.amplitudeMultiplier + property alias waveDuration: waveProgAnim.duration + property alias waveFrequency: wave.frequency + property bool wavePaused + property bool wavy: false - asynchronous: true - preferredRendererType: Shape.CurveRenderer + implicitHeight: implicitSize + implicitWidth: implicitSize - ShapePath { - capStyle: Tokens.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap - fillColor: "transparent" - strokeColor: root.bgColour - strokeWidth: root.strokeWidth + Shape { + asynchronous: true + opacity: Math.min(1, remainingArc.sweepAngle) + preferredRendererType: Shape.CurveRenderer - Behavior on strokeColor { - CAnim { - duration: Tokens.anim.durations.large + ShapePath { + capStyle: ShapePath.RoundCap + fillColor: "transparent" + strokeColor: root.bgColor + strokeWidth: Math.min(1, remainingArc.sweepAngle) * root.strokeWidth + + Behavior on strokeColor { + CAnim { + } } - } - PathAngleArc { - centerX: root.size / 2 - centerY: root.size / 2 - radiusX: root.arcRadius - radiusY: root.arcRadius - startAngle: root.startAngle + 360 * root.vValue + root.gapAngle - sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2) + PathAngleArc { + id: remainingArc + + centerX: root.size / 2 + centerY: root.size / 2 + radiusX: root.arcRadius + radiusY: root.arcRadius + startAngle: root.startAngle + root.clampedVal * root.sweepAngle + root.gapAngle + sweepAngle: Math.max(1 / 360, root.sweepAngle * (1 - root.clampedVal) - root.gapAngle * (root.sweepAngle < 360 ? 1 : 2)) + } } } - ShapePath { - capStyle: Tokens.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap - fillColor: "transparent" - strokeColor: root.fgColour - strokeWidth: root.strokeWidth + WavyLine { + id: wave - Behavior on strokeColor { - CAnim { - duration: Tokens.anim.durations.large + amplitudeMultiplier: root.wavy ? 0.5 : 0 + anchors.fill: parent + anchors.margins: -lineWidth * amplitudeMultiplier + color: root.fgColor + frequency: 8 + fullAngle: root.sweepAngle + lineWidth: root.strokeWidth + pathType: WavyLine.Arc + radius: root.arcRadius + startAngle: root.startAngle + value: root.clampedVal + + Behavior on amplitudeMultiplier { + Anim { + type: Anim.DefaultEffects } } + Behavior on color { + CAnim { + } + } + Anim on waveProgress { + id: waveProgAnim - PathAngleArc { - centerX: root.size / 2 - centerY: root.size / 2 - radiusX: root.arcRadius - radiusY: root.arcRadius - startAngle: root.startAngle - sweepAngle: 360 * root.vValue + duration: 2000 + easing.type: Easing.Linear + from: 0 + loops: Animation.Infinite + paused: root.wavePaused || wave.amplitudeMultiplier === 0 + running: true + to: 1 + } + } + + Loader { + id: dot + + x: root.size / 2 + root.arcRadius * Math.cos(root.dotAngleRad) - width / 2 + y: root.size / 2 + root.arcRadius * Math.sin(root.dotAngleRad) - height / 2 + + sourceComponent: CustomRect { + color: root.fgColor + implicitHeight: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth) + implicitWidth: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth) + opacity: Math.min(1, remainingArc.sweepAngle) + radius: Tokens.rounding.full } } } diff --git a/Greeter/Components/CollapsibleSection.qml b/Greeter/Components/CollapsibleSection.qml deleted file mode 100644 index ddf4792..0000000 --- a/Greeter/Components/CollapsibleSection.qml +++ /dev/null @@ -1,136 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import ZShell.Config -import qs.Services - -ColumnLayout { - id: root - - default property alias content: contentColumn.data - property string description: "" - property bool expanded: false - property bool nested: false - property bool showBackground: false - required property string title - - signal toggleRequested - - Layout.fillWidth: true - spacing: Tokens.spacing.small - - Item { - id: sectionHeaderItem - - Layout.fillWidth: true - Layout.preferredHeight: Math.max(titleRow.implicitHeight + Tokens.padding.normal * 2, 48) - - RowLayout { - id: titleRow - - anchors.left: parent.left - anchors.leftMargin: Tokens.padding.normal - anchors.right: parent.right - anchors.rightMargin: Tokens.padding.normal - anchors.verticalCenter: parent.verticalCenter - spacing: Tokens.spacing.normal - - CustomText { - font.pointSize: Tokens.font.size.larger - font.weight: 500 - text: root.title - } - - Item { - Layout.fillWidth: true - } - - MaterialIcon { - color: Colors.palette.m3onSurfaceVariant - font.pointSize: Tokens.font.size.normal - rotation: root.expanded ? 180 : 0 - text: "expand_more" - - Behavior on rotation { - Anim { - duration: Tokens.anim.durations.small - easing.bezierCurve: Tokens.anim.curves.standard - } - } - } - } - - StateLayer { - anchors.fill: parent - color: Colors.palette.m3onSurface - radius: Tokens.rounding.normal - showHoverBackground: false - - onClicked: { - root.toggleRequested(); - root.expanded = !root.expanded; - } - } - } - - Item { - id: contentWrapper - - Layout.fillWidth: true - Layout.preferredHeight: root.expanded ? (contentColumn.implicitHeight + Tokens.spacing.small * 2) : 0 - clip: true - - Behavior on Layout.preferredHeight { - Anim { - easing.bezierCurve: Tokens.anim.curves.standard - } - } - - CustomRect { - id: backgroundRect - - anchors.fill: parent - color: Colors.transparency.enabled ? Colors.layer(Colors.palette.m3surfaceContainer, root.nested ? 3 : 2) : (root.nested ? Colors.palette.m3surfaceContainerHigh : Colors.palette.m3surfaceContainer) - opacity: root.showBackground && root.expanded ? 1.0 : 0.0 - radius: Tokens.rounding.normal - visible: root.showBackground - - Behavior on opacity { - Anim { - easing.bezierCurve: Tokens.anim.curves.standard - } - } - } - - ColumnLayout { - id: contentColumn - - anchors.bottomMargin: Tokens.spacing.small - anchors.left: parent.left - anchors.leftMargin: Tokens.padding.normal - anchors.right: parent.right - anchors.rightMargin: Tokens.padding.normal - opacity: root.expanded ? 1.0 : 0.0 - spacing: Tokens.spacing.small - y: Tokens.spacing.small - - Behavior on opacity { - Anim { - easing.bezierCurve: Tokens.anim.curves.standard - } - } - - CustomText { - id: descriptionText - - Layout.bottomMargin: root.description !== "" ? Tokens.spacing.small : 0 - Layout.fillWidth: true - Layout.topMargin: root.description !== "" ? Tokens.spacing.smaller : 0 - color: Colors.palette.m3onSurfaceVariant - font.pointSize: Tokens.font.size.small - text: root.description - visible: root.description !== "" - wrapMode: Text.Wrap - } - } - } -} diff --git a/Greeter/Components/ColorArcPicker.qml b/Greeter/Components/ColorArcPicker.qml deleted file mode 100644 index f910b8b..0000000 --- a/Greeter/Components/ColorArcPicker.qml +++ /dev/null @@ -1,209 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import ZShell.Config -import qs.Services - -Item { - id: root - - readonly property real arcStartAngle: 0.75 * Math.PI - readonly property real arcSweep: 1.5 * Math.PI - property real currentHue: 0 - property bool dragActive: false - required property var drawing - readonly property real handleAngle: hueToAngle(currentHue) - readonly property real handleCenterX: width / 2 + radius * Math.cos(handleAngle) - readonly property real handleCenterY: height / 2 + radius * Math.sin(handleAngle) - property real handleSize: 32 - property real lastChromaticHue: 0 - readonly property real radius: (Math.min(width, height) - handleSize) / 2 - readonly property int segmentCount: 240 - readonly property color thumbColor: Colors.palette.m3inverseSurface - readonly property color thumbContentColor: Colors.palette.m3inverseOnSurface - readonly property color trackColor: Colors.layer(Colors.palette.m3surfaceContainer, 2) - - function hueToAngle(hue) { - return arcStartAngle + arcSweep * hue; - } - - function normalizeAngle(angle) { - const tau = Math.PI * 2; - let a = angle % tau; - if (a < 0) - a += tau; - return a; - } - - function pointIsOnTrack(x, y) { - const cx = width / 2; - const cy = height / 2; - const dx = x - cx; - const dy = y - cy; - const distance = Math.sqrt(dx * dx + dy * dy); - - return distance >= radius - handleSize / 2 && distance <= radius + handleSize / 2; - } - - function syncFromPenColor() { - if (!drawing) - return; - - const c = drawing.penColor; - - if (c.hsvSaturation > 0) { - currentHue = c.hsvHue; - lastChromaticHue = c.hsvHue; - } else { - currentHue = lastChromaticHue; - } - - canvas.requestPaint(); - } - - function updateHueFromPoint(x, y, force = false) { - const cx = width / 2; - const cy = height / 2; - const dx = x - cx; - const dy = y - cy; - - const distance = Math.sqrt(dx * dx + dy * dy); - - if (!force && (distance < radius - handleSize / 2 || distance > radius + handleSize / 2)) - return; - - const angle = normalizeAngle(Math.atan2(dy, dx)); - const start = normalizeAngle(arcStartAngle); - - let relative = angle - start; - if (relative < 0) - relative += Math.PI * 2; - - if (relative > arcSweep) { - const gap = Math.PI * 2 - arcSweep; - relative = relative < arcSweep + gap / 2 ? arcSweep : 0; - } - - currentHue = relative / arcSweep; - lastChromaticHue = currentHue; - drawing.penColor = Qt.hsva(currentHue, drawing.penColor.hsvSaturation, drawing.penColor.hsvValue, drawing.penColor.a); - } - - implicitHeight: 180 - implicitWidth: 220 - - Component.onCompleted: syncFromPenColor() - onCurrentHueChanged: canvas.requestPaint() - onDrawingChanged: syncFromPenColor() - onHandleSizeChanged: canvas.requestPaint() - onHeightChanged: canvas.requestPaint() - onWidthChanged: canvas.requestPaint() - - Connections { - function onPenColorChanged() { - root.syncFromPenColor(); - } - - target: root.drawing - } - - Canvas { - id: canvas - - anchors.fill: parent - renderStrategy: Canvas.Threaded - renderTarget: Canvas.Image - - Component.onCompleted: requestPaint() - onPaint: { - const ctx = getContext("2d"); - ctx.reset(); - ctx.clearRect(0, 0, width, height); - - const cx = width / 2; - const cy = height / 2; - const radius = root.radius; - const trackWidth = root.handleSize; - - // Background track: always show the full hue spectrum - for (let i = 0; i < root.segmentCount; ++i) { - const t1 = i / root.segmentCount; - const t2 = (i + 1) / root.segmentCount; - const a1 = root.arcStartAngle + root.arcSweep * t1; - const a2 = root.arcStartAngle + root.arcSweep * t2; - - ctx.beginPath(); - ctx.arc(cx, cy, radius, a1, a2); - ctx.lineWidth = trackWidth; - ctx.lineCap = "round"; - ctx.strokeStyle = Qt.hsla(t1, 1.0, 0.5, 1.0); - ctx.stroke(); - } - } - } - - Item { - id: handle - - height: root.handleSize - width: root.handleSize - x: root.handleCenterX - width / 2 - y: root.handleCenterY - height / 2 - z: 1 - - Elevation { - anchors.fill: parent - level: handleHover.containsMouse ? 2 : 1 - radius: rect.radius - } - - Rectangle { - id: rect - - anchors.fill: parent - color: root.thumbColor - radius: width / 2 - - MouseArea { - id: handleHover - - acceptedButtons: Qt.NoButton - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - } - - Rectangle { - anchors.centerIn: parent - color: root.drawing ? root.drawing.penColor : Qt.hsla(root.currentHue, 1.0, 0.5, 1.0) - height: width - radius: width / 2 - width: parent.width - 12 - } - } - } - - MouseArea { - id: dragArea - - acceptedButtons: Qt.LeftButton - anchors.fill: parent - hoverEnabled: true - - onCanceled: { - root.dragActive = false; - } - onPositionChanged: mouse => { - if ((mouse.buttons & Qt.LeftButton) && root.dragActive) - root.updateHueFromPoint(mouse.x, mouse.y, true); - } - onPressed: mouse => { - root.dragActive = root.pointIsOnTrack(mouse.x, mouse.y); - if (root.dragActive) - root.updateHueFromPoint(mouse.x, mouse.y); - } - onReleased: { - root.dragActive = false; - } - } -} diff --git a/Greeter/Components/ColoredIcon.qml b/Greeter/Components/ColoredIcon.qml deleted file mode 100644 index a4711c6..0000000 --- a/Greeter/Components/ColoredIcon.qml +++ /dev/null @@ -1,34 +0,0 @@ -pragma ComponentBehavior: Bound - -import ZShell -import Quickshell.Widgets -import QtQuick - -IconImage { - id: root - - required property color color - - asynchronous: true - layer.enabled: true - - layer.effect: Coloriser { - colorizationColor: root.color - sourceColor: analyser.dominantColour - } - - layer.onEnabledChanged: { - if (layer.enabled && status === Image.Ready) - analyser.requestUpdate(); - } - onStatusChanged: { - if (layer.enabled && status === Image.Ready) - analyser.requestUpdate(); - } - - ImageAnalyser { - id: analyser - - sourceItem: root - } -} diff --git a/Greeter/Components/Coloriser.qml b/Greeter/Components/Coloriser.qml deleted file mode 100644 index 77bdf8d..0000000 --- a/Greeter/Components/Coloriser.qml +++ /dev/null @@ -1,14 +0,0 @@ -import QtQuick -import QtQuick.Effects - -MultiEffect { - property color sourceColor: "black" - - brightness: 1 - sourceColor.hslLightness - colorization: 1 - - Behavior on colorizationColor { - CAnim { - } - } -} diff --git a/Greeter/Components/CustomAudioSlider.qml b/Greeter/Components/CustomAudioSlider.qml deleted file mode 100644 index 5c3240b..0000000 --- a/Greeter/Components/CustomAudioSlider.qml +++ /dev/null @@ -1,71 +0,0 @@ -import QtQuick -import QtQuick.Templates -import ZShell.Config -import qs.Services - -Slider { - id: root - - property color nonPeakColor: Colors.tPalette.m3primary - required property real peak - property color peakColor: Colors.palette.m3primary - - background: Item { - CustomRect { - anchors.bottom: parent.bottom - anchors.bottomMargin: root.implicitHeight / 3 - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: root.implicitHeight / 3 - bottomRightRadius: root.implicitHeight / 15 - color: root.nonPeakColor - implicitWidth: root.handle.x - root.implicitHeight - radius: Tokens.rounding.full - topRightRadius: root.implicitHeight / 15 - - CustomRect { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.top: parent.top - bottomRightRadius: root.implicitHeight / 15 - color: root.peakColor - implicitWidth: parent.width * root.peak - radius: Tokens.rounding.full - topRightRadius: root.implicitHeight / 15 - - Behavior on implicitWidth { - Anim { - duration: 50 - } - } - } - } - - CustomRect { - anchors.bottom: parent.bottom - anchors.bottomMargin: root.implicitHeight / 3 - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: root.implicitHeight / 3 - bottomLeftRadius: root.implicitHeight / 15 - color: Colors.tPalette.m3surfaceContainer - implicitWidth: root.implicitWidth - root.handle.x - root.handle.implicitWidth - root.implicitHeight - radius: Tokens.rounding.full - topLeftRadius: root.implicitHeight / 15 - } - } - handle: CustomRect { - anchors.verticalCenter: parent.verticalCenter - color: Colors.palette.m3primary - implicitHeight: 15 - implicitWidth: 5 - radius: Tokens.rounding.full - x: root.visualPosition * root.availableWidth - implicitWidth / 2 - - MouseArea { - acceptedButtons: Qt.NoButton - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - } - } -} diff --git a/Greeter/Components/CustomBusyIndicator.qml b/Greeter/Components/CustomBusyIndicator.qml deleted file mode 100644 index 877db30..0000000 --- a/Greeter/Components/CustomBusyIndicator.qml +++ /dev/null @@ -1,69 +0,0 @@ -import QtQuick -import QtQuick.Controls.Basic - -BusyIndicator { - id: control - - property int busySize: 64 - property color color: delegate.color - - contentItem: Item { - implicitHeight: control.busySize - implicitWidth: control.busySize - - Item { - id: item - - height: control.busySize - opacity: control.running ? 1 : 0 - width: control.busySize - x: parent.width / 2 - (control.busySize / 2) - y: parent.height / 2 - (control.busySize / 2) - - Behavior on opacity { - OpacityAnimator { - duration: 250 - } - } - - RotationAnimator { - duration: 1250 - from: 0 - loops: Animation.Infinite - running: control.visible && control.running - target: item - to: 360 - } - - Repeater { - id: repeater - - model: 6 - - CustomRect { - id: delegate - - required property int index - - color: control.color - implicitHeight: 10 - implicitWidth: 10 - radius: 5 - x: item.width / 2 - width / 2 - y: item.height / 2 - height / 2 - - transform: [ - Translate { - y: -Math.min(item.width, item.height) * 0.5 + 5 - }, - Rotation { - angle: delegate.index / repeater.count * 360 - origin.x: 5 - origin.y: 5 - } - ] - } - } - } - } -} diff --git a/Greeter/Components/CustomButton.qml b/Greeter/Components/CustomButton.qml deleted file mode 100644 index 3e14dc3..0000000 --- a/Greeter/Components/CustomButton.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick -import QtQuick.Controls -import ZShell.Config -import qs.Services - -Button { - id: control - - property color bgColor: Colors.palette.m3primary - property int radius: Tokens.rounding.smallest / 2 - property color textColor: Colors.palette.m3onPrimary - - background: CustomRect { - color: control.bgColor - opacity: control.enabled ? 1.0 : 0.5 - radius: control.radius - } - contentItem: CustomText { - color: control.textColor - horizontalAlignment: Text.AlignHCenter - opacity: control.enabled ? 1.0 : 0.5 - text: control.text - verticalAlignment: Text.AlignVCenter - } - - StateLayer { - radius: control.radius - - onClicked: { - control.clicked(); - } - } -} diff --git a/Greeter/Components/CustomCheckbox.qml b/Greeter/Components/CustomCheckbox.qml deleted file mode 100644 index 2366010..0000000 --- a/Greeter/Components/CustomCheckbox.qml +++ /dev/null @@ -1,38 +0,0 @@ -import QtQuick -import QtQuick.Controls -import ZShell.Config -import qs.Services - -CheckBox { - id: control - - property int checkHeight: 20 - property int checkWidth: 20 - - contentItem: CustomText { - anchors.left: parent.left - anchors.leftMargin: control.checkWidth + control.leftPadding + 8 - anchors.verticalCenter: parent.verticalCenter - font.pointSize: control.font.pointSize - text: control.text - } - indicator: CustomRect { - // x: control.leftPadding - // y: parent.implicitHeight / 2 - implicitHeight / 2 - border.color: control.checked ? Colors.palette.m3primary : "transparent" - color: Colors.palette.m3surfaceVariant - implicitHeight: control.checkHeight - implicitWidth: control.checkWidth - radius: Tokens.rounding.smallest / 2 - - CustomRect { - color: Colors.palette.m3primary - implicitHeight: control.checkHeight - (y * 2) - implicitWidth: control.checkWidth - (x * 2) - radius: 3 - visible: control.checked - x: 4 - y: 4 - } - } -} diff --git a/Greeter/Components/CustomComboBox.qml b/Greeter/Components/CustomComboBox.qml deleted file mode 100644 index 8f9f9e2..0000000 --- a/Greeter/Components/CustomComboBox.qml +++ /dev/null @@ -1,170 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls -import ZShell.Config -import qs.Services - -ComboBox { - id: root - - property int cornerRadius: Tokens.rounding.normal - property int fieldHeight: 42 - property bool filled: true - property real focusRingOpacity: 0.70 - property int hPadding: 16 - property int menuCornerRadius: 16 - property int menuRowHeight: 46 - property int menuVisibleRows: 7 - property bool preferPopupWindow: false - - hoverEnabled: true - implicitHeight: fieldHeight - implicitWidth: 240 - spacing: 8 - - // ---------- Field background (filled/outlined + state layers + focus ring) ---------- - background: Item { - anchors.fill: parent - - CustomRect { - id: container - - anchors.fill: parent - color: Colors.palette.m3surfaceVariant - radius: root.cornerRadius - - StateLayer { - } - } - } - - // ---------- Content ---------- - contentItem: RowLayout { - anchors.fill: parent - anchors.leftMargin: root.hPadding - anchors.rightMargin: root.hPadding - spacing: 12 - - // Display text - CustomText { - Layout.fillWidth: true - color: root.enabled ? Colors.palette.m3onSurface : Colors.palette.m3onSurfaceVariant - elide: Text.ElideRight - font.pixelSize: 16 - font.weight: Font.Medium - text: root.currentText - verticalAlignment: Text.AlignVCenter - } - - // Indicator chevron (simple, replace with your icon system) - CustomText { - color: root.enabled ? Colors.palette.m3onSurfaceVariant : Colors.palette.m3onSurfaceVariant - rotation: root.popup.visible ? 180 : 0 - text: "▾" - transformOrigin: Item.Center - verticalAlignment: Text.AlignVCenter - - Behavior on rotation { - NumberAnimation { - duration: 140 - easing.type: Easing.OutCubic - } - } - } - } - popup: Popup { - id: p - - implicitHeight: list.contentItem.height + Tokens.padding.small * 2 - implicitWidth: root.width - modal: true - popupType: root.preferPopupWindow ? Popup.Window : Popup.Item - y: -list.currentIndex * (root.menuRowHeight + Tokens.spacing.small) - Tokens.padding.small - - background: CustomRect { - color: Colors.palette.m3surface - radius: root.menuCornerRadius - } - contentItem: ListView { - id: list - - anchors.bottomMargin: Tokens.padding.small - anchors.fill: parent - anchors.topMargin: Tokens.padding.small - clip: true - currentIndex: root.currentIndex - model: root.delegateModel - spacing: Tokens.spacing.small - - delegate: CustomRect { - required property int index - required property var modelData - - anchors.horizontalCenter: parent.horizontalCenter - color: (index === root.currentIndex) ? Colors.palette.m3primary : "transparent" - implicitHeight: root.menuRowHeight - implicitWidth: p.implicitWidth - Tokens.padding.small * 2 - radius: Tokens.rounding.normal - Tokens.padding.small - - RowLayout { - anchors.fill: parent - spacing: 10 - - CustomText { - Layout.fillWidth: true - color: Colors.palette.m3onSurface - elide: Text.ElideRight - font.pixelSize: 15 - text: modelData - verticalAlignment: Text.AlignVCenter - } - - CustomText { - color: Colors.palette.m3onSurfaceVariant - text: "✓" - verticalAlignment: Text.AlignVCenter - visible: index === root.currentIndex - } - } - - StateLayer { - onClicked: { - root.currentIndex = index; - p.close(); - } - } - } - } - - // Expressive-ish open/close motion: subtle scale+fade (tune to taste). :contentReference[oaicite:5]{index=5} - enter: Transition { - Anim { - from: 0 - property: "opacity" - to: 1 - } - - Anim { - from: 0.98 - property: "scale" - to: 1.0 - } - } - exit: Transition { - Anim { - from: 1 - property: "opacity" - to: 0 - } - } - - Elevation { - anchors.fill: parent - level: 2 - radius: root.menuCornerRadius - z: -1 - } - } -} diff --git a/Greeter/Components/CustomIcon.qml b/Greeter/Components/CustomIcon.qml deleted file mode 100644 index 8201305..0000000 --- a/Greeter/Components/CustomIcon.qml +++ /dev/null @@ -1,10 +0,0 @@ -pragma ComponentBehavior: Bound - -import Quickshell.Widgets -import QtQuick - -IconImage { - id: root - - asynchronous: true -} diff --git a/Greeter/Components/CustomRadioButton.qml b/Greeter/Components/CustomRadioButton.qml deleted file mode 100644 index aca7899..0000000 --- a/Greeter/Components/CustomRadioButton.qml +++ /dev/null @@ -1,54 +0,0 @@ -import QtQuick -import QtQuick.Templates -import ZShell.Config -import qs.Services - -RadioButton { - id: root - - font.pointSize: Tokens.font.size.normal - implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight) - implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin - - contentItem: CustomText { - anchors.left: outerCircle.right - anchors.leftMargin: 10 - anchors.verticalCenter: parent.verticalCenter - font.pointSize: root.font.pointSize - text: root.text - } - indicator: Rectangle { - id: outerCircle - - anchors.verticalCenter: parent.verticalCenter - border.color: root.checked ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant - border.width: 2 - color: "transparent" - implicitHeight: 16 - implicitWidth: 16 - radius: Tokens.rounding.full - - Behavior on border.color { - CAnim { - } - } - - StateLayer { - anchors.margins: -7 - color: root.checked ? Colors.palette.m3onSurface : Colors.palette.m3primary - z: -1 - - onClicked: { - root.click(); - } - } - - CustomRect { - anchors.centerIn: parent - color: Qt.alpha(Colors.palette.m3primary, root.checked ? 1 : 0) - implicitHeight: 8 - implicitWidth: 8 - radius: Tokens.rounding.full - } - } -} diff --git a/Greeter/Components/CustomScrollBar.qml b/Greeter/Components/CustomScrollBar.qml deleted file mode 100644 index 281f533..0000000 --- a/Greeter/Components/CustomScrollBar.qml +++ /dev/null @@ -1,190 +0,0 @@ -import ZShell.Config -import QtQuick -import QtQuick.Templates -import qs.Services - -ScrollBar { - id: root - - property bool _updatingFromFlickable: false - property bool _updatingFromUser: false - property bool animating - required property Flickable flickable - property real nonAnimPosition - property bool shouldBeActive - - implicitWidth: 8 - - contentItem: CustomRect { - anchors.left: parent.left - anchors.right: parent.right - color: Colors.palette.m3secondary - opacity: { - if (root.size === 1) - return 0; - if (fullMouse.pressed) - return 1; - if (mouse.containsMouse) - return 0.8; - if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive) - return 0.6; - return 0; - } - radius: Tokens.rounding.full - - Behavior on opacity { - Anim { - } - } - - MouseArea { - id: mouse - - acceptedButtons: Qt.NoButton - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - } - } - Behavior on position { - enabled: !fullMouse.pressed - - Anim { - } - } - - Component.onCompleted: { - if (flickable) { - const contentHeight = flickable.contentHeight; - const height = flickable.height; - if (contentHeight > height) { - nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); - } - } - } - onHoveredChanged: { - if (hovered) - shouldBeActive = true; - else - shouldBeActive = flickable.moving; - } - - // Sync nonAnimPosition with Qt's automatic position binding - onPositionChanged: { - if (_updatingFromUser) { - _updatingFromUser = false; - return; - } - if (position === nonAnimPosition) { - animating = false; - return; - } - if (!animating && !_updatingFromFlickable && !fullMouse.pressed) { - nonAnimPosition = position; - } - } - - // Sync nonAnimPosition with flickable when not animating - Connections { - function onContentYChanged() { - if (!animating && !fullMouse.pressed) { - _updatingFromFlickable = true; - const contentHeight = flickable.contentHeight; - const height = flickable.height; - if (contentHeight > height) { - nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); - } else { - nonAnimPosition = 0; - } - _updatingFromFlickable = false; - } - } - - target: flickable - } - - Connections { - function onMovingChanged(): void { - if (root.flickable.moving) - root.shouldBeActive = true; - else - hideDelay.restart(); - } - - target: root.flickable - } - - Timer { - id: hideDelay - - interval: 600 - - onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered - } - - CustomMouseArea { - id: fullMouse - - function onWheel(event: WheelEvent): void { - root.animating = true; - root._updatingFromUser = true; - let newPos = root.nonAnimPosition; - if (event.angleDelta.y > 0) - newPos = Math.max(0, root.nonAnimPosition - 0.1); - else if (event.angleDelta.y < 0) - newPos = Math.min(1 - root.size, root.nonAnimPosition + 0.1); - root.nonAnimPosition = newPos; - // Update flickable position - // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] - if (root.flickable) { - const contentHeight = root.flickable.contentHeight; - const height = root.flickable.height; - if (contentHeight > height) { - const maxContentY = contentHeight - height; - const maxPos = 1 - root.size; - const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; - root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); - } - } - } - - anchors.fill: parent - preventStealing: true - - onPositionChanged: event => { - root._updatingFromUser = true; - const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2)); - root.nonAnimPosition = newPos; - // Update flickable position - // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] - if (root.flickable) { - const contentHeight = root.flickable.contentHeight; - const height = root.flickable.height; - if (contentHeight > height) { - const maxContentY = contentHeight - height; - const maxPos = 1 - root.size; - const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; - root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); - } - } - } - onPressed: event => { - root.animating = true; - root._updatingFromUser = true; - const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2)); - root.nonAnimPosition = newPos; - // Update flickable position - // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] - if (root.flickable) { - const contentHeight = root.flickable.contentHeight; - const height = root.flickable.height; - if (contentHeight > height) { - const maxContentY = contentHeight - height; - const maxPos = 1 - root.size; - const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; - root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); - } - } - } - } -} diff --git a/Greeter/Components/CustomShortcut.qml b/Greeter/Components/CustomShortcut.qml deleted file mode 100644 index c60cbef..0000000 --- a/Greeter/Components/CustomShortcut.qml +++ /dev/null @@ -1,5 +0,0 @@ -import Quickshell.Hyprland - -GlobalShortcut { - appid: "zshell" -} diff --git a/Greeter/Components/CustomSlider.qml b/Greeter/Components/CustomSlider.qml deleted file mode 100644 index 093d80c..0000000 --- a/Greeter/Components/CustomSlider.qml +++ /dev/null @@ -1,175 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Templates -import ZShell.Components -import ZShell -import qs.Components -import ZShell.Config -import qs.Services - -Slider { - id: root - - property bool animateWave - property color bgColor: enabled ? Colors.palette.m3secondaryContainer : Qt.alpha(Colors.palette.m3onSurface, 0.1) - property color fgColor: enabled ? Colors.palette.m3primary : Qt.alpha(Colors.palette.m3onSurface, 0.38) - property real filledWidth - property real pos: visualPosition - property int waveDuration: 1000 - property real waveFrequency: 6 - property bool wavy - - signal interaction(v: real) - - implicitHeight: 12 - implicitWidth: 200 - - contentItem: Item { - anchors.fill: parent - - CustomRect { - id: remaining - - anchors.left: handle.right - anchors.leftMargin: Tokens.spacing.extraSmall - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - bottomLeftRadius: Tokens.rounding.extraSmall / 2 - color: root.bgColor - implicitHeight: parent.height * (parent.height <= 12 ? opacity : Math.min(opacity * 2, 1)) - opacity: Math.min(width, 12) / 12 - radius: Tokens.rounding.small - topLeftRadius: Tokens.rounding.extraSmall / 2 - } - - CustomRect { - anchors.right: parent.right - anchors.rightMargin: 4 * remaining.opacity - anchors.verticalCenter: parent.verticalCenter - color: root.fgColor - implicitHeight: 4 * remaining.opacity - implicitWidth: implicitHeight - opacity: remaining.opacity - radius: Tokens.rounding.full - } - - CustomRect { - id: handle - - anchors.left: filled.right - anchors.leftMargin: Tokens.spacing.extraSmall - anchors.verticalCenter: parent.verticalCenter - color: root.fgColor - implicitHeight: { - const mult = parent.height <= 12 ? 3 : 1.2; - const pressMult = parent.height <= 12 ? 4 : 1.5; - return parent.height * (mouse.pressed ? pressMult : mult); - } - implicitWidth: 4 - radius: Tokens.rounding.full - - Behavior on implicitHeight { - Anim { - type: Anim.FastSpatial - } - } - } - - Loader { - id: filled - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - asynchronous: true - sourceComponent: root.wavy ? waveComp : lineComp - } - - Component { - id: lineComp - - CustomRect { - bottomRightRadius: Tokens.rounding.extraSmall / 2 - color: root.fgColor - implicitHeight: root.height - implicitWidth: root.filledWidth - radius: Tokens.rounding.small - topRightRadius: Tokens.rounding.extraSmall / 2 - } - } - - Component { - id: waveComp - - WavyLine { - color: root.fgColor - frequency: root.waveFrequency - fullLength: root.width - handle.implicitWidth - handle.anchors.leftMargin - implicitHeight: lineWidth * amplitudeMultiplier * 2 + lineWidth - implicitWidth: root.filledWidth - lineWidth: root.height * 0.7 - startX: x - - Behavior on color { - CAnim { - } - } - Anim on waveProgress { - duration: root.waveDuration - easing.type: Easing.Linear - from: 0 - loops: Animation.Infinite - paused: !root.animateWave - running: true - to: 1 - } - } - } - } - Behavior on filledWidth { - id: widthBehavior - - Anim { - } - } - - Component.onCompleted: filledWidth = Qt.binding(() => (width - handle.implicitWidth - handle.anchors.leftMargin) * pos) - - Binding { - id: posBinding - - property: "pos" - target: root - value: ZUtils.clamp(mouse.pressStartPos + mouse.dragMovement, 0, 1) - when: mouse.pressed - } - - MouseArea { - id: mouse - - property real dragMovement - property real pressStartPos - property real pressStartX - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - implicitHeight: handle.implicitHeight - preventStealing: true - - onPositionChanged: e => { - dragMovement = (e.x - pressStartX) / width; - root.interaction(posBinding.value); - } - onPressed: e => { - widthBehavior.enabled = false; - pressStartX = e.x; - pressStartPos = root.visualPosition; - } - onReleased: e => { - root.interaction(posBinding.value); - widthBehavior.enabled = true; - dragMovement = 0; - } - } -} diff --git a/Greeter/Components/CustomSpinBox.qml b/Greeter/Components/CustomSpinBox.qml deleted file mode 100644 index a6d4648..0000000 --- a/Greeter/Components/CustomSpinBox.qml +++ /dev/null @@ -1,169 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import ZShell.Config -import qs.Services - -RowLayout { - id: root - - property string displayText: root.value.toString() - property bool isEditing: false - property real max: Infinity - property real min: -Infinity - property alias repeatRate: timer.interval - property real step: 1 - property real value - - signal valueModified(value: real) - - spacing: Tokens.spacing.small - - onValueChanged: { - if (!root.isEditing) { - root.displayText = root.value.toString(); - } - } - - CustomTextField { - id: textField - - color: root.enabled ? Colors.palette.m3onSurface : Qt.alpha(Colors.palette.m3onSurface, 0.5) - implicitHeight: upButton.implicitHeight - inputMethodHints: Qt.ImhFormattedNumbersOnly - leftPadding: Tokens.padding.normal - padding: Tokens.padding.small - rightPadding: Tokens.padding.normal - text: root.isEditing ? text : root.displayText - - background: CustomRect { - color: root.enabled ? Colors.tPalette.m3surfaceContainerHigh : Colors.tPalette.m3surfaceContainerLow - implicitWidth: 100 - radius: Tokens.rounding.full - } - validator: DoubleValidator { - bottom: root.min - decimals: root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0 - top: root.max - } - - onAccepted: { - const numValue = parseFloat(text); - if (!isNaN(numValue)) { - const clampedValue = Math.max(root.min, Math.min(root.max, numValue)); - root.value = clampedValue; - root.displayText = clampedValue.toString(); - root.valueModified(clampedValue); - } else { - text = root.displayText; - } - root.isEditing = false; - } - onActiveFocusChanged: { - if (activeFocus) { - root.isEditing = true; - } else { - root.isEditing = false; - root.displayText = root.value.toString(); - } - } - onEditingFinished: { - if (text !== root.displayText) { - const numValue = parseFloat(text); - if (!isNaN(numValue)) { - const clampedValue = Math.max(root.min, Math.min(root.max, numValue)); - root.value = clampedValue; - root.displayText = clampedValue.toString(); - root.valueModified(clampedValue); - } else { - text = root.displayText; - } - } - root.isEditing = false; - } - } - - CustomRect { - id: upButton - - color: root.enabled ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHighest, 1) - implicitHeight: upIcon.implicitHeight + Tokens.padding.small * 2 - implicitWidth: implicitHeight - radius: Tokens.rounding.full - - StateLayer { - id: upState - - color: Colors.palette.m3onPrimary - - onClicked: { - let newValue = Math.min(root.max, root.value + root.step); - // Round to avoid floating point precision errors - const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0; - newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals); - root.value = newValue; - root.displayText = newValue.toString(); - root.valueModified(newValue); - } - onPressAndHold: timer.start() - onReleased: timer.stop() - } - - MaterialIcon { - id: upIcon - - anchors.centerIn: parent - color: root.enabled ? Colors.palette.m3onPrimary : Qt.alpha(Colors.palette.m3onSurface, 0.5) - text: "keyboard_arrow_up" - } - } - - CustomRect { - color: root.enabled ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHighest, 1) - implicitHeight: downIcon.implicitHeight + Tokens.padding.small * 2 - implicitWidth: implicitHeight - radius: Tokens.rounding.full - - StateLayer { - id: downState - - color: Colors.palette.m3onPrimary - - onClicked: { - let newValue = Math.max(root.min, root.value - root.step); - // Round to avoid floating point precision errors - const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0; - newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals); - root.value = newValue; - root.displayText = newValue.toString(); - root.valueModified(newValue); - } - onPressAndHold: timer.start() - onReleased: timer.stop() - } - - MaterialIcon { - id: downIcon - - anchors.centerIn: parent - color: root.enabled ? Colors.palette.m3onPrimary : Qt.alpha(Colors.palette.m3onSurface, 0.5) - text: "keyboard_arrow_down" - } - } - - Timer { - id: timer - - interval: 100 - repeat: true - triggeredOnStart: true - - onTriggered: { - if (upState.pressed) - upState.onClicked(); - else if (downState.pressed) - downState.onClicked(); - } - } -} diff --git a/Greeter/Components/CustomSplitButton.qml b/Greeter/Components/CustomSplitButton.qml deleted file mode 100644 index 034f6d7..0000000 --- a/Greeter/Components/CustomSplitButton.qml +++ /dev/null @@ -1,149 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import ZShell.Config -import qs.Services - -Row { - id: root - - enum Type { - Filled, - Tonal - } - - property alias active: menu.active - property color colour: type == CustomSplitButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondaryContainer - property bool disabled - property color disabledColour: Qt.alpha(Colors.palette.m3onSurface, 0.1) - property color disabledTextColour: Qt.alpha(Colors.palette.m3onSurface, 0.38) - readonly property alias expandBtn: expandBtn - property alias expanded: menu.expanded - property string fallbackIcon - property string fallbackText - property real horizontalPadding: Tokens.padding.larger - readonly property alias iconLabel: iconLabel - readonly property alias label: label - readonly property alias menu: menu - property alias menuItems: menu.items - property bool menuOnTop - property real minLeftWidth - readonly property alias stateLayer: stateLayer - property color textColour: type == CustomSplitButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondaryContainer - readonly property alias textRow: textRow - property int type: CustomSplitButton.Filled - property real verticalPadding: Tokens.padding.small - - spacing: Math.floor(Tokens.spacing.extraSmall) - - CustomRect { - bottomRightRadius: Tokens.rounding.small / 2 - color: root.disabled ? root.disabledColour : root.colour - implicitHeight: expandBtn.implicitHeight - implicitWidth: Math.max(root.minLeftWidth, textRow.implicitWidth + root.horizontalPadding * 2) - radius: implicitHeight / 2 * Math.min(1, Tokens.rounding.scale) - topRightRadius: Tokens.rounding.small / 2 - - StateLayer { - id: stateLayer - - bottomRightRadius: parent.bottomRightRadius - color: root.textColour - disabled: root.disabled - topRightRadius: parent.topRightRadius - - onClicked: root.active?.clicked() - } - - RowLayout { - id: textRow - - anchors.centerIn: parent - anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4) - spacing: Tokens.spacing.small - - MaterialIcon { - id: iconLabel - - Layout.alignment: Qt.AlignVCenter - animate: true - color: root.disabled ? root.disabledTextColour : root.textColour - fill: 1 - text: root.active?.activeIcon ?? root.fallbackIcon - } - - CustomText { - id: label - - Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: implicitWidth - animate: true - clip: true - color: root.disabled ? root.disabledTextColour : root.textColour - text: root.active?.activeText ?? root.fallbackText - - Behavior on Layout.preferredWidth { - Anim { - type: Anim.Emphasized - } - } - } - } - } - - CustomRect { - id: expandBtn - - property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Tokens.rounding.scale) : Tokens.rounding.small / 2 - - bottomLeftRadius: rad - color: root.disabled ? root.disabledColour : root.colour - implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2 - implicitWidth: implicitHeight - radius: implicitHeight / 2 * Math.min(1, Tokens.rounding.scale) - topLeftRadius: rad - - Behavior on rad { - Anim { - } - } - - StateLayer { - id: expandStateLayer - - color: root.textColour - disabled: root.disabled - rect.bottomLeftRadius: parent.bottomLeftRadius - rect.topLeftRadius: parent.topLeftRadius - - onClicked: root.expanded = !root.expanded - } - - MaterialIcon { - id: expandIcon - - anchors.centerIn: parent - anchors.horizontalCenterOffset: root.expanded ? 0 : -Math.floor(root.verticalPadding / 4) - color: root.disabled ? root.disabledTextColour : root.textColour - rotation: root.expanded ? 180 : 0 - text: "expand_more" - - Behavior on anchors.horizontalCenterOffset { - Anim { - } - } - Behavior on rotation { - Anim { - } - } - } - } - - Menu { - id: menu - - attachSideY: root.menuOnTop ? Menu.Top : Menu.Bottom - attachTo: expandBtn - marginY: Tokens.spacing.small * (root.menuOnTop ? -1 : 1) - thisSideY: root.menuOnTop ? Menu.Bottom : Menu.Top - } -} diff --git a/Greeter/Components/CustomSplitButtonRow.qml b/Greeter/Components/CustomSplitButtonRow.qml deleted file mode 100644 index 5631606..0000000 --- a/Greeter/Components/CustomSplitButtonRow.qml +++ /dev/null @@ -1,70 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import ZShell.Config -import qs.Services - -Item { - id: root - - property alias active: splitButton.active - property alias buttonAlias: splitButton - property alias expanded: splitButton.expanded - property int expandedZ: 100 - required property string label - property alias menuItems: splitButton.menuItems - property bool shouldBeActive: true - property alias type: splitButton.type - - signal selected(item: MenuItem) - - anchors.left: parent.left - anchors.right: parent.right - clip: false - implicitHeight: row.implicitHeight + Tokens.padding.smaller * 2 - opacity: shouldBeActive ? 1 : 0 - scale: shouldBeActive ? 1 : 0.8 - z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1 - - Behavior on opacity { - Anim { - } - } - Behavior on scale { - Anim { - } - } - - RowLayout { - id: row - - anchors.left: parent.left - anchors.margins: Tokens.padding.small - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Tokens.spacing.normal - - CustomText { - Layout.fillWidth: true - color: root.enabled ? Colors.palette.m3onSurface : Colors.palette.m3onSurfaceVariant - font.pointSize: Tokens.font.size.larger - text: root.label - } - - CustomSplitButton { - id: splitButton - - enabled: root.enabled - type: CustomSplitButton.Filled - z: 2 - - menu.onItemSelected: item => { - root.selected(item); - } - stateLayer.onClicked: { - splitButton.expanded = !splitButton.expanded; - } - } - } -} diff --git a/Greeter/Components/CustomSwitch.qml b/Greeter/Components/CustomSwitch.qml deleted file mode 100644 index e41e773..0000000 --- a/Greeter/Components/CustomSwitch.qml +++ /dev/null @@ -1,158 +0,0 @@ -import QtQuick -import QtQuick.Shapes -import QtQuick.Templates -import ZShell.Config -import qs.Services - -Switch { - id: root - - property int cLayer: 1 - - implicitHeight: implicitIndicatorHeight - implicitWidth: implicitIndicatorWidth - - indicator: CustomRect { - color: root.checked && root.enabled ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) - implicitHeight: Tokens.font.size.medium + Tokens.padding.normal * 2 - implicitWidth: implicitHeight * 1.7 - radius: Tokens.rounding.full - - CustomRect { - readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.2 : implicitHeight - - anchors.verticalCenter: parent.verticalCenter - color: root.checked && root.enabled ? Colors.palette.m3onPrimary : Colors.layer(Colors.palette.m3outline, root.cLayer + 1) - implicitHeight: parent.implicitHeight - Tokens.padding.extraSmall - implicitWidth: nonAnimWidth - radius: Tokens.rounding.full - x: root.checked ? parent.implicitWidth - nonAnimWidth - Tokens.padding.extraSmall / 2 : Tokens.padding.extraSmall / 2 - - Behavior on implicitWidth { - Anim { - type: Anim.FastSpatial - } - } - Behavior on x { - Anim { - type: Anim.FastSpatial - } - } - - CustomRect { - anchors.fill: parent - color: root.checked && root.enabled ? Colors.palette.m3primary : Colors.palette.m3onSurface - opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0 - radius: parent.radius - - Behavior on opacity { - Anim { - type: Anim.DefaultEffects - } - } - } - - Shape { - id: icon - - property point end1: { - if (root.pressed) { - if (root.checked) - return Qt.point(width * 0.4, height / 2); - return Qt.point(width * 0.8, height / 2); - } - if (root.checked) - return Qt.point(width * 0.4, height * 0.7); - return Qt.point(width * 0.85, height * 0.85); - } - property point end2: { - if (root.pressed) - return Qt.point(width * 0.8, height / 2); - if (root.checked) - return Qt.point(width * 0.85, height * 0.2); - return Qt.point(width * 0.85, height * 0.15); - } - property point start1: { - if (root.pressed) - return Qt.point(width * 0.2, height / 2); - if (root.checked) - return Qt.point(width * 0.15, height / 2); - return Qt.point(width * 0.15, height * 0.15); - } - property point start2: { - if (root.pressed) { - if (root.checked) - return Qt.point(width * 0.4, height / 2); - return Qt.point(width * 0.2, height / 2); - } - if (root.checked) - return Qt.point(width * 0.4, height * 0.7); - return Qt.point(width * 0.15, height * 0.85); - } - - anchors.centerIn: parent - asynchronous: true - height: parent.implicitHeight - Tokens.padding.larger - preferredRendererType: Shape.CurveRenderer - width: height - - Behavior on end1 { - PropAnim { - } - } - Behavior on end2 { - PropAnim { - } - } - Behavior on start1 { - PropAnim { - } - } - Behavior on start2 { - PropAnim { - } - } - - ShapePath { - capStyle: ShapePath.RoundCap - fillColor: "transparent" - startX: icon.start1.x - startY: icon.start1.y - strokeColor: root.checked && root.enabled ? Colors.palette.m3primary : Colors.palette.m3surfaceContainerHighest - strokeWidth: Tokens.font.size.larger * 0.15 - - Behavior on strokeColor { - CAnim { - } - } - - PathLine { - x: icon.end1.x - y: icon.end1.y - } - - PathMove { - x: icon.start2.x - y: icon.start2.y - } - - PathLine { - x: icon.end2.x - y: icon.end2.y - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false - } - - component PropAnim: PropertyAnimation { - duration: Tokens.anim.durations.expressiveFastSpatial - easing.bezierCurve: Tokens.anim.curves.expressiveFastSpatial - } -} diff --git a/Greeter/Components/CustomTextField.qml b/Greeter/Components/CustomTextField.qml index 6fb81f2..4edfe69 100644 --- a/Greeter/Components/CustomTextField.qml +++ b/Greeter/Components/CustomTextField.qml @@ -11,7 +11,7 @@ TextField { background: null color: Colors.palette.m3onSurface cursorVisible: !readOnly - font.family: Appearance.font.family.sans + font.family: Config.appearance.font.family.sans font.pointSize: Tokens.font.size.smaller placeholderTextColor: Colors.palette.m3outline renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering diff --git a/Greeter/Components/CustomTextInput.qml b/Greeter/Components/CustomTextInput.qml index 0f474d5..2a6dcc6 100644 --- a/Greeter/Components/CustomTextInput.qml +++ b/Greeter/Components/CustomTextInput.qml @@ -6,11 +6,11 @@ import qs.Services TextInput { renderType: Text.NativeRendering selectedTextColor: Colors.palette.m3onSecondaryContainer - selectionColor: Colors.tPalette.colSecondaryContainer + selectionColor: Colors.tPalette.m3onSecondaryContainer font { - family: Appearance?.font.family.sans ?? "sans-serif" + family: Config.appearance?.font.family.sans ?? "sans-serif" hintingPreference: Font.PreferFullHinting - pixelSize: Appearance?.font.size.normal ?? 15 + pixelSize: Config.appearance?.font.size.normal ?? 15 } } diff --git a/Greeter/Components/CustomTooltip.qml b/Greeter/Components/CustomTooltip.qml deleted file mode 100644 index 59cb1ad..0000000 --- a/Greeter/Components/CustomTooltip.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Components - -ToolTip { - id: root - - property bool alternativeVisibleCondition: false - property bool extraVisibleCondition: true - readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition - - background: null - horizontalPadding: 10 - verticalPadding: 5 - visible: internalVisibleCondition - - contentItem: CustomTooltipContent { - id: contentItem - - horizontalPadding: root.horizontalPadding - shown: root.internalVisibleCondition - text: root.text - verticalPadding: root.verticalPadding - } -} diff --git a/Greeter/Components/CustomTooltipContent.qml b/Greeter/Components/CustomTooltipContent.qml deleted file mode 100644 index fe297ad..0000000 --- a/Greeter/Components/CustomTooltipContent.qml +++ /dev/null @@ -1,55 +0,0 @@ -import QtQuick -import qs.Components -import ZShell.Config -import qs.Services - -Item { - id: root - - property real horizontalPadding: 10 - property bool isVisible: backgroundRectangle.implicitHeight > 0 - property bool shown: false - required property string text - property real verticalPadding: 5 - - implicitHeight: tooltipTextObject.implicitHeight + 2 * root.verticalPadding - implicitWidth: tooltipTextObject.implicitWidth + 2 * root.horizontalPadding - - Rectangle { - id: backgroundRectangle - - clip: true - color: Colors.tPalette.m3inverseSurface ?? "#3C4043" - implicitHeight: shown ? (tooltipTextObject.implicitHeight + 2 * root.verticalPadding) : 0 - implicitWidth: shown ? (tooltipTextObject.implicitWidth + 2 * root.horizontalPadding) : 0 - opacity: shown ? 1 : 0 - radius: Tokens.rounding.smallest - - Behavior on implicitHeight { - Anim { - } - } - Behavior on implicitWidth { - Anim { - } - } - Behavior on opacity { - Anim { - } - } - - anchors { - bottom: root.bottom - horizontalCenter: root.horizontalCenter - } - - CustomText { - id: tooltipTextObject - - anchors.centerIn: parent - color: Colors.palette.m3inverseOnSurface ?? "#FFFFFF" - text: root.text - wrapMode: Text.Wrap - } - } -} diff --git a/Greeter/Components/ExtraIndicator.qml b/Greeter/Components/ExtraIndicator.qml deleted file mode 100644 index 6ba3977..0000000 --- a/Greeter/Components/ExtraIndicator.qml +++ /dev/null @@ -1,44 +0,0 @@ -import ZShell.Config -import QtQuick -import qs.Services - -CustomRect { - required property int extra - - anchors.margins: 8 - anchors.right: parent.right - color: Colors.palette.m3tertiary - implicitHeight: count.implicitHeight + 4 * 2 - implicitWidth: count.implicitWidth + 8 * 2 - opacity: extra > 0 ? 1 : 0 - radius: Tokens.rounding.smallest - scale: extra > 0 ? 1 : 0.5 - - Behavior on opacity { - Anim { - type: Anim.FastEffects - } - } - Behavior on scale { - Anim { - type: Anim.FastEffects - } - } - - Elevation { - anchors.fill: parent - level: 2 - opacity: parent.opacity - radius: parent.radius - z: -1 - } - - CustomText { - id: count - - anchors.centerIn: parent - animate: parent.opacity > 0 - color: Colors.palette.m3onTertiary - text: qsTr("+%1").arg(parent.extra) - } -} diff --git a/Greeter/Components/FilledSlider.qml b/Greeter/Components/FilledSlider.qml deleted file mode 100644 index d901662..0000000 --- a/Greeter/Components/FilledSlider.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick -import ZShell.Config - -BaseStyledSlider { - id: root - - trackContent: Component { - Item { - property var groove - readonly property real handleHeight: handleItem ? handleItem.height : 0 - property var handleItem - readonly property real handleWidth: handleItem ? handleItem.width : 0 - - // Set by BaseStyledSlider's Loader - property var rootSlider - - anchors.fill: parent - - CustomRect { - color: rootSlider?.color - height: rootSlider?.isVertical ? handleHeight + (1 - rootSlider?.visualPosition) * (groove?.height - handleHeight) : groove?.height - radius: groove?.radius - width: rootSlider?.isHorizontal ? handleWidth + rootSlider?.visualPosition * (groove?.width - handleWidth) : groove?.width - x: rootSlider?.isHorizontal ? (rootSlider?.mirrored ? groove?.width - width : 0) : 0 - y: rootSlider?.isVertical ? groove?.height - height : 0 - } - } - } -} diff --git a/Greeter/Components/GradientSlider.qml b/Greeter/Components/GradientSlider.qml deleted file mode 100644 index ea60509..0000000 --- a/Greeter/Components/GradientSlider.qml +++ /dev/null @@ -1,47 +0,0 @@ -import QtQuick -import ZShell.Config - -BaseStyledSlider { - id: root - - property real alpha: 1.0 - property real brightness: 1.0 - property string channel: "saturation" - readonly property color currentColor: Qt.hsva(hue, channel === "saturation" ? value : saturation, channel === "brightness" ? value : brightness, alpha) - property real hue: 0.0 - property real saturation: 1.0 - - from: 0 - to: 1 - - trackContent: Component { - Item { - property var groove - property var handleItem - property var rootSlider - - anchors.fill: parent - - Rectangle { - anchors.fill: parent - antialiasing: true - color: "transparent" - radius: groove?.radius ?? 0 - - gradient: Gradient { - orientation: rootSlider?.isHorizontal ? Gradient.Horizontal : Gradient.Vertical - - GradientStop { - color: root.channel === "saturation" ? Qt.hsva(root.hue, 0.0, root.brightness, root.alpha) : Qt.hsva(root.hue, root.saturation, 0.0, root.alpha) - position: 0.0 - } - - GradientStop { - color: root.channel === "saturation" ? Qt.hsva(root.hue, 1.0, root.brightness, root.alpha) : Qt.hsva(root.hue, root.saturation, 1.0, root.alpha) - position: 1.0 - } - } - } - } - } -} diff --git a/Greeter/Components/HoverIconButton.qml b/Greeter/Components/HoverIconButton.qml deleted file mode 100644 index ab8999b..0000000 --- a/Greeter/Components/HoverIconButton.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick -import QtQuick.Controls -import ZShell.Config - -IconButton { - id: root - - required property bool shouldBeVisible - - opacity: 0 - scale: 0 - visible: root.scale > 0 - - Behavior on opacity { - Anim { - duration: Tokens.anim.durations.small - } - } - Behavior on scale { - Anim { - } - } - - onShouldBeVisibleChanged: { - if (root.shouldBeVisible) { - root.opacity = 1; - root.scale = 1; - } else { - root.opacity = 0; - root.scale = 0; - } - } -} diff --git a/Greeter/Components/IconButton.qml b/Greeter/Components/IconButton.qml deleted file mode 100644 index b8ccb71..0000000 --- a/Greeter/Components/IconButton.qml +++ /dev/null @@ -1,80 +0,0 @@ -import ZShell.Config -import QtQuick -import qs.Services - -CustomRect { - id: root - - enum Type { - Filled, - Tonal, - Text - } - - property color activeColour: type === IconButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondary - property color activeOnColour: type === IconButton.Filled ? Colors.palette.m3onPrimary : type === IconButton.Tonal ? Colors.palette.m3onSecondary : Colors.palette.m3primary - property bool checked - property bool disabled - property color disabledColour: Qt.alpha(Colors.palette.m3onSurface, 0.1) - property color disabledOnColour: Qt.alpha(Colors.palette.m3onSurface, 0.38) - property alias font: label.font - property alias icon: label.text - property color inactiveColour: { - if (!toggle && type === IconButton.Filled) - return Colors.palette.m3primary; - return type === IconButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer; - } - property color inactiveOnColour: { - if (!toggle && type === IconButton.Filled) - return Colors.palette.m3onPrimary; - return type === IconButton.Tonal ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onSurfaceVariant; - } - property bool internalChecked - property alias label: label - property real padding: type === IconButton.Text ? 10 / 2 : 7 - property alias radiusAnim: radiusAnim - property alias stateLayer: stateLayer - property bool toggle - property int type: IconButton.Filled - - signal clicked - - color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour - implicitHeight: label.implicitHeight + padding * 2 - implicitWidth: implicitHeight - radius: internalChecked ? 6 : (implicitHeight / 2 * Math.min(1, 1)) * Tokens.rounding.scale - - Behavior on radius { - Anim { - id: radiusAnim - } - } - - onCheckedChanged: internalChecked = checked - - StateLayer { - id: stateLayer - - color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour - disabled: root.disabled - - onClicked: { - if (root.toggle) - root.internalChecked = !root.internalChecked; - root.clicked(); - } - } - - MaterialIcon { - id: label - - anchors.centerIn: parent - color: root.disabled ? root.disabledOnColour : root.internalChecked ? root.activeOnColour : root.inactiveOnColour - fill: !root.toggle || root.internalChecked ? 1 : 0 - - Behavior on fill { - Anim { - } - } - } -} diff --git a/Greeter/Components/MarqueeText.qml b/Greeter/Components/MarqueeText.qml deleted file mode 100644 index 5f1322c..0000000 --- a/Greeter/Components/MarqueeText.qml +++ /dev/null @@ -1,224 +0,0 @@ -import QtQuick -import ZShell.Config -import qs.Services - -Item { - id: root - - property alias anim: marqueeAnim - property bool animate: false - property color color: Colors.palette.m3onSurface - property int fadeStrengthAnimMs: 180 - property real fadeStrengthIdle: 0.0 - property real fadeStrengthMoving: 1.0 - property alias font: elideText.font - property int gap: 40 - property alias horizontalAlignment: elideText.horizontalAlignment - property bool leftFadeEnabled: false - property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle - property int leftFadeWidth: 28 - property bool marqueeEnabled: true - readonly property bool overflowing: metrics.width > root.width - property int pauseMs: 1200 - property real pixelsPerSecond: 40 - property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle - property int rightFadeWidth: 28 - property bool sliding: false - property alias text: elideText.text - - function durationForDistance(px): int { - return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000)); - } - - function resetMarquee() { - marqueeAnim.stop(); - strip.x = 0; - root.sliding = false; - root.leftFadeEnabled = false; - - if (root.marqueeEnabled && root.overflowing && root.visible) { - marqueeAnim.restart(); - } - } - - clip: true - implicitHeight: elideText.implicitHeight - - Behavior on leftFadeStrength { - Anim { - } - } - Behavior on rightFadeStrength { - Anim { - } - } - - onTextChanged: resetMarquee() - onVisibleChanged: if (!visible) - resetMarquee() - onWidthChanged: resetMarquee() - - TextMetrics { - id: metrics - - font: elideText.font - text: elideText.text - } - - CustomText { - id: elideText - - anchors.verticalCenter: parent.verticalCenter - animate: root.animate - animateProp: "scale,opacity" - color: root.color - elide: Text.ElideNone - visible: !root.overflowing - width: root.width - } - - Item { - id: marqueeViewport - - anchors.fill: parent - clip: true - layer.enabled: true - visible: root.overflowing - - layer.effect: OpacityMask { - maskSource: rightFadeMask - } - - Item { - id: strip - - anchors.verticalCenter: parent.verticalCenter - height: t1.implicitHeight - width: t1.width + root.gap + t2.width - x: 0 - - CustomText { - id: t1 - - animate: root.animate - animateProp: "opacity" - color: root.color - font.pointSize: elideText.font.pointSize - text: elideText.text - } - - CustomText { - id: t2 - - animate: root.animate - animateProp: "opacity" - color: root.color - font.pointSize: elideText.font.pointSize - text: t1.text - x: t1.width + root.gap - } - } - - SequentialAnimation { - id: marqueeAnim - - running: false - - onFinished: pauseTimer.restart() - - ScriptAction { - script: { - root.sliding = true; - root.leftFadeEnabled = true; - } - } - - Anim { - duration: root.durationForDistance(t1.width) - easing.bezierCurve: Easing.Linear - easing.type: Easing.Linear - from: 0 - property: "x" - target: strip - to: -t1.width - } - - ScriptAction { - script: { - root.leftFadeEnabled = false; - } - } - - Anim { - duration: root.durationForDistance(root.gap) - easing.bezierCurve: Easing.Linear - easing.type: Easing.Linear - from: -t1.width - property: "x" - target: strip - to: -(t1.width + root.gap) - } - - ScriptAction { - script: { - root.sliding = false; - strip.x = 0; - } - } - } - - Timer { - id: pauseTimer - - interval: root.pauseMs - repeat: false - running: true - - onTriggered: { - if (root.marqueeEnabled) - marqueeAnim.start(); - } - } - } - - Rectangle { - id: rightFadeMask - - readonly property real fadeStartPos: { - const w = Math.max(1, width); - return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w)); - } - readonly property real leftFadeEndPos: { - const w = Math.max(1, width); - return Math.max(0, Math.min(1, root.leftFadeWidth / w)); - } - - anchors.fill: marqueeViewport - layer.enabled: true - visible: false - - gradient: Gradient { - orientation: Gradient.Horizontal - - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength) - position: 0.0 - } - - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0) - position: rightFadeMask.leftFadeEndPos - } - - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0) - position: rightFadeMask.fadeStartPos - } - - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength) - position: 1.0 - } - } - } -} diff --git a/Greeter/Components/Menu.qml b/Greeter/Components/Menu.qml deleted file mode 100644 index 9975af0..0000000 --- a/Greeter/Components/Menu.qml +++ /dev/null @@ -1,176 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell -import ZShell.Config -import qs.Drawers -import qs.Services - -MouseArea { - id: root - - enum Side { - Top, - Bottom, - Left, - Right - } - - property MenuItem active: items[0] ?? null - property int attachSideX: Menu.Right - property int attachSideY: Menu.Bottom - required property Item attachTo - property bool expanded - property list items - property real marginX - property real marginY - property int thisSideX: Menu.Right - property int thisSideY: Menu.Top - - signal itemSelected(item: MenuItem) - - anchors.fill: parent - enabled: expanded - layer.enabled: opacity < 1 - opacity: expanded ? 1 : 0 - parent: { - const win = QsWindow.window; - const contentWin = win as Windows; - return contentWin ? contentWin.interactionWrapper : (win as QsWindow).contentItem; - } - - Behavior on opacity { - Anim { - type: Anim.DefaultEffects - } - } - - onClicked: expanded = false - - TransformWatcher { - id: watcher - - a: root.parent - b: root.attachTo - } - - Elevation { - id: menu - - implicitHeight: column.implicitHeight + column.anchors.margins * 2 - implicitWidth: Math.max(200, column.implicitWidth + column.anchors.margins * 2) - level: 2 - radius: Tokens.rounding.medium - x: { - watcher.transform; - const item = root.attachTo; - let off = root.attachSideX === Menu.Left ? 0 : item.width; - if (root.thisSideX === Menu.Right) - off -= width; - return item.mapToItem(root.parent, off, 0).x + root.marginX; - } - y: { - watcher.transform; - const item = root.attachTo; - let off = root.attachSideY === Menu.Top ? 0 : item.height; - if (root.thisSideY === Menu.Bottom) - off -= height; - return item.mapToItem(root.parent, 0, off).y + root.marginY; - } - - transform: Scale { - origin.y: root.thisSideY === Menu.Bottom ? menu.height : 0 - yScale: root.expanded ? 1 : 0.1 - - Behavior on yScale { - Anim { - } - } - } - - CustomRect { - anchors.fill: parent - color: Colors.palette.m3surfaceContainerLow - radius: parent.radius - - ColumnLayout { - id: column - - anchors.fill: parent - anchors.margins: Tokens.padding.extraSmall - spacing: Tokens.spacing.extraSmall - - Repeater { - id: repeater - - model: root.items - - CustomRect { - id: item - - readonly property bool active: modelData === root.active - required property int index - required property MenuItem modelData - - Layout.fillWidth: true - color: Qt.alpha(Colors.palette.m3tertiaryContainer, active ? 1 : 0) - implicitHeight: menuOptionRow.implicitHeight + Tokens.padding.larger * 2 - implicitWidth: menuOptionRow.implicitWidth + Tokens.padding.larger * 2 - radius: Tokens.rounding.small - - Behavior on radius { - Anim { - } - } - - StateLayer { - color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface - disabled: !root.expanded - - onClicked: { - root.itemSelected(item.modelData); - root.active = item.modelData; - item.modelData.clicked(); - root.expanded = false; - } - } - - RowLayout { - id: menuOptionRow - - anchors.fill: parent - anchors.margins: Tokens.padding.larger - spacing: Tokens.spacing.small - - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant - text: item.modelData.icon - } - - CustomText { - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface - text: item.modelData.text - } - - Loader { - Layout.alignment: Qt.AlignVCenter - active: item.modelData.trailingIcon.length > 0 - asynchronous: true - visible: active - - sourceComponent: MaterialIcon { - color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant - text: item.modelData.trailingIcon - } - } - } - } - } - } - } - } -} diff --git a/Greeter/Components/MenuItem.qml b/Greeter/Components/MenuItem.qml deleted file mode 100644 index 2378dd9..0000000 --- a/Greeter/Components/MenuItem.qml +++ /dev/null @@ -1,12 +0,0 @@ -import QtQuick - -QtObject { - property string activeIcon: icon - property string activeText: text - property string icon - required property string text - property string trailingIcon - property var value - - signal clicked -} diff --git a/Greeter/Components/PathMenu.qml b/Greeter/Components/PathMenu.qml deleted file mode 100644 index 0e2d10d..0000000 --- a/Greeter/Components/PathMenu.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick - -Path { - id: root - - required property real viewHeight - required property real viewWidth - - startX: root.viewWidth / 2 - startY: 0 - - PathAttribute { - name: "itemOpacity" - value: 0.25 - } - - PathLine { - x: root.viewWidth / 2 - y: root.viewHeight * (1 / 6) - } - - PathAttribute { - name: "itemOpacity" - value: 0.45 - } - - PathLine { - x: root.viewWidth / 2 - y: root.viewHeight * (2 / 6) - } - - PathAttribute { - name: "itemOpacity" - value: 0.70 - } - - PathLine { - x: root.viewWidth / 2 - y: root.viewHeight * (3 / 6) - } - - PathAttribute { - name: "itemOpacity" - value: 1.00 - } - - PathLine { - x: root.viewWidth / 2 - y: root.viewHeight * (4 / 6) - } - - PathAttribute { - name: "itemOpacity" - value: 0.70 - } - - PathLine { - x: root.viewWidth / 2 - y: root.viewHeight * (5 / 6) - } - - PathAttribute { - name: "itemOpacity" - value: 0.45 - } - - PathLine { - x: root.viewWidth / 2 - y: root.viewHeight - } - - PathAttribute { - name: "itemOpacity" - value: 0.25 - } -} diff --git a/Greeter/Components/PathViewMenu.qml b/Greeter/Components/PathViewMenu.qml deleted file mode 100644 index 3af3c1a..0000000 --- a/Greeter/Components/PathViewMenu.qml +++ /dev/null @@ -1,181 +0,0 @@ -import QtQuick -import QtQuick.Effects -import ZShell.Config -import qs.Services - -Elevation { - id: root - - required property int currentIndex - property bool expanded - required property int from - property color insideTextColor: Colors.palette.m3onPrimary - property int itemHeight - property int listHeight: 200 - property color outsideTextColor: Colors.palette.m3onSurfaceVariant - readonly property var spinnerModel: root.range(root.from, root.to) - required property int to - property Item triggerItem - - signal itemSelected(item: int) - - function range(first, last) { - let out = []; - for (let i = first; i <= last; ++i) - out.push(i); - return out; - } - - implicitHeight: root.expanded ? view.implicitHeight : 0 - level: root.expanded ? 2 : 0 - radius: itemHeight / 2 - visible: implicitHeight > 0 - z: root.expanded ? 100 : 0 - - Behavior on implicitHeight { - Anim { - } - } - - onExpandedChanged: { - if (!root.expanded) - root.itemSelected(view.currentIndex + 1); - } - - Component { - id: spinnerDelegate - - Item { - id: wrapper - - readonly property color delegateTextColor: wrapper.PathView.view ? wrapper.PathView.view.delegateTextColor : "white" - required property var modelData - - height: root.itemHeight - opacity: wrapper.PathView.itemOpacity - visible: wrapper.PathView.onPath - width: wrapper.PathView.view ? wrapper.PathView.view.width : 0 - z: wrapper.PathView.isCurrentItem ? 100 : Math.round(wrapper.PathView.itemScale * 100) - - CustomText { - anchors.centerIn: parent - color: wrapper.delegateTextColor - font.pointSize: Tokens.font.size.large - text: wrapper.modelData - } - } - } - - CustomClippingRect { - anchors.fill: parent - color: Colors.palette.m3surfaceContainer - radius: parent.radius - z: root.z - - // Main visible spinner: normal/outside text color - PathView { - id: view - - property color delegateTextColor: root.outsideTextColor - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - clip: true - currentIndex: root.currentIndex - 1 - delegate: spinnerDelegate - dragMargin: width - highlightRangeMode: PathView.StrictlyEnforceRange - implicitHeight: root.listHeight - model: root.spinnerModel - pathItemCount: 7 - preferredHighlightBegin: 0.5 - preferredHighlightEnd: 0.5 - snapMode: PathView.SnapToItem - - path: PathMenu { - viewHeight: view.height - viewWidth: view.width - } - } - - // The selection rectangle itself - CustomRect { - id: selectionRect - - anchors.verticalCenter: parent.verticalCenter - color: Colors.palette.m3primary - height: root.itemHeight - radius: root.itemHeight / 2 - width: parent.width - z: 2 - } - - // Hidden source: same PathView, but with the "inside selection" text color - Item { - id: selectedTextSource - - anchors.fill: parent - layer.enabled: true - visible: false - - PathView { - id: selectedTextView - - property color delegateTextColor: root.insideTextColor - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - clip: true - currentIndex: view.currentIndex - delegate: spinnerDelegate - dragMargin: view.dragMargin - highlightRangeMode: view.highlightRangeMode - implicitHeight: root.listHeight - interactive: false - model: view.model - - // Keep this PathView visually locked to the real one - offset: view.offset - pathItemCount: view.pathItemCount - preferredHighlightBegin: view.preferredHighlightBegin - preferredHighlightEnd: view.preferredHighlightEnd - snapMode: view.snapMode - - path: PathMenu { - viewHeight: selectedTextView.height - viewWidth: selectedTextView.width - } - } - } - - // Mask matching the selection rectangle - Item { - id: selectionMask - - anchors.fill: parent - layer.enabled: true - visible: false - - CustomRect { - color: "white" - height: selectionRect.height - radius: selectionRect.radius - width: selectionRect.width - x: selectionRect.x - y: selectionRect.y - } - } - - // Only show the "inside selection" text where the mask exists - MultiEffect { - anchors.fill: selectedTextSource - maskEnabled: true - maskInverted: false - maskSource: selectionMask - source: selectedTextSource - z: 3 - } - } -} diff --git a/Greeter/Components/Ref.qml b/Greeter/Components/Ref.qml deleted file mode 100644 index 14f03d6..0000000 --- a/Greeter/Components/Ref.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick - -QtObject { - required property var service - - Component.onCompleted: service.refCount++ - Component.onDestruction: service.refCount-- -} diff --git a/Greeter/Components/SpinBoxRow.qml b/Greeter/Components/SpinBoxRow.qml deleted file mode 100644 index 7afb7d0..0000000 --- a/Greeter/Components/SpinBoxRow.qml +++ /dev/null @@ -1,51 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import ZShell.Config -import qs.Services - -CustomRect { - id: root - - required property string label - required property real max - required property real min - property var onValueModified: function (value) {} - property real step: 1 - required property real value - - Layout.fillWidth: true - color: Colors.layer(Colors.palette.m3surfaceContainer, 2) - implicitHeight: row.implicitHeight + Tokens.padding.large * 2 - radius: Tokens.rounding.normal - - Behavior on implicitHeight { - Anim { - } - } - - RowLayout { - id: row - - anchors.left: parent.left - anchors.margins: Tokens.padding.large - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Tokens.spacing.normal - - CustomText { - Layout.fillWidth: true - text: root.label - } - - CustomSpinBox { - max: root.max - min: root.min - step: root.step - value: root.value - - onValueModified: value => { - root.onValueModified(value); - } - } - } -} diff --git a/Greeter/Components/StateLayer.qml b/Greeter/Components/StateLayer.qml index 6399662..e228449 100644 --- a/Greeter/Components/StateLayer.qml +++ b/Greeter/Components/StateLayer.qml @@ -66,7 +66,6 @@ MouseArea { if (!(pressed || manualPressOverride) && circleRadius > endRadiusAtPress * 0.99 && !fadeAnim.running) fadeAnim.start(); } - onClicked: event => !disabled && onClicked(event) onManualPressOverrideChanged: { if (!(pressed || manualPressOverride) && circleRadius > endRadiusAtPress * 0.99 && !fadeAnim.running) fadeAnim.start(); diff --git a/Greeter/Components/Toast/ToastItem.qml b/Greeter/Components/Toast/ToastItem.qml deleted file mode 100644 index 997cd06..0000000 --- a/Greeter/Components/Toast/ToastItem.qml +++ /dev/null @@ -1,132 +0,0 @@ -import ZShell -import QtQuick -import QtQuick.Layouts -import qs.Components -import ZShell.Config -import qs.Services - -CustomRect { - id: root - - required property Toast modelData - - anchors.left: parent.left - anchors.right: parent.right - border.color: { - let colour = Colors.palette.m3outlineVariant; - if (root.modelData.type === Toast.Success) - colour = Colors.palette.m3success; - if (root.modelData.type === Toast.Warning) - colour = Colors.palette.m3secondaryContainer; - if (root.modelData.type === Toast.Error) - colour = Colors.palette.m3error; - return Qt.alpha(colour, 0.3); - } - border.width: 1 - color: { - if (root.modelData.type === Toast.Success) - return Colors.palette.m3successContainer; - if (root.modelData.type === Toast.Warning) - return Colors.palette.m3secondary; - if (root.modelData.type === Toast.Error) - return Colors.palette.m3errorContainer; - return Colors.palette.m3surface; - } - implicitHeight: layout.implicitHeight + Tokens.padding.smaller * 2 - radius: Tokens.rounding.normal - - Behavior on border.color { - CAnim { - } - } - - Elevation { - anchors.fill: parent - level: 3 - opacity: parent.opacity - radius: parent.radius - z: -1 - } - - RowLayout { - id: layout - - anchors.fill: parent - anchors.leftMargin: Tokens.padding.normal - anchors.margins: Tokens.padding.smaller - anchors.rightMargin: Tokens.padding.normal - spacing: Tokens.spacing.normal - - CustomRect { - color: { - if (root.modelData.type === Toast.Success) - return Colors.palette.m3success; - if (root.modelData.type === Toast.Warning) - return Colors.palette.m3secondaryContainer; - if (root.modelData.type === Toast.Error) - return Colors.palette.m3error; - return Colors.palette.m3surfaceContainerHigh; - } - implicitHeight: icon.implicitHeight + Tokens.padding.smaller * 2 - implicitWidth: implicitHeight - radius: Tokens.rounding.normal - - MaterialIcon { - id: icon - - anchors.centerIn: parent - color: { - if (root.modelData.type === Toast.Success) - return Colors.palette.m3onSuccess; - if (root.modelData.type === Toast.Warning) - return Colors.palette.m3onSecondaryContainer; - if (root.modelData.type === Toast.Error) - return Colors.palette.m3onError; - return Colors.palette.m3onSurfaceVariant; - } - font.pointSize: Math.round(Tokens.font.size.large * 1.2) - text: root.modelData.icon - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: 0 - - CustomText { - id: title - - Layout.fillWidth: true - color: { - if (root.modelData.type === Toast.Success) - return Colors.palette.m3onSuccessContainer; - if (root.modelData.type === Toast.Warning) - return Colors.palette.m3onSecondary; - if (root.modelData.type === Toast.Error) - return Colors.palette.m3onErrorContainer; - return Colors.palette.m3onSurface; - } - elide: Text.ElideRight - font.pointSize: Tokens.font.size.normal - text: root.modelData.title - } - - CustomText { - Layout.fillWidth: true - color: { - if (root.modelData.type === Toast.Success) - return Colors.palette.m3onSuccessContainer; - if (root.modelData.type === Toast.Warning) - return Colors.palette.m3onSecondary; - if (root.modelData.type === Toast.Error) - return Colors.palette.m3onErrorContainer; - return Colors.palette.m3onSurface; - } - elide: Text.ElideRight - opacity: 0.8 - text: root.modelData.message - textFormat: Text.StyledText - } - } - } -} diff --git a/Greeter/Components/Toast/Toasts.qml b/Greeter/Components/Toast/Toasts.qml deleted file mode 100644 index feab2e8..0000000 --- a/Greeter/Components/Toast/Toasts.qml +++ /dev/null @@ -1,142 +0,0 @@ -pragma ComponentBehavior: Bound - -import ZShell -import Quickshell -import QtQuick -import qs.Components -import ZShell.Config - -Item { - id: root - - property bool flag - readonly property int spacing: Tokens.spacing.small - - implicitHeight: { - let h = -spacing; - for (let i = 0; i < repeater.count; i++) { - const item = repeater.itemAt(i) as ToastWrapper; - if (!item.modelData.closed && !item.previewHidden) - h += item.implicitHeight + spacing; - } - return h; - } - implicitWidth: Config.utilities.sizes.toastWidth - Tokens.padding.normal * 2 - - Repeater { - id: repeater - - model: ScriptModel { - values: { - const toasts = []; - let count = 0; - for (const toast of Toaster.toasts) { - toasts.push(toast); - if (!toast.closed) { - count++; - if (count > Config.utilities.maxToasts) - break; - } - } - return toasts; - } - - onValuesChanged: root.flagChanged() - } - - ToastWrapper { - } - } - - component ToastWrapper: MouseArea { - id: toast - - required property int index - required property Toast modelData - readonly property bool previewHidden: { - let extraHidden = 0; - for (let i = 0; i < index; i++) - if (Toaster.toasts[i].closed) - extraHidden++; - return index >= Config.utilities.maxToasts + extraHidden; - } - - acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton - anchors.bottom: parent.bottom - anchors.bottomMargin: { - root.flag; // Force update - let y = 0; - for (let i = 0; i < index; i++) { - const item = repeater.itemAt(i) as ToastWrapper; - if (item && !item.modelData.closed && !item.previewHidden) - y += item.implicitHeight + root.spacing; - } - return y; - } - anchors.left: parent.left - anchors.right: parent.right - implicitHeight: toastInner.implicitHeight - opacity: modelData.closed || previewHidden ? 0 : 1 - scale: modelData.closed || previewHidden ? 0.7 : 1 - - Behavior on anchors.bottomMargin { - Anim { - duration: Tokens.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Tokens.anim.curves.expressiveDefaultSpatial - } - } - Behavior on opacity { - Anim { - } - } - Behavior on scale { - Anim { - } - } - - Component.onCompleted: modelData.lock(this) - onClicked: modelData.close() - onPreviewHiddenChanged: { - if (initAnim.running && previewHidden) - initAnim.stop(); - } - - Anim { - id: initAnim - - duration: Tokens.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Tokens.anim.curves.expressiveDefaultSpatial - from: 0 - properties: "opacity,scale" - target: toast - to: 1 - - Component.onCompleted: running = !toast.previewHidden - } - - ParallelAnimation { - running: toast.modelData.closed - - onFinished: toast.modelData.unlock(toast) - onStarted: toast.anchors.bottomMargin = toast.anchors.bottomMargin - - Anim { - property: "opacity" - target: toast - to: 0 - } - - Anim { - property: "scale" - target: toast - to: 0.7 - } - } - - ToastItem { - id: toastInner - - modelData: toast.modelData - } - } -} diff --git a/Greeter/Config/AccentColor.qml b/Greeter/Config/AccentColor.qml deleted file mode 100644 index 82a0157..0000000 --- a/Greeter/Config/AccentColor.qml +++ /dev/null @@ -1,13 +0,0 @@ -import Quickshell.Io - -JsonObject { - property Accents accents: Accents { - } - - component Accents: JsonObject { - property string primary: "#4080ff" - property string primaryAlt: "#60a0ff" - property string warning: "#ff6b6b" - property string warningAlt: "#ff8787" - } -} diff --git a/Greeter/Config/Appearance.qml b/Greeter/Config/Appearance.qml deleted file mode 100644 index 7be277e..0000000 --- a/Greeter/Config/Appearance.qml +++ /dev/null @@ -1,13 +0,0 @@ -pragma Singleton - -import Quickshell - -Singleton { - readonly property AppearanceConf.Anim anim: Config.appearance.anim - readonly property AppearanceConf.Deform deform: Config.appearance.deform - readonly property AppearanceConf.FontStuff font: Config.appearance.font - readonly property AppearanceConf.Padding padding: Config.appearance.padding - readonly property AppearanceConf.Rounding rounding: Config.appearance.rounding - readonly property AppearanceConf.Spacing spacing: Config.appearance.spacing - readonly property AppearanceConf.Transparency transparency: Config.appearance.transparency -} diff --git a/Greeter/Config/AppearanceConf.qml b/Greeter/Config/AppearanceConf.qml deleted file mode 100644 index 859e0a3..0000000 --- a/Greeter/Config/AppearanceConf.qml +++ /dev/null @@ -1,114 +0,0 @@ -import Quickshell.Io - -JsonObject { - property Anim anim: Anim { - } - property Deform deform: Deform { - } - property FontStuff font: FontStuff { - } - property Padding padding: Padding { - } - property Rounding rounding: Rounding { - } - property Spacing spacing: Spacing { - } - property Transparency transparency: Transparency { - } - - component Anim: JsonObject { - property AnimCurves curves: AnimCurves { - } - property AnimDurations durations: AnimDurations { - } - property real mediaGifSpeedAdjustment: 300 - property real sessionGifSpeed: 0.7 - } - component AnimCurves: JsonObject { - property list emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] - property list emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] - property list emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] - property list expressiveDefaultEffects: [0.34, 0.8, 0.34, 1, 1, 1] - property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1] - property list expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1] - property list expressiveFastEffects: [0.31, 0.94, 0.34, 1, 1, 1] - property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1] - property list expressiveSlowEffects: [0.34, 0.88, 0.34, 1, 1, 1] - property list expressiveSlowSpatial: [0.39, 1.29, 0.35, 0.98, 1, 1] - property list standard: [0.2, 0, 0, 1, 1, 1] - property list standardAccel: [0.3, 0, 1, 1, 1, 1] - property list standardDecel: [0, 0, 0, 1, 1, 1] - } - component AnimDurations: JsonObject { - property int expressiveDefaultSpatial: 500 * scale - property int expressiveEffects: 200 * scale - property int expressiveFastEffects: 150 * scale - property int expressiveFastSpatial: 350 * scale - property int expressiveSlowEffects: 300 * scale - property int extraLarge: 1000 * scale - property int large: 600 * scale - property int normal: 400 * scale - property real scale: 1 - property int small: 200 * scale - } - component Deform: JsonObject { - property real scale: 1 - } - component FontFamily: JsonObject { - property string clock: "Rubik" - property string material: "Material Symbols Rounded" - property string mono: "CaskaydiaCove NF" - property string sans: "Segoe UI Variable Text" - } - component FontSize: JsonObject { - property int extraLarge: 28 * scale - property int large: 18 * scale - property int larger: 16 * scale - property int medium: 14 * scale - property int normal: 13 * scale - property real scale: 1 - property int small: 11 * scale - property int smaller: 12 * scale - } - component FontStuff: JsonObject { - property FontFamily family: FontFamily { - } - property FontSize size: FontSize { - } - } - component Padding: JsonObject { - property int extraLargeIncreased: 32 * scale - property int extraSmall: 4 * scale - property int large: 16 * scale - property int larger: 12 * scale - property int normal: 8 * scale - property real scale: 1 - property int small: 5 * scale - property int smaller: 7 * scale - property int smallest: 2 * scale - } - component Rounding: JsonObject { - property int extraSmall: 4 * scale - property int full: 1000 * scale - property int large: 24 * scale - property int medium: 16 * scale - property int normal: 18 * scale - property real scale: 1 - property int small: 12 * scale - property int smallest: 8 * scale - } - component Spacing: JsonObject { - property int extraSmall: 4 * scale - property int large: 20 * scale - property int larger: 16 * scale - property int normal: 12 * scale - property real scale: 1 - property int small: 8 * scale - property int smaller: 10 * scale - } - component Transparency: JsonObject { - property real base: 0.85 - property bool enabled: false - property real layers: 0.4 - } -} diff --git a/Greeter/Config/BackgroundConfig.qml b/Greeter/Config/BackgroundConfig.qml deleted file mode 100644 index 36a386a..0000000 --- a/Greeter/Config/BackgroundConfig.qml +++ /dev/null @@ -1,14 +0,0 @@ -import Quickshell.Io -import ZShell.Config - -JsonObject { - property bool enabled: true - property int wallFadeDuration: MaterialEasing.standardTime - property real alignX: 0.5 - property real alignY: 0.5 - property real zoom: 1.0 - property real sourceClipX: 0 - property real sourceClipY: 0 - property real sourceClipW: 0 - property real sourceClipH: 0 -} diff --git a/Greeter/Config/BarConfig.qml b/Greeter/Config/BarConfig.qml deleted file mode 100644 index 0f489ef..0000000 --- a/Greeter/Config/BarConfig.qml +++ /dev/null @@ -1,77 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool autoHide: false - property int border: 8 - property list entries: [ - { - id: "workspaces", - enabled: true - }, - { - id: "media", - enabled: true - }, - { - id: "resources", - enabled: true - }, - { - id: "updates", - enabled: true - }, - { - id: "spacer", - enabled: true - }, - { - id: "activeWindow", - enabled: true - }, - { - id: "spacer", - enabled: true - }, - { - id: "hyprsunset", - enabled: true - }, - { - id: "tray", - enabled: true - }, - { - id: "network", - enabled: false - }, - { - id: "clock", - enabled: true - }, - { - id: "notifBell", - enabled: true - }, - ] - property int height: 34 - property bool hideWhenNotif: false - property Popouts popouts: Popouts { - } - property int rounding: 8 - property int smoothing: 32 - property Tray tray: Tray { - } - - component Popouts: JsonObject { - property bool activeWindow: true - property bool audio: true - property bool clock: true - property bool network: true - property bool resources: true - property bool tray: true - property bool upower: true - } - component Tray: JsonObject { - property int trayIconSize: 24 - } -} diff --git a/Greeter/Config/Colors.qml b/Greeter/Config/Colors.qml deleted file mode 100644 index 3b99070..0000000 --- a/Greeter/Config/Colors.qml +++ /dev/null @@ -1,13 +0,0 @@ -import Quickshell.Io - -JsonObject { - property Presets presets: Presets { - } - property string schemeType: "vibrant" - - component Presets: JsonObject { - property string accent: "" - property string name: "" - property string variant: "" - } -} diff --git a/Greeter/Config/Config.qml b/Greeter/Config/Config.qml deleted file mode 100644 index decd07c..0000000 --- a/Greeter/Config/Config.qml +++ /dev/null @@ -1,474 +0,0 @@ -pragma Singleton - -import Quickshell -import Quickshell.Io -import ZShell -import QtQuick - -Singleton { - id: root - - property alias appearance: adapter.appearance - property alias background: adapter.background - property alias barConfig: adapter.barConfig - property alias colors: adapter.colors - property alias dashboard: adapter.dashboard - property alias dock: adapter.dock - property alias general: adapter.general - property alias launcher: adapter.launcher - property alias lock: adapter.lock - property alias notifs: adapter.notifs - property alias osd: adapter.osd - property alias overview: adapter.overview - property bool recentlySaved: false - property alias screenshot: adapter.screenshot - property alias services: adapter.services - property alias sidebar: adapter.sidebar - property alias utilities: adapter.utilities - - function save(): void { - saveTimer.restart(); - recentlySaved = true; - recentSaveCooldown.restart(); - } - - function saveNoToast(): void { - saveTimer.restart(); - } - - function serializeAppearance(): var { - return { - rounding: { - scale: appearance.rounding.scale - }, - spacing: { - scale: appearance.spacing.scale - }, - padding: { - scale: appearance.padding.scale - }, - deform: { - scale: appearance.deform.scale - }, - font: { - family: { - sans: appearance.font.family.sans, - mono: appearance.font.family.mono, - material: appearance.font.family.material, - clock: appearance.font.family.clock - }, - size: { - scale: appearance.font.size.scale - } - }, - anim: { - mediaGifSpeedAdjustment: appearance.anim.mediaGifSpeedAdjustment, - sessionGifSpeed: appearance.anim.sessionGifSpeed, - durations: { - scale: appearance.anim.durations.scale - } - }, - transparency: { - enabled: appearance.transparency.enabled, - base: appearance.transparency.base, - layers: appearance.transparency.layers - } - }; - } - - function serializeBackground(): var { - return { - wallFadeDuration: background.wallFadeDuration, - enabled: background.enabled, - alignX: background.alignX, - sourceClipX: background.sourceClipX, - sourceClipY: background.sourceClipY, - sourceClipW: background.sourceClipW, - sourceClipH: background.sourceClipH, - alignY: background.alignY, - zoom: background.zoom - }; - } - - function serializeBar(): var { - return { - autoHide: barConfig.autoHide, - hideWhenNotif: barConfig.hideWhenNotif, - rounding: barConfig.rounding, - border: barConfig.border, - smoothing: barConfig.smoothing, - height: barConfig.height, - tray: { - trayIconSize: barConfig.tray.trayIconSize - }, - popouts: { - tray: barConfig.popouts.tray, - audio: barConfig.popouts.audio, - activeWindow: barConfig.popouts.activeWindow, - resources: barConfig.popouts.resources, - clock: barConfig.popouts.clock, - network: barConfig.popouts.network, - upower: barConfig.popouts.upower - }, - entries: barConfig.entries - }; - } - - function serializeColors(): var { - return { - schemeType: colors.schemeType, - presets: { - name: colors.presets.name, - variant: colors.presets.variant, - accent: colors.presets.accent - } - }; - } - - function serializeConfig(): var { - return { - barConfig: serializeBar(), - lock: serializeLock(), - general: serializeGeneral(), - services: serializeServices(), - notifs: serializeNotifs(), - sidebar: serializeSidebar(), - utilities: serializeUtilities(), - dashboard: serializeDashboard(), - appearance: serializeAppearance(), - osd: serializeOsd(), - background: serializeBackground(), - launcher: serializeLauncher(), - colors: serializeColors(), - dock: serializeDock(), - screenshot: serializeScreenshot() - }; - } - - function serializeDashboard(): var { - return { - enabled: dashboard.enabled, - mediaUpdateInterval: dashboard.mediaUpdateInterval, - resourceUpdateInterval: dashboard.resourceUpdateInterval, - dragThreshold: dashboard.dragThreshold, - performance: { - showBattery: dashboard.performance.showBattery, - showGpu: dashboard.performance.showGpu, - showCpu: dashboard.performance.showCpu, - showMemory: dashboard.performance.showMemory, - showStorage: dashboard.performance.showStorage, - showNetwork: dashboard.performance.showNetwork - }, - sizes: { - tabIndicatorHeight: dashboard.sizes.tabIndicatorHeight, - tabIndicatorSpacing: dashboard.sizes.tabIndicatorSpacing, - infoWidth: dashboard.sizes.infoWidth, - infoIconSize: dashboard.sizes.infoIconSize, - dateTimeWidth: dashboard.sizes.dateTimeWidth, - mediaWidth: dashboard.sizes.mediaWidth, - mediaProgressSweep: dashboard.sizes.mediaProgressSweep, - mediaProgressThickness: dashboard.sizes.mediaProgressThickness, - resourceProgessThickness: dashboard.sizes.resourceProgessThickness, - weatherWidth: dashboard.sizes.weatherWidth, - mediaCoverArtSize: dashboard.sizes.mediaCoverArtSize, - mediaVisualiserSize: dashboard.sizes.mediaVisualiserSize, - resourceSize: dashboard.sizes.resourceSize - } - }; - } - - function serializeDock(): var { - return { - enable: dock.enable, - height: dock.height, - hoverToReveal: dock.hoverToReveal, - pinnedApps: dock.pinnedApps, - pinnedOnStartup: dock.pinnedOnStartup, - ignoredAppRegexes: dock.ignoredAppRegexes - }; - } - - function serializeGeneral(): var { - return { - logo: general.logo, - wallpaperPath: general.wallpaperPath, - desktopIcons: general.desktopIcons, - dateFormat: general.dateFormat, - color: { - mode: general.color.mode, - smart: general.color.smart, - scheduleDark: general.color.scheduleDark, - scheduleHyprsunset: general.color.scheduleHyprsunset, - scheduleHyprsunsetStart: general.color.scheduleHyprsunsetStart, - hyprsunsetTemp: general.color.hyprsunsetTemp, - scheduleHyprsunsetEnd: general.color.scheduleHyprsunsetEnd, - schemeGeneration: general.color.schemeGeneration, - scheduleDarkStart: general.color.scheduleDarkStart, - scheduleDarkEnd: general.color.scheduleDarkEnd, - neovimColors: general.color.neovimColors - }, - apps: { - terminal: general.apps.terminal, - audio: general.apps.audio, - playback: general.apps.playback, - explorer: general.apps.explorer - }, - idle: { - timeouts: general.idle.timeouts - }, - battery: { - popupThresholds: general.battery.popupThresholds, - critPerc: general.battery.critPerc - } - }; - } - - function serializeLauncher(): var { - return { - maxAppsShown: launcher.maxAppsShown, - maxWallpapers: launcher.maxWallpapers, - uwsm: launcher.uwsm, - actionPrefix: launcher.actionPrefix, - specialPrefix: launcher.specialPrefix, - useFuzzy: { - apps: launcher.useFuzzy.apps, - actions: launcher.useFuzzy.actions, - schemes: launcher.useFuzzy.schemes, - variants: launcher.useFuzzy.variants, - wallpapers: launcher.useFuzzy.wallpapers - }, - sizes: { - itemWidth: launcher.sizes.itemWidth, - itemHeight: launcher.sizes.itemHeight, - wallpaperWidth: launcher.sizes.wallpaperWidth, - wallpaperHeight: launcher.sizes.wallpaperHeight - }, - actions: launcher.actions - }; - } - - function serializeLock(): var { - return { - recolorLogo: lock.recolorLogo, - enableFprint: lock.enableFprint, - showNotifContent: lock.showNotifContent, - showNotifIcon: lock.showNotifIcon, - maxFprintTries: lock.maxFprintTries, - blurAmount: lock.blurAmount, - sizes: { - heightMult: lock.sizes.heightMult, - ratio: lock.sizes.ratio, - centerWidth: lock.sizes.centerWidth - } - }; - } - - function serializeNotifs(): var { - return { - expire: notifs.expire, - defaultExpireTimeout: notifs.defaultExpireTimeout, - appNotifCooldown: notifs.appNotifCooldown, - clearThreshold: notifs.clearThreshold, - expandThreshold: notifs.expandThreshold, - actionOnClick: notifs.actionOnClick, - groupPreviewNum: notifs.groupPreviewNum, - sizes: { - width: notifs.sizes.width, - image: notifs.sizes.image, - badge: notifs.sizes.badge - } - }; - } - - function serializeOsd(): var { - return { - enabled: osd.enabled, - hideDelay: osd.hideDelay, - enableBrightness: osd.enableBrightness, - enableMicrophone: osd.enableMicrophone, - allMonBrightness: osd.allMonBrightness, - sizes: { - sliderWidth: osd.sizes.sliderWidth, - sliderHeight: osd.sizes.sliderHeight - } - }; - } - - function serializeScreenshot(): var { - return { - enable_pp: screenshot.enable_pp, - mode: screenshot.mode, - radius: screenshot.radius, - shadow: screenshot.shadow, - rounding: screenshot.rounding, - shadow_blur: screenshot.shadow_blur, - shadow_color: screenshot.shadow_color, - shadow_offset_x: screenshot.shadow_offset_x, - shadow_offset_y: screenshot.shadow_offset_y - }; - } - - function serializeServices(): var { - return { - weatherLocation: services.weatherLocation, - updates: services.updates, - useFahrenheit: services.useFahrenheit, - ddcutilService: services.ddcutilService, - useTwelveHourClock: services.useTwelveHourClock, - gpuType: services.gpuType, - audioIncrement: services.audioIncrement, - brightnessIncrement: services.brightnessIncrement, - maxVolume: services.maxVolume, - defaultPlayer: services.defaultPlayer, - playerAliases: services.playerAliases, - visualizerBars: services.visualizerBars - }; - } - - function serializeSidebar(): var { - return { - enabled: sidebar.enabled, - sizes: { - width: sidebar.sizes.width - } - }; - } - - function serializeUtilities(): var { - return { - enabled: utilities.enabled, - maxToasts: utilities.maxToasts, - sizes: { - width: utilities.sizes.width, - toastWidth: utilities.sizes.toastWidth - }, - toasts: { - configLoaded: utilities.toasts.configLoaded, - chargingChanged: utilities.toasts.chargingChanged, - gameModeChanged: utilities.toasts.gameModeChanged, - dndChanged: utilities.toasts.dndChanged, - audioOutputChanged: utilities.toasts.audioOutputChanged, - audioInputChanged: utilities.toasts.audioInputChanged, - capsLockChanged: utilities.toasts.capsLockChanged, - numLockChanged: utilities.toasts.numLockChanged, - kbLayoutChanged: utilities.toasts.kbLayoutChanged, - vpnChanged: utilities.toasts.vpnChanged, - nowPlaying: utilities.toasts.nowPlaying - }, - vpn: { - enabled: utilities.vpn.enabled, - provider: utilities.vpn.provider - } - }; - } - - ElapsedTimer { - id: timer - } - - Timer { - id: saveTimer - - interval: 500 - - onTriggered: { - timer.restart(); - try { - let config = {}; - try { - config = JSON.parse(fileView.text()); - } catch (e) { - config = {}; - } - - config = root.serializeConfig(); - - fileView.setText(JSON.stringify(config, null, 4)); - } catch (e) { - Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error); - } - } - } - - Timer { - id: recentSaveCooldown - - interval: 2000 - - onTriggered: { - root.recentlySaved = false; - } - } - - FileView { - id: fileView - - path: "/etc/zshell-greeter/config.json" - watchChanges: true - - onFileChanged: { - if (!root.recentlySaved) { - timer.restart(); - reload(); - } else { - reload(); - } - } - onLoadFailed: err => { - if (err !== FileViewError.FileNotFound) - Toaster.toast(qsTr("Failed to read config"), FileViewError.toString(err), "settings_alert", Toast.Warning); - } - onLoaded: { - try { - JSON.parse(text()); - const elapsed = timer.elapsedMs(); - - if (adapter.utilities.toasts.configLoaded && !root.recentlySaved) { - Toaster.toast(qsTr("Config loaded"), qsTr("Config loaded in %1ms").arg(elapsed), "rule_settings"); - } else if (adapter.utilities.toasts.configLoaded && root.recentlySaved) { - Toaster.toast(qsTr("Config saved"), qsTr("Config reloaded in %1ms").arg(elapsed), "settings_alert"); - } - } catch (e) { - Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error); - } - } - onSaveFailed: err => Toaster.toast(qsTr("Failed to save config"), FileViewError.toString(err), "settings_alert", Toast.Error) - - JsonAdapter { - id: adapter - - property AppearanceConf appearance: AppearanceConf { - } - property BackgroundConfig background: BackgroundConfig { - } - property BarConfig barConfig: BarConfig { - } - property Colors colors: Colors { - } - property DashboardConfig dashboard: DashboardConfig { - } - property DockConfig dock: DockConfig { - } - property General general: General { - } - property Launcher launcher: Launcher { - } - property LockConf lock: LockConf { - } - property NotifConfig notifs: NotifConfig { - } - property Osd osd: Osd { - } - property Overview overview: Overview { - } - property Screenshot screenshot: Screenshot { - } - property Services services: Services { - } - property SidebarConfig sidebar: SidebarConfig { - } - property UtilConfig utilities: UtilConfig { - } - } - } -} diff --git a/Greeter/Config/DashboardConfig.qml b/Greeter/Config/DashboardConfig.qml deleted file mode 100644 index 0b6a610..0000000 --- a/Greeter/Config/DashboardConfig.qml +++ /dev/null @@ -1,36 +0,0 @@ -import Quickshell.Io - -JsonObject { - property int dragThreshold: 50 - property bool enabled: true - property int mediaUpdateInterval: 500 - property Performance performance: Performance { - } - property int resourceUpdateInterval: 1000 - property Sizes sizes: Sizes { - } - - component Performance: JsonObject { - property bool showBattery: true - property bool showCpu: true - property bool showGpu: true - property bool showMemory: true - property bool showNetwork: true - property bool showStorage: true - } - component Sizes: JsonObject { - readonly property int dateTimeWidth: 110 - readonly property int infoIconSize: 25 - readonly property int infoWidth: 200 - readonly property int mediaCoverArtSize: 150 - readonly property int mediaProgressSweep: 180 - readonly property int mediaProgressThickness: 8 - readonly property int mediaVisualiserSize: 80 - readonly property int mediaWidth: 200 - readonly property int resourceProgessThickness: 10 - readonly property int resourceSize: 200 - readonly property int tabIndicatorHeight: 3 - readonly property int tabIndicatorSpacing: 5 - readonly property int weatherWidth: 250 - } -} diff --git a/Greeter/Config/DockConfig.qml b/Greeter/Config/DockConfig.qml deleted file mode 100644 index eeaf1de..0000000 --- a/Greeter/Config/DockConfig.qml +++ /dev/null @@ -1,10 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool enable: false - property real height: 60 - property bool hoverToReveal: true - property list ignoredAppRegexes: [] - property list pinnedApps: ["org.kde.dolphin", "kitty",] - property bool pinnedOnStartup: false -} diff --git a/Greeter/Config/General.qml b/Greeter/Config/General.qml deleted file mode 100644 index 45d3513..0000000 --- a/Greeter/Config/General.qml +++ /dev/null @@ -1,63 +0,0 @@ -import Quickshell.Io -import Quickshell - -JsonObject { - property Apps apps: Apps { - } - property Battery battery: Battery { - } - property Color color: Color { - } - property string dateFormat: "ddd d MMM - hh:mm:ss" - property bool desktopIcons: false - property Idle idle: Idle { - } - property string logo: "" - property string wallpaperPath: Quickshell.env("HOME") + "/Pictures/Wallpapers" - - component Apps: JsonObject { - property list audio: ["pavucontrol"] - property list explorer: ["dolphin"] - property list playback: ["mpv"] - property list terminal: ["kitty"] - } - component Battery: JsonObject { - property int critPerc: 5 - property list popupThresholds: [ - { - perc: 20, - name: qsTr("Low battery"), - message: qsTr("Battery is low"), - icon: "battery_android_frame_2" - }, - ] - } - component Color: JsonObject { - property int hyprsunsetTemp: 5000 - property string mode: "dark" - property bool neovimColors: false - property bool scheduleDark: false - property int scheduleDarkEnd: 0 - property int scheduleDarkStart: 0 - property bool scheduleHyprsunset: false - property int scheduleHyprsunsetEnd: 0 - property int scheduleHyprsunsetStart: 0 - property bool schemeGeneration: true - property bool smart: false - } - component Idle: JsonObject { - property list timeouts: [ - { - name: "Lock", - timeout: 180, - idleAction: "lock" - }, - { - name: "Screen", - timeout: 300, - idleAction: "dpms off", - activeAction: "dpms on" - } - ] - } -} diff --git a/Greeter/Config/IdleTimeout.qml b/Greeter/Config/IdleTimeout.qml deleted file mode 100644 index c1db937..0000000 --- a/Greeter/Config/IdleTimeout.qml +++ /dev/null @@ -1,15 +0,0 @@ -import Quickshell.Io - -JsonObject { - property list timeouts: [ - { - timeout: 180, - idleAction: "lock" - }, - { - timeout: 300, - idleAction: "dpms off", - activeAction: "dpms on" - } - ] -} diff --git a/Greeter/Config/Launcher.qml b/Greeter/Config/Launcher.qml deleted file mode 100644 index 5ab58cc..0000000 --- a/Greeter/Config/Launcher.qml +++ /dev/null @@ -1,109 +0,0 @@ -import Quickshell.Io - -JsonObject { - property string actionPrefix: ">" - property list actions: [ - { - name: "Calculator", - icon: "calculate", - description: "Do simple math equations", - command: ["autocomplete", "calc"], - enabled: true, - dangerous: false - }, - { - name: "Light", - icon: "light_mode", - description: "Change to light mode", - command: ["setMode", "light"], - enabled: true, - dangerous: false - }, - { - name: "Dark", - icon: "dark_mode", - description: "Change to dark mode", - command: ["setMode", "dark"], - enabled: true, - dangerous: false - }, - { - name: "Wallpaper", - icon: "image", - description: "Change the current wallpaper", - command: ["autocomplete", "wallpaper"], - enabled: true, - dangerous: false - }, - { - name: "Variant", - icon: "colors", - description: "Change the current scheme variant", - command: ["autocomplete", "variant"], - enabled: true, - dangerous: false - }, - { - name: "Shutdown", - icon: "power_settings_new", - description: "Shutdown the system", - command: ["systemctl", "poweroff"], - enabled: true, - dangerous: true - }, - { - name: "Reboot", - icon: "cached", - description: "Reboot the system", - command: ["systemctl", "reboot"], - enabled: true, - dangerous: true - }, - { - name: "Logout", - icon: "logout", - description: "Log out of the current session", - command: ["loginctl", "terminate-user", ""], - enabled: true, - dangerous: true - }, - { - name: "Lock", - icon: "lock", - description: "Lock the current session", - command: ["loginctl", "lock-session"], - enabled: true, - dangerous: false - }, - { - name: "Sleep", - icon: "bedtime", - description: "Suspend then hibernate", - command: ["systemctl", "suspend-then-hibernate"], - enabled: true, - dangerous: false - }, - ] - property int maxAppsShown: 10 - property int maxWallpapers: 7 - property Sizes sizes: Sizes { - } - property string specialPrefix: "@" - property UseFuzzy useFuzzy: UseFuzzy { - } - property bool uwsm: true - - component Sizes: JsonObject { - property int itemHeight: 50 - property int itemWidth: 600 - property int wallpaperHeight: 200 - property int wallpaperWidth: 280 - } - component UseFuzzy: JsonObject { - property bool actions: false - property bool apps: false - property bool schemes: false - property bool variants: false - property bool wallpapers: false - } -} diff --git a/Greeter/Config/LockConf.qml b/Greeter/Config/LockConf.qml deleted file mode 100644 index 87a4f4e..0000000 --- a/Greeter/Config/LockConf.qml +++ /dev/null @@ -1,18 +0,0 @@ -import Quickshell.Io - -JsonObject { - property int blurAmount: 40 - property bool enableFprint: true - property int maxFprintTries: 3 - property bool recolorLogo: false - property bool showNotifContent: false - property bool showNotifIcon: true - property Sizes sizes: Sizes { - } - - component Sizes: JsonObject { - property int centerWidth: 600 - property real heightMult: 0.7 - property real ratio: 16 / 9 - } -} diff --git a/Greeter/Config/MaterialEasing.qml b/Greeter/Config/MaterialEasing.qml deleted file mode 100644 index 53256d5..0000000 --- a/Greeter/Config/MaterialEasing.qml +++ /dev/null @@ -1,26 +0,0 @@ -pragma Singleton -import Quickshell - -Singleton { - id: root - - readonly property list emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] - readonly property list emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] - readonly property int emphasizedAccelTime: 200 * scale - readonly property list emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] - readonly property int emphasizedDecelTime: 400 * scale - readonly property int emphasizedTime: 500 * scale - readonly property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1] - readonly property int expressiveDefaultSpatialTime: 500 * scale - readonly property list expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1] - readonly property int expressiveEffectsTime: 200 * scale - readonly property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] - readonly property int expressiveFastSpatialTime: 350 * scale - property real scale: Tokens.anim.durations.scale - readonly property list standard: [0.2, 0, 0, 1, 1, 1] - readonly property list standardAccel: [0.3, 0, 1, 1, 1, 1] - readonly property int standardAccelTime: 200 * scale - readonly property list standardDecel: [0, 0, 0, 1, 1, 1] - readonly property int standardDecelTime: 250 * scale - readonly property int standardTime: 300 * scale -} diff --git a/Greeter/Config/NotifConfig.qml b/Greeter/Config/NotifConfig.qml deleted file mode 100644 index 0a11d46..0000000 --- a/Greeter/Config/NotifConfig.qml +++ /dev/null @@ -1,20 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool actionOnClick: false - property int appNotifCooldown: 0 - property real clearThreshold: 0.3 - property int defaultExpireTimeout: 5000 - property int expandThreshold: 20 - property bool expire: true - property int groupPreviewNum: 3 - property bool openExpanded: false - property Sizes sizes: Sizes { - } - - component Sizes: JsonObject { - property int badge: 20 - property int image: 41 - property int width: 400 - } -} diff --git a/Greeter/Config/Osd.qml b/Greeter/Config/Osd.qml deleted file mode 100644 index 79da85b..0000000 --- a/Greeter/Config/Osd.qml +++ /dev/null @@ -1,16 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool allMonBrightness: false - property bool enableBrightness: true - property bool enableMicrophone: true - property bool enabled: true - property int hideDelay: 3000 - property Sizes sizes: Sizes { - } - - component Sizes: JsonObject { - property int sliderHeight: 150 - property int sliderWidth: 30 - } -} diff --git a/Greeter/Config/Overview.qml b/Greeter/Config/Overview.qml deleted file mode 100644 index 5e1a615..0000000 --- a/Greeter/Config/Overview.qml +++ /dev/null @@ -1,8 +0,0 @@ -import Quickshell.Io - -JsonObject { - property int columns: 5 - property bool enable: false - property int rows: 2 - property real scale: 0.16 -} diff --git a/Greeter/Config/Screenshot.qml b/Greeter/Config/Screenshot.qml deleted file mode 100644 index cd6dd49..0000000 --- a/Greeter/Config/Screenshot.qml +++ /dev/null @@ -1,13 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool enable_pp: true - property string mode: "manual" - property real radius: 12.0 - property bool rounding: false - property bool shadow: true - property real shadow_blur: 22.0 - property list shadow_color: [0, 0, 0, 160] - property real shadow_offset_x: 5.0 - property real shadow_offset_y: 5.0 -} diff --git a/Greeter/Config/Services.qml b/Greeter/Config/Services.qml deleted file mode 100644 index 4711120..0000000 --- a/Greeter/Config/Services.qml +++ /dev/null @@ -1,22 +0,0 @@ -import Quickshell.Io -import QtQuick - -JsonObject { - property real audioIncrement: 0.1 - property real brightnessIncrement: 0.1 - property bool ddcutilService: false - property string defaultPlayer: "Spotify" - property string gpuType: "" - property real maxVolume: 1.0 - property list playerAliases: [ - { - "from": "com.github.th_ch.youtube_music", - "to": "YT Music" - } - ] - property bool updates: true - property bool useFahrenheit: false - property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a") - property int visualizerBars: 30 - property string weatherLocation: "" -} diff --git a/Greeter/Config/SidebarConfig.qml b/Greeter/Config/SidebarConfig.qml deleted file mode 100644 index 80800ce..0000000 --- a/Greeter/Config/SidebarConfig.qml +++ /dev/null @@ -1,11 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool enabled: true - property Sizes sizes: Sizes { - } - - component Sizes: JsonObject { - property int width: 430 - } -} diff --git a/Greeter/Config/Transparency.qml b/Greeter/Config/Transparency.qml deleted file mode 100644 index e687cfb..0000000 --- a/Greeter/Config/Transparency.qml +++ /dev/null @@ -1,7 +0,0 @@ -import Quickshell.Io - -JsonObject { - property real base: 0.85 - property bool enabled: false - property real layers: 0.4 -} diff --git a/Greeter/Config/UtilConfig.qml b/Greeter/Config/UtilConfig.qml deleted file mode 100644 index c4a2087..0000000 --- a/Greeter/Config/UtilConfig.qml +++ /dev/null @@ -1,35 +0,0 @@ -import Quickshell.Io - -JsonObject { - property bool enabled: true - property int maxToasts: 4 - property Sizes sizes: Sizes { - } - property Toasts toasts: Toasts { - } - property Vpn vpn: Vpn { - } - - component Sizes: JsonObject { - property int toastWidth: 430 - property int width: 430 - } - component Toasts: JsonObject { - property bool audioInputChanged: true - property bool audioOutputChanged: true - property bool capsLockChanged: true - property bool chargingChanged: true - property bool configLoaded: true - property bool dndChanged: true - property bool gameModeChanged: true - property bool kbLayoutChanged: true - property bool kbLimit: true - property bool nowPlaying: false - property bool numLockChanged: true - property bool vpnChanged: true - } - component Vpn: JsonObject { - property bool enabled: false - property list provider: ["netbird"] - } -} diff --git a/Greeter/Config/WorkspaceWidget.qml b/Greeter/Config/WorkspaceWidget.qml deleted file mode 100644 index 10a6969..0000000 --- a/Greeter/Config/WorkspaceWidget.qml +++ /dev/null @@ -1,6 +0,0 @@ -import Quickshell.Io - -JsonObject { - property string inactiveTextColor: "white" - property string textColor: "black" -} diff --git a/Greeter/Helpers/Brightness.qml b/Greeter/Helpers/Brightness.qml deleted file mode 100644 index 9476050..0000000 --- a/Greeter/Helpers/Brightness.qml +++ /dev/null @@ -1,264 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import Quickshell -import Quickshell.Io -import QtQuick -import ZShell.Config -import qs.Components - -Singleton { - id: root - - property bool appleDisplayPresent: false - property list ddcMonitors: [] - property list ddcServiceMon: [] - readonly property list monitors: variants.instances - - function decreaseBrightness(): void { - const monitor = getMonitor("active"); - if (monitor) - monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); - } - - function getMonitor(query: string): var { - if (query === "active") { - return monitors.find(m => Hypr.monitorFor(m.modelData)?.focused); - } - - if (query.startsWith("model:")) { - const model = query.slice(6); - return monitors.find(m => m.modelData.model === model); - } - - if (query.startsWith("serial:")) { - const serial = query.slice(7); - return monitors.find(m => m.modelData.serialNumber === serial); - } - - if (query.startsWith("id:")) { - const id = parseInt(query.slice(3), 10); - return monitors.find(m => Hypr.monitorFor(m.modelData)?.id === id); - } - - return monitors.find(m => m.modelData.name === query); - } - - function getMonitorForScreen(screen: ShellScreen): var { - return monitors.find(m => m.modelData === screen); - } - - function increaseBrightness(): void { - const monitor = getMonitor("active"); - if (monitor) - monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); - } - - onMonitorsChanged: { - ddcMonitors = []; - ddcServiceMon = []; - ddcServiceProc.running = true; - ddcProc.running = true; - } - - Variants { - id: variants - - model: Quickshell.screens - - Monitor { - } - } - - Process { - command: ["sh", "-c", "asdbctl get"] - running: true - - stdout: StdioCollector { - onStreamFinished: root.appleDisplayPresent = text.trim().length > 0 - } - } - - Process { - id: ddcProc - - command: ["ddcutil", "detect", "--brief"] - - stdout: StdioCollector { - onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({ - busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1], - connector: d.match(/DRM connector:\s+(.*)/)[1].replace(/^card\d+-/, "") // strip "card1-" - })) - } - } - - Process { - id: ddcServiceProc - - command: ["ddcutil-client", "detect"] - - // running: true - - stdout: StdioCollector { - onStreamFinished: { - const t = text.replace(/\r\n/g, "\n").trim(); - - const output = ("\n" + t).split(/\n(?=display:\s*\d+\s*\n)/).filter(b => b.startsWith("display:")).map(b => ({ - display: Number(b.match(/^display:\s*(\d+)/m)?.[1] ?? -1), - name: (b.match(/^\s*product_name:\s*(.*)$/m)?.[1] ?? "").trim() - })).filter(d => d.display > 0); - root.ddcServiceMon = output; - } - } - } - - CustomShortcut { - description: "Increase brightness" - name: "brightnessUp" - - onPressed: root.increaseBrightness() - } - - CustomShortcut { - description: "Decrease brightness" - name: "brightnessDown" - - onPressed: root.decreaseBrightness() - } - - IpcHandler { - function get(): real { - return getFor("active"); - } - - // Allows searching by active/model/serial/id/name - function getFor(query: string): real { - return root.getMonitor(query)?.brightness ?? -1; - } - - function set(value: string): string { - return setFor("active", value); - } - - // Handles brightness value like brightnessctl: 0.1, +0.1, 0.1-, 10%, +10%, 10%- - function setFor(query: string, value: string): string { - const monitor = root.getMonitor(query); - if (!monitor) - return "Invalid monitor: " + query; - - let targetBrightness; - if (value.endsWith("%-")) { - const percent = parseFloat(value.slice(0, -2)); - targetBrightness = monitor.brightness - (percent / 100); - } else if (value.startsWith("+") && value.endsWith("%")) { - const percent = parseFloat(value.slice(1, -1)); - targetBrightness = monitor.brightness + (percent / 100); - } else if (value.endsWith("%")) { - const percent = parseFloat(value.slice(0, -1)); - targetBrightness = percent / 100; - } else if (value.startsWith("+")) { - const increment = parseFloat(value.slice(1)); - targetBrightness = monitor.brightness + increment; - } else if (value.endsWith("-")) { - const decrement = parseFloat(value.slice(0, -1)); - targetBrightness = monitor.brightness - decrement; - } else if (value.includes("%") || value.includes("-") || value.includes("+")) { - return `Invalid brightness format: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`; - } else { - targetBrightness = parseFloat(value); - } - - if (isNaN(targetBrightness)) - return `Failed to parse value: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`; - - monitor.setBrightness(targetBrightness); - - return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`; - } - - target: "brightness" - } - - component Monitor: QtObject { - id: monitor - - property real brightness - readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? "" - readonly property string displayNum: root.ddcServiceMon.find(m => m.name === modelData.model)?.display ?? "" - readonly property Process initProc: Process { - stdout: StdioCollector { - onStreamFinished: { - if (monitor.isDdcService) { - const output = text.split("\n").filter(o => o.startsWith("vcp_current_value:"))[0].split(":")[1]; - const val = parseInt(output.trim()); - monitor.brightness = val / 100; - } else if (monitor.isAppleDisplay) { - const val = parseInt(text.trim()); - monitor.brightness = val / 101; - } else { - const [, , , cur, max] = text.split(" "); - monitor.brightness = parseInt(cur) / parseInt(max); - } - } - } - } - readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay") - readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name) - readonly property bool isDdcService: Config.services.ddcutilService - required property ShellScreen modelData - property real queuedBrightness: NaN - readonly property Timer timer: Timer { - interval: 500 - - onTriggered: { - if (!isNaN(monitor.queuedBrightness)) { - monitor.setBrightness(monitor.queuedBrightness); - monitor.queuedBrightness = NaN; - } - } - } - - function initBrightness(): void { - if (isDdcService) - initProc.command = ["ddcutil-client", "-d", displayNum, "getvcp", "10"]; - else if (isAppleDisplay) - initProc.command = ["asdbctl", "get"]; - else if (isDdc) - initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"]; - else - initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"]; - - initProc.running = true; - } - - function setBrightness(value: real): void { - value = Math.max(0, Math.min(1, value)); - const rounded = Math.round(value * 100); - if (Math.round(brightness * 100) === rounded) - return; - - if ((isDdc || isDdcService) && timer.running) { - queuedBrightness = value; - return; - } - - brightness = value; - - if (isDdcService) - Quickshell.execDetached(["ddcutil-client", "-d", displayNum, "setvcp", "10", rounded]); - else if (isAppleDisplay) - Quickshell.execDetached(["asdbctl", "set", rounded]); - else if (isDdc) - Quickshell.execDetached(["ddcutil", "--disable-dynamic-sleep", "--sleep-multiplier", ".1", "--skip-ddc-checks", "-b", busNum, "setvcp", "10", rounded]); - else - Quickshell.execDetached(["brightnessctl", "s", `${rounded}%`]); - - if (isDdc || isDdcService) - timer.restart(); - } - - Component.onCompleted: initBrightness() - onBusNumChanged: initBrightness() - onDisplayNumChanged: initBrightness() - } -} diff --git a/Greeter/Helpers/Hypr.qml b/Greeter/Helpers/Hypr.qml index 2d3eb31..682b710 100644 --- a/Greeter/Helpers/Hypr.qml +++ b/Greeter/Helpers/Hypr.qml @@ -149,15 +149,7 @@ Singleton { target: "hypr" } - CustomShortcut { - name: "refreshDevices" - - onPressed: extras.refreshDevices() - onReleased: extras.refreshDevices() - } - HyprExtras { id: extras - } } diff --git a/Greeter/Helpers/SystemInfo.qml b/Greeter/Helpers/SystemInfo.qml deleted file mode 100644 index a4dcc16..0000000 --- a/Greeter/Helpers/SystemInfo.qml +++ /dev/null @@ -1,83 +0,0 @@ -pragma Singleton - -import ZShell.Config -import Quickshell -import Quickshell.Io -import QtQuick - -Singleton { - id: root - - property bool isDefaultLogo: true - property string osId - property list osIdLike - property string osLogo - property string osName - property string osPrettyName - readonly property string shell: Quickshell.env("SHELL").split("/").pop() - property string uptime - readonly property string user: Quickshell.env("USER") - readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP") - - FileView { - id: osRelease - - path: "/etc/os-release" - - onLoaded: { - const lines = text().split("\n"); - - const fd = key => lines.find(l => l.startsWith(`${key}=`))?.split("=")[1].replace(/"/g, "") ?? ""; - - root.osName = fd("NAME"); - root.osPrettyName = fd("PRETTY_NAME"); - root.osId = fd("ID"); - root.osIdLike = fd("ID_LIKE").split(" "); - - const logo = Quickshell.iconPath(fd("LOGO"), true); - if (Config.general.logo) { - root.osLogo = Quickshell.iconPath(Config.general.logo, true) || "file://" + Paths.absolutePath(Config.general.logo); - root.isDefaultLogo = false; - } else if (logo) { - root.osLogo = logo; - root.isDefaultLogo = false; - } - } - } - - Connections { - function onLogoChanged(): void { - osRelease.reload(); - } - - target: Config.general - } - - Timer { - interval: 15000 - repeat: true - running: true - - onTriggered: fileUptime.reload() - } - - FileView { - id: fileUptime - - path: "/proc/uptime" - - onLoaded: { - const up = parseInt(text().split(" ")[0] ?? 0); - - const hours = Math.floor(up / 3600); - const minutes = Math.floor((up % 3600) / 60); - - let str = ""; - if (hours > 0) - str += `${hours} hour${hours === 1 ? "" : "s"}`; - if (minutes > 0 || !str) - str += `${str ? ", " : ""}${minutes} minute${minutes === 1 ? "" : "s"}`; - root.uptime = str; - } - } -} diff --git a/Greeter/InputField.qml b/Greeter/InputField.qml index 21c37b1..157f97f 100644 --- a/Greeter/InputField.qml +++ b/Greeter/InputField.qml @@ -3,9 +3,8 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts -import qs.Components -import qs.Helpers import ZShell.Config +import qs.Components import qs.Services Item { @@ -40,7 +39,7 @@ Item { anchors.centerIn: parent animate: true color: root.greeter.launching ? Colors.palette.m3secondary : Colors.palette.m3outline - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.normal opacity: root.buffer ? 0 : 1 text: { @@ -65,7 +64,7 @@ Item { anchors.verticalCenter: parent.verticalCenter color: Colors.palette.m3onSurface elide: Text.ElideLeft - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.normal horizontalAlignment: Qt.AlignHCenter opacity: root.greeter.echoResponse && root.buffer ? 1 : 0 diff --git a/Greeter/Config/DynamicColors.qml b/Greeter/Services/Colors.qml similarity index 89% rename from Greeter/Config/DynamicColors.qml rename to Greeter/Services/Colors.qml index 2b2be28..ee9d678 100644 --- a/Greeter/Config/DynamicColors.qml +++ b/Greeter/Services/Colors.qml @@ -3,8 +3,10 @@ pragma ComponentBehavior: Bound import Quickshell import Quickshell.Io +import Quickshell.Hyprland import QtQuick import ZShell +import ZShell.Config import qs.Helpers import qs.Paths @@ -79,6 +81,35 @@ Singleton { return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1); } + function reloadHyprRules(): void { + const blur = transparency.enabled ? 1 : 0; + const alpha = transparency.base - 0.03; + + const rules = ` + hl.layer_rule({ + match = { namespace = "ZShell-Bar" }, + blur = ${blur} + }) + + hl.layer_rule({ + match = { namespace = "ZShell-Bar" }, + ignore_alpha = ${alpha} + }) + + hl.layer_rule({ + match = { namespace = "ZShell-Auth" }, + blur = ${blur} + }) + + hl.layer_rule({ + match = { namespace = "ZShell-Auth" }, + ignore_alpha = ${alpha} + }) + `; + + Hypr.extras.message(`eval ${rules}`); + } + function setMode(mode: string): void { Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]); Config.general.color.mode = mode; @@ -89,6 +120,24 @@ Singleton { return Qt.rgba(c.g, c.r, c.b, c.a); } + Component.onCompleted: debounceTimer.triggered() + + Connections { + function onUsingLuaChanged(): void { + root.reloadHyprRules(); + } + + target: Hyprland + } + + Connections { + function onConfigReloaded(): void { + root.reloadHyprRules(); + } + + target: Hypr + } + FileView { path: "/etc/zshell-greeter/scheme.json" watchChanges: true @@ -97,6 +146,14 @@ Singleton { onLoaded: root.load(text(), false) } + Timer { + id: debounceTimer + + interval: 300 + + onTriggered: root.reloadHyprRules() + } + ImageAnalyser { id: analyser @@ -224,9 +281,9 @@ Singleton { readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor) } component Transparency: QtObject { - readonly property real base: Math.max(0, Math.min(1, Appearance.transparency.base - (root.light ? 0.1 : 0))) - readonly property bool enabled: Appearance.transparency.enabled - readonly property real layers: Appearance.transparency.layers + readonly property real base: Math.max(0, Math.min(1, Config.appearance.transparency.base - (root.light ? 0.1 : 0))) + readonly property bool enabled: Config.appearance.transparency.enabled + readonly property real layers: Config.appearance.transparency.layers onBaseChanged: debounceTimer.restart() onEnabledChanged: debounceTimer.restart() diff --git a/Greeter/SessionDock.qml b/Greeter/SessionDock.qml index 1f7181c..24d5fd5 100644 --- a/Greeter/SessionDock.qml +++ b/Greeter/SessionDock.qml @@ -2,9 +2,8 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts -import qs.Components -import qs.Helpers import ZShell.Config +import qs.Components import qs.Services ColumnLayout { @@ -20,7 +19,7 @@ ColumnLayout { Layout.fillWidth: true color: Colors.palette.m3outline elide: Text.ElideRight - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.weight: 500 text: root.greeter.sessions.length > 0 ? qsTr("%1 session%2").arg(root.greeter.sessions.length).arg(root.greeter.sessions.length === 1 ? "" : "s") : qsTr("Sessions") } @@ -54,7 +53,7 @@ ColumnLayout { CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.large font.weight: 500 text: qsTr("No Sessions Found") @@ -119,7 +118,7 @@ ColumnLayout { Layout.fillWidth: true color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimaryFixedVariant : Colors.palette.m3onSurfaceVariant elide: Text.ElideRight - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.small text: modelData.kind } diff --git a/Greeter/UserDock.qml b/Greeter/UserDock.qml index b6825ce..366842c 100644 --- a/Greeter/UserDock.qml +++ b/Greeter/UserDock.qml @@ -2,9 +2,9 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Config import qs.Components import qs.Helpers -import ZShell.Config import qs.Services ColumnLayout { @@ -20,7 +20,7 @@ ColumnLayout { Layout.fillWidth: true color: Colors.palette.m3outline elide: Text.ElideRight - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.weight: 500 text: root.greeter.users.length > 0 ? qsTr("%1 user%2").arg(root.greeter.users.length).arg(root.greeter.users.length === 1 ? "" : "s") : qsTr("Users") } @@ -55,7 +55,7 @@ ColumnLayout { CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant - font.family: Appearance.font.family.mono + font.family: Config.appearance.font.family.mono font.pointSize: Tokens.font.size.large font.weight: 500 text: qsTr("No Users Found") diff --git a/Greeter/WeatherInfo.qml b/Greeter/WeatherInfo.qml index 85f862b..3a69bcd 100644 --- a/Greeter/WeatherInfo.qml +++ b/Greeter/WeatherInfo.qml @@ -2,9 +2,9 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Config import qs.Components import qs.Helpers -import ZShell.Config import qs.Services ColumnLayout { diff --git a/Helpers/Players.qml b/Helpers/Players.qml index 30d94a3..21c7148 100644 --- a/Helpers/Players.qml +++ b/Helpers/Players.qml @@ -33,7 +33,7 @@ Singleton { function getIdentity(player: MprisPlayer): string { if (!player) return ""; - const alias = Config.services.playerAliases.find(a => a.from === player.identity); + const alias = Config.services.playerAliases.values.find(a => a.from === player.identity); return alias?.to ?? player.identity; } diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index faa1fe3..949c706 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -74,7 +74,7 @@ RowLayout { id: repeater model: ScriptModel { - values: Config.bar.entries.filter(e => e.enabled) + values: Config.bar.entries.values.filter(e => e.enabled) } DelegateChooser { diff --git a/Modules/Launcher/Services/Actions.qml b/Modules/Launcher/Services/Actions.qml index 7f3288b..80df3fc 100644 --- a/Modules/Launcher/Services/Actions.qml +++ b/Modules/Launcher/Services/Actions.qml @@ -20,7 +20,7 @@ Searcher { Variants { id: variants - model: Config.launcher.actions.filter(a => (a.enabled ?? true) && (Config.launcher.enableDangerousActions || !(a.dangerous ?? false))) + model: Config.launcher.actions.values.filter(a => (a.enabled ?? true) && (Config.launcher.enableDangerousActions || !(a.dangerous ?? false))) Action { } diff --git a/Modules/Lock/Fetch.qml b/Modules/Lock/Fetch.qml deleted file mode 100644 index 99dab27..0000000 --- a/Modules/Lock/Fetch.qml +++ /dev/null @@ -1,162 +0,0 @@ -pragma ComponentBehavior: Bound - -import Quickshell.Services.UPower -import QtQuick -import QtQuick.Layouts -import qs.Modules -import qs.Components -import qs.Helpers -import ZShell.Config -import qs.Services - -ColumnLayout { - id: root - - anchors.fill: parent - anchors.margins: Tokens.padding.large * 2 - anchors.topMargin: Tokens.padding.large - spacing: Tokens.spacing.small - - RowLayout { - Layout.fillHeight: false - Layout.fillWidth: true - spacing: Tokens.spacing.normal - - CustomRect { - color: Colors.palette.m3primary - implicitHeight: prompt.implicitHeight + Tokens.padding.normal * 2 - implicitWidth: prompt.implicitWidth + Tokens.padding.normal * 2 - radius: Tokens.rounding.small - - MonoText { - id: prompt - - anchors.centerIn: parent - color: Colors.palette.m3onPrimary - font.pointSize: root.width > 400 ? Tokens.font.size.larger : Tokens.font.size.normal - text: ">" - } - } - - MonoText { - Layout.fillWidth: true - elide: Text.ElideRight - font.pointSize: root.width > 400 ? Tokens.font.size.larger : Tokens.font.size.normal - text: "caelestiafetch.sh" - } - - WrappedLoader { - Layout.fillHeight: true - active: !iconLoader.active - - sourceComponent: OsLogo { - } - } - } - - RowLayout { - Layout.fillHeight: false - Layout.fillWidth: true - spacing: height * 0.15 - - WrappedLoader { - id: iconLoader - - Layout.fillHeight: true - active: root.width > 320 - - sourceComponent: OsLogo { - } - } - - ColumnLayout { - Layout.bottomMargin: Tokens.padding.normal - Layout.fillWidth: true - Layout.leftMargin: iconLoader.active ? 0 : width * 0.1 - Layout.topMargin: Tokens.padding.normal - spacing: Tokens.spacing.normal - - WrappedLoader { - Layout.fillWidth: true - active: !batLoader.active && root.height > 200 - - sourceComponent: FetchText { - text: `OS : ${SystemInfo.osPrettyName || SysInfo.osName}` - } - } - - WrappedLoader { - Layout.fillWidth: true - active: root.height > (batLoader.active ? 200 : 110) - - sourceComponent: FetchText { - text: `WM : ${SystemInfo.wm}` - } - } - - WrappedLoader { - Layout.fillWidth: true - active: !batLoader.active || root.height > 110 - - sourceComponent: FetchText { - text: `USER: ${SystemInfo.user}` - } - } - - FetchText { - text: `UP : ${SystemInfo.uptime}` - } - - WrappedLoader { - id: batLoader - - Layout.fillWidth: true - active: UPower.displayDevice.isLaptopBattery - - sourceComponent: FetchText { - text: `BATT: ${[UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state) ? "(+) " : ""}${Math.round(UPower.displayDevice.percentage * 100)}%` - } - } - } - } - - WrappedLoader { - Layout.alignment: Qt.AlignHCenter - active: root.height > 180 - - sourceComponent: RowLayout { - spacing: Tokens.spacing.large - - Repeater { - model: Math.max(0, Math.min(8, root.width / (Tokens.font.size.larger * 2 + Tokens.spacing.large))) - - CustomRect { - required property int index - - color: Colors.palette[`term${index}`] - implicitHeight: Tokens.font.size.larger * 2 - implicitWidth: implicitHeight - radius: Tokens.rounding.small - } - } - } - } - - component FetchText: MonoText { - Layout.fillWidth: true - elide: Text.ElideRight - font.pointSize: root.width > 400 ? Tokens.font.size.larger : Tokens.font.size.normal - } - component MonoText: CustomText { - font.family: Appearance.font.family.mono - } - component OsLogo: ColoredIcon { - color: Colors.palette.m3primary - implicitSize: height - layer.enabled: Config.lock.recolorLogo || SystemInfo.isDefaultLogo - source: SystemInfo.osLogo - } - component WrappedLoader: Loader { - visible: active - } -} diff --git a/Modules/Settings/Common/ListEditor.qml b/Modules/Settings/Common/ListEditor.qml index 9bc5bfc..a380e94 100644 --- a/Modules/Settings/Common/ListEditor.qml +++ b/Modules/Settings/Common/ListEditor.qml @@ -171,10 +171,11 @@ ListView { item.held = true; itemContent.x = Qt.binding(() => { - if (!root) + if (!root) { return 0; + } - const maxOvershoot = Tokens.padding.extraExtraLarge; + const maxOvershoot = Tokens.padding.extraLargeIncreased; const x = mouse.mouseX - item.pressPos.x; return root.dampOvershoot(Math.abs(x), maxOvershoot) * Math.sign(x); }); diff --git a/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml b/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml index 63fea38..ae17efa 100644 --- a/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml +++ b/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml @@ -1,5 +1,3 @@ -pragma ComponentBehavior: Bound - import QtQuick.Layouts import ZShell.Config import qs.Modules.Settings.Common @@ -42,42 +40,24 @@ PageBase { } first: true - values: Config.bar.tray.statusIcons + values: Config.bar.tray.statusIcons.values z: 1 - onItemMoved: (from, to) => { - const icons = Config.bar.tray.statusIcons.slice(); - const [moved] = icons.splice(from, 1); - icons.splice(to, 0, moved); - Config.bar.tray.statusIcons = icons; - } - onItemRemoved: index => { - const icons = Config.bar.tray.statusIcons.slice(); - icons.splice(index, 1); - Config.bar.tray.statusIcons = icons; - } - onItemToggled: (index, checked) => { - const icons = Config.bar.tray.statusIcons.slice(); - icons[index] = Object.assign({}, icons[index], { - enabled: checked - }); - Config.bar.tray.statusIcons = icons; - } + onItemMoved: (from, to) => Config.bar.tray.statusIcons.move(from, to) + onItemRemoved: index => Config.bar.tray.statusIcons.remove(index) + onItemToggled: (index, checked) => Config.bar.tray.statusIcons.at(index).enabled = checked } DialogSelectButton { id: addItemContainer acceptLabel: qsTr("Add") - enabled: { - console.log(Object.keys(model).length); - return Object.keys(model).length > 0; - } + enabled: Object.keys(model).length > 0 header: qsTr("Add new entry") icon: "add" label: qsTr("Add entry") model: { - const present = new Set(Config.bar.tray.statusIcons.map(item => item.id)); + const present = new Set(Config.bar.tray.statusIcons.values.map(item => item.id)); return Object.keys(root.builtinIcons).filter(id => !present.has(id)).map(id => ({ id: id, label: root.builtinIcons[id] @@ -89,12 +69,10 @@ PageBase { if (!selectedItem) return; - const icons = Config.bar.tray.statusIcons.slice(); - icons.push({ + Config.bar.tray.statusIcons.insert({ id: selectedItem, enabled: true }); - Config.bar.tray.statusIcons = icons; } } @@ -106,6 +84,7 @@ PageBase { ToggleRow { checked: Config.bar.popouts.statusIcons first: true + last: true settingAnchor: "bar-status-popout-on-hover" subtext: qsTr("Show a details popout when hovering the status icons") text: qsTr("Popout on hover") diff --git a/Modules/SysTray/StatusIcons.qml b/Modules/SysTray/StatusIcons.qml index c297fe8..cb85c92 100644 --- a/Modules/SysTray/StatusIcons.qml +++ b/Modules/SysTray/StatusIcons.qml @@ -56,7 +56,7 @@ CustomClippingRect { model: ScriptModel { id: model - values: Config.bar.tray.statusIcons.filter(e => e.enabled) + values: Config.bar.tray.statusIcons.values.filter(e => e.enabled) } DelegateChooser { diff --git a/Plugins/ZShell/Config/Appearance.cpp b/Plugins/ZShell/Config/Appearance.cpp deleted file mode 100644 index 0970e75..0000000 --- a/Plugins/ZShell/Config/Appearance.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Appearance.hpp" - -Anim::Anim(QObject *parent) : ConfigSection(parent) { - m_mediaGifSpeedAdjustment = 300; - m_sessionGifSpeed = 0.7; - wireSignals(); -} - -Deform::Deform(QObject *parent) : ConfigSection(parent) { - m_scale = 1; - wireSignals(); -} - -FontFamily::FontFamily(QObject *parent) : ConfigSection(parent) { - m_clock = QStringLiteral("Rubik"); - m_material = QStringLiteral("Material Symbols Rounded"); - m_mono = QStringLiteral("SegoeUI Variable"); - m_sans = QStringLiteral("SegoeUI Variable"); - wireSignals(); -} - -Font::Font(QObject *parent) : ConfigSection(parent) { - m_family = new FontFamily(this); - wireSignals(); -} - -Transparency::Transparency(QObject *parent) : ConfigSection(parent) { - m_base = 0.75; - m_enabled = true; - m_layers = 0.4; - wireSignals(); -} - -Appearance::Appearance(QObject *parent) : ConfigSection(parent) { - m_anim = new Anim(this); - m_deform = new Deform(this); - m_font = new Font(this); - m_transparency = new Transparency(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Appearance.hpp b/Plugins/ZShell/Config/Appearance.hpp deleted file mode 100644 index a4e03a1..0000000 --- a/Plugins/ZShell/Config/Appearance.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include "ConfigSection.hpp" -#include - -// NOTE: multiple classes per file is fine - moc processes every Q_OBJECT -// class it finds in a header, regardless of how many. Config.appearance.anim -// works purely through object composition (Appearance owns an Anim*), which -// has nothing to do with how the files are split. - -class Anim : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, mediaGifSpeedAdjustment, MediaGifSpeedAdjustment) - CFG_PROPERTY(qreal, sessionGifSpeed, SessionGifSpeed) - -public: - explicit Anim(QObject *parent = nullptr); -}; - -class Deform : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(qreal, scale, Scale) - -public: - explicit Deform(QObject *parent = nullptr); -}; - -class FontFamily : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(QString, clock, Clock) - CFG_PROPERTY(QString, material, Material) - CFG_PROPERTY(QString, mono, Mono) - CFG_PROPERTY(QString, sans, Sans) - -public: - explicit FontFamily(QObject *parent = nullptr); -}; - -class Font : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_SECTION(FontFamily, family, Family) - -public: - explicit Font(QObject *parent = nullptr); -}; - -class Transparency : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(qreal, base, Base) - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(qreal, layers, Layers) - -public: - explicit Transparency(QObject *parent = nullptr); -}; - -class Appearance : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_SECTION(Anim, anim, Anim) - CFG_SECTION(Deform, deform, Deform) - CFG_SECTION(Font, font, Font) - CFG_SECTION(Transparency, transparency, Transparency) - -public: - explicit Appearance(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Background.cpp b/Plugins/ZShell/Config/Background.cpp deleted file mode 100644 index 82ba725..0000000 --- a/Plugins/ZShell/Config/Background.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "Background.hpp" - -Background::Background(QObject *parent) : ConfigSection(parent) { - m_enabled = true; - m_wallFadeDuration = 300; - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Background.hpp b/Plugins/ZShell/Config/Background.hpp deleted file mode 100644 index 35d9c2d..0000000 --- a/Plugins/ZShell/Config/Background.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class Background : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(int, wallFadeDuration, WallFadeDuration) - -public: - explicit Background(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Bar.cpp b/Plugins/ZShell/Config/Bar.cpp deleted file mode 100644 index 708705f..0000000 --- a/Plugins/ZShell/Config/Bar.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "Bar.hpp" - -namespace { -QVariantMap entry(bool enabled, const char *id) { - QVariantMap m; - m["enabled"] = enabled; - m["id"] = QString::fromLatin1(id); - return m; -} -} - -Popouts::Popouts(QObject *parent) : ConfigSection(parent) { - m_statusIcons = true; - m_tray = true; - wireSignals(); -} - -Tray::Tray(QObject *parent) : ConfigSection(parent) { - m_recolorIcons = false; - m_showOnHover = true; - m_statusIcons = { - entry(true, "audio"), - entry(true, "microphone"), - entry(true, "bluetooth"), - entry(false, "network"), - entry(false, "wifi"), - entry(true, "power"), - }; - m_trayIconSize = 24; - wireSignals(); -} - -Bar::Bar(QObject *parent) : ConfigSection(parent) { - m_autoHide = false; - m_border = 4; - m_entries = { - entry(true, "workspaces"), - entry(true, "audio"), - entry(true, "media"), - entry(true, "resources"), - entry(true, "updates"), - entry(false, "dash"), - entry(true, "spacer"), - entry(true, "activeWindow"), - entry(true, "spacer"), - entry(true, "hyprsunset"), - entry(true, "tray"), - entry(true, "statusIcons"), - entry(false, "network"), - entry(true, "upower"), - entry(true, "clock"), - entry(true, "notifBell"), - }; - m_fullscreenReveal = true; - m_height = 24; - m_hideWhenNotif = true; - m_popouts = new Popouts(this); - m_revealDelay = 100; - m_rounding = 14; - m_smoothing = 32; - m_tray = new Tray(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Bar.hpp b/Plugins/ZShell/Config/Bar.hpp deleted file mode 100644 index 435286c..0000000 --- a/Plugins/ZShell/Config/Bar.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class Popouts : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, statusIcons, StatusIcons) - CFG_PROPERTY(bool, tray, Tray) - -public: - explicit Popouts(QObject *parent = nullptr); -}; - -class Tray : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, recolorIcons, RecolorIcons) - CFG_PROPERTY(bool, showOnHover, ShowOnHover) - // Array of { enabled, id } objects. QML can't mutate array elements in - // place - assign the whole list back to change it, e.g. - // Config.bar.tray.statusIcons = updatedList - CFG_PROPERTY(QVariantList, statusIcons, StatusIcons) - CFG_PROPERTY(int, trayIconSize, TrayIconSize) - -public: - explicit Tray(QObject *parent = nullptr); -}; - -class Bar : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, autoHide, AutoHide) - CFG_PROPERTY(int, border, Border) - // Array of { enabled, id } objects, in display order. - CFG_PROPERTY(QVariantList, entries, Entries) - CFG_PROPERTY(bool, fullscreenReveal, FullscreenReveal) - CFG_PROPERTY(int, height, Height) - CFG_PROPERTY(bool, hideWhenNotif, HideWhenNotif) - CFG_SECTION(Popouts, popouts, Popouts) - CFG_PROPERTY(int, revealDelay, RevealDelay) - CFG_PROPERTY(int, rounding, Rounding) - CFG_PROPERTY(int, smoothing, Smoothing) - CFG_SECTION(Tray, tray, Tray) - -public: - explicit Bar(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/CMakeLists.txt b/Plugins/ZShell/Config/CMakeLists.txt index 92ff721..0e46ebf 100644 --- a/Plugins/ZShell/Config/CMakeLists.txt +++ b/Plugins/ZShell/Config/CMakeLists.txt @@ -1,24 +1,25 @@ qml_module(ZShell-config URI ZShell.Config SOURCES - ConfigSection.hpp ConfigSection.cpp - Config.hpp Config.cpp - Tokens.hpp Tokens.cpp - Appearance.hpp Appearance.cpp - Background.hpp Background.cpp - Bar.hpp Bar.cpp - Clipboard.hpp Clipboard.cpp - Colors.hpp Colors.cpp - Dashboard.hpp Dashboard.cpp - Dock.hpp Dock.cpp - General.hpp General.cpp - Launcher.hpp Launcher.cpp - Lock.hpp Lock.cpp - Notifs.hpp Notifs.cpp - Osd.hpp Osd.cpp - Overview.hpp Overview.cpp - Screenshot.hpp Screenshot.cpp - Services.hpp Services.cpp - Sidebar.hpp Sidebar.cpp - Utilities.hpp Utilities.cpp + confignode.hpp confignode.cpp + configobject.hpp configobject.cpp + configlist.hpp configlist.cpp + config.hpp config.cpp + tokens.hpp + appearance.hpp + background.hpp + bar.hpp + clipboard.hpp + colors.hpp + dashboard.hpp + dock.hpp + general.hpp + launcher.hpp + lock.hpp + notifs.hpp + osd.hpp + screenshot.hpp + services.hpp + sidebar.hpp + utilities.hpp ) diff --git a/Plugins/ZShell/Config/Clipboard.cpp b/Plugins/ZShell/Config/Clipboard.cpp deleted file mode 100644 index 4973329..0000000 --- a/Plugins/ZShell/Config/Clipboard.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "Clipboard.hpp" - -ClipboardSizes::ClipboardSizes(QObject *parent) : ConfigSection(parent) { - m_itemHeight = 60; - m_minPreviewWidth = 200; - m_previewWidth = 800; - m_width = 500; - wireSignals(); -} - -Clipboard::Clipboard(QObject *parent) : ConfigSection(parent) { - m_enabled = true; - m_maxEntriesShown = 10; - m_sizes = new ClipboardSizes(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Clipboard.hpp b/Plugins/ZShell/Config/Clipboard.hpp deleted file mode 100644 index 2d3fa54..0000000 --- a/Plugins/ZShell/Config/Clipboard.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class ClipboardSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, itemHeight, ItemHeight) - CFG_PROPERTY(int, minPreviewWidth, MinPreviewWidth) - CFG_PROPERTY(int, previewWidth, PreviewWidth) - CFG_PROPERTY(int, width, Width) - -public: - explicit ClipboardSizes(QObject *parent = nullptr); -}; - -class Clipboard : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(int, maxEntriesShown, MaxEntriesShown) - CFG_SECTION(ClipboardSizes, sizes, Sizes) - -public: - explicit Clipboard(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Colors.cpp b/Plugins/ZShell/Config/Colors.cpp deleted file mode 100644 index 5059ae6..0000000 --- a/Plugins/ZShell/Config/Colors.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Colors.hpp" - -Presets::Presets(QObject *parent) : ConfigSection(parent) { - m_accent = QString(); - m_name = QStringLiteral("Catppuccin"); - m_variant = QStringLiteral("latte"); - wireSignals(); -} - -Colors::Colors(QObject *parent) : ConfigSection(parent) { - m_presets = new Presets(this); - m_schemeType = QStringLiteral("fidelity"); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Colors.hpp b/Plugins/ZShell/Config/Colors.hpp deleted file mode 100644 index 403215c..0000000 --- a/Plugins/ZShell/Config/Colors.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class Presets : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(QString, accent, Accent) - CFG_PROPERTY(QString, name, Name) - CFG_PROPERTY(QString, variant, Variant) - -public: - explicit Presets(QObject *parent = nullptr); -}; - -class Colors : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_SECTION(Presets, presets, Presets) - CFG_PROPERTY(QString, schemeType, SchemeType) - -public: - explicit Colors(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Config.hpp b/Plugins/ZShell/Config/Config.hpp deleted file mode 100644 index 67e5df2..0000000 --- a/Plugins/ZShell/Config/Config.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include "ConfigSection.hpp" -#include -#include -#include -#include - -#include "Appearance.hpp" -#include "Background.hpp" -#include "Bar.hpp" -#include "Clipboard.hpp" -#include "Colors.hpp" -#include "Dashboard.hpp" -#include "Dock.hpp" -#include "General.hpp" -#include "Launcher.hpp" -#include "Lock.hpp" -#include "Notifs.hpp" -#include "Osd.hpp" -#include "Overview.hpp" -#include "Screenshot.hpp" -#include "Services.hpp" -#include "Sidebar.hpp" -#include "Utilities.hpp" - -class QQmlEngine; -class QJSEngine; - -// The central hub. Exposed to QML as a singleton, so `Config.appearance. -// anim.sessionGifSpeed` just works from anywhere without an import context -// juggle. Every top-level JSON key is a CFG_SECTION child object; the -// generic load()/save() logic lives entirely in ConfigSection, this class -// only adds: the file path, the debounced/atomic write, and the QML -// singleton factory. -class Config : public ConfigSection { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - - CFG_SECTION(Appearance, appearance, Appearance) - CFG_SECTION(Background, background, Background) - CFG_SECTION(Bar, bar, Bar) - CFG_SECTION(Clipboard, clipboard, Clipboard) - CFG_SECTION(Colors, colors, Colors) - CFG_SECTION(Dashboard, dashboard, Dashboard) - CFG_SECTION(Dock, dock, Dock) - CFG_SECTION(General, general, General) - CFG_SECTION(Launcher, launcher, Launcher) - CFG_SECTION(Lock, lock, Lock) - CFG_SECTION(Notifs, notifs, Notifs) - CFG_SECTION(Osd, osd, Osd) - CFG_SECTION(Overview, overview, Overview) - CFG_SECTION(Screenshot, screenshot, Screenshot) - CFG_SECTION(Services, services, Services) - CFG_SECTION(Sidebar, sidebar, Sidebar) - CFG_SECTION(Utilities, utilities, Utilities) - - public: - explicit Config(QObject* parent = nullptr); - static Config* create(QQmlEngine*, QJSEngine*); - - // Reload from disk, discarding any unsaved in-memory changes. - // Synchronous for first load on startup, async for subsequent reloads. - Q_INVOKABLE void load(); - // Force an immediate synchronous write, bypassing the debounce timer. - // Call this from your shell's shutdown handler so nothing gets lost. - Q_INVOKABLE void saveNow(); - // Reload from disk asynchronously (for file change notifications). - Q_INVOKABLE void reloadAsync(); - - private Q_SLOTS: - void scheduleSave(); - void flushAsync(); - - private: - QString filePath() const; - void writeAtomically(const QByteArray& data); - void loadSync(); - void loadAsync(); - - QTimer m_saveTimer; - bool m_loading = false; - bool m_firstLoadDone = false; - QFuture m_loadFuture; -}; diff --git a/Plugins/ZShell/Config/ConfigSection.cpp b/Plugins/ZShell/Config/ConfigSection.cpp deleted file mode 100644 index 13a1f93..0000000 --- a/Plugins/ZShell/Config/ConfigSection.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "ConfigSection.hpp" - -#include -#include - -namespace { -// Property index to start scanning from - skips QObject's own "objectName" -// property, which we never want in the JSON. -int firstOwnProperty() { - return QObject::staticMetaObject.propertyCount(); -} -} - -ConfigSection::ConfigSection(QObject *parent) : QObject(parent) {} - -void ConfigSection::wireSignals() { - if (m_wired) return; - m_wired = true; - - const QMetaObject *mo = metaObject(); - const int slotIdx = mo->indexOfSlot("onPropertyChanged()"); - Q_ASSERT(slotIdx != -1); - const QMetaMethod slot = mo->method(slotIdx); - - const int start = firstOwnProperty(); - for (int i = start; i < mo->propertyCount(); ++i) { - const QMetaProperty prop = mo->property(i); - - if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) { - if (auto *child = qobject_cast(prop.read(this).value())) { - // Child sections bubble their changes straight up as our - // own changed() - no need to also react to our own notify. - connect(child, &ConfigSection::changed, this, &ConfigSection::changed); - continue; - } - } - - if (prop.hasNotifySignal()) - connect(this, prop.notifySignal(), this, slot); - } -} - -void ConfigSection::onPropertyChanged() { - Q_EMIT changed(); -} - -void ConfigSection::fromJson(const QJsonObject &obj) { - const QMetaObject *mo = metaObject(); - const int start = firstOwnProperty(); - - for (int i = start; i < mo->propertyCount(); ++i) { - const QMetaProperty prop = mo->property(i); - const QLatin1String name(prop.name()); - - if (!obj.contains(name)) continue; - - if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) { - if (auto *child = qobject_cast(prop.read(this).value())) { - child->fromJson(obj.value(name).toObject()); - continue; - } - } - - if (prop.isWritable()) - prop.write(this, obj.value(name).toVariant()); - } -} - -QJsonObject ConfigSection::toJson() const { - QJsonObject obj; - const QMetaObject *mo = metaObject(); - const int start = firstOwnProperty(); - - for (int i = start; i < mo->propertyCount(); ++i) { - const QMetaProperty prop = mo->property(i); - - if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) { - if (auto *child = qobject_cast(prop.read(this).value())) { - obj.insert(QLatin1String(prop.name()), child->toJson()); - continue; - } - } - - obj.insert(QLatin1String(prop.name()), QJsonValue::fromVariant(prop.read(this))); - } - return obj; -} diff --git a/Plugins/ZShell/Config/ConfigSection.hpp b/Plugins/ZShell/Config/ConfigSection.hpp deleted file mode 100644 index 8da0825..0000000 --- a/Plugins/ZShell/Config/ConfigSection.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -// --------------------------------------------------------------------------- -// CFG_PROPERTY / CFG_SECTION -// -// These generate exactly the boilerplate you'd write by hand for a -// Q_PROPERTY with a backing member, getter, setter and NOTIFY signal - just -// in one line instead of ~8. Because everything they generate is a normal -// compiled getter/setter, there is *zero* extra runtime cost vs hand-written -// code: reading Config.appearance.anim.sessionGifSpeed from QML calls a -// plain inline getter. Reflection (QMetaObject) is only walked at load time, -// save time, and once at construction time to wire change signals - never -// on the read/write path itself. -// -// CFG_PROPERTY(type, name, Name) -// - type: C++ type (bool, int, qreal, QString, QVariantList, ...) -// - name: property name as it must appear in the JSON file (camelCase, -// or whatever the JSON actually uses - it MUST match exactly) -// - Name: same name, capitalized, used to build setName()/NameChanged() -// -// CFG_SECTION(Type, name, Name) -// - Declares a child ConfigSection* property (e.g. Anim inside Appearance) -// - The pointer itself is CONSTANT (never reassigned); the object it -// points to is what actually changes. -// --------------------------------------------------------------------------- - -#define CFG_PROPERTY(type, name, Name) \ - Q_PROPERTY(type name READ name WRITE set##Name NOTIFY Name##Changed) \ -public: \ - type name() const { return m_##name; } \ - void set##Name(const type &value) { \ - if (m_##name == value) return; \ - m_##name = value; \ - Q_EMIT Name##Changed(); \ - } \ -Q_SIGNALS: \ - void Name##Changed(); \ -private: \ - type m_##name{}; - -#define CFG_SECTION(Type, name, Name) \ -public: \ - Q_PROPERTY(Type *name READ name CONSTANT) \ - Type *name() const { return m_##name; } \ -private: \ - Type *m_##name = nullptr; - -class ConfigSection : public QObject { - Q_OBJECT -public: - explicit ConfigSection(QObject *parent = nullptr); - - // Populate this section (and all child sections) from JSON. Unknown - // keys in obj are ignored; missing keys keep their current value. - void fromJson(const QJsonObject &obj); - // Serialize this section (and all child sections) to JSON. - QJsonObject toJson() const; - -Q_SIGNALS: - // Emitted whenever any property in this section, or any nested section, - // changes. Config listens on the root section to know a save is needed, - // without every leaf class needing to know about Config. - void changed(); - -protected: - // Call once, at the end of every subclass constructor, after all child - // ConfigSection* members have been constructed (new'd with `this` as - // parent). Sets up the reflection-based signal forwarding. - void wireSignals(); - -private Q_SLOTS: - void onPropertyChanged(); - -private: - bool m_wired = false; -}; diff --git a/Plugins/ZShell/Config/Dashboard.cpp b/Plugins/ZShell/Config/Dashboard.cpp deleted file mode 100644 index 6c7ff29..0000000 --- a/Plugins/ZShell/Config/Dashboard.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "Dashboard.hpp" - -Performance::Performance(QObject *parent) : ConfigSection(parent) { - m_enabled = true; - m_showBattery = false; - m_showCpu = true; - m_showGpu = true; - m_showMemory = true; - m_showNetwork = true; - m_showStorage = true; - m_showVram = true; - wireSignals(); -} - -DashboardSizes::DashboardSizes(QObject *parent) : ConfigSection(parent) { - m_dateTimeWidth = 110; - m_infoIconSize = 25; - m_infoWidth = 200; - m_mediaCoverArtSize = 150; - m_mediaProgressSweep = 180; - m_mediaProgressThickness = 8; - m_mediaVisualizerSize = 200; - m_mediaWidth = 200; - m_resourceProgessThickness = 10; - m_resourceSize = 200; - m_tabIndicatorHeight = 3; - m_tabIndicatorSpacing = 5; - m_weatherWidth = 250; - wireSignals(); -} - -Dashboard::Dashboard(QObject *parent) : ConfigSection(parent) { - m_enabled = true; - m_mediaUpdateInterval = 2000; - m_performance = new Performance(this); - m_resourceUpdateInterval = 1000; - m_sizes = new DashboardSizes(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Dashboard.hpp b/Plugins/ZShell/Config/Dashboard.hpp deleted file mode 100644 index 9e1ffea..0000000 --- a/Plugins/ZShell/Config/Dashboard.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class Performance : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(bool, showBattery, ShowBattery) - CFG_PROPERTY(bool, showCpu, ShowCpu) - CFG_PROPERTY(bool, showGpu, ShowGpu) - CFG_PROPERTY(bool, showMemory, ShowMemory) - CFG_PROPERTY(bool, showNetwork, ShowNetwork) - CFG_PROPERTY(bool, showStorage, ShowStorage) - CFG_PROPERTY(bool, showVram, ShowVram) - -public: - explicit Performance(QObject *parent = nullptr); -}; - -class DashboardSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, dateTimeWidth, DateTimeWidth) - CFG_PROPERTY(int, infoIconSize, InfoIconSize) - CFG_PROPERTY(int, infoWidth, InfoWidth) - CFG_PROPERTY(int, mediaCoverArtSize, MediaCoverArtSize) - CFG_PROPERTY(int, mediaProgressSweep, MediaProgressSweep) - CFG_PROPERTY(int, mediaProgressThickness, MediaProgressThickness) - CFG_PROPERTY(int, mediaVisualizerSize, MediaVisualizerSize) - CFG_PROPERTY(int, mediaWidth, MediaWidth) - CFG_PROPERTY(int, resourceProgessThickness, ResourceProgessThickness) - CFG_PROPERTY(int, resourceSize, ResourceSize) - CFG_PROPERTY(int, tabIndicatorHeight, TabIndicatorHeight) - CFG_PROPERTY(int, tabIndicatorSpacing, TabIndicatorSpacing) - CFG_PROPERTY(int, weatherWidth, WeatherWidth) - -public: - explicit DashboardSizes(QObject *parent = nullptr); -}; - -class Dashboard : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(int, mediaUpdateInterval, MediaUpdateInterval) - CFG_SECTION(Performance, performance, Performance) - CFG_PROPERTY(int, resourceUpdateInterval, ResourceUpdateInterval) - CFG_SECTION(DashboardSizes, sizes, Sizes) - -public: - explicit Dashboard(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Dock.cpp b/Plugins/ZShell/Config/Dock.cpp deleted file mode 100644 index dfe2f0c..0000000 --- a/Plugins/ZShell/Config/Dock.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Dock.hpp" - -Dock::Dock(QObject *parent) : ConfigSection(parent) { - m_enable = false; - m_height = 80; - m_hoverToReveal = false; - m_ignoredAppRegexes = {}; - m_pinnedApps = { - QStringLiteral("com.ayugram.desktop"), - QStringLiteral("com.obsproject.studio"), - QStringLiteral("librewolf"), - }; - m_pinnedOnStartup = false; - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Dock.hpp b/Plugins/ZShell/Config/Dock.hpp deleted file mode 100644 index 51a9e51..0000000 --- a/Plugins/ZShell/Config/Dock.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class Dock : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enable, Enable) - CFG_PROPERTY(int, height, Height) - CFG_PROPERTY(bool, hoverToReveal, HoverToReveal) - CFG_PROPERTY(QVariantList, ignoredAppRegexes, IgnoredAppRegexes) - CFG_PROPERTY(QVariantList, pinnedApps, PinnedApps) - CFG_PROPERTY(bool, pinnedOnStartup, PinnedOnStartup) - -public: - explicit Dock(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/General.cpp b/Plugins/ZShell/Config/General.cpp deleted file mode 100644 index 9f914c3..0000000 --- a/Plugins/ZShell/Config/General.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "General.hpp" - -namespace { -QVariantList strList(std::initializer_list items) { - QVariantList list; - for (auto *item : items) list << QString::fromLatin1(item); - return list; -} - -QVariantMap threshold(const char *icon, const char *message, const char *name, int perc) { - QVariantMap m; - m["icon"] = QString::fromLatin1(icon); - m["message"] = QString::fromLatin1(message); - m["name"] = QString::fromLatin1(name); - m["perc"] = perc; - return m; -} -} - -Apps::Apps(QObject *parent) : ConfigSection(parent) { - m_archiver = strList({"ark"}); - m_audio = strList({"pavucontrol"}); - m_document = strList({"libreoffice"}); - m_editor = strList({"kate"}); - m_explorer = strList({"dolphin"}); - m_image = strList({"imv"}); - m_playback = strList({"vlc"}); - m_terminal = strList({"wezterm"}); - wireSignals(); -} - -Battery::Battery(QObject *parent) : ConfigSection(parent) { - m_critPerc = 5; - m_popupThresholds = { - threshold("battery_android_frame_2", "Battery low", "Low battery", 20), - threshold("battery_android_frame_2", "Battery lower", "Low battery", 15), - threshold("battery_android_frame_2", "Battery lowest", "Low battery", 10), - }; - wireSignals(); -} - -ColorSettings::ColorSettings(QObject *parent) : ConfigSection(parent) { - m_hyprsunsetTemp = 2600; - m_mode = QStringLiteral("dark"); - m_neovimColors = false; - m_scheduleDark = false; - m_scheduleDarkEnd = 600; - m_scheduleDarkStart = 1140; - m_scheduleHyprsunset = true; - m_scheduleHyprsunsetEnd = 570; - m_scheduleHyprsunsetStart = 1200; - m_schemeGeneration = true; - m_smart = false; - wireSignals(); -} - -Idle::Idle(QObject *parent) : ConfigSection(parent) { - QVariantMap lock; - lock["idleAction"] = QStringLiteral("lock"); - lock["name"] = QStringLiteral("Lock"); - lock["timeout"] = 180; - m_timeouts = { lock }; - wireSignals(); -} - -General::General(QObject *parent) : ConfigSection(parent) { - m_apps = new Apps(this); - m_battery = new Battery(this); - m_color = new ColorSettings(this); - m_dateFormat = QStringLiteral("ddd d MMM - hh:mm:ss"); - m_desktopIcons = true; - m_idle = new Idle(this); - m_logo = QString(); - m_showOverFullscreen = true; - m_wallpaperPath = QStringLiteral("/mnt/IronWolf/SDImages/SWWW_Wals/"); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/General.hpp b/Plugins/ZShell/Config/General.hpp deleted file mode 100644 index 8bfbbf6..0000000 --- a/Plugins/ZShell/Config/General.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class Apps : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(QVariantList, archiver, Archiver) - CFG_PROPERTY(QVariantList, audio, Audio) - CFG_PROPERTY(QVariantList, document, Document) - CFG_PROPERTY(QVariantList, editor, Editor) - CFG_PROPERTY(QVariantList, explorer, Explorer) - CFG_PROPERTY(QVariantList, image, Image) - CFG_PROPERTY(QVariantList, playback, Playback) - CFG_PROPERTY(QVariantList, terminal, Terminal) - -public: - explicit Apps(QObject *parent = nullptr); -}; - -class Battery : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, critPerc, CritPerc) - // Array of { icon, message, name, perc } objects. - CFG_PROPERTY(QVariantList, popupThresholds, PopupThresholds) - -public: - explicit Battery(QObject *parent = nullptr); -}; - -class ColorSettings : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, hyprsunsetTemp, HyprsunsetTemp) - CFG_PROPERTY(QString, mode, Mode) - CFG_PROPERTY(bool, neovimColors, NeovimColors) - CFG_PROPERTY(bool, scheduleDark, ScheduleDark) - CFG_PROPERTY(int, scheduleDarkEnd, ScheduleDarkEnd) - CFG_PROPERTY(int, scheduleDarkStart, ScheduleDarkStart) - CFG_PROPERTY(bool, scheduleHyprsunset, ScheduleHyprsunset) - CFG_PROPERTY(int, scheduleHyprsunsetEnd, ScheduleHyprsunsetEnd) - CFG_PROPERTY(int, scheduleHyprsunsetStart, ScheduleHyprsunsetStart) - CFG_PROPERTY(bool, schemeGeneration, SchemeGeneration) - CFG_PROPERTY(bool, smart, Smart) - -public: - explicit ColorSettings(QObject *parent = nullptr); -}; - -class Idle : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - // Array of { idleAction, name, timeout } objects. - CFG_PROPERTY(QVariantList, timeouts, Timeouts) - -public: - explicit Idle(QObject *parent = nullptr); -}; - -class General : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_SECTION(Apps, apps, Apps) - CFG_SECTION(Battery, battery, Battery) - CFG_SECTION(ColorSettings, color, Color) - CFG_PROPERTY(QString, dateFormat, DateFormat) - CFG_PROPERTY(bool, desktopIcons, DesktopIcons) - CFG_SECTION(Idle, idle, Idle) - CFG_PROPERTY(QString, logo, Logo) - CFG_PROPERTY(bool, showOverFullscreen, ShowOverFullscreen) - CFG_PROPERTY(QString, wallpaperPath, WallpaperPath) - -public: - explicit General(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Launcher.cpp b/Plugins/ZShell/Config/Launcher.cpp deleted file mode 100644 index 6a0f475..0000000 --- a/Plugins/ZShell/Config/Launcher.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "Launcher.hpp" - -namespace { -QVariantList strList(std::initializer_list items) { - QVariantList list; - for (auto *item : items) list << QString::fromLatin1(item); - return list; -} - -QVariantMap action(QVariantList command, bool dangerous, const char *description, - bool enabled, const char *icon, const char *name) { - QVariantMap m; - m["command"] = std::move(command); - m["dangerous"] = dangerous; - m["description"] = QString::fromLatin1(description); - m["enabled"] = enabled; - m["icon"] = QString::fromLatin1(icon); - m["name"] = QString::fromLatin1(name); - return m; -} -} - -LauncherSizes::LauncherSizes(QObject *parent) : ConfigSection(parent) { - m_itemHeight = 50; - m_itemWidth = 600; - m_wallpaperHeight = 200; - m_wallpaperWidth = 280; - wireSignals(); -} - -UseFuzzy::UseFuzzy(QObject *parent) : ConfigSection(parent) { - m_actions = true; - m_apps = true; - m_schemes = true; - m_variants = true; - m_wallpapers = true; - wireSignals(); -} - -Launcher::Launcher(QObject *parent) : ConfigSection(parent) { - m_actionPrefix = QStringLiteral("<"); - m_actions = { - action(strList({"autocomplete", "calc"}), false, "Do simple math equations", true, "calculate", "Calculator"), - action(strList({"setMode", "light"}), false, "Change to light mode", true, "light_mode", "Light"), - action(strList({"setMode", "dark"}), false, "Change to dark mode", true, "dark_mode", "Dark"), - action(strList({"autocomplete", "wallpaper"}), false, "Change the current wallpaper", true, "image", "Wallpaper"), - action(strList({"autocomplete", "variant"}), false, "Change the current scheme variant", true, "colors", "Variant"), - action(strList({"systemctl", "poweroff"}), true, "Shutdown the system", true, "power_settings_new", "Shutdown"), - action(strList({"systemctl", "reboot"}), true, "Reboot the system", true, "cached", "Reboot"), - action(strList({"loginctl", "terminate-user", ""}), true, "Log out of the current session", true, "logout", "Logout"), - action(strList({"loginctl", "lock-session"}), false, "Lock the current session", true, "lock", "Lock"), - action(strList({"systemctl", "suspend-then-hibernate"}), false, "Suspend then hibernate", true, "bedtime", "Sleep"), - }; - m_dragThreshold = 150; - m_enableDangerousActions = true; - m_enabled = true; - m_favoriteApps = strList({"Balatro", "Slay the Spire 2", "com.obsproject.Studio"}); - m_hiddenApps = strList({ - "zellij", "vim", "jshell-java-openjdk", "jconsole-java-openjdk", - "jshell-java21-openjdk", "jconsole-java21-openjdk", "jshell-java17-openjdk", - "jconsole-java17-openjdk", "org.neovim.nvim", "avahi-discover", "bvnc", - "bssh", "nm-connection-editor", - }); - m_maxAppsShown = 18; - m_maxWallpapers = 7; - m_sizes = new LauncherSizes(this); - m_specialPrefix = QStringLiteral("@"); - m_useFuzzy = new UseFuzzy(this); - m_uwsm = true; - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Launcher.hpp b/Plugins/ZShell/Config/Launcher.hpp deleted file mode 100644 index 785364b..0000000 --- a/Plugins/ZShell/Config/Launcher.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class LauncherSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, itemHeight, ItemHeight) - CFG_PROPERTY(int, itemWidth, ItemWidth) - CFG_PROPERTY(int, wallpaperHeight, WallpaperHeight) - CFG_PROPERTY(int, wallpaperWidth, WallpaperWidth) - -public: - explicit LauncherSizes(QObject *parent = nullptr); -}; - -class UseFuzzy : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, actions, Actions) - CFG_PROPERTY(bool, apps, Apps) - CFG_PROPERTY(bool, schemes, Schemes) - CFG_PROPERTY(bool, variants, Variants) - CFG_PROPERTY(bool, wallpapers, Wallpapers) - -public: - explicit UseFuzzy(QObject *parent = nullptr); -}; - -class Launcher : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(QString, actionPrefix, ActionPrefix) - // Array of action-definition objects (command, dangerous, description, - // enabled, icon, name). - CFG_PROPERTY(QVariantList, actions, Actions) - CFG_PROPERTY(int, dragThreshold, DragThreshold) - CFG_PROPERTY(bool, enableDangerousActions, EnableDangerousActions) - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(QVariantList, favoriteApps, FavoriteApps) - CFG_PROPERTY(QVariantList, hiddenApps, HiddenApps) - CFG_PROPERTY(int, maxAppsShown, MaxAppsShown) - CFG_PROPERTY(int, maxWallpapers, MaxWallpapers) - CFG_SECTION(LauncherSizes, sizes, Sizes) - CFG_PROPERTY(QString, specialPrefix, SpecialPrefix) - CFG_SECTION(UseFuzzy, useFuzzy, UseFuzzy) - CFG_PROPERTY(bool, uwsm, Uwsm) - -public: - explicit Launcher(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Lock.cpp b/Plugins/ZShell/Config/Lock.cpp deleted file mode 100644 index 7b1f6bd..0000000 --- a/Plugins/ZShell/Config/Lock.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "Lock.hpp" - -LockSizes::LockSizes(QObject *parent) : ConfigSection(parent) { - m_centerWidth = 600; - m_heightMult = 0.7; - m_ratio = 1.78; - wireSignals(); -} - -Lock::Lock(QObject *parent) : ConfigSection(parent) { - m_blurAmount = 10; - m_enableFprint = true; - m_maxFprintTries = 3; - m_recolorLogo = false; - m_showNotifContent = true; - m_showNotifIcon = true; - m_sizes = new LockSizes(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Lock.hpp b/Plugins/ZShell/Config/Lock.hpp deleted file mode 100644 index e753339..0000000 --- a/Plugins/ZShell/Config/Lock.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class LockSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, centerWidth, CenterWidth) - CFG_PROPERTY(qreal, heightMult, HeightMult) - CFG_PROPERTY(qreal, ratio, Ratio) - -public: - explicit LockSizes(QObject *parent = nullptr); -}; - -class Lock : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, blurAmount, BlurAmount) - CFG_PROPERTY(bool, enableFprint, EnableFprint) - CFG_PROPERTY(int, maxFprintTries, MaxFprintTries) - CFG_PROPERTY(bool, recolorLogo, RecolorLogo) - CFG_PROPERTY(bool, showNotifContent, ShowNotifContent) - CFG_PROPERTY(bool, showNotifIcon, ShowNotifIcon) - CFG_SECTION(LockSizes, sizes, Sizes) - -public: - explicit Lock(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Notifs.cpp b/Plugins/ZShell/Config/Notifs.cpp deleted file mode 100644 index e3ef624..0000000 --- a/Plugins/ZShell/Config/Notifs.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "Notifs.hpp" - -NotifsSizes::NotifsSizes(QObject *parent) : ConfigSection(parent) { - m_badge = 20; - m_image = 41; - m_width = 400; - wireSignals(); -} - -Notifs::Notifs(QObject *parent) : ConfigSection(parent) { - m_actionOnClick = false; - m_appNotifCooldown = 0; - m_clearThreshold = 0.3; - m_defaultExpireTimeout = 5000; - m_expandThreshold = 20; - m_expire = true; - m_groupPreviewNum = 5; - m_openExpanded = false; - m_showInFullscreen = false; - m_sizes = new NotifsSizes(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Notifs.hpp b/Plugins/ZShell/Config/Notifs.hpp deleted file mode 100644 index 12ffe13..0000000 --- a/Plugins/ZShell/Config/Notifs.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class NotifsSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, badge, Badge) - CFG_PROPERTY(int, image, Image) - CFG_PROPERTY(int, width, Width) - -public: - explicit NotifsSizes(QObject *parent = nullptr); -}; - -class Notifs : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, actionOnClick, ActionOnClick) - CFG_PROPERTY(int, appNotifCooldown, AppNotifCooldown) - CFG_PROPERTY(qreal, clearThreshold, ClearThreshold) - CFG_PROPERTY(int, defaultExpireTimeout, DefaultExpireTimeout) - CFG_PROPERTY(int, expandThreshold, ExpandThreshold) - CFG_PROPERTY(bool, expire, Expire) - CFG_PROPERTY(int, groupPreviewNum, GroupPreviewNum) - CFG_PROPERTY(bool, openExpanded, OpenExpanded) - CFG_PROPERTY(bool, showInFullscreen, ShowInFullscreen) - CFG_SECTION(NotifsSizes, sizes, Sizes) - -public: - explicit Notifs(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Osd.cpp b/Plugins/ZShell/Config/Osd.cpp deleted file mode 100644 index 5f54754..0000000 --- a/Plugins/ZShell/Config/Osd.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "Osd.hpp" - -OsdSizes::OsdSizes(QObject *parent) : ConfigSection(parent) { - m_sliderHeight = 150; - m_sliderWidth = 30; - wireSignals(); -} - -Osd::Osd(QObject *parent) : ConfigSection(parent) { - m_allMonBrightness = true; - m_enableBrightness = true; - m_enableMicrophone = true; - m_enabled = true; - m_hideDelay = 3000; - m_sizes = new OsdSizes(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Osd.hpp b/Plugins/ZShell/Config/Osd.hpp deleted file mode 100644 index e5b9e45..0000000 --- a/Plugins/ZShell/Config/Osd.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class OsdSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, sliderHeight, SliderHeight) - CFG_PROPERTY(int, sliderWidth, SliderWidth) - -public: - explicit OsdSizes(QObject *parent = nullptr); -}; - -class Osd : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, allMonBrightness, AllMonBrightness) - CFG_PROPERTY(bool, enableBrightness, EnableBrightness) - CFG_PROPERTY(bool, enableMicrophone, EnableMicrophone) - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(int, hideDelay, HideDelay) - CFG_SECTION(OsdSizes, sizes, Sizes) - -public: - explicit Osd(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Overview.cpp b/Plugins/ZShell/Config/Overview.cpp deleted file mode 100644 index c7c54de..0000000 --- a/Plugins/ZShell/Config/Overview.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Overview.hpp" - -Overview::Overview(QObject *parent) : ConfigSection(parent) { - m_columns = 5; - m_enable = false; - m_rows = 2; - m_scale = 0.16; - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Overview.hpp b/Plugins/ZShell/Config/Overview.hpp deleted file mode 100644 index 7b10475..0000000 --- a/Plugins/ZShell/Config/Overview.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class Overview : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, columns, Columns) - CFG_PROPERTY(bool, enable, Enable) - CFG_PROPERTY(int, rows, Rows) - CFG_PROPERTY(qreal, scale, Scale) - -public: - explicit Overview(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Screenshot.cpp b/Plugins/ZShell/Config/Screenshot.cpp deleted file mode 100644 index 03c18f6..0000000 --- a/Plugins/ZShell/Config/Screenshot.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Screenshot.hpp" - -Screenshot::Screenshot(QObject *parent) : ConfigSection(parent) { - m_enable_pp = false; - m_mode = QStringLiteral("manual"); - m_radius = 49; - m_rounding = false; - m_saveOnCopy = false; - m_shadow = true; - m_shadow_blur = 0; - m_shadow_color = { 0, 0, 0, 160 }; - m_shadow_offset_x = 30; - m_shadow_offset_y = 50; - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Screenshot.hpp b/Plugins/ZShell/Config/Screenshot.hpp deleted file mode 100644 index 6d846c6..0000000 --- a/Plugins/ZShell/Config/Screenshot.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class Screenshot : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - // Property names below must match the JSON keys exactly (the JSON here - // uses snake_case for these particular keys, so we do too). - CFG_PROPERTY(bool, enable_pp, EnablePp) - CFG_PROPERTY(QString, mode, Mode) - CFG_PROPERTY(int, radius, Radius) - CFG_PROPERTY(bool, rounding, Rounding) - CFG_PROPERTY(bool, saveOnCopy, SaveOnCopy) - CFG_PROPERTY(bool, shadow, Shadow) - CFG_PROPERTY(int, shadow_blur, ShadowBlur) - // [r, g, b, a] - CFG_PROPERTY(QVariantList, shadow_color, ShadowColor) - CFG_PROPERTY(int, shadow_offset_x, ShadowOffsetX) - CFG_PROPERTY(int, shadow_offset_y, ShadowOffsetY) - -public: - explicit Screenshot(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Services.cpp b/Plugins/ZShell/Config/Services.cpp deleted file mode 100644 index 2ab3abc..0000000 --- a/Plugins/ZShell/Config/Services.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "Services.hpp" - -Services::Services(QObject *parent) : ConfigSection(parent) { - m_audioIncrement = 0.1; - m_brightnessIncrement = 0.1; - m_ddcutilService = true; - m_defaultPlayer = QStringLiteral("Spotify"); - m_gpuType = QStringLiteral("NVIDIA"); - m_maxVolume = 1; - m_minBrightness = 0.01; - - QVariantMap alias; - alias["from"] = QStringLiteral("com.github.th_ch.youtube_music"); - alias["to"] = QStringLiteral("YT Music"); - m_playerAliases = { alias }; - - m_updates = true; - m_useFahrenheit = false; - m_useTwelveHourClock = false; - m_visualizerBars = 50; - m_weatherLocation = QString(); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Services.hpp b/Plugins/ZShell/Config/Services.hpp deleted file mode 100644 index b16eda9..0000000 --- a/Plugins/ZShell/Config/Services.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class Services : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(qreal, audioIncrement, AudioIncrement) - CFG_PROPERTY(qreal, brightnessIncrement, BrightnessIncrement) - CFG_PROPERTY(bool, ddcutilService, DdcutilService) - CFG_PROPERTY(QString, defaultPlayer, DefaultPlayer) - CFG_PROPERTY(QString, gpuType, GpuType) - CFG_PROPERTY(qreal, maxVolume, MaxVolume) - CFG_PROPERTY(qreal, minBrightness, MinBrightness) - // Array of { from, to } objects. - CFG_PROPERTY(QVariantList, playerAliases, PlayerAliases) - CFG_PROPERTY(bool, updates, Updates) - CFG_PROPERTY(bool, useFahrenheit, UseFahrenheit) - CFG_PROPERTY(bool, useTwelveHourClock, UseTwelveHourClock) - CFG_PROPERTY(int, visualizerBars, VisualizerBars) - CFG_PROPERTY(QString, weatherLocation, WeatherLocation) - -public: - explicit Services(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Sidebar.cpp b/Plugins/ZShell/Config/Sidebar.cpp deleted file mode 100644 index 2025cc0..0000000 --- a/Plugins/ZShell/Config/Sidebar.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "Sidebar.hpp" - -SidebarSizes::SidebarSizes(QObject *parent) : ConfigSection(parent) { - m_width = 520; - wireSignals(); -} - -Sidebar::Sidebar(QObject *parent) : ConfigSection(parent) { - m_dragThreshold = 30; - m_enabled = true; - m_sizes = new SidebarSizes(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Sidebar.hpp b/Plugins/ZShell/Config/Sidebar.hpp deleted file mode 100644 index 2f72713..0000000 --- a/Plugins/ZShell/Config/Sidebar.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include - -class SidebarSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, width, Width) - -public: - explicit SidebarSizes(QObject *parent = nullptr); -}; - -class Sidebar : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, dragThreshold, DragThreshold) - CFG_PROPERTY(bool, enabled, Enabled) - CFG_SECTION(SidebarSizes, sizes, Sizes) - -public: - explicit Sidebar(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/Tokens.cpp b/Plugins/ZShell/Config/Tokens.cpp deleted file mode 100644 index c16934c..0000000 --- a/Plugins/ZShell/Config/Tokens.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "Tokens.hpp" - -TokensRounding::TokensRounding(QObject* parent) : QObject(parent) { - m_extraSmall = 4; - m_full = 1000; - m_large = 24; - m_medium = 16; - m_normal = 18; - m_scale = 1; - m_small = 12; - m_smallest = 8; -} - -TokensPadding::TokensPadding(QObject* parent) : QObject(parent) { - m_extraLarge = 28; - m_extraLargeIncreased = 32; - m_extraSmall = 4; - m_large = 16; - m_largeIncreased = 20; - m_larger = 12; - m_normal = 8; - m_scale = 1; - m_small = 5; - m_smaller = 7; - m_smallest = 2; -} - -TokensSpacing::TokensSpacing(QObject* parent) : QObject(parent) { - m_extraSmall = 4; - m_large = 20; - m_larger = 16; - m_normal = 12; - m_scale = 1; - m_small = 8; - m_smaller = 10; -} - -TokensFontSize::TokensFontSize(QObject* parent) : QObject(parent) { - m_extraLarge = 28; - m_large = 18; - m_larger = 16; - m_medium = 14; - m_normal = 13; - m_scale = 1; - m_small = 11; - m_smaller = 12; -} - -TokensFont::TokensFont(QObject* parent) : QObject(parent) { - m_size = new TokensFontSize(this); -} - -TokensAnimCurves::TokensAnimCurves(QObject* parent) : QObject(parent) { - m_emphasized = { - 0.05, - 0, - 2.0 / 15.0, - 0.06, - 1.0 / 6.0, - 0.4, - 5.0 / 24.0, - 0.82, - 0.25, - 1, - 1, - 1}; - m_emphasizedAccel = {0.3, 0, 0.8, 0.15, 1, 1}; - m_emphasizedDecel = {0.05, 0.7, 0.1, 1, 1, 1}; - m_expressiveDefaultEffects = {0.34, 0.8, 0.34, 1, 1, 1}; - m_expressiveDefaultSpatial = {0.38, 1.21, 0.22, 1, 1, 1}; - m_expressiveEffects = {0.34, 0.8, 0.34, 1, 1, 1}; - m_expressiveFastEffects = {0.31, 0.94, 0.34, 1, 1, 1}; - m_expressiveFastSpatial = {0.42, 1.67, 0.21, 0.9, 1, 1}; - m_expressiveSlowEffects = {0.34, 0.88, 0.34, 1, 1, 1}; - m_expressiveSlowSpatial = {0.39, 1.29, 0.35, 0.98, 1, 1}; - m_standard = {0.2, 0, 0, 1, 1, 1}; - m_standardAccel = {0.3, 0, 1, 1, 1, 1}; - m_standardDecel = {0, 0, 0, 1, 1, 1}; -} - -TokensAnimDurations::TokensAnimDurations(QObject* parent) : QObject(parent) { - m_expressiveDefaultSpatial = 500; - m_expressiveEffects = 200; - m_expressiveFastEffects = 150; - m_expressiveFastSpatial = 350; - m_expressiveSlowEffects = 300; - m_extraLarge = 1000; - m_large = 600; - m_normal = 400; - m_scale = 1; - m_small = 200; -} - -TokensAnim::TokensAnim(QObject* parent) : QObject(parent) { - m_curves = new TokensAnimCurves(this); - m_durations = new TokensAnimDurations(this); -} - -Tokens::Tokens(QObject* parent) : QObject(parent) { - m_rounding = new TokensRounding(this); - m_padding = new TokensPadding(this); - m_spacing = new TokensSpacing(this); - m_font = new TokensFont(this); - m_anim = new TokensAnim(this); -} - -Tokens* Tokens::create(QQmlEngine*, QJSEngine*) { - return new Tokens(); -} diff --git a/Plugins/ZShell/Config/Tokens.hpp b/Plugins/ZShell/Config/Tokens.hpp deleted file mode 100644 index 9b87bd0..0000000 --- a/Plugins/ZShell/Config/Tokens.hpp +++ /dev/null @@ -1,348 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -class TokensRounding : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(qreal extraSmall READ extraSmall CONSTANT) - Q_PROPERTY(qreal full READ full CONSTANT) - Q_PROPERTY(qreal large READ large CONSTANT) - Q_PROPERTY(qreal medium READ medium CONSTANT) - Q_PROPERTY(qreal normal READ normal CONSTANT) - Q_PROPERTY(qreal scale READ scale CONSTANT) - Q_PROPERTY(qreal small READ small CONSTANT) - Q_PROPERTY(qreal smallest READ smallest CONSTANT) - - public: - explicit TokensRounding(QObject* parent = nullptr); - - qreal extraSmall() const { return m_extraSmall; } - qreal full() const { return m_full; } - qreal large() const { return m_large; } - qreal medium() const { return m_medium; } - qreal normal() const { return m_normal; } - qreal scale() const { return m_scale; } - qreal small() const { return m_small; } - qreal smallest() const { return m_smallest; } - - private: - qreal m_extraSmall; - qreal m_full; - qreal m_large; - qreal m_medium; - qreal m_normal; - qreal m_scale; - qreal m_small; - qreal m_smallest; -}; - -class TokensPadding : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(qreal extraLarge READ extraLarge CONSTANT) - Q_PROPERTY(qreal extraLargeIncreased READ extraLargeIncreased CONSTANT) - Q_PROPERTY(qreal extraSmall READ extraSmall CONSTANT) - Q_PROPERTY(qreal large READ large CONSTANT) - Q_PROPERTY(qreal largeIncreased READ largeIncreased CONSTANT) - Q_PROPERTY(qreal larger READ larger CONSTANT) - Q_PROPERTY(qreal normal READ normal CONSTANT) - Q_PROPERTY(qreal scale READ scale CONSTANT) - Q_PROPERTY(qreal small READ small CONSTANT) - Q_PROPERTY(qreal smaller READ smaller CONSTANT) - Q_PROPERTY(qreal smallest READ smallest CONSTANT) - - public: - explicit TokensPadding(QObject* parent = nullptr); - - qreal extraLarge() const { return m_extraLarge; } - qreal extraLargeIncreased() const { return m_extraLargeIncreased; } - qreal extraSmall() const { return m_extraSmall; } - qreal large() const { return m_large; } - qreal largeIncreased() const { return m_largeIncreased; } - qreal larger() const { return m_larger; } - qreal normal() const { return m_normal; } - qreal scale() const { return m_scale; } - qreal small() const { return m_small; } - qreal smaller() const { return m_smaller; } - qreal smallest() const { return m_smallest; } - - private: - qreal m_extraLarge; - qreal m_extraLargeIncreased; - qreal m_extraSmall; - qreal m_large; - qreal m_largeIncreased; - qreal m_larger; - qreal m_normal; - qreal m_scale; - qreal m_small; - qreal m_smaller; - qreal m_smallest; -}; - -class TokensSpacing : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(qreal extraSmall READ extraSmall CONSTANT) - Q_PROPERTY(qreal large READ large CONSTANT) - Q_PROPERTY(qreal larger READ larger CONSTANT) - Q_PROPERTY(qreal normal READ normal CONSTANT) - Q_PROPERTY(qreal scale READ scale CONSTANT) - Q_PROPERTY(qreal small READ small CONSTANT) - Q_PROPERTY(qreal smaller READ smaller CONSTANT) - - public: - explicit TokensSpacing(QObject* parent = nullptr); - - qreal extraSmall() const { return m_extraSmall; } - qreal large() const { return m_large; } - qreal larger() const { return m_larger; } - qreal normal() const { return m_normal; } - qreal scale() const { return m_scale; } - qreal small() const { return m_small; } - qreal smaller() const { return m_smaller; } - - private: - qreal m_extraSmall; - qreal m_large; - qreal m_larger; - qreal m_normal; - qreal m_scale; - qreal m_small; - qreal m_smaller; -}; - -class TokensFontSize : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(qreal extraLarge READ extraLarge CONSTANT) - Q_PROPERTY(qreal large READ large CONSTANT) - Q_PROPERTY(qreal larger READ larger CONSTANT) - Q_PROPERTY(qreal medium READ medium CONSTANT) - Q_PROPERTY(qreal normal READ normal CONSTANT) - Q_PROPERTY(qreal scale READ scale CONSTANT) - Q_PROPERTY(qreal small READ small CONSTANT) - Q_PROPERTY(qreal smaller READ smaller CONSTANT) - - public: - explicit TokensFontSize(QObject* parent = nullptr); - - qreal extraLarge() const { return m_extraLarge; } - qreal large() const { return m_large; } - qreal larger() const { return m_larger; } - qreal medium() const { return m_medium; } - qreal normal() const { return m_normal; } - qreal scale() const { return m_scale; } - qreal small() const { return m_small; } - qreal smaller() const { return m_smaller; } - - private: - qreal m_extraLarge; - qreal m_large; - qreal m_larger; - qreal m_medium; - qreal m_normal; - qreal m_scale; - qreal m_small; - qreal m_smaller; -}; - -class TokensFont : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(TokensFontSize* size READ size CONSTANT) - - public: - explicit TokensFont(QObject* parent = nullptr); - - TokensFontSize* size() const { return m_size; } - - private: - TokensFontSize* m_size = nullptr; -}; - -class TokensAnimCurves : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(QVariantList emphasized READ emphasized CONSTANT) - Q_PROPERTY(QVariantList emphasizedAccel READ emphasizedAccel CONSTANT) - Q_PROPERTY(QVariantList emphasizedDecel READ emphasizedDecel CONSTANT) - Q_PROPERTY( - QVariantList expressiveDefaultEffects READ expressiveDefaultEffects - CONSTANT) - Q_PROPERTY( - QVariantList expressiveDefaultSpatial READ expressiveDefaultSpatial - CONSTANT) - Q_PROPERTY(QVariantList expressiveEffects READ expressiveEffects CONSTANT) - Q_PROPERTY( - QVariantList expressiveFastEffects READ expressiveFastEffects CONSTANT) - Q_PROPERTY( - QVariantList expressiveFastSpatial READ expressiveFastSpatial CONSTANT) - Q_PROPERTY( - QVariantList expressiveSlowEffects READ expressiveSlowEffects CONSTANT) - Q_PROPERTY( - QVariantList expressiveSlowSpatial READ expressiveSlowSpatial CONSTANT) - Q_PROPERTY(QVariantList standard READ standard CONSTANT) - Q_PROPERTY(QVariantList standardAccel READ standardAccel CONSTANT) - Q_PROPERTY(QVariantList standardDecel READ standardDecel CONSTANT) - - public: - explicit TokensAnimCurves(QObject* parent = nullptr); - - QVariantList emphasized() const { return m_emphasized; } - QVariantList emphasizedAccel() const { return m_emphasizedAccel; } - QVariantList emphasizedDecel() const { return m_emphasizedDecel; } - QVariantList expressiveDefaultEffects() const { - return m_expressiveDefaultEffects; - } - QVariantList expressiveDefaultSpatial() const { - return m_expressiveDefaultSpatial; - } - QVariantList expressiveEffects() const { return m_expressiveEffects; } - QVariantList expressiveFastEffects() const { - return m_expressiveFastEffects; - } - QVariantList expressiveFastSpatial() const { - return m_expressiveFastSpatial; - } - QVariantList expressiveSlowEffects() const { - return m_expressiveSlowEffects; - } - QVariantList expressiveSlowSpatial() const { - return m_expressiveSlowSpatial; - } - QVariantList standard() const { return m_standard; } - QVariantList standardAccel() const { return m_standardAccel; } - QVariantList standardDecel() const { return m_standardDecel; } - - private: - QVariantList m_emphasized; - QVariantList m_emphasizedAccel; - QVariantList m_emphasizedDecel; - QVariantList m_expressiveDefaultEffects; - QVariantList m_expressiveDefaultSpatial; - QVariantList m_expressiveEffects; - QVariantList m_expressiveFastEffects; - QVariantList m_expressiveFastSpatial; - QVariantList m_expressiveSlowEffects; - QVariantList m_expressiveSlowSpatial; - QVariantList m_standard; - QVariantList m_standardAccel; - QVariantList m_standardDecel; -}; - -class TokensAnimDurations : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY( - int expressiveDefaultSpatial READ expressiveDefaultSpatial CONSTANT) - Q_PROPERTY(int expressiveEffects READ expressiveEffects CONSTANT) - Q_PROPERTY(int expressiveFastEffects READ expressiveFastEffects CONSTANT) - Q_PROPERTY(int expressiveFastSpatial READ expressiveFastSpatial CONSTANT) - Q_PROPERTY(int expressiveSlowEffects READ expressiveSlowEffects CONSTANT) - Q_PROPERTY(int extraLarge READ extraLarge CONSTANT) - Q_PROPERTY(int large READ large CONSTANT) - Q_PROPERTY(int normal READ normal CONSTANT) - Q_PROPERTY(qreal scale READ scale CONSTANT) - Q_PROPERTY(int small READ small CONSTANT) - - public: - explicit TokensAnimDurations(QObject* parent = nullptr); - - int expressiveDefaultSpatial() const { return m_expressiveDefaultSpatial; } - int expressiveEffects() const { return m_expressiveEffects; } - int expressiveFastEffects() const { return m_expressiveFastEffects; } - int expressiveFastSpatial() const { return m_expressiveFastSpatial; } - int expressiveSlowEffects() const { return m_expressiveSlowEffects; } - int extraLarge() const { return m_extraLarge; } - int large() const { return m_large; } - int normal() const { return m_normal; } - qreal scale() const { return m_scale; } - int small() const { return m_small; } - - private: - int m_expressiveDefaultSpatial; - int m_expressiveEffects; - int m_expressiveFastEffects; - int m_expressiveFastSpatial; - int m_expressiveSlowEffects; - int m_extraLarge; - int m_large; - int m_normal; - qreal m_scale; - int m_small; -}; - -class TokensAnim : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - QML_UNCREATABLE("Instantiated internally by Tokens") - - Q_PROPERTY(TokensAnimCurves* curves READ curves CONSTANT) - Q_PROPERTY(TokensAnimDurations* durations READ durations CONSTANT) - - public: - explicit TokensAnim(QObject* parent = nullptr); - - TokensAnimCurves* curves() const { return m_curves; } - TokensAnimDurations* durations() const { return m_durations; } - - private: - TokensAnimCurves* m_curves = nullptr; - TokensAnimDurations* m_durations = nullptr; -}; - -class Tokens : public QObject { - Q_OBJECT - QML_ELEMENT - QML_SINGLETON - - Q_PROPERTY(TokensRounding* rounding READ rounding CONSTANT) - Q_PROPERTY(TokensPadding* padding READ padding CONSTANT) - Q_PROPERTY(TokensSpacing* spacing READ spacing CONSTANT) - Q_PROPERTY(TokensFont* font READ font CONSTANT) - Q_PROPERTY(TokensAnim* anim READ anim CONSTANT) - - public: - explicit Tokens(QObject* parent = nullptr); - static Tokens* create(QQmlEngine*, QJSEngine*); - - TokensRounding* rounding() const { return m_rounding; } - TokensPadding* padding() const { return m_padding; } - TokensSpacing* spacing() const { return m_spacing; } - TokensFont* font() const { return m_font; } - TokensAnim* anim() const { return m_anim; } - - private: - TokensRounding* m_rounding = nullptr; - TokensPadding* m_padding = nullptr; - TokensSpacing* m_spacing = nullptr; - TokensFont* m_font = nullptr; - TokensAnim* m_anim = nullptr; -}; diff --git a/Plugins/ZShell/Config/Utilities.cpp b/Plugins/ZShell/Config/Utilities.cpp deleted file mode 100644 index fd3e5e9..0000000 --- a/Plugins/ZShell/Config/Utilities.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "Utilities.hpp" - -UtilitiesSizes::UtilitiesSizes(QObject *parent) : ConfigSection(parent) { - m_toastWidth = 430; - m_width = 430; - wireSignals(); -} - -Toasts::Toasts(QObject *parent) : ConfigSection(parent) { - m_audioInputChanged = true; - m_audioOutputChanged = true; - m_capsLockChanged = true; - m_chargingChanged = true; - m_configLoaded = true; - m_dndChanged = true; - m_gameModeChanged = true; - m_kbLayoutChanged = true; - m_kbLimit = true; - m_nowPlaying = false; - m_numLockChanged = true; - m_vpnChanged = true; - wireSignals(); -} - -Vpn::Vpn(QObject *parent) : ConfigSection(parent) { - m_enabled = false; - m_provider = { QStringLiteral("netbird") }; - wireSignals(); -} - -Utilities::Utilities(QObject *parent) : ConfigSection(parent) { - m_enabled = true; - m_maxToasts = 4; - m_sizes = new UtilitiesSizes(this); - m_toasts = new Toasts(this); - m_vpn = new Vpn(this); - wireSignals(); -} diff --git a/Plugins/ZShell/Config/Utilities.hpp b/Plugins/ZShell/Config/Utilities.hpp deleted file mode 100644 index 6751241..0000000 --- a/Plugins/ZShell/Config/Utilities.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include "ConfigSection.hpp" -#include -#include - -class UtilitiesSizes : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(int, toastWidth, ToastWidth) - CFG_PROPERTY(int, width, Width) - -public: - explicit UtilitiesSizes(QObject *parent = nullptr); -}; - -class Toasts : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, audioInputChanged, AudioInputChanged) - CFG_PROPERTY(bool, audioOutputChanged, AudioOutputChanged) - CFG_PROPERTY(bool, capsLockChanged, CapsLockChanged) - CFG_PROPERTY(bool, chargingChanged, ChargingChanged) - CFG_PROPERTY(bool, configLoaded, ConfigLoaded) - CFG_PROPERTY(bool, dndChanged, DndChanged) - CFG_PROPERTY(bool, gameModeChanged, GameModeChanged) - CFG_PROPERTY(bool, kbLayoutChanged, KbLayoutChanged) - CFG_PROPERTY(bool, kbLimit, KbLimit) - CFG_PROPERTY(bool, nowPlaying, NowPlaying) - CFG_PROPERTY(bool, numLockChanged, NumLockChanged) - CFG_PROPERTY(bool, vpnChanged, VpnChanged) - -public: - explicit Toasts(QObject *parent = nullptr); -}; - -class Vpn : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(QVariantList, provider, Provider) - -public: - explicit Vpn(QObject *parent = nullptr); -}; - -class Utilities : public ConfigSection { - Q_OBJECT - QML_UNCREATABLE("Instantiated internally by Config") - - CFG_PROPERTY(bool, enabled, Enabled) - CFG_PROPERTY(int, maxToasts, MaxToasts) - CFG_SECTION(UtilitiesSizes, sizes, Sizes) - CFG_SECTION(Toasts, toasts, Toasts) - CFG_SECTION(Vpn, vpn, Vpn) - -public: - explicit Utilities(QObject *parent = nullptr); -}; diff --git a/Plugins/ZShell/Config/appearance.hpp b/Plugins/ZShell/Config/appearance.hpp new file mode 100644 index 0000000..b4b0e5a --- /dev/null +++ b/Plugins/ZShell/Config/appearance.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class Anim : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, mediaGifSpeedAdjustment, 300) + CFG_PROPERTY(qreal, sessionGifSpeed, 0.7) + + public: + explicit Anim(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Deform : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, scale, 1) + + public: + explicit Deform(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class FontFamily : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, clock, QStringLiteral("Rubik")) + CFG_PROPERTY(QString, material, QStringLiteral("Material Symbols Rounded")) + CFG_PROPERTY(QString, mono, QStringLiteral("CaskaydiaCove NF")) + CFG_PROPERTY(QString, sans, QStringLiteral("Segoe UI Variable Text")) + + public: + explicit FontFamily(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Font : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_SUBOBJECT(FontFamily, family) + + public: + explicit Font(QObject* parent = nullptr) + : ConfigObject(parent), m_family(new FontFamily(this)) {} +}; + +class Transparency : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, base, 0.85) + CFG_PROPERTY(bool, enabled, false) + CFG_PROPERTY(qreal, layers, 0.4) + + public: + explicit Transparency(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Appearance : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_SUBOBJECT(Anim, anim) + CONFIG_SUBOBJECT(Deform, deform) + CONFIG_SUBOBJECT(Font, font) + CONFIG_SUBOBJECT(Transparency, transparency) + + public: + explicit Appearance(QObject* parent = nullptr) + : ConfigObject(parent) + , m_anim(new Anim(this)) + , m_deform(new Deform(this)) + , m_font(new Font(this)) + , m_transparency(new Transparency(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/background.hpp b/Plugins/ZShell/Config/background.hpp new file mode 100644 index 0000000..98331f8 --- /dev/null +++ b/Plugins/ZShell/Config/background.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class Background : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(int, wallFadeDuration, 300) + + public: + explicit Background(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/bar.hpp b/Plugins/ZShell/Config/bar.hpp new file mode 100644 index 0000000..fdb1c6c --- /dev/null +++ b/Plugins/ZShell/Config/bar.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include "configlist.hpp" +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class BarEntry : public ListEntry { + Q_OBJECT + QML_ANONYMOUS + + public: + explicit BarEntry(QObject* parent = nullptr) : ListEntry(parent) {} +}; + +class Popouts : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, statusIcons, true) + CFG_PROPERTY(bool, tray, true) + + public: + explicit Popouts(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Tray : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, recolorIcons, false) + CFG_PROPERTY(bool, showOnHover, true) + CFG_PROPERTY(int, trayIconSize, 24) + CONFIG_LIST( + EntryList, + statusIcons, + { + LIST_ENTRY(audio, true), + LIST_ENTRY(microphone, true), + LIST_ENTRY(bluetooth, false), + LIST_ENTRY(network, false), + LIST_ENTRY(wifi, false), + LIST_ENTRY(power, true), + }) + + public: + explicit Tray(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Bar : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, autoHide, false) + CFG_PROPERTY(int, border, 4) + CFG_PROPERTY(bool, fullscreenReveal, true) + CFG_PROPERTY(int, height, 24) + CFG_PROPERTY(bool, hideWhenNotif, true) + CONFIG_SUBOBJECT(Popouts, popouts) + CFG_PROPERTY(int, revealDelay, 100) + CFG_PROPERTY(int, rounding, 14) + CFG_PROPERTY(int, smoothing, 32) + CONFIG_SUBOBJECT(Tray, tray) + CONFIG_LIST( + EntryList, + entries, + { + LIST_ENTRY(workspaces, true), + LIST_ENTRY(audio, true), + LIST_ENTRY(media, true), + LIST_ENTRY(resources, true), + LIST_ENTRY(updates, true), + LIST_ENTRY(dash, false), + LIST_ENTRY(spacer, true), + LIST_ENTRY(activeWindow, true), + LIST_ENTRY(spacer, true), + LIST_ENTRY(hyprsunset, true), + LIST_ENTRY(tray, true), + LIST_ENTRY(statusIcons, true), + LIST_ENTRY(network, false), + LIST_ENTRY(upower, true), + LIST_ENTRY(clock, true), + LIST_ENTRY(notifBell, true), + }) + + public: + explicit Bar(QObject* parent = nullptr) + : ConfigObject(parent) + , m_popouts(new Popouts(this)) + , m_tray(new Tray(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/clipboard.hpp b/Plugins/ZShell/Config/clipboard.hpp new file mode 100644 index 0000000..b2c0708 --- /dev/null +++ b/Plugins/ZShell/Config/clipboard.hpp @@ -0,0 +1,33 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class ClipboardSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, itemHeight, 60) + CFG_PROPERTY(int, minPreviewWidth, 200) + CFG_PROPERTY(int, previewWidth, 800) + CFG_PROPERTY(int, width, 500) + + public: + explicit ClipboardSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Clipboard : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(int, maxEntriesShown, 10) + CONFIG_SUBOBJECT(ClipboardSizes, sizes) + + public: + explicit Clipboard(QObject* parent = nullptr) + : ConfigObject(parent), m_sizes(new ClipboardSizes(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/colors.hpp b/Plugins/ZShell/Config/colors.hpp new file mode 100644 index 0000000..0554df6 --- /dev/null +++ b/Plugins/ZShell/Config/colors.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class Presets : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, accent, QString()) + CFG_PROPERTY(QString, name, QStringLiteral("Catppuccin")) + CFG_PROPERTY(QString, variant, QStringLiteral("latte")) + + public: + explicit Presets(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Colors : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_SUBOBJECT(Presets, presets) + CFG_PROPERTY(QString, schemeType, QStringLiteral("fidelity")) + + public: + explicit Colors(QObject* parent = nullptr) + : ConfigObject(parent), m_presets(new Presets(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/Config.cpp b/Plugins/ZShell/Config/config.cpp similarity index 52% rename from Plugins/ZShell/Config/Config.cpp rename to Plugins/ZShell/Config/config.cpp index 2dae732..6f17668 100644 --- a/Plugins/ZShell/Config/Config.cpp +++ b/Plugins/ZShell/Config/config.cpp @@ -1,4 +1,21 @@ -#include "Config.hpp" +#include "config.hpp" + +#include "appearance.hpp" +#include "background.hpp" +#include "bar.hpp" +#include "clipboard.hpp" +#include "colors.hpp" +#include "dashboard.hpp" +#include "dock.hpp" +#include "general.hpp" +#include "launcher.hpp" +#include "lock.hpp" +#include "notifs.hpp" +#include "osd.hpp" +#include "screenshot.hpp" +#include "services.hpp" +#include "sidebar.hpp" +#include "utilities.hpp" #include #include @@ -8,31 +25,30 @@ #include #include -Config::Config(QObject* parent) : ConfigSection(parent) { - m_appearance = new Appearance(this); - m_background = new Background(this); - m_bar = new Bar(this); - m_clipboard = new Clipboard(this); - m_colors = new Colors(this); - m_dashboard = new Dashboard(this); - m_dock = new Dock(this); - m_general = new General(this); - m_launcher = new Launcher(this); - m_lock = new Lock(this); - m_notifs = new Notifs(this); - m_osd = new Osd(this); - m_overview = new Overview(this); - m_screenshot = new Screenshot(this); - m_services = new Services(this); - m_sidebar = new Sidebar(this); - m_utilities = new Utilities(this); - wireSignals(); // forwards every child's changed() up to our own changed() +namespace ZShell::config { - connect(this, &ConfigSection::changed, this, &Config::scheduleSave); +Config::Config(QObject* parent) + : ConfigObject(parent) + , m_appearance(new Appearance(this)) + , m_background(new Background(this)) + , m_bar(new Bar(this)) + , m_clipboard(new Clipboard(this)) + , m_colors(new Colors(this)) + , m_dashboard(new Dashboard(this)) + , m_dock(new Dock(this)) + , m_general(new General(this)) + , m_launcher(new Launcher(this)) + , m_lock(new Lock(this)) + , m_notifs(new Notifs(this)) + , m_osd(new Osd(this)) + , m_screenshot(new Screenshot(this)) + , m_services(new Services(this)) + , m_sidebar(new Sidebar(this)) + , m_utilities(new Utilities(this)) { + connect(this, &ConfigObject::propertiesChanged, this, &Config::scheduleSave); m_saveTimer.setSingleShot(true); - m_saveTimer.setInterval( - 300); // debounce: coalesce rapid-fire edits (e.g. dragging a slider) + m_saveTimer.setInterval(300); connect(&m_saveTimer, &QTimer::timeout, this, &Config::flushAsync); loadSync(); @@ -40,7 +56,6 @@ Config::Config(QObject* parent) : ConfigSection(parent) { } Config* Config::create(QQmlEngine*, QJSEngine*) { - // The QML engine takes ownership of singletons created this way. return new Config(); } @@ -53,12 +68,11 @@ QString Config::filePath() const { } void Config::loadSync() { - m_loading = - true; // suppress scheduleSave() while properties are set from disk + m_loading = true; QFile f(filePath()); if (f.open(QIODevice::ReadOnly)) { const auto doc = QJsonDocument::fromJson(f.readAll()); - if (doc.isObject()) fromJson(doc.object()); + if (doc.isObject()) loadFromJson(QJsonValue(doc.object())); } else { qInfo() << "Config: no existing config at" << filePath() << "- using defaults"; @@ -73,21 +87,24 @@ void Config::loadAsync() { if (f.open(QIODevice::ReadOnly)) { const auto doc = QJsonDocument::fromJson(f.readAll()); if (doc.isObject()) { - QMetaObject::invokeMethod(this, [this, doc]() { - fromJson(doc.object()); - m_loading = false; - }, Qt::QueuedConnection); + QMetaObject::invokeMethod( + this, + [this, doc]() { + loadFromJson(QJsonValue(doc.object())); + m_loading = false; + }, + Qt::QueuedConnection); } else { - QMetaObject::invokeMethod(this, [this]() { - m_loading = false; - }, Qt::QueuedConnection); + QMetaObject::invokeMethod( + this, + [this]() { m_loading = false; }, + Qt::QueuedConnection); } } else { qInfo() << "Config: failed to reload from" << filePath() << "- using in-memory values"; - QMetaObject::invokeMethod(this, [this]() { - m_loading = false; - }, Qt::QueuedConnection); + QMetaObject::invokeMethod( + this, [this]() { m_loading = false; }, Qt::QueuedConnection); } }); m_loadFuture = future; @@ -107,12 +124,13 @@ void Config::reloadAsync() { void Config::scheduleSave() { if (m_loading) return; - m_saveTimer.start(); // restarts the window if it's already running + m_saveTimer.start(); } void Config::flushAsync() { auto future = QtConcurrent::run([this]() { - const QByteArray data = QJsonDocument(toJson()).toJson(QJsonDocument::Indented); + const QByteArray data = + QJsonDocument(toJson().toObject()).toJson(QJsonDocument::Indented); writeAtomically(data); }); } @@ -123,9 +141,6 @@ void Config::saveNow() { } void Config::writeAtomically(const QByteArray& data) { - // QSaveFile writes to a temp file next to the target and atomically - // renames it into place on commit() - a crash or power loss mid-write - // can never leave config.json half-written. QSaveFile f(filePath()); if (!f.open(QIODevice::WriteOnly)) { qWarning() << "Config: failed to open for atomic write:" @@ -135,3 +150,5 @@ void Config::writeAtomically(const QByteArray& data) { f.write(data); if (!f.commit()) qWarning() << "Config: commit failed:" << f.errorString(); } + +}; // namespace ZShell::config diff --git a/Plugins/ZShell/Config/config.hpp b/Plugins/ZShell/Config/config.hpp new file mode 100644 index 0000000..477b741 --- /dev/null +++ b/Plugins/ZShell/Config/config.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "configobject.hpp" +#include +#include +#include +#include +#include + +class QQmlEngine; +class QJSEngine; + +namespace ZShell::config { + +class Appearance; +class Background; +class Bar; +class Clipboard; +class Colors; +class Dashboard; +class Dock; +class General; +class Launcher; +class Lock; +class Notifs; +class Osd; +class Screenshot; +class Services; +class Sidebar; +class Utilities; + +class Config : public ConfigObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + Q_MOC_INCLUDE("appearance.hpp") + Q_MOC_INCLUDE("background.hpp") + Q_MOC_INCLUDE("bar.hpp") + Q_MOC_INCLUDE("clipboard.hpp") + Q_MOC_INCLUDE("colors.hpp") + Q_MOC_INCLUDE("dashboard.hpp") + Q_MOC_INCLUDE("dock.hpp") + Q_MOC_INCLUDE("general.hpp") + Q_MOC_INCLUDE("launcher.hpp") + Q_MOC_INCLUDE("lock.hpp") + Q_MOC_INCLUDE("notifs.hpp") + Q_MOC_INCLUDE("osd.hpp") + Q_MOC_INCLUDE("screenshot.hpp") + Q_MOC_INCLUDE("services.hpp") + Q_MOC_INCLUDE("sidebar.hpp") + Q_MOC_INCLUDE("utilities.hpp") + + CONFIG_SUBOBJECT(Appearance, appearance) + CONFIG_SUBOBJECT(Background, background) + CONFIG_SUBOBJECT(Bar, bar) + CONFIG_SUBOBJECT(Clipboard, clipboard) + CONFIG_SUBOBJECT(Colors, colors) + CONFIG_SUBOBJECT(Dashboard, dashboard) + CONFIG_SUBOBJECT(Dock, dock) + CONFIG_SUBOBJECT(General, general) + CONFIG_SUBOBJECT(Launcher, launcher) + CONFIG_SUBOBJECT(Lock, lock) + CONFIG_SUBOBJECT(Notifs, notifs) + CONFIG_SUBOBJECT(Osd, osd) + CONFIG_SUBOBJECT(Screenshot, screenshot) + CONFIG_SUBOBJECT(Services, services) + CONFIG_SUBOBJECT(Sidebar, sidebar) + CONFIG_SUBOBJECT(Utilities, utilities) + + public: + explicit Config(QObject* parent = nullptr); + static Config* create(QQmlEngine*, QJSEngine*); + + Q_INVOKABLE void load(); + Q_INVOKABLE void saveNow(); + Q_INVOKABLE void reloadAsync(); + + private Q_SLOTS: + void scheduleSave(); + void flushAsync(); + + private: + QString filePath() const; + void writeAtomically(const QByteArray& data); + void loadSync(); + void loadAsync(); + + QTimer m_saveTimer; + bool m_loading = false; + bool m_firstLoadDone = false; + QFuture m_loadFuture; +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/configlist.cpp b/Plugins/ZShell/Config/configlist.cpp new file mode 100644 index 0000000..ef60bbd --- /dev/null +++ b/Plugins/ZShell/Config/configlist.cpp @@ -0,0 +1,305 @@ +#include "configlist.hpp" + +#include +#include +#include +#include + +namespace ZShell::config { + +ConfigList::ConfigList(QObject* parent, const QVariantList& defaults) + : ConfigNode(parent), m_defaults(QJsonArray::fromVariantList(defaults)) {} + +int ConfigList::count() const { + return static_cast(m_items.size()); +} + +QVariantList ConfigList::values() const { + QVariantList vals; + vals.reserve(m_items.size()); + for (auto* const item : m_items) + vals.append(QVariant::fromValue(item)); + return vals; +} + +ConfigObject* ConfigList::itemAt(int index) const { + if (index < 0 || index >= m_items.size()) return nullptr; + + return m_items.at(index); +} + +const QList& ConfigList::items() const { + return m_items; +} + +void ConfigList::remove(int index) { + if (index < 0 || index >= m_items.size()) { + qCWarning(lcConfig) + << metaObject()->className() << "cannot remove index" << index + << "of" << count(); + return; + } + + destroyItem(m_items.takeAt(index)); + + m_loaded = true; + emit countChanged(); + emit valuesChanged(); + notifyChanged(); +} + +void ConfigList::move(int from, int to) { + if (from < 0 || from >= m_items.size() || to < 0 || to >= m_items.size()) { + qCWarning(lcConfig) << metaObject()->className() << "cannot move" + << from << "to" << to << "of" << count(); + return; + } + + if (from == to) return; + + m_items.move(from, to); + + m_loaded = true; + emit valuesChanged(); + notifyChanged(); +} + +void ConfigList::clear() { + if (m_items.isEmpty()) return; + + destroyItems(); + + m_loaded = true; + emit countChanged(); + emit valuesChanged(); + notifyChanged(); +} + +void ConfigList::loadFromJson(const QJsonValue& json) { + if (!json.isArray()) { + qCWarning( + lcConfig, + "Option '%s' must be a list, ignoring", + qUtf8Printable(propertyPath())); + m_rejectedJson = json; + return; + } + + m_rejectedJson = QJsonValue::Undefined; + populate(json.toArray()); + m_loaded = true; +} + +QJsonValue ConfigList::toJson() const { + if (m_loaded) return elementsToJson(); + + return m_rejectedJson; +} + +void ConfigList::clearLoadedKeys() { + m_loaded = false; + m_rejectedJson = QJsonValue::Undefined; +} + +QStringList ConfigList::unknownKeys() const { + QStringList keys; + + for (int i = 0; i < m_items.size(); ++i) { + const auto childKeys = m_items.at(i)->unknownKeys(); + for (const auto& childKey : childKeys) + keys.append(joinPath(QString("[%1]").arg(i), childKey)); + } + + return keys; +} + +void ConfigList::resyncFromGlobal() { + syncValuesFromGlobal(); +} + +ConfigObject* ConfigList::insertItem(const QVariantMap& props, int index) { + const auto pos = index < 0 || index > m_items.size() ? m_items.size() + : index; + + appendItem(QJsonObject::fromVariantMap(props)); + m_items.move(m_items.size() - 1, pos); + + auto* const item = m_items.at(pos); + const auto unknown = item->unknownKeys(); + for (const auto& key : unknown) + qCWarning(lcConfig) << "Unknown option" << key << "for" + << item->metaObject()->className(); + + m_loaded = true; + emit countChanged(); + emit valuesChanged(); + notifyChanged(); + + return item; +} + +QJsonArray ConfigList::elementsToJson() const { + QJsonArray arr; + + for (auto* const item : m_items) + arr.append(item->toJson().toObject()); + + return arr; +} + +void ConfigList::resetToDefaults() { + loadFromJsonQuietly(m_defaults); + m_loaded = false; +} + +void ConfigList::syncValuesFromGlobal() { + if (m_loaded) return; + + if (auto* const global = qobject_cast(m_global)) + populate(global->elementsToJson()); +} + +void ConfigList::onGlobalPropertiesChanged(const QMap&) { + syncValuesFromGlobal(); +} + +QString ConfigList::childPath(const ConfigNode* child) const { + for (int i = 0; i < m_items.size(); ++i) + if (m_items.at(i) == child) return QString("[%1]").arg(i); + + return {}; +} + +void ConfigList::populate(const QJsonArray& arr) { + const auto current = elementsToJson(); + if (current == arr) return; + + const auto old = m_items; + QList reused(old.size(), false); + + m_items.clear(); + m_items.reserve(arr.size()); + + for (int i = 0; i < arr.size(); ++i) { + auto match = + i < old.size() && !reused.at(i) && current.at(i) == arr.at(i) ? i + : -1; + + for (int j = 0; match < 0 && j < old.size(); ++j) + if (!reused.at(j) && current.at(j) == arr.at(i)) match = j; + + auto update = false; + for (int j = 0; match < 0 && j < old.size(); ++j) { + if (!reused.at(j) && + sameElement(old.at(j), current.at(j), arr.at(i))) { + match = j; + update = true; + } + } + + if (match < 0) { + appendItem(arr.at(i)); + continue; + } + + reused[match] = true; + + if (update) old.at(match)->loadFromJsonQuietly(arr.at(i)); + + m_items.append(old.at(match)); + } + + for (int i = 0; i < old.size(); ++i) + if (!reused.at(i)) destroyItem(old.at(i)); + + if (m_items.size() != old.size()) emit countChanged(); + + emit valuesChanged(); + + notifyChanged(); +} + +bool ConfigList::sameElement( + const ConfigObject* item, + const QJsonValue& current, + const QJsonValue& json) { + const auto keys = item->identityKeys(); + if (keys.isEmpty()) return false; + + const auto currentObj = current.toObject(); + const auto newObj = json.toObject(); + + if (currentObj.keys() != newObj.keys()) return false; + + for (const auto& key : keys) + if (!newObj.contains(key) || currentObj.value(key) != newObj.value(key)) + return false; + + return true; +} + +void ConfigList::appendItem(const QJsonValue& json) { + auto* const item = createItem(); + QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership); + + if (m_items.isEmpty()) rejectGlobalOnlyElement(item); + + item->loadFromJsonQuietly(json); + + connectItem(item); + + m_items.append(item); +} + +void ConfigList::rejectGlobalOnlyElement(const ConfigObject* item) const { + const auto keys = item->globalOnlyKeys(); + if (keys.isEmpty()) return; + + qCCritical( + lcConfig, + "%s declares global-only options (%s) which do not work inside a list, " + "use CONFIG_GLOBAL_LIST on %s instead", + item->metaObject()->className(), + qUtf8Printable(keys.join(", ")), + metaObject()->className()); +} + +void ConfigList::connectItem(ConfigNode* node) { + connect( + node, &ConfigNode::propertiesChanged, this, &ConfigList::onItemChanged); + + const auto children = node->childNodes(); + for (auto* const child : children) + connectItem(child); +} + +void ConfigList::disconnectItem(ConfigNode* node) { + node->disconnect(this); + + const auto children = node->childNodes(); + for (auto* const child : children) + disconnectItem(child); +} + +void ConfigList::destroyItems() { + for (auto* const item : std::as_const(m_items)) + destroyItem(item); + + m_items.clear(); +} + +void ConfigList::destroyItem(ConfigObject* item) { + disconnectItem(item); + item->deleteLater(); +} + +void ConfigList::onItemChanged() { + m_loaded = true; + notifyChanged(); +} + +void ConfigList::notifyChanged() { + notifyPropertyChanged("values", count()); +} + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/configlist.hpp b/Plugins/ZShell/Config/configlist.hpp new file mode 100644 index 0000000..3ee24ba --- /dev/null +++ b/Plugins/ZShell/Config/configlist.hpp @@ -0,0 +1,141 @@ +#pragma once + +#include "configobject.hpp" + +#include +#include +#include +#include + +namespace ZShell::config { + +class ConfigList : public ConfigNode { + Q_OBJECT + QML_ANONYMOUS + + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(QVariantList values READ values NOTIFY valuesChanged) + + public: + explicit ConfigList( + QObject* parent = nullptr, const QVariantList& defaults = {}); + + [[nodiscard]] int count() const; + [[nodiscard]] QVariantList values() const; + [[nodiscard]] ConfigObject* itemAt(int index) const; + [[nodiscard]] const QList& items() const; + + Q_INVOKABLE void remove(int index); + Q_INVOKABLE void move(int from, int to); + Q_INVOKABLE void clear(); + + void loadFromJson(const QJsonValue& json) override; + [[nodiscard]] QJsonValue toJson() const override; + void clearLoadedKeys() override; + [[nodiscard]] QStringList unknownKeys() const override; + void resyncFromGlobal() override; + + signals: + void countChanged(); + void valuesChanged(); + + protected: + virtual ConfigObject* createItem() = 0; + + void resetToDefaults(); + + ConfigObject* insertItem(const QVariantMap& props, int index = -1); + + [[nodiscard]] QJsonArray elementsToJson() const; + + void syncValuesFromGlobal() override; + void onGlobalPropertiesChanged( + const QMap& changed) override; + [[nodiscard]] QString childPath(const ConfigNode* child) const override; + + private: + void populate(const QJsonArray& arr); + static bool sameElement( + const ConfigObject* item, + const QJsonValue& current, + const QJsonValue& json); + void appendItem(const QJsonValue& json); + void destroyItems(); + void destroyItem(ConfigObject* item); + void rejectGlobalOnlyElement(const ConfigObject* item) const; + void connectItem(ConfigNode* node); + void disconnectItem(ConfigNode* node); + void onItemChanged(); + void notifyChanged(); + + QJsonArray m_defaults; + QList m_items; + bool m_loaded = false; + QJsonValue m_rejectedJson = QJsonValue::Undefined; +}; + +} // namespace ZShell::config + +#define CONFIG_LIST_TYPE(Element, Name) \ + class Name : public ZShell::config::ConfigList { \ + Q_OBJECT \ + QML_ANONYMOUS \ + \ + public: \ + explicit Name( \ + QObject* parent = nullptr, const QVariantList& defaults = {}) \ + : ZShell::config::ConfigList(parent, defaults) { \ + resetToDefaults(); \ + } \ + \ + Q_INVOKABLE ZShell::config::Element* at(int index) const { \ + return static_cast(itemAt(index)); \ + } \ + Q_INVOKABLE ZShell::config::Element* insert( \ + const QVariantMap& props, int index = -1) { \ + return static_cast( \ + insertItem(props, index)); \ + } \ + \ + protected: \ + [[nodiscard]] ZShell::config::ConfigObject* createItem() override { \ + return new ZShell::config::Element(this); \ + } \ + }; + + +#define CONFIG_LIST(Type, name, ...) \ + Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \ + \ + public: \ + [[nodiscard]] Type* name() const { \ + return m_##name; \ + } \ + \ + private: \ + Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__)); + + +namespace ZShell::config { + +class ListEntry : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, id) + CFG_PROPERTY(bool, enabled, true) + + public: + explicit ListEntry(QObject* parent = nullptr) : ConfigObject(parent) {} + + [[nodiscard]] QStringList identityKeys() const override { + return {QStringLiteral("id")}; + } +}; + +CONFIG_LIST_TYPE(ListEntry, EntryList) + +} // namespace ZShell::config + +#define LIST_ENTRY(id, enabled) \ + vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}}) diff --git a/Plugins/ZShell/Config/confignode.cpp b/Plugins/ZShell/Config/confignode.cpp new file mode 100644 index 0000000..b120c6e --- /dev/null +++ b/Plugins/ZShell/Config/confignode.cpp @@ -0,0 +1,89 @@ +#include "confignode.hpp" + +#include +#include +#include +#include + +namespace ZShell::config { + +Q_LOGGING_CATEGORY(lcConfig, "zshell.config") + +ConfigNode::ConfigNode(QObject* parent) : QObject(parent) { + m_batchTimer = new QTimer(this); + m_batchTimer->setSingleShot(true); + m_batchTimer->setInterval(0); + connect( + m_batchTimer, &QTimer::timeout, this, &ConfigNode::emitBatchedChanges); +} + +void ConfigNode::loadFromJsonQuietly(const QJsonValue& json) { + setNotifySuppressed(true); + loadFromJson(json); + setNotifySuppressed(false); +} + +void ConfigNode::setNotifySuppressed(bool suppressed) { + m_suppressNotify = suppressed; + + const auto children = childNodes(); + for (auto* const child : children) + child->setNotifySuppressed(suppressed); +} + +QList ConfigNode::childNodes() const { + return {}; +} + +void ConfigNode::syncFromGlobal(ConfigNode* global) { + m_global = global; + resyncFromGlobal(); +} + +bool ConfigNode::isOverlay() const { + return m_global != nullptr && this != m_global; +} + +QString ConfigNode::propertyPath(const QString& name) const { + if (name.isEmpty()) return objectName(); + + QObject* const parentObj = parent(); + if (parentObj) { + if (auto* parentNode = qobject_cast(parentObj)) { + const auto childName = parentNode->childPath(this); + if (!childName.isEmpty()) { + return joinPath(parentNode->propertyPath(childName), name); + } + } + } + return name; +} + +int ConfigNode::basePropertyOffset() { + return QObject::staticMetaObject.propertyCount(); +} + +void ConfigNode::notifyPropertyChanged( + const QString& name, const QVariant& value) { + if (m_suppressNotify) return; + + m_pendingChanges[name] = value; + if (m_batchTimer && !m_batchTimer->isActive()) m_batchTimer->start(); +} + +QString ConfigNode::joinPath(const QString& parent, const QString& child) { + // List elements are addressed as parent[i], everything else as parent.child + if (child.startsWith(QLatin1Char('['))) return parent + child; + + return parent + QLatin1Char('.') + child; +} + +void ConfigNode::emitBatchedChanges() { + if (m_pendingChanges.isEmpty()) return; + + QMap changes = m_pendingChanges; + m_pendingChanges.clear(); + emit propertiesChanged(changes); +} + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/confignode.hpp b/Plugins/ZShell/Config/confignode.hpp new file mode 100644 index 0000000..4316f34 --- /dev/null +++ b/Plugins/ZShell/Config/confignode.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ZShell::config { + +Q_DECLARE_LOGGING_CATEGORY(lcConfig) + +class ConfigNode : public QObject { + Q_OBJECT + + public: + explicit ConfigNode(QObject* parent = nullptr); + + virtual void loadFromJson(const QJsonValue& json) = 0; + void loadFromJsonQuietly(const QJsonValue& json); + [[nodiscard]] virtual QJsonValue toJson() const = 0; + + virtual void clearLoadedKeys() = 0; + [[nodiscard]] virtual QStringList unknownKeys() const = 0; + [[nodiscard]] virtual QList childNodes() const; + + void syncFromGlobal(ConfigNode* global); + virtual void resyncFromGlobal() = 0; + + [[nodiscard]] bool isOverlay() const; + [[nodiscard]] QString propertyPath(const QString& name = {}) const; + + [[nodiscard]] static int basePropertyOffset(); + + signals: + void propertiesChanged(const QMap& changed); + + protected: + virtual void syncValuesFromGlobal() = 0; + virtual void onGlobalPropertiesChanged( + const QMap& changed) = 0; + + [[nodiscard]] virtual QString childPath(const ConfigNode* child) const = 0; + + void notifyPropertyChanged(const QString& name, const QVariant& value); + + [[nodiscard]] static QString joinPath( + const QString& parent, const QString& child); + + ConfigNode* m_global = nullptr; + + private: + void setNotifySuppressed(bool suppressed); + void emitBatchedChanges(); + + QMap m_pendingChanges; + QTimer* m_batchTimer = nullptr; + bool m_suppressNotify = false; +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/configobject.cpp b/Plugins/ZShell/Config/configobject.cpp new file mode 100644 index 0000000..4fb0056 --- /dev/null +++ b/Plugins/ZShell/Config/configobject.cpp @@ -0,0 +1,270 @@ +#include "configobject.hpp" + +#include +#include +#include +#include + +namespace ZShell::config { + +ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {} + +void ConfigObject::loadFromJson(const QJsonValue& json) { + const auto obj = json.toObject(); + const auto* meta = metaObject(); + + QSet known; + + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + auto prop = meta->property(i); + const auto key = QString::fromUtf8(prop.name()); + + known.insert(key); + + if (!obj.contains(key)) continue; + + const auto jsonVal = obj.value(key); + + if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) { + if (auto* const node = prop.read(this).value()) { + node->loadFromJson(jsonVal); + continue; + } + } + + if (!prop.isWritable()) continue; + + if (prop.metaType().id() == QMetaType::QStringList) { + QStringList list; + const auto jsonArr = jsonVal.toArray(); + for (const auto& v : jsonArr) + list.append(v.toString()); + prop.write(this, QVariant::fromValue(list)); + m_loadedKeys.insert(key); + continue; + } + + if (prop.metaType().id() == QMetaType::QVariantList) { + prop.write(this, jsonVal.toVariant()); + m_loadedKeys.insert(key); + continue; + } + + prop.write(this, jsonVal.toVariant()); + m_loadedKeys.insert(key); + } + + m_extras = {}; + for (auto it = obj.begin(); it != obj.end(); ++it) { + if (!known.contains(it.key())) { + m_extras.insert(it.key(), it.value()); + } + } +} + +QJsonValue ConfigObject::toJson() const { + QJsonObject obj; + const auto* meta = metaObject(); + + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + const auto prop = meta->property(i); + + if (!prop.isReadable()) continue; + + const auto key = QString::fromUtf8(prop.name()); + + const auto value = prop.read(this); + + if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) { + if (auto* const node = value.value()) { + const auto childJson = node->toJson(); + if (!childJson.isUndefined()) obj.insert(key, childJson); + continue; + } + } + + if (!m_loadedKeys.contains(key)) continue; + + if (!prop.isWritable()) continue; + + if (prop.metaType().id() == QMetaType::QStringList) { + QJsonArray arr; + const auto strList = value.toStringList(); + for (const auto& s : strList) + arr.append(s); + obj.insert(key, arr); + continue; + } + + if (prop.metaType().id() == QMetaType::QVariantList) { + obj.insert(key, QJsonArray::fromVariantList(value.toList())); + continue; + } + + obj.insert(key, QJsonValue::fromVariant(value)); + } + + for (auto it = m_extras.begin(); it != m_extras.end(); ++it) + obj.insert(it.key(), it.value()); + + if (obj.isEmpty()) return QJsonValue::Undefined; + + return obj; +} + +void ConfigObject::clearLoadedKeys() { + m_loadedKeys.clear(); + m_extras = {}; + + const auto* meta = metaObject(); + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + auto prop = meta->property(i); + if (auto* const node = prop.read(this).value()) + node->clearLoadedKeys(); + } +} + +QStringList ConfigObject::identityKeys() const { + return {}; +} + +QStringList ConfigObject::unknownKeys() const { + auto keys = m_extras.keys(); + + const auto* meta = metaObject(); + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + const auto prop = meta->property(i); + auto* const node = prop.read(this).value(); + if (!node) continue; + + const auto childKeys = node->unknownKeys(); + for (const auto& childKey : childKeys) + keys.append(joinPath(QString::fromUtf8(prop.name()), childKey)); + } + + return keys; +} + +QList ConfigObject::childNodes() const { + QList nodes; + + const auto* meta = metaObject(); + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + const auto prop = meta->property(i); + + if (auto* const node = prop.read(this).value()) + nodes.append(node); + } + + return nodes; +} + +void ConfigObject::syncValuesFromGlobal() { + const auto* meta = metaObject(); + + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + auto prop = meta->property(i); + const auto key = QString::fromUtf8(prop.name()); + + if (auto* const node = prop.read(this).value()) { + if (auto* const globalNode = + prop.read(m_global).value()) + node->syncFromGlobal(globalNode); + continue; + } + + if (!prop.isWritable()) continue; + + if (!m_loadedKeys.contains(key)) { + auto val = prop.read(m_global); + prop.write(this, val); + m_loadedKeys.remove(key); + } + } +} + +void ConfigObject::resyncFromGlobal() { + if (!m_global) return; + + const auto* meta = metaObject(); + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + auto prop = meta->property(i); + const auto key = QString::fromUtf8(prop.name()); + + if (auto* const node = prop.read(this).value()) { + node->resyncFromGlobal(); + continue; + } + + if (!prop.isWritable()) continue; + + if (!m_loadedKeys.contains(key)) { + prop.write(this, prop.read(m_global)); + m_loadedKeys.remove(key); + } + } +} + +bool ConfigObject::isPropertyLoaded(const QString& name) const { + return m_loadedKeys.contains(name); +} + +bool ConfigObject::isGlobalOnly(const QString& name) const { + return m_globalOnlyKeys.contains(name); +} + +QStringList ConfigObject::globalOnlyKeys() const { + return {m_globalOnlyKeys.begin(), m_globalOnlyKeys.end()}; +} + +void ConfigObject::resetOption(const QString& name) { + m_loadedKeys.remove(name); + + const int idx = metaObject()->indexOfProperty(name.toUtf8().constData()); + if (idx < 0) return; + + const auto prop = metaObject()->property(idx); + + if (auto* const node = prop.read(this).value()) { + node->clearLoadedKeys(); + node->resyncFromGlobal(); + return; + } + + if (m_global && prop.isWritable()) prop.write(this, prop.read(m_global)); +} + +void ConfigObject::onGlobalPropertiesChanged( + const QMap& changed) { + for (auto it = changed.begin(); it != changed.end(); ++it) { + if (m_loadedKeys.contains(it.key()) || isGlobalOnly(it.key())) continue; + + int idx = metaObject()->indexOfProperty(it.key().toUtf8().constData()); + if (idx >= 0) { + metaObject()->property(idx).write(this, it.value()); + m_loadedKeys.remove(it.key()); + } + } +} + +QString ConfigObject::childPath(const ConfigNode* child) const { + const auto* meta = metaObject(); + for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { + const auto prop = meta->property(i); + + if (prop.read(this).value() == child) + return QString::fromUtf8(prop.name()); + } + + return {}; +} + +void ConfigObject::markPropertyLoaded(const QString& name) { + m_loadedKeys.insert(name); +} + +void ConfigObject::markGlobalOnly(const QString& name) { + m_globalOnlyKeys.insert(name); +} + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/configobject.hpp b/Plugins/ZShell/Config/configobject.hpp new file mode 100644 index 0000000..4814e6f --- /dev/null +++ b/Plugins/ZShell/Config/configobject.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include "confignode.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ZShell::config { + +inline QVariantMap vmap( + std::initializer_list> entries) { + QVariantMap map; + for (const auto& [key, value] : entries) + map.insert(key, value); + return map; +} + +#define CFG_PROPERTY(Type, name, ...) \ + Q_PROPERTY(Type name READ name WRITE set_##name NOTIFY name##Changed) \ + public: \ + [[nodiscard]] Type name() const { \ + return m_##name; \ + } \ + void set_##name(const Type& value) { \ + if (ConfigObject::updateMember(m_##name, value)) { \ + markPropertyLoaded(QStringLiteral(#name)); \ + Q_EMIT name##Changed(); \ + notifyPropertyChanged( \ + QStringLiteral(#name), QVariant::fromValue(m_##name)); \ + } \ + } \ + Q_SIGNAL void name##Changed(); \ + \ + private: \ + Type m_##name __VA_OPT__(= __VA_ARGS__); + +#define CONFIG_SUBOBJECT(Type, name) \ + Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \ + \ + public: \ + [[nodiscard]] Type* name() const { \ + return m_##name; \ + } \ + \ + private: \ + Type* m_##name = nullptr; + +class ConfigObject : public ConfigNode { + Q_OBJECT + + public: + explicit ConfigObject(QObject* parent = nullptr); + + void loadFromJson(const QJsonValue& json) override; + [[nodiscard]] QJsonValue toJson() const override; + void clearLoadedKeys() override; + [[nodiscard]] QStringList unknownKeys() const override; + [[nodiscard]] QList childNodes() const override; + void resyncFromGlobal() override; + + [[nodiscard]] virtual QStringList identityKeys() const; + + [[nodiscard]] bool isPropertyLoaded(const QString& name) const; + [[nodiscard]] bool isGlobalOnly(const QString& name) const; + [[nodiscard]] QStringList globalOnlyKeys() const; + + Q_INVOKABLE void resetOption(const QString& name); + + template static bool updateMember(T& member, const T& value) { + if constexpr (std::is_floating_point_v) { + if (qFuzzyCompare(member + 1.0, value + 1.0)) return false; + } else { + if (member == value) return false; + } + member = value; + return true; + } + + protected: + void syncValuesFromGlobal() override; + void onGlobalPropertiesChanged( + const QMap& changed) override; + [[nodiscard]] QString childPath(const ConfigNode* child) const override; + + void markPropertyLoaded(const QString& name); + void markGlobalOnly(const QString& name); + + private: + QSet m_loadedKeys; + QSet m_globalOnlyKeys; + QJsonObject m_extras; +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/dashboard.hpp b/Plugins/ZShell/Config/dashboard.hpp new file mode 100644 index 0000000..97471b8 --- /dev/null +++ b/Plugins/ZShell/Config/dashboard.hpp @@ -0,0 +1,63 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class Performance : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(bool, showBattery, false) + CFG_PROPERTY(bool, showCpu, true) + CFG_PROPERTY(bool, showGpu, true) + CFG_PROPERTY(bool, showMemory, true) + CFG_PROPERTY(bool, showNetwork, true) + CFG_PROPERTY(bool, showStorage, true) + CFG_PROPERTY(bool, showVram, true) + + public: + explicit Performance(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class DashboardSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, dateTimeWidth, 110) + CFG_PROPERTY(int, infoIconSize, 25) + CFG_PROPERTY(int, infoWidth, 200) + CFG_PROPERTY(int, mediaCoverArtSize, 150) + CFG_PROPERTY(int, mediaProgressSweep, 180) + CFG_PROPERTY(int, mediaProgressThickness, 8) + CFG_PROPERTY(int, mediaVisualizerSize, 200) + CFG_PROPERTY(int, mediaWidth, 200) + CFG_PROPERTY(int, resourceProgessThickness, 10) + CFG_PROPERTY(int, resourceSize, 200) + CFG_PROPERTY(int, tabIndicatorHeight, 3) + CFG_PROPERTY(int, tabIndicatorSpacing, 5) + CFG_PROPERTY(int, weatherWidth, 250) + + public: + explicit DashboardSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Dashboard : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(int, mediaUpdateInterval, 2000) + CONFIG_SUBOBJECT(Performance, performance) + CFG_PROPERTY(int, resourceUpdateInterval, 1000) + CONFIG_SUBOBJECT(DashboardSizes, sizes) + + public: + explicit Dashboard(QObject* parent = nullptr) + : ConfigObject(parent) + , m_performance(new Performance(this)) + , m_sizes(new DashboardSizes(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/dock.hpp b/Plugins/ZShell/Config/dock.hpp new file mode 100644 index 0000000..817ce9a --- /dev/null +++ b/Plugins/ZShell/Config/dock.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "configobject.hpp" +#include +#include + +namespace ZShell::config { + +class Dock : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enable, false) + CFG_PROPERTY(int, height, 80) + CFG_PROPERTY(bool, hoverToReveal, false) + CFG_PROPERTY(QStringList, ignoredAppRegexes, {}) + CFG_PROPERTY( + QStringList, + pinnedApps, + (QStringList{ + QStringLiteral("com.ayugram.desktop"), + QStringLiteral("com.obsproject.studio"), + QStringLiteral("librewolf")})) + CFG_PROPERTY(bool, pinnedOnStartup, false) + + public: + explicit Dock(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/general.hpp b/Plugins/ZShell/Config/general.hpp new file mode 100644 index 0000000..9d0f8fd --- /dev/null +++ b/Plugins/ZShell/Config/general.hpp @@ -0,0 +1,158 @@ +#pragma once +#include "configlist.hpp" +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class BatteryThresholdEntry : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, icon) + CFG_PROPERTY(QString, message) + CFG_PROPERTY(QString, name) + CFG_PROPERTY(int, perc) + + public: + explicit BatteryThresholdEntry(QObject* parent = nullptr) + : ConfigObject(parent) {} + + [[nodiscard]] QStringList identityKeys() const override { + return {QStringLiteral("perc")}; + } +}; + +CONFIG_LIST_TYPE(BatteryThresholdEntry, BatteryThresholdList) + +class IdleTimeoutEntry : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, idleAction) + CFG_PROPERTY(QString, name) + CFG_PROPERTY(int, timeout) + + public: + explicit IdleTimeoutEntry(QObject* parent = nullptr) + : ConfigObject(parent) {} + + [[nodiscard]] QStringList identityKeys() const override { + return {QStringLiteral("name")}; + } +}; + +CONFIG_LIST_TYPE(IdleTimeoutEntry, IdleTimeoutList) + +class Apps : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QStringList, archiver, {QStringLiteral("ark")}) + CFG_PROPERTY(QStringList, audio, {QStringLiteral("pavucontrol")}) + CFG_PROPERTY(QStringList, document, {QStringLiteral("libreoffice")}) + CFG_PROPERTY(QStringList, editor, {QStringLiteral("kate")}) + CFG_PROPERTY(QStringList, explorer, {QStringLiteral("dolphin")}) + CFG_PROPERTY(QStringList, image, {QStringLiteral("imv")}) + CFG_PROPERTY(QStringList, playback, {QStringLiteral("vlc")}) + CFG_PROPERTY(QStringList, terminal, {QStringLiteral("wezterm")}) + + public: + explicit Apps(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Battery : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, critPerc, 5) + CONFIG_LIST( + BatteryThresholdList, + popupThresholds, + { + vmap( + {{"icon", "battery_android_frame_2"}, + {"message", "Battery low"}, + {"name", "Low battery"}, + {"perc", 20}}), + vmap( + {{"icon", "battery_android_frame_2"}, + {"message", "Battery lower"}, + {"name", "Low battery"}, + {"perc", 15}}), + vmap( + {{"icon", "battery_android_frame_2"}, + {"message", "Battery lowest"}, + {"name", "Low battery"}, + {"perc", 10}}), + }) + + public: + explicit Battery(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class ColorSettings : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, hyprsunsetTemp, 2600) + CFG_PROPERTY(QString, mode, QStringLiteral("dark")) + CFG_PROPERTY(bool, neovimColors, false) + CFG_PROPERTY(bool, scheduleDark, false) + CFG_PROPERTY(int, scheduleDarkEnd, 600) + CFG_PROPERTY(int, scheduleDarkStart, 1140) + CFG_PROPERTY(bool, scheduleHyprsunset, true) + CFG_PROPERTY(int, scheduleHyprsunsetEnd, 570) + CFG_PROPERTY(int, scheduleHyprsunsetStart, 1200) + CFG_PROPERTY(bool, schemeGeneration, true) + CFG_PROPERTY(bool, smart, false) + + public: + explicit ColorSettings(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Idle : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_LIST( + IdleTimeoutList, + timeouts, + { + vmap( + {{"idleAction", QStringLiteral("lock")}, + {"name", QStringLiteral("Lock")}, + {"timeout", 180}}), + }) + + public: + explicit Idle(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class General : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_SUBOBJECT(Apps, apps) + CONFIG_SUBOBJECT(Battery, battery) + CONFIG_SUBOBJECT(ColorSettings, color) + CFG_PROPERTY(QString, dateFormat, QStringLiteral("ddd d MMM - hh:mm:ss")) + CFG_PROPERTY(bool, desktopIcons, true) + CONFIG_SUBOBJECT(Idle, idle) + CFG_PROPERTY(QString, logo, QString()) + CFG_PROPERTY(bool, showOverFullscreen, true) + CFG_PROPERTY( + QString, + wallpaperPath, + QStringLiteral("/mnt/IronWolf/SDImages/SWWW_Wals/")) + + public: + explicit General(QObject* parent = nullptr) + : ConfigObject(parent) + , m_apps(new Apps(this)) + , m_battery(new Battery(this)) + , m_color(new ColorSettings(this)) + , m_idle(new Idle(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/launcher.hpp b/Plugins/ZShell/Config/launcher.hpp new file mode 100644 index 0000000..24976ca --- /dev/null +++ b/Plugins/ZShell/Config/launcher.hpp @@ -0,0 +1,177 @@ +#pragma once +#include "configlist.hpp" +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class LauncherActionEntry : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QVariantList, command) + CFG_PROPERTY(bool, dangerous, false) + CFG_PROPERTY(QString, description) + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(QString, icon) + CFG_PROPERTY(QString, name) + + public: + explicit LauncherActionEntry(QObject* parent = nullptr) + : ConfigObject(parent) {} + + [[nodiscard]] QStringList identityKeys() const override { + return {QStringLiteral("name")}; + } +}; + +CONFIG_LIST_TYPE(LauncherActionEntry, LauncherActionList) + +class LauncherSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, itemHeight, 50) + CFG_PROPERTY(int, itemWidth, 600) + CFG_PROPERTY(int, wallpaperHeight, 200) + CFG_PROPERTY(int, wallpaperWidth, 280) + + public: + explicit LauncherSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class UseFuzzy : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, actions, true) + CFG_PROPERTY(bool, apps, true) + CFG_PROPERTY(bool, schemes, true) + CFG_PROPERTY(bool, variants, true) + CFG_PROPERTY(bool, wallpapers, true) + + public: + explicit UseFuzzy(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Launcher : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, actionPrefix, QStringLiteral("<")) + CONFIG_LIST( + LauncherActionList, + actions, + { + vmap( + {{"command", QVariantList{"autocomplete", "calc"}}, + {"dangerous", false}, + {"description", "Do simple math equations"}, + {"enabled", true}, + {"icon", "calculate"}, + {"name", "Calculator"}}), + vmap( + {{"command", QVariantList{"setMode", "light"}}, + {"dangerous", false}, + {"description", "Change to light mode"}, + {"enabled", true}, + {"icon", "light_mode"}, + {"name", "Light"}}), + vmap( + {{"command", QVariantList{"setMode", "dark"}}, + {"dangerous", false}, + {"description", "Change to dark mode"}, + {"enabled", true}, + {"icon", "dark_mode"}, + {"name", "Dark"}}), + vmap( + {{"command", QVariantList{"autocomplete", "wallpaper"}}, + {"dangerous", false}, + {"description", "Change the current wallpaper"}, + {"enabled", true}, + {"icon", "image"}, + {"name", "Wallpaper"}}), + vmap( + {{"command", QVariantList{"autocomplete", "variant"}}, + {"dangerous", false}, + {"description", "Change the current scheme variant"}, + {"enabled", true}, + {"icon", "colors"}, + {"name", "Variant"}}), + vmap( + {{"command", QVariantList{"systemctl", "poweroff"}}, + {"dangerous", true}, + {"description", "Shutdown the system"}, + {"enabled", true}, + {"icon", "power_settings_new"}, + {"name", "Shutdown"}}), + vmap( + {{"command", QVariantList{"systemctl", "reboot"}}, + {"dangerous", true}, + {"description", "Reboot the system"}, + {"enabled", true}, + {"icon", "cached"}, + {"name", "Reboot"}}), + vmap( + {{"command", QVariantList{"loginctl", "terminate-user", ""}}, + {"dangerous", true}, + {"description", "Log out of the current session"}, + {"enabled", true}, + {"icon", "logout"}, + {"name", "Logout"}}), + vmap( + {{"command", QVariantList{"loginctl", "lock-session"}}, + {"dangerous", false}, + {"description", "Lock the current session"}, + {"enabled", true}, + {"icon", "lock"}, + {"name", "Lock"}}), + vmap( + {{"command", + QVariantList{"systemctl", "suspend-then-hibernate"}}, + {"dangerous", false}, + {"description", "Suspend then hibernate"}, + {"enabled", true}, + {"icon", "bedtime"}, + {"name", "Sleep"}}), + }) + CFG_PROPERTY(int, dragThreshold, 150) + CFG_PROPERTY(bool, enableDangerousActions, true) + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY( + QStringList, + favoriteApps, + {QStringLiteral("Balatro"), + QStringLiteral("Slay the Spire 2"), + QStringLiteral("com.obsproject.Studio")}) + CFG_PROPERTY( + QStringList, + hiddenApps, + {QStringLiteral("zellij"), + QStringLiteral("vim"), + QStringLiteral("jshell-java-openjdk"), + QStringLiteral("jconsole-java-openjdk"), + QStringLiteral("jshell-java21-openjdk"), + QStringLiteral("jconsole-java21-openjdk"), + QStringLiteral("jshell-java17-openjdk"), + QStringLiteral("jconsole-java17-openjdk"), + QStringLiteral("org.neovim.nvim"), + QStringLiteral("avahi-discover"), + QStringLiteral("bvnc"), + QStringLiteral("bssh"), + QStringLiteral("nm-connection-editor")}) + CFG_PROPERTY(int, maxAppsShown, 18) + CFG_PROPERTY(int, maxWallpapers, 7) + CONFIG_SUBOBJECT(LauncherSizes, sizes) + CFG_PROPERTY(QString, specialPrefix, QStringLiteral("@")) + CONFIG_SUBOBJECT(UseFuzzy, useFuzzy) + CFG_PROPERTY(bool, uwsm, true) + + public: + explicit Launcher(QObject* parent = nullptr) + : ConfigObject(parent) + , m_sizes(new LauncherSizes(this)) + , m_useFuzzy(new UseFuzzy(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/lock.hpp b/Plugins/ZShell/Config/lock.hpp new file mode 100644 index 0000000..479f3ef --- /dev/null +++ b/Plugins/ZShell/Config/lock.hpp @@ -0,0 +1,36 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class LockSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, centerWidth, 600) + CFG_PROPERTY(qreal, heightMult, 0.7) + CFG_PROPERTY(qreal, ratio, 1.78) + + public: + explicit LockSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Lock : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, blurAmount, 10) + CFG_PROPERTY(bool, enableFprint, true) + CFG_PROPERTY(int, maxFprintTries, 3) + CFG_PROPERTY(bool, recolorLogo, false) + CFG_PROPERTY(bool, showNotifContent, true) + CFG_PROPERTY(bool, showNotifIcon, true) + CONFIG_SUBOBJECT(LockSizes, sizes) + + public: + explicit Lock(QObject* parent = nullptr) + : ConfigObject(parent), m_sizes(new LockSizes(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/notifs.hpp b/Plugins/ZShell/Config/notifs.hpp new file mode 100644 index 0000000..b229f11 --- /dev/null +++ b/Plugins/ZShell/Config/notifs.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class NotifsSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, badge, 20) + CFG_PROPERTY(int, image, 41) + CFG_PROPERTY(int, width, 400) + + public: + explicit NotifsSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Notifs : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, actionOnClick, false) + CFG_PROPERTY(int, appNotifCooldown, 0) + CFG_PROPERTY(qreal, clearThreshold, 0.3) + CFG_PROPERTY(int, defaultExpireTimeout, 5000) + CFG_PROPERTY(int, expandThreshold, 20) + CFG_PROPERTY(bool, expire, true) + CFG_PROPERTY(int, groupPreviewNum, 5) + CFG_PROPERTY(bool, openExpanded, false) + CFG_PROPERTY(bool, showInFullscreen, false) + CONFIG_SUBOBJECT(NotifsSizes, sizes) + + public: + explicit Notifs(QObject* parent = nullptr) + : ConfigObject(parent), m_sizes(new NotifsSizes(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/osd.hpp b/Plugins/ZShell/Config/osd.hpp new file mode 100644 index 0000000..bb4bae3 --- /dev/null +++ b/Plugins/ZShell/Config/osd.hpp @@ -0,0 +1,34 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class OsdSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, sliderHeight, 150) + CFG_PROPERTY(int, sliderWidth, 30) + + public: + explicit OsdSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Osd : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, allMonBrightness, true) + CFG_PROPERTY(bool, enableBrightness, true) + CFG_PROPERTY(bool, enableMicrophone, true) + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(int, hideDelay, 3000) + CONFIG_SUBOBJECT(OsdSizes, sizes) + + public: + explicit Osd(QObject* parent = nullptr) + : ConfigObject(parent), m_sizes(new OsdSizes(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/screenshot.hpp b/Plugins/ZShell/Config/screenshot.hpp new file mode 100644 index 0000000..101ea41 --- /dev/null +++ b/Plugins/ZShell/Config/screenshot.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "configobject.hpp" +#include +#include + +namespace ZShell::config { + +class Screenshot : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enable_pp, false) + CFG_PROPERTY(QString, mode, QStringLiteral("manual")) + CFG_PROPERTY(int, radius, 49) + CFG_PROPERTY(bool, rounding, false) + CFG_PROPERTY(bool, saveOnCopy, false) + CFG_PROPERTY(bool, shadow, true) + CFG_PROPERTY(int, shadow_blur, 0) + CFG_PROPERTY(QVariantList, shadow_color, (QVariantList{0, 0, 0, 160})) + CFG_PROPERTY(int, shadow_offset_x, 30) + CFG_PROPERTY(int, shadow_offset_y, 50) + + public: + explicit Screenshot(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/services.hpp b/Plugins/ZShell/Config/services.hpp new file mode 100644 index 0000000..45d2c2e --- /dev/null +++ b/Plugins/ZShell/Config/services.hpp @@ -0,0 +1,54 @@ +#pragma once +#include "configlist.hpp" +#include "configobject.hpp" + +namespace ZShell::config { + +class PlayerAliasEntry : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(QString, from) + CFG_PROPERTY(QString, to) + + public: + explicit PlayerAliasEntry(QObject* parent = nullptr) + : ConfigObject(parent) {} + + [[nodiscard]] QStringList identityKeys() const override { + return {QStringLiteral("from")}; + } +}; + +CONFIG_LIST_TYPE(PlayerAliasEntry, PlayerAliasList) + +class Services : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, audioIncrement, 0.1) + CFG_PROPERTY(qreal, brightnessIncrement, 0.1) + CFG_PROPERTY(bool, ddcutilService, true) + CFG_PROPERTY(QString, defaultPlayer, QStringLiteral("Spotify")) + CFG_PROPERTY(QString, gpuType, QStringLiteral("NVIDIA")) + CFG_PROPERTY(qreal, maxVolume, 1) + CFG_PROPERTY(qreal, minBrightness, 0.01) + CONFIG_LIST( + PlayerAliasList, + playerAliases, + { + vmap( + {{"from", QStringLiteral("com.github.th_ch.youtube_music")}, + {"to", QStringLiteral("YT Music")}}), + }) + CFG_PROPERTY(bool, updates, true) + CFG_PROPERTY(bool, useFahrenheit, false) + CFG_PROPERTY(bool, useTwelveHourClock, false) + CFG_PROPERTY(int, visualizerBars, 50) + CFG_PROPERTY(QString, weatherLocation, QString()) + + public: + explicit Services(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/sidebar.hpp b/Plugins/ZShell/Config/sidebar.hpp new file mode 100644 index 0000000..bd9840a --- /dev/null +++ b/Plugins/ZShell/Config/sidebar.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "configobject.hpp" +#include + +namespace ZShell::config { + +class SidebarSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, width, 520) + + public: + explicit SidebarSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Sidebar : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, dragThreshold, 30) + CFG_PROPERTY(bool, enabled, true) + CONFIG_SUBOBJECT(SidebarSizes, sizes) + + public: + explicit Sidebar(QObject* parent = nullptr) + : ConfigObject(parent), m_sizes(new SidebarSizes(this)) {} +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/tokens.hpp b/Plugins/ZShell/Config/tokens.hpp new file mode 100644 index 0000000..79056c1 --- /dev/null +++ b/Plugins/ZShell/Config/tokens.hpp @@ -0,0 +1,221 @@ +#pragma once + +#include "configobject.hpp" + +#include +#include +#include + +namespace ZShell::config { + +class AppearanceRounding : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, extraSmall, 4) + CFG_PROPERTY(qreal, full, 1000) + CFG_PROPERTY(qreal, large, 24) + CFG_PROPERTY(qreal, medium, 16) + CFG_PROPERTY(qreal, normal, 18) + CFG_PROPERTY(qreal, scale, 1) + CFG_PROPERTY(qreal, small, 12) + CFG_PROPERTY(qreal, smallest, 8) + + public: + explicit AppearanceRounding(QObject* parent = nullptr) + : ConfigObject(parent) {} +}; + +class AppearancePadding : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, extraLarge, 28) + CFG_PROPERTY(qreal, extraLargeIncreased, 32) + CFG_PROPERTY(qreal, extraSmall, 4) + CFG_PROPERTY(qreal, large, 16) + CFG_PROPERTY(qreal, largeIncreased, 20) + CFG_PROPERTY(qreal, larger, 12) + CFG_PROPERTY(qreal, normal, 8) + CFG_PROPERTY(qreal, scale, 1) + CFG_PROPERTY(qreal, small, 5) + CFG_PROPERTY(qreal, smaller, 7) + CFG_PROPERTY(qreal, smallest, 2) + + public: + explicit AppearancePadding(QObject* parent = nullptr) + : ConfigObject(parent) {} +}; + +class AppearanceSpacing : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, extraSmall, 4) + CFG_PROPERTY(qreal, large, 20) + CFG_PROPERTY(qreal, larger, 16) + CFG_PROPERTY(qreal, normal, 12) + CFG_PROPERTY(qreal, scale, 1) + CFG_PROPERTY(qreal, small, 8) + CFG_PROPERTY(qreal, smaller, 10) + + public: + explicit AppearanceSpacing(QObject* parent = nullptr) + : ConfigObject(parent) {} +}; + +class FontSizeTokens : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(qreal, extraLarge, 28) + CFG_PROPERTY(qreal, large, 18) + CFG_PROPERTY(qreal, larger, 16) + CFG_PROPERTY(qreal, medium, 14) + CFG_PROPERTY(qreal, normal, 13) + CFG_PROPERTY(qreal, scale, 1) + CFG_PROPERTY(qreal, small, 11) + CFG_PROPERTY(qreal, smaller, 12) + + public: + explicit FontSizeTokens(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class FontTokens : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_SUBOBJECT(FontSizeTokens, size) + + public: + explicit FontTokens(QObject* parent = nullptr) + : ConfigObject(parent), m_size(new FontSizeTokens(this)) {} +}; + +class AnimCurves : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY( + QVariantList, + emphasized, + QVariantList{ + 0.05, + 0, + 2.0 / 15.0, + 0.06, + 1.0 / 6.0, + 0.4, + 5.0 / 24.0, + 0.82, + 0.25, + 1, + 1, + 1}) + + CFG_PROPERTY( + QVariantList, emphasizedAccel, QVariantList{0.3, 0, 0.8, 0.15, 1, 1}) + + CFG_PROPERTY( + QVariantList, emphasizedDecel, QVariantList{0.05, 0.7, 0.1, 1, 1, 1}) + + CFG_PROPERTY( + QVariantList, + expressiveDefaultEffects, + QVariantList{0.34, 0.8, 0.34, 1, 1, 1}) + + CFG_PROPERTY( + QVariantList, + expressiveDefaultSpatial, + QVariantList{0.38, 1.21, 0.22, 1, 1, 1}) + + CFG_PROPERTY( + QVariantList, expressiveEffects, QVariantList{0.34, 0.8, 0.34, 1, 1, 1}) + + CFG_PROPERTY( + QVariantList, + expressiveFastEffects, + QVariantList{0.31, 0.94, 0.34, 1, 1, 1}) + + CFG_PROPERTY( + QVariantList, + expressiveFastSpatial, + QVariantList{0.42, 1.67, 0.21, 0.9, 1, 1}) + + CFG_PROPERTY( + QVariantList, + expressiveSlowEffects, + QVariantList{0.34, 0.88, 0.34, 1, 1, 1}) + + CFG_PROPERTY( + QVariantList, + expressiveSlowSpatial, + QVariantList{0.39, 1.29, 0.35, 0.98, 1, 1}) + + CFG_PROPERTY(QVariantList, standard, QVariantList{0.2, 0, 0, 1, 1, 1}) + + CFG_PROPERTY(QVariantList, standardAccel, QVariantList{0.3, 0, 1, 1, 1, 1}) + + CFG_PROPERTY(QVariantList, standardDecel, QVariantList{0, 0, 0, 1, 1, 1}) + + public: + explicit AnimCurves(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class AnimDurations : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, expressiveDefaultSpatial, 500) + CFG_PROPERTY(int, expressiveEffects, 200) + CFG_PROPERTY(int, expressiveFastEffects, 150) + CFG_PROPERTY(int, expressiveFastSpatial, 350) + CFG_PROPERTY(int, expressiveSlowEffects, 300) + CFG_PROPERTY(int, extraLarge, 1000) + CFG_PROPERTY(int, large, 600) + CFG_PROPERTY(int, normal, 400) + CFG_PROPERTY(qreal, scale, 1) + CFG_PROPERTY(int, small, 200) + + public: + explicit AnimDurations(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class AnimTokens : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CONFIG_SUBOBJECT(AnimCurves, curves) + CONFIG_SUBOBJECT(AnimDurations, durations) + + public: + explicit AnimTokens(QObject* parent = nullptr) + : ConfigObject(parent) + , m_curves(new AnimCurves(this)) + , m_durations(new AnimDurations(this)) {} +}; + +class Tokens : public ConfigObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + CONFIG_SUBOBJECT(AppearanceRounding, rounding) + CONFIG_SUBOBJECT(AppearancePadding, padding) + CONFIG_SUBOBJECT(AppearanceSpacing, spacing) + CONFIG_SUBOBJECT(FontTokens, font) + CONFIG_SUBOBJECT(AnimTokens, anim) + + public: + explicit Tokens(QObject* parent = nullptr) + : ConfigObject(parent) + , m_rounding(new AppearanceRounding(this)) + , m_padding(new AppearancePadding(this)) + , m_spacing(new AppearanceSpacing(this)) + , m_font(new FontTokens(this)) + , m_anim(new AnimTokens(this)) {} + + static Tokens* create(QQmlEngine*, QJSEngine*) { return new Tokens(); } +}; + +} // namespace ZShell::config diff --git a/Plugins/ZShell/Config/utilities.hpp b/Plugins/ZShell/Config/utilities.hpp new file mode 100644 index 0000000..ae97ed7 --- /dev/null +++ b/Plugins/ZShell/Config/utilities.hpp @@ -0,0 +1,70 @@ +#pragma once +#include "configobject.hpp" +#include +#include +#include + +namespace ZShell::config { + +class UtilitiesSizes : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(int, toastWidth, 430) + CFG_PROPERTY(int, width, 430) + + public: + explicit UtilitiesSizes(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Toasts : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, audioInputChanged, true) + CFG_PROPERTY(bool, audioOutputChanged, true) + CFG_PROPERTY(bool, capsLockChanged, true) + CFG_PROPERTY(bool, chargingChanged, true) + CFG_PROPERTY(bool, configLoaded, true) + CFG_PROPERTY(bool, dndChanged, true) + CFG_PROPERTY(bool, gameModeChanged, true) + CFG_PROPERTY(bool, kbLayoutChanged, true) + CFG_PROPERTY(bool, kbLimit, true) + CFG_PROPERTY(bool, nowPlaying, false) + CFG_PROPERTY(bool, numLockChanged, true) + CFG_PROPERTY(bool, vpnChanged, true) + + public: + explicit Toasts(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Vpn : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enabled, false) + CFG_PROPERTY(QStringList, provider, (QStringList{QStringLiteral("netbird")})) + + public: + explicit Vpn(QObject* parent = nullptr) : ConfigObject(parent) {} +}; + +class Utilities : public ConfigObject { + Q_OBJECT + QML_ANONYMOUS + + CFG_PROPERTY(bool, enabled, true) + CFG_PROPERTY(int, maxToasts, 4) + CONFIG_SUBOBJECT(UtilitiesSizes, sizes) + CONFIG_SUBOBJECT(Toasts, toasts) + CONFIG_SUBOBJECT(Vpn, vpn) + + public: + explicit Utilities(QObject* parent = nullptr) + : ConfigObject(parent) + , m_sizes(new UtilitiesSizes(this)) + , m_toasts(new Toasts(this)) + , m_vpn(new Vpn(this)) {} +}; + +} // namespace ZShell::config