From f989f74282f2baec534446594c8dbf3328422bf9 Mon Sep 17 00:00:00 2001 From: Zacharias-Brohn Date: Sun, 1 Mar 2026 18:12:43 +0100 Subject: [PATCH] menu switch --- Components/CustomComboBox.qml | 169 +++++++++++++++++++ Components/CustomSplitButton.qml | 159 +++++++++++++++++ Components/CustomSplitButtonRow.qml | 56 ++++++ Components/Menu.qml | 32 ++-- Drawers/Backgrounds.qml | 16 +- Drawers/Panels.qml | 20 +-- Modules/Bar/BarLoader.qml | 1 + Modules/Dashboard/Background.qml | 4 +- Modules/Lock/LockSurface.qml | 15 ++ Modules/Resources/Background.qml | 5 +- Modules/Settings/Background.qml | 66 ++++++++ Modules/Settings/Categories.qml | 178 ++++++++++++++++++++ Modules/Settings/Categories/Appearance.qml | 97 +++++++++++ Modules/Settings/Categories/Background.qml | 13 ++ Modules/Settings/Categories/General.qml | 55 ++++++ Modules/Settings/Content.qml | 102 +++++++++++ Modules/Settings/Controls/SettingSwitch.qml | 36 ++++ Modules/Settings/Wrapper.qml | 61 +++++++ 18 files changed, 1050 insertions(+), 35 deletions(-) create mode 100644 Components/CustomComboBox.qml create mode 100644 Components/CustomSplitButton.qml create mode 100644 Components/CustomSplitButtonRow.qml create mode 100644 Modules/Settings/Background.qml create mode 100644 Modules/Settings/Categories.qml create mode 100644 Modules/Settings/Categories/Appearance.qml create mode 100644 Modules/Settings/Categories/Background.qml create mode 100644 Modules/Settings/Categories/General.qml create mode 100644 Modules/Settings/Content.qml create mode 100644 Modules/Settings/Controls/SettingSwitch.qml create mode 100644 Modules/Settings/Wrapper.qml diff --git a/Components/CustomComboBox.qml b/Components/CustomComboBox.qml new file mode 100644 index 0000000..2a0186f --- /dev/null +++ b/Components/CustomComboBox.qml @@ -0,0 +1,169 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import qs.Config + +ComboBox { + id: root + + property int cornerRadius: Appearance.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: DynamicColors.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 ? DynamicColors.palette.m3onSurface : DynamicColors.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 ? DynamicColors.palette.m3onSurfaceVariant : DynamicColors.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 + Appearance.padding.small * 2 + implicitWidth: root.width + modal: true + popupType: root.preferPopupWindow ? Popup.Window : Popup.Item + y: -list.currentIndex * (root.menuRowHeight + Appearance.spacing.small) - Appearance.padding.small + + background: CustomRect { + color: DynamicColors.palette.m3surface + radius: root.menuCornerRadius + } + contentItem: ListView { + id: list + + anchors.bottomMargin: Appearance.padding.small + anchors.fill: parent + anchors.topMargin: Appearance.padding.small + clip: true + currentIndex: root.currentIndex + model: root.delegateModel + spacing: Appearance.spacing.small + + delegate: CustomRect { + required property int index + required property var modelData + + anchors.horizontalCenter: parent.horizontalCenter + color: (index === root.currentIndex) ? DynamicColors.palette.m3primary : "transparent" + implicitHeight: root.menuRowHeight + implicitWidth: p.implicitWidth - Appearance.padding.small * 2 + radius: Appearance.rounding.normal - Appearance.padding.small + + RowLayout { + anchors.fill: parent + spacing: 10 + + CustomText { + Layout.fillWidth: true + color: DynamicColors.palette.m3onSurface + elide: Text.ElideRight + font.pixelSize: 15 + text: modelData + verticalAlignment: Text.AlignVCenter + } + + CustomText { + color: DynamicColors.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/Components/CustomSplitButton.qml b/Components/CustomSplitButton.qml new file mode 100644 index 0000000..becabf5 --- /dev/null +++ b/Components/CustomSplitButton.qml @@ -0,0 +1,159 @@ +import QtQuick +import QtQuick.Layouts +import qs.Config + +Row { + id: root + + enum Type { + Filled, + Tonal + } + + property alias active: menu.active + property color color: type == CustomSplitButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondaryContainer + property bool disabled + property color disabledColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1) + property color disabledTextColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38) + property alias expanded: menu.expanded + property string fallbackIcon + property string fallbackText + property real horizontalPadding: Appearance.padding.normal + property alias iconLabel: iconLabel + property alias label: label + property alias menu: menu + property alias menuItems: menu.items + property bool menuOnTop + property alias stateLayer: stateLayer + property color textColor: type == CustomSplitButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer + property int type: CustomSplitButton.Filled + property real verticalPadding: Appearance.padding.smaller + + spacing: Math.floor(Appearance.spacing.small / 2) + + CustomRect { + bottomRightRadius: Appearance.rounding.small / 2 + color: root.disabled ? root.disabledColor : root.color + implicitHeight: expandBtn.implicitHeight + implicitWidth: textRow.implicitWidth + root.horizontalPadding * 2 + radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + topRightRadius: Appearance.rounding.small / 2 + + StateLayer { + id: stateLayer + + function onClicked(): void { + root.active?.clicked(); + } + + color: root.textColor + disabled: root.disabled + rect.bottomRightRadius: parent.bottomRightRadius + rect.topRightRadius: parent.topRightRadius + } + + RowLayout { + id: textRow + + anchors.centerIn: parent + anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4) + spacing: Appearance.spacing.small + + MaterialIcon { + id: iconLabel + + Layout.alignment: Qt.AlignVCenter + animate: true + color: root.disabled ? root.disabledTextColor : root.textColor + 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.disabledTextColor : root.textColor + text: root.active?.activeText ?? root.fallbackText + + Behavior on Layout.preferredWidth { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + } + } + + CustomRect { + id: expandBtn + + property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) : Appearance.rounding.small / 2 + + bottomLeftRadius: rad + color: root.disabled ? root.disabledColor : root.color + implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2 + implicitWidth: implicitHeight + radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + topLeftRadius: rad + + Behavior on rad { + Anim { + } + } + + StateLayer { + id: expandStateLayer + + function onClicked(): void { + root.expanded = !root.expanded; + } + + color: root.textColor + disabled: root.disabled + rect.bottomLeftRadius: parent.bottomLeftRadius + rect.topLeftRadius: parent.topLeftRadius + } + + MaterialIcon { + id: expandIcon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: root.expanded ? 0 : -Math.floor(root.verticalPadding / 4) + color: root.disabled ? root.disabledTextColor : root.textColor + rotation: root.expanded ? 180 : 0 + text: "expand_more" + + Behavior on anchors.horizontalCenterOffset { + Anim { + } + } + Behavior on rotation { + Anim { + } + } + } + + Menu { + id: menu + + anchors.bottomMargin: Appearance.spacing.small + anchors.right: parent.right + anchors.top: parent.bottom + anchors.topMargin: Appearance.spacing.small + + states: State { + when: root.menuOnTop + + AnchorChanges { + anchors.bottom: expandBtn.top + anchors.top: undefined + target: menu + } + } + } + } +} diff --git a/Components/CustomSplitButtonRow.qml b/Components/CustomSplitButtonRow.qml new file mode 100644 index 0000000..763ca8a --- /dev/null +++ b/Components/CustomSplitButtonRow.qml @@ -0,0 +1,56 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Config + +CustomRect { + id: root + + property alias active: splitButton.active + property bool enabled: true + property alias expanded: splitButton.expanded + property int expandedZ: 100 + required property string label + property alias menuItems: splitButton.menuItems + property alias type: splitButton.type + + signal selected(item: MenuItem) + + Layout.fillWidth: true + clip: false + color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2) + implicitHeight: row.implicitHeight + Appearance.padding.large * 2 + opacity: enabled ? 1.0 : 0.5 + radius: Appearance.rounding.normal + z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1 + + RowLayout { + id: row + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + CustomText { + Layout.fillWidth: true + color: root.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSurfaceVariant + text: root.label + } + + CustomSplitButton { + id: splitButton + + enabled: root.enabled + menu.z: 1 + type: CustomSplitButton.Filled + + menu.onItemSelected: item => { + root.selected(item); + } + stateLayer.onClicked: { + splitButton.expanded = !splitButton.expanded; + } + } + } +} diff --git a/Components/Menu.qml b/Components/Menu.qml index d4ffb02..8222359 100644 --- a/Components/Menu.qml +++ b/Components/Menu.qml @@ -13,11 +13,11 @@ Elevation { signal itemSelected(item: MenuItem) - implicitHeight: root.expanded ? column.implicitHeight : 0 + implicitHeight: root.expanded ? column.implicitHeight + Appearance.padding.small * 2 : 0 implicitWidth: Math.max(200, column.implicitWidth) level: 2 opacity: root.expanded ? 1 : 0 - radius: Appearance.rounding.small / 2 + radius: Appearance.rounding.normal Behavior on implicitHeight { Anim { @@ -41,7 +41,8 @@ Elevation { anchors.left: parent.left anchors.right: parent.right - spacing: 0 + anchors.verticalCenter: parent.verticalCenter + spacing: 5 Repeater { model: root.items @@ -54,19 +55,26 @@ Elevation { required property MenuItem modelData Layout.fillWidth: true - color: Qt.alpha(DynamicColors.palette.m3secondaryContainer, active ? 1 : 0) implicitHeight: menuOptionRow.implicitHeight + Appearance.padding.normal * 2 implicitWidth: menuOptionRow.implicitWidth + Appearance.padding.normal * 2 - StateLayer { - function onClicked(): void { - root.itemSelected(item.modelData); - root.active = item.modelData; - root.expanded = false; - } + CustomRect { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.small + anchors.rightMargin: Appearance.padding.small + color: Qt.alpha(DynamicColors.palette.m3secondaryContainer, active ? 1 : 0) + radius: Appearance.rounding.normal - Appearance.padding.small - color: item.active ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface - disabled: !root.expanded + StateLayer { + function onClicked(): void { + root.itemSelected(item.modelData); + root.active = item.modelData; + root.expanded = false; + } + + color: item.active ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface + disabled: !root.expanded + } } RowLayout { diff --git a/Drawers/Backgrounds.qml b/Drawers/Backgrounds.qml index c97e2ee..bcd1488 100644 --- a/Drawers/Backgrounds.qml +++ b/Drawers/Backgrounds.qml @@ -12,7 +12,7 @@ import qs.Modules.Osd as Osd import qs.Modules.Launcher as Launcher import qs.Modules.Resources as Resources -// import qs.Modules.Settings as Settings +import qs.Modules.Settings as Settings Shape { id: root @@ -85,11 +85,11 @@ Shape { wrapper: root.panels.sidebar } - // Settings.Background { - // id: settings - // - // startX: (root.width - wrapper.width) / 2 - rounding - // startY: 0 - // wrapper: root.panels.settings - // } + Settings.Background { + id: settings + + startX: (root.width - wrapper.width) / 2 - rounding + startY: 0 + wrapper: root.panels.settings + } } diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index 508b5ee..7dea587 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -10,7 +10,7 @@ import qs.Modules.Osd as Osd import qs.Components.Toast as Toasts import qs.Modules.Launcher as Launcher import qs.Modules.Resources as Resources -// import qs.Modules.Settings as Settings +import qs.Modules.Settings as Settings import qs.Config Item { @@ -24,7 +24,7 @@ Item { readonly property alias popouts: popouts readonly property alias resources: resources required property ShellScreen screen - // readonly property alias settings: settings + readonly property alias settings: settings readonly property alias sidebar: sidebar readonly property alias toasts: toasts readonly property alias utilities: utilities @@ -127,12 +127,12 @@ Item { visibilities: root.visibilities } - // Settings.Wrapper { - // id: settings - // - // anchors.horizontalCenter: parent.horizontalCenter - // anchors.top: parent.top - // panels: root - // visibilities: root.visibilities - // } + Settings.Wrapper { + id: settings + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + panels: root + visibilities: root.visibilities + } } diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index f72a32a..df21fd4 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -73,6 +73,7 @@ RowLayout { Repeater { id: repeater + // model: Config.barConfig.entries.filted(n => n.index > 50).sort(n => n.index) model: Config.barConfig.entries DelegateChooser { diff --git a/Modules/Dashboard/Background.qml b/Modules/Dashboard/Background.qml index 5341a92..f192a11 100644 --- a/Modules/Dashboard/Background.qml +++ b/Modules/Dashboard/Background.qml @@ -49,12 +49,12 @@ ShapePath { radiusX: root.rounding radiusY: Math.min(root.rounding, root.wrapper.height) relativeX: root.rounding - relativeY: -root.roundingY + relativeY: root.roundingY } PathLine { relativeX: 0 - relativeY: -(root.wrapper.height - root.roundingY * 2) + relativeY: -(root.wrapper.height) } PathArc { diff --git a/Modules/Lock/LockSurface.qml b/Modules/Lock/LockSurface.qml index 2739713..73ee33b 100644 --- a/Modules/Lock/LockSurface.qml +++ b/Modules/Lock/LockSurface.qml @@ -164,6 +164,21 @@ WlSessionLockSurface { implicitWidth: size scale: 0 + // MultiEffect { + // anchors.fill: lockBg + // autoPaddingEnabled: false + // blur: 1 + // blurEnabled: true + // blurMax: 64 + // maskEnabled: true + // maskSource: lockBg + // + // source: ShaderEffectSource { + // sourceItem: background + // sourceRect: Qt.rect(lockBg.x, lockBg.y, lockBg.width, lockBg, height) + // } + // } + CustomRect { id: lockBg diff --git a/Modules/Resources/Background.qml b/Modules/Resources/Background.qml index bb55258..48a7eb8 100644 --- a/Modules/Resources/Background.qml +++ b/Modules/Resources/Background.qml @@ -28,15 +28,14 @@ ShapePath { PathLine { relativeX: 0 - relativeY: root.wrapper.height - root.roundingY * 2 + relativeY: root.wrapper.height } PathArc { - direction: PathArc.Counterclockwise radiusX: root.rounding radiusY: Math.min(root.rounding, root.wrapper.height) relativeX: root.rounding - relativeY: root.roundingY + relativeY: -root.roundingY } PathLine { diff --git a/Modules/Settings/Background.qml b/Modules/Settings/Background.qml new file mode 100644 index 0000000..cc242f7 --- /dev/null +++ b/Modules/Settings/Background.qml @@ -0,0 +1,66 @@ +import QtQuick +import QtQuick.Shapes +import qs.Components +import qs.Config + +ShapePath { + id: root + + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real rounding: 8 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + required property Wrapper wrapper + + fillColor: DynamicColors.palette.m3surface + strokeWidth: -1 + + Behavior on fillColor { + CAnim { + } + } + + PathArc { + radiusX: root.rounding + radiusY: Math.min(root.roundingY, root.wrapper.height) + relativeX: root.rounding + relativeY: root.roundingY + } + + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + + PathArc { + direction: PathArc.Counterclockwise + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + relativeX: root.rounding + relativeY: root.roundingY + } + + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + + PathArc { + direction: PathArc.Counterclockwise + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + relativeX: root.rounding + relativeY: -root.roundingY + } + + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + + PathArc { + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + relativeX: root.rounding + relativeY: -root.roundingY + } +} diff --git a/Modules/Settings/Categories.qml b/Modules/Settings/Categories.qml new file mode 100644 index 0000000..08bcacc --- /dev/null +++ b/Modules/Settings/Categories.qml @@ -0,0 +1,178 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +Item { + id: root + + required property Item content + + implicitHeight: clayout.contentHeight + Appearance.padding.smaller * 2 + implicitWidth: clayout.contentWidth + Appearance.padding.smaller * 2 + + ListModel { + id: listModel + + ListElement { + icon: "settings" + name: "General" + } + + ListElement { + icon: "wallpaper" + name: "Wallpaper" + } + + ListElement { + icon: "settop_component" + name: "Bar" + } + + ListElement { + icon: "lock" + name: "Lockscreen" + } + + ListElement { + icon: "build_circle" + name: "Services" + } + + ListElement { + icon: "notifications" + name: "Notifications" + } + + ListElement { + icon: "view_sidebar" + name: "Sidebar" + } + + ListElement { + icon: "handyman" + name: "Utilities" + } + + ListElement { + icon: "dashboard" + name: "Dashboard" + } + + ListElement { + icon: "colors" + name: "Appearance" + } + + ListElement { + icon: "display_settings" + name: "On screen display" + } + + ListElement { + icon: "rocket_launch" + name: "Launcher" + } + + ListElement { + icon: "colors" + name: "Colors" + } + } + + CustomRect { + anchors.fill: parent + color: DynamicColors.tPalette.m3surfaceContainer + radius: 4 + + CustomListView { + id: clayout + + anchors.centerIn: parent + contentHeight: contentItem.childrenRect.height + contentWidth: contentItem.childrenRect.width + highlightFollowsCurrentItem: false + implicitHeight: contentItem.childrenRect.height + implicitWidth: contentItem.childrenRect.width + model: listModel + spacing: 5 + + delegate: Category { + } + highlight: CustomRect { + color: DynamicColors.palette.m3primary + implicitHeight: clayout.currentItem?.implicitHeight ?? 0 + implicitWidth: clayout.width + radius: 4 + y: clayout.currentItem?.y ?? 0 + + Behavior on y { + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.expressiveEffects + } + } + } + } + } + + component Category: CustomRect { + id: categoryItem + + required property string icon + required property int index + required property string name + + implicitHeight: 42 + implicitWidth: 200 + radius: 4 + + RowLayout { + id: layout + + anchors.left: parent.left + anchors.margins: Appearance.padding.smaller + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + MaterialIcon { + id: icon + + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillHeight: true + Layout.preferredWidth: icon.contentWidth + color: categoryItem.index === clayout.currentIndex ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + font.pointSize: 22 + text: categoryItem.icon + verticalAlignment: Text.AlignVCenter + } + + CustomText { + id: text + + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillHeight: true + Layout.fillWidth: true + Layout.leftMargin: Appearance.spacing.normal + color: categoryItem.index === clayout.currentIndex ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + text: categoryItem.name + verticalAlignment: Text.AlignVCenter + } + } + + StateLayer { + id: layer + + onClicked: { + root.content.currentCategory = categoryItem.name.toLowerCase(); + clayout.currentIndex = categoryItem.index; + } + } + } +} diff --git a/Modules/Settings/Categories/Appearance.qml b/Modules/Settings/Categories/Appearance.qml new file mode 100644 index 0000000..78c18a0 --- /dev/null +++ b/Modules/Settings/Categories/Appearance.qml @@ -0,0 +1,97 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Modules.Settings.Controls +import qs.Config +import qs.Helpers + +CustomRect { + id: root + + ColumnLayout { + id: clayout + + anchors.left: parent.left + anchors.right: parent.right + + CustomRect { + Layout.fillWidth: true + Layout.preferredHeight: colorLayout.implicitHeight + color: DynamicColors.tPalette.m3surfaceContainer + + ColumnLayout { + id: colorLayout + + anchors.left: parent.left + anchors.margins: Appearance.padding.large + anchors.right: parent.right + + Settings { + name: "smth" + } + + SettingSwitch { + name: "wallust" + object: Config.general.color + setting: "wallust" + } + + CustomSplitButtonRow { + enabled: true + label: qsTr("Scheme mode") + + menuItems: [ + MenuItem { + property string val: "light" + + icon: "light_mode" + text: qsTr("Light") + }, + MenuItem { + property string val: "dark" + + icon: "dark_mode" + text: qsTr("Dark") + } + ] + + Component.onCompleted: { + if (Config.general.color.mode === "light") + active = menuItems[0]; + else + active = menuItems[1]; + } + onSelected: item => { + Config.general.color.mode = item.val; + Config.save(); + } + } + } + } + } + + component Settings: CustomRect { + id: settingsItem + + required property string name + + Layout.preferredHeight: 42 + Layout.preferredWidth: 200 + radius: 4 + + CustomText { + id: text + + anchors.left: parent.left + anchors.margins: Appearance.padding.smaller + anchors.right: parent.right + font.bold: true + font.pointSize: 32 + text: settingsItem.name + verticalAlignment: Text.AlignVCenter + } + } +} diff --git a/Modules/Settings/Categories/Background.qml b/Modules/Settings/Categories/Background.qml new file mode 100644 index 0000000..2d24d68 --- /dev/null +++ b/Modules/Settings/Categories/Background.qml @@ -0,0 +1,13 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +CustomRect { + id: root + +} diff --git a/Modules/Settings/Categories/General.qml b/Modules/Settings/Categories/General.qml new file mode 100644 index 0000000..3e8335c --- /dev/null +++ b/Modules/Settings/Categories/General.qml @@ -0,0 +1,55 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Modules as Modules +import qs.Config +import qs.Helpers + +CustomRect { + id: root + + ColumnLayout { + id: clayout + + anchors.fill: parent + + Settings { + name: "apps" + } + + Item { + } + } + + component Settings: CustomRect { + id: settingsItem + + required property string name + + implicitHeight: 42 + implicitWidth: 200 + radius: 4 + + RowLayout { + id: layout + + anchors.left: parent.left + anchors.margins: Appearance.padding.smaller + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + CustomText { + id: text + + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillHeight: true + Layout.fillWidth: true + Layout.leftMargin: Appearance.spacing.normal + text: settingsItem.name + verticalAlignment: Text.AlignVCenter + } + } + } +} diff --git a/Modules/Settings/Content.qml b/Modules/Settings/Content.qml new file mode 100644 index 0000000..1037a21 --- /dev/null +++ b/Modules/Settings/Content.qml @@ -0,0 +1,102 @@ +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Controls +import qs.Components +import qs.Modules as Modules +import qs.Modules.Settings.Categories as Cat +import qs.Config +import qs.Helpers + +Item { + id: root + + property string currentCategory: "general" + readonly property real nonAnimHeight: view.implicitHeight + viewWrapper.anchors.margins * 2 + readonly property real nonAnimWidth: view.implicitWidth + 500 + viewWrapper.anchors.margins * 2 + required property PersistentProperties visibilities + + implicitHeight: nonAnimHeight + implicitWidth: nonAnimWidth + + Connections { + function onCurrentCategoryChanged() { + stack.pop(); + if (currentCategory === "general") { + stack.push(general); + } else if (currentCategory === "wallpaper") { + stack.push(background); + } else if (currentCategory === "appearance") { + stack.push(appearance); + } + } + + target: root + } + + ClippingRectangle { + id: viewWrapper + + anchors.fill: parent + anchors.margins: Appearance.padding.smaller + color: "transparent" + + Item { + id: view + + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.top: parent.top + implicitHeight: layout.implicitHeight + implicitWidth: layout.implicitWidth + + Categories { + id: layout + + anchors.fill: parent + content: root + } + } + + CustomClippingRect { + id: categoryContent + + anchors.bottom: parent.bottom + anchors.left: view.right + anchors.leftMargin: Appearance.spacing.smaller + anchors.right: parent.right + anchors.top: parent.top + color: DynamicColors.tPalette.m3surfaceContainer + radius: 4 + + StackView { + id: stack + + anchors.fill: parent + anchors.margins: Appearance.padding.smaller + initialItem: general + } + } + } + + Component { + id: general + + Cat.General { + } + } + + Component { + id: background + + Cat.Background { + } + } + + Component { + id: appearance + + Cat.Appearance { + } + } +} diff --git a/Modules/Settings/Controls/SettingSwitch.qml b/Modules/Settings/Controls/SettingSwitch.qml new file mode 100644 index 0000000..524e740 --- /dev/null +++ b/Modules/Settings/Controls/SettingSwitch.qml @@ -0,0 +1,36 @@ +import QtQuick +import QtQuick.Layouts +import qs.Components +import qs.Config + +RowLayout { + id: root + + required property string name + required property var object + required property string setting + + Layout.fillWidth: true + Layout.preferredHeight: 42 + + CustomText { + id: text + + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + font.pointSize: 16 + text: root.name + } + + CustomSwitch { + id: cswitch + + Layout.alignment: Qt.AlignRight + checked: root.object[root.setting] + + onToggled: { + root.object[root.setting] = checked; + Config.save(); + } + } +} diff --git a/Modules/Settings/Wrapper.qml b/Modules/Settings/Wrapper.qml new file mode 100644 index 0000000..dec6264 --- /dev/null +++ b/Modules/Settings/Wrapper.qml @@ -0,0 +1,61 @@ +import Quickshell +import QtQuick +import qs.Components +import qs.Config +import qs.Helpers + +Item { + id: root + + required property var panels + required property PersistentProperties visibilities + + implicitHeight: 0 + implicitWidth: content.implicitWidth + visible: height > 0 + + states: State { + name: "visible" + when: root.visibilities.settings + + PropertyChanges { + root.implicitHeight: content.implicitHeight + } + } + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + property: "implicitHeight" + target: root + } + }, + Transition { + from: "visible" + to: "" + + Anim { + easing.bezierCurve: MaterialEasing.expressiveEffects + property: "implicitHeight" + target: root + } + } + ] + + Loader { + id: content + + active: true + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + visible: true + + sourceComponent: Content { + visibilities: root.visibilities + } + } +}