Merge settings window to main #23

Merged
Zacharias-Brohn merged 48 commits from settingsWindow into main 2026-03-18 16:27:50 +01:00
32 changed files with 2825 additions and 224 deletions
Showing only changes of commit 35fe6c1e5f - Show all commits
+6 -3
View File
@@ -28,6 +28,7 @@ RowLayout {
CustomTextField {
id: textField
implicitHeight: upButton.implicitHeight
inputMethodHints: Qt.ImhFormattedNumbersOnly
leftPadding: Appearance.padding.normal
padding: Appearance.padding.small
@@ -37,7 +38,7 @@ RowLayout {
background: CustomRect {
color: DynamicColors.tPalette.m3surfaceContainerHigh
implicitWidth: 100
radius: Appearance.rounding.small
radius: Appearance.rounding.full
}
validator: DoubleValidator {
bottom: root.min
@@ -82,10 +83,12 @@ RowLayout {
}
CustomRect {
id: upButton
color: DynamicColors.palette.m3primary
implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.small
radius: Appearance.rounding.full
StateLayer {
id: upState
@@ -119,7 +122,7 @@ RowLayout {
color: DynamicColors.palette.m3primary
implicitHeight: downIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.small
radius: Appearance.rounding.full
StateLayer {
id: downState
+3 -2
View File
@@ -20,7 +20,7 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
clip: false
z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1
z: root.expanded ? expandedZ : -1
RowLayout {
id: row
@@ -36,14 +36,15 @@ Item {
color: root.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.larger
text: root.label
z: root.expanded ? root.expandedZ : -1
}
CustomSplitButton {
id: splitButton
enabled: root.enabled
menu.z: 1
type: CustomSplitButton.Filled
z: root.expanded ? root.expandedZ : -1
menu.onItemSelected: item => {
root.selected(item);
+3 -3
View File
@@ -60,8 +60,8 @@ Singleton {
}
},
anim: {
mediaGifSpeedAdjustment: 300,
sessionGifSpeed: 0.7,
mediaGifSpeedAdjustment: appearance.anim.mediaGifSpeedAdjustment,
sessionGifSpeed: appearance.anim.sessionGifSpeed,
durations: {
scale: appearance.anim.durations.scale
}
@@ -189,7 +189,7 @@ Singleton {
explorer: general.apps.explorer
},
idle: {
timouts: general.idle.timeouts
timeouts: general.idle.timeouts
}
};
}
+16 -1
View File
@@ -123,6 +123,7 @@ CustomMouseArea {
root.dashboardShortcutActive = true;
}
root.visibilities.settings = false;
root.visibilities.sidebar = false;
root.popouts.hasCurrent = false;
} else {
@@ -149,8 +150,10 @@ CustomMouseArea {
}
}
if (root.visibilities.launcher)
if (root.visibilities.launcher) {
root.visibilities.dock = false;
root.visibilities.settings = false;
}
}
function onOsdChanged() {
@@ -168,6 +171,18 @@ CustomMouseArea {
if (root.visibilities.resources && root.popouts.currentName.startsWith("audio")) {
root.popouts.hasCurrent = false;
}
if (root.visibilities.resources)
root.visibilities.settings = false;
}
function onSettingsChanged() {
if (root.visibilities.settings) {
root.visibilities.resources = false;
root.visibilities.dashboard = false;
root.panels.popouts.hasCurrent = false;
root.visibilities.launcher = false;
}
}
function onSidebarChanged() {
+14 -6
View File
@@ -22,68 +22,75 @@ Item {
ListElement {
icon: "settings"
key: "general"
name: "General"
}
ListElement {
icon: "wallpaper"
key: "wallpaper"
name: "Wallpaper"
}
ListElement {
icon: "settop_component"
key: "bar"
name: "Bar"
}
ListElement {
icon: "lock"
key: "lockscreen"
name: "Lockscreen"
}
ListElement {
icon: "build_circle"
key: "services"
name: "Services"
}
ListElement {
icon: "notifications"
key: "notifications"
name: "Notifications"
}
ListElement {
icon: "view_sidebar"
key: "sidebar"
name: "Sidebar"
}
ListElement {
icon: "handyman"
key: "utilities"
name: "Utilities"
}
ListElement {
icon: "dashboard"
key: "dashboard"
name: "Dashboard"
}
ListElement {
icon: "colors"
key: "appearance"
name: "Appearance"
}
ListElement {
icon: "display_settings"
key: "osd"
name: "On screen display"
}
ListElement {
icon: "rocket_launch"
key: "launcher"
name: "Launcher"
}
ListElement {
icon: "colors"
name: "Colors"
}
}
CustomClippingRect {
@@ -129,6 +136,7 @@ Item {
required property string icon
required property int index
required property string key
required property string name
implicitHeight: 42
@@ -172,7 +180,7 @@ Item {
id: layer
onClicked: {
root.content.currentCategory = categoryItem.name.toLowerCase();
root.content.currentCategory = categoryItem.key;
clayout.currentIndex = categoryItem.index;
}
}
+124 -106
View File
@@ -1,141 +1,159 @@
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
CustomFlickable {
SettingsPage {
id: root
contentHeight: clayout.implicitHeight
SettingsSection {
SettingsHeader {
name: "Scale"
}
TapHandler {
acceptedButtons: Qt.LeftButton
SettingSpinBox {
name: "Rounding scale"
object: Config.appearance.rounding
setting: "scale"
step: 0.1
}
onTapped: function (eventPoint) {
const menu = SettingsDropdowns.activeMenu;
if (!menu)
return;
Separator {
}
const p = eventPoint.scenePosition;
SettingSpinBox {
name: "Spacing scale"
object: Config.appearance.spacing
setting: "scale"
step: 0.1
}
if (SettingsDropdowns.hit(SettingsDropdowns.activeTrigger, p))
return;
Separator {
}
if (SettingsDropdowns.hit(menu, p))
return;
SettingSpinBox {
name: "Padding scale"
object: Config.appearance.padding
setting: "scale"
step: 0.1
}
SettingsDropdowns.closeActive();
Separator {
}
SettingSpinBox {
name: "Font size scale"
object: Config.appearance.font.size
setting: "scale"
step: 0.1
}
Separator {
}
SettingSpinBox {
name: "Animation duration scale"
object: Config.appearance.anim.durations
setting: "scale"
step: 0.1
}
}
ColumnLayout {
id: clayout
SettingsSection {
SettingsHeader {
name: "Fonts"
}
anchors.left: parent.left
anchors.right: parent.right
SettingInput {
name: "Sans family"
object: Config.appearance.font.family
setting: "sans"
}
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: colorLayout.implicitHeight + Appearance.padding.normal * 2
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal - Appearance.padding.smaller
Separator {
}
ColumnLayout {
id: colorLayout
SettingInput {
name: "Monospace family"
object: Config.appearance.font.family
setting: "mono"
}
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
Separator {
}
Settings {
name: "Color"
SettingInput {
name: "Material family"
object: Config.appearance.font.family
setting: "material"
}
Separator {
}
SettingInput {
name: "Clock family"
object: Config.appearance.font.family
setting: "clock"
}
}
SettingsSection {
SettingsHeader {
name: "Animation"
}
SettingSpinBox {
name: "Media GIF speed adjustment"
object: Config.appearance.anim
setting: "mediaGifSpeedAdjustment"
step: 10
}
Separator {
}
SettingSpinBox {
name: "Session GIF speed"
max: 5
min: 0
object: Config.appearance.anim
setting: "sessionGifSpeed"
step: 0.1
}
}
SettingsSection {
SettingsHeader {
name: "Transparency"
}
SettingSwitch {
name: "Automatic color scheme"
object: Config.general.color
setting: "schemeGeneration"
name: "Enable transparency"
object: Config.appearance.transparency
setting: "enabled"
}
Separator {
}
SettingSwitch {
name: "Smart color scheme"
object: Config.general.color
setting: "smart"
SettingSpinBox {
name: "Base opacity"
max: 1
min: 0
object: Config.appearance.transparency
setting: "base"
step: 0.05
}
Separator {
}
SettingSpinner {
name: "Schedule dark mode"
object: Config.general.color
settings: ["scheduleDarkStart", "scheduleDarkEnd"]
z: 2
}
Separator {
}
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: 60
Layout.preferredWidth: 200
CustomText {
id: text
anchors.fill: parent
font.bold: true
font.pointSize: Appearance.font.size.large * 2
text: settingsItem.name
verticalAlignment: Text.AlignVCenter
SettingSpinBox {
name: "Layer opacity"
max: 1
min: 0
object: Config.appearance.transparency
setting: "layers"
step: 0.05
}
}
}
+24 -8
View File
@@ -1,13 +1,29 @@
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 {
SettingsPage {
id: root
SettingsSection {
SettingsHeader {
name: "Wallpaper"
}
SettingSwitch {
name: "Enable wallpaper rendering"
object: Config.background
setting: "enabled"
}
Separator {
}
SettingSpinBox {
name: "Fade duration"
min: 0
object: Config.background
setting: "wallFadeDuration"
step: 50
}
}
}
+184
View File
@@ -0,0 +1,184 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Bar"
}
SettingSwitch {
name: "Auto hide"
object: Config.barConfig
setting: "autoHide"
}
Separator {
}
SettingSpinBox {
name: "Height"
min: 1
object: Config.barConfig
setting: "height"
}
Separator {
}
SettingSpinBox {
name: "Rounding"
min: 0
object: Config.barConfig
setting: "rounding"
}
Separator {
}
SettingSpinBox {
name: "Border"
min: 0
object: Config.barConfig
setting: "border"
}
}
SettingsSection {
SettingsHeader {
name: "Popouts"
}
SettingSwitch {
name: "Tray"
object: Config.barConfig.popouts
setting: "tray"
}
Separator {
}
SettingSwitch {
name: "Audio"
object: Config.barConfig.popouts
setting: "audio"
}
Separator {
}
SettingSwitch {
name: "Active window"
object: Config.barConfig.popouts
setting: "activeWindow"
}
Separator {
}
SettingSwitch {
name: "Resources"
object: Config.barConfig.popouts
setting: "resources"
}
Separator {
}
SettingSwitch {
name: "Clock"
object: Config.barConfig.popouts
setting: "clock"
}
Separator {
}
SettingSwitch {
name: "Network"
object: Config.barConfig.popouts
setting: "network"
}
Separator {
}
SettingSwitch {
name: "Power"
object: Config.barConfig.popouts
setting: "upower"
}
}
SettingsSection {
SettingsHeader {
name: "Entries"
}
SettingBarEntryList {
name: "Bar entries"
object: Config.barConfig
setting: "entries"
}
}
SettingsSection {
SettingsHeader {
name: "Dock"
}
SettingSwitch {
name: "Enable dock"
object: Config.dock
setting: "enable"
}
Separator {
}
SettingSpinBox {
name: "Dock height"
min: 1
object: Config.dock
setting: "height"
}
Separator {
}
SettingSwitch {
name: "Hover to reveal"
object: Config.dock
setting: "hoverToReveal"
}
Separator {
}
SettingSwitch {
name: "Pin on startup"
object: Config.dock
setting: "pinnedOnStartup"
}
Separator {
}
SettingStringList {
name: "Pinned apps"
addLabel: qsTr("Add pinned app")
object: Config.dock
setting: "pinnedApps"
}
Separator {
}
SettingStringList {
name: "Ignored app regexes"
addLabel: qsTr("Add ignored regex")
object: Config.dock
setting: "ignoredAppRegexes"
}
}
}
+212
View File
@@ -0,0 +1,212 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Dashboard"
}
SettingSwitch {
name: "Enable dashboard"
object: Config.dashboard
setting: "enabled"
}
Separator {
}
SettingSpinBox {
name: "Media update interval"
min: 0
object: Config.dashboard
setting: "mediaUpdateInterval"
step: 50
}
Separator {
}
SettingSpinBox {
name: "Resource update interval"
min: 0
object: Config.dashboard
setting: "resourceUpdateInterval"
step: 50
}
Separator {
}
SettingSpinBox {
name: "Drag threshold"
min: 0
object: Config.dashboard
setting: "dragThreshold"
}
}
SettingsSection {
SettingsHeader {
name: "Performance"
}
SettingSwitch {
name: "Show battery"
object: Config.dashboard.performance
setting: "showBattery"
}
Separator {
}
SettingSwitch {
name: "Show GPU"
object: Config.dashboard.performance
setting: "showGpu"
}
Separator {
}
SettingSwitch {
name: "Show CPU"
object: Config.dashboard.performance
setting: "showCpu"
}
Separator {
}
SettingSwitch {
name: "Show memory"
object: Config.dashboard.performance
setting: "showMemory"
}
Separator {
}
SettingSwitch {
name: "Show storage"
object: Config.dashboard.performance
setting: "showStorage"
}
Separator {
}
SettingSwitch {
name: "Show network"
object: Config.dashboard.performance
setting: "showNetwork"
}
}
SettingsSection {
SettingsHeader {
name: "Layout Sizes"
}
SettingReadOnly {
name: "Tab indicator height"
value: String(Config.dashboard.sizes.tabIndicatorHeight)
}
Separator {
}
SettingReadOnly {
name: "Tab indicator spacing"
value: String(Config.dashboard.sizes.tabIndicatorSpacing)
}
Separator {
}
SettingReadOnly {
name: "Info width"
value: String(Config.dashboard.sizes.infoWidth)
}
Separator {
}
SettingReadOnly {
name: "Info icon size"
value: String(Config.dashboard.sizes.infoIconSize)
}
Separator {
}
SettingReadOnly {
name: "Date time width"
value: String(Config.dashboard.sizes.dateTimeWidth)
}
Separator {
}
SettingReadOnly {
name: "Media width"
value: String(Config.dashboard.sizes.mediaWidth)
}
Separator {
}
SettingReadOnly {
name: "Media progress sweep"
value: String(Config.dashboard.sizes.mediaProgressSweep)
}
Separator {
}
SettingReadOnly {
name: "Media progress thickness"
value: String(Config.dashboard.sizes.mediaProgressThickness)
}
Separator {
}
SettingReadOnly {
name: "Resource progress thickness"
value: String(Config.dashboard.sizes.resourceProgessThickness)
}
Separator {
}
SettingReadOnly {
name: "Weather width"
value: String(Config.dashboard.sizes.weatherWidth)
}
Separator {
}
SettingReadOnly {
name: "Media cover art size"
value: String(Config.dashboard.sizes.mediaCoverArtSize)
}
Separator {
}
SettingReadOnly {
name: "Media visualiser size"
value: String(Config.dashboard.sizes.mediaVisualiserSize)
}
Separator {
}
SettingReadOnly {
name: "Resource size"
value: String(Config.dashboard.sizes.resourceSize)
}
}
}
+199 -24
View File
@@ -1,37 +1,212 @@
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
import qs.Components
CustomRect {
SettingsPage {
id: root
ColumnLayout {
id: clayout
anchors.fill: parent
function schemeTypeItem(items, value) {
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.value === value)
return item;
}
component Settings: CustomRect {
id: settingsItem
return items[0] ?? null;
}
required property string name
SettingsSection {
SettingsHeader {
name: "General"
}
Layout.preferredHeight: 60
Layout.preferredWidth: 200
SettingInput {
name: "Logo"
object: Config.general
setting: "logo"
}
CustomText {
id: text
Separator {
}
anchors.fill: parent
font.bold: true
font.pointSize: Appearance.font.size.large * 2
text: settingsItem.name
verticalAlignment: Text.AlignVCenter
SettingInput {
name: "Wallpaper path"
object: Config.general
setting: "wallpaperPath"
}
Separator {
}
SettingSwitch {
name: "Desktop icons"
object: Config.general
setting: "desktopIcons"
}
}
SettingsSection {
SettingsHeader {
name: "Color"
}
CustomSplitButtonRow {
active: Config.general.color.mode === "light" ? menuItems[0] : menuItems[1]
label: qsTr("Scheme mode")
menuItems: [
MenuItem {
icon: "light_mode"
text: qsTr("Light")
value: "light"
},
MenuItem {
icon: "dark_mode"
text: qsTr("Dark")
value: "dark"
}
]
onSelected: item => {
Config.general.color.mode = item.value;
Config.save();
}
}
Separator {
}
CustomSplitButtonRow {
id: schemeType
active: root.schemeTypeItem(menuItems, Config.colors.schemeType)
label: qsTr("Scheme type")
z: 2
menuItems: [
MenuItem {
icon: "palette"
text: qsTr("Vibrant")
value: "vibrant"
},
MenuItem {
icon: "gesture"
text: qsTr("Expressive")
value: "expressive"
},
MenuItem {
icon: "contrast"
text: qsTr("Monochrome")
value: "monochrome"
},
MenuItem {
icon: "tonality"
text: qsTr("Neutral")
value: "neutral"
},
MenuItem {
icon: "gradient"
text: qsTr("Tonal spot")
value: "tonalSpot"
},
MenuItem {
icon: "target"
text: qsTr("Fidelity")
value: "fidelity"
},
MenuItem {
icon: "article"
text: qsTr("Content")
value: "content"
},
MenuItem {
icon: "colors"
text: qsTr("Rainbow")
value: "rainbow"
},
MenuItem {
icon: "nutrition"
text: qsTr("Fruit salad")
value: "fruitSalad"
}
]
onSelected: item => {
Config.colors.schemeType = item.value;
Config.save();
}
}
Separator {
}
SettingSwitch {
name: "Automatic color scheme"
object: Config.general.color
setting: "schemeGeneration"
}
Separator {
}
SettingSwitch {
name: "Smart color scheme"
object: Config.general.color
setting: "smart"
}
Separator {
}
SettingSpinner {
name: "Schedule dark mode"
object: Config.general.color
settings: ["scheduleDarkStart", "scheduleDarkEnd"]
}
}
SettingsSection {
z: -1
SettingsHeader {
name: "Default Apps"
}
SettingStringList {
addLabel: qsTr("Add terminal command")
name: "Terminal"
object: Config.general.apps
setting: "terminal"
}
Separator {
}
SettingStringList {
addLabel: qsTr("Add audio command")
name: "Audio"
object: Config.general.apps
setting: "audio"
}
Separator {
}
SettingStringList {
addLabel: qsTr("Add playback command")
name: "Playback"
object: Config.general.apps
setting: "playback"
}
Separator {
}
SettingStringList {
addLabel: qsTr("Add explorer command")
name: "Explorer"
object: Config.general.apps
setting: "explorer"
}
}
}
+148
View File
@@ -0,0 +1,148 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Launcher"
}
SettingSpinBox {
name: "Max apps shown"
min: 1
object: Config.launcher
setting: "maxAppsShown"
}
Separator {
}
SettingSpinBox {
name: "Max wallpapers shown"
min: 1
object: Config.launcher
setting: "maxWallpapers"
}
Separator {
}
SettingInput {
name: "Action prefix"
object: Config.launcher
setting: "actionPrefix"
}
Separator {
}
SettingInput {
name: "Special prefix"
object: Config.launcher
setting: "specialPrefix"
}
}
SettingsSection {
SettingsHeader {
name: "Fuzzy Search"
}
SettingSwitch {
name: "Apps"
object: Config.launcher.useFuzzy
setting: "apps"
}
Separator {
}
SettingSwitch {
name: "Actions"
object: Config.launcher.useFuzzy
setting: "actions"
}
Separator {
}
SettingSwitch {
name: "Schemes"
object: Config.launcher.useFuzzy
setting: "schemes"
}
Separator {
}
SettingSwitch {
name: "Variants"
object: Config.launcher.useFuzzy
setting: "variants"
}
Separator {
}
SettingSwitch {
name: "Wallpapers"
object: Config.launcher.useFuzzy
setting: "wallpapers"
}
}
SettingsSection {
SettingsHeader {
name: "Sizes"
}
SettingSpinBox {
name: "Item width"
min: 1
object: Config.launcher.sizes
setting: "itemWidth"
}
Separator {
}
SettingSpinBox {
name: "Item height"
min: 1
object: Config.launcher.sizes
setting: "itemHeight"
}
Separator {
}
SettingSpinBox {
name: "Wallpaper width"
min: 1
object: Config.launcher.sizes
setting: "wallpaperWidth"
}
Separator {
}
SettingSpinBox {
name: "Wallpaper height"
min: 1
object: Config.launcher.sizes
setting: "wallpaperHeight"
}
}
SettingsSection {
SettingsHeader {
name: "Actions"
}
SettingActionList {
name: "Launcher actions"
object: Config.launcher
setting: "actions"
}
}
}
+72 -59
View File
@@ -1,77 +1,90 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules as Modules
import qs.Modules.Settings.Categories.Lockscreen
import qs.Modules.Settings.Controls
import qs.Config
import qs.Helpers
CustomFlickable {
SettingsPage {
id: root
contentHeight: clayout.implicitHeight
SettingsSection {
SettingsHeader {
name: "Lockscreen"
}
TapHandler {
acceptedButtons: Qt.LeftButton
SettingSwitch {
name: "Recolor logo"
object: Config.lock
setting: "recolorLogo"
}
onTapped: function (eventPoint) {
const menu = SettingsDropdowns.activeMenu;
if (!menu)
return;
Separator {
}
const p = eventPoint.scenePosition;
SettingSwitch {
name: "Enable fingerprint"
object: Config.lock
setting: "enableFprint"
}
if (SettingsDropdowns.hit(SettingsDropdowns.activeTrigger, p))
return;
Separator {
}
if (SettingsDropdowns.hit(menu, p))
return;
SettingSpinBox {
name: "Max fingerprint tries"
min: 1
object: Config.lock
setting: "maxFprintTries"
step: 1
}
SettingsDropdowns.closeActive();
Separator {
}
SettingSpinBox {
name: "Blur amount"
min: 0
object: Config.lock
setting: "blurAmount"
step: 1
}
Separator {
}
SettingSpinBox {
name: "Height multiplier"
max: 2
min: 0.1
object: Config.lock.sizes
setting: "heightMult"
step: 0.05
}
Separator {
}
SettingSpinBox {
name: "Aspect ratio"
max: 4
min: 0.5
object: Config.lock.sizes
setting: "ratio"
step: 0.05
}
Separator {
}
SettingSpinBox {
name: "Center width"
min: 100
object: Config.lock.sizes
setting: "centerWidth"
step: 10
}
}
ColumnLayout {
id: clayout
anchors.fill: parent
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: idleLayout.implicitHeight + Appearance.padding.normal * 2
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal - Appearance.padding.smaller
z: -1
SettingsSection {
Idle {
id: idleLayout
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
}
}
component Settings: CustomRect {
id: settingsItem
required property string name
Layout.preferredHeight: 60
Layout.preferredWidth: 200
CustomText {
id: text
anchors.fill: parent
font.bold: true
font.pointSize: Appearance.font.size.large * 2
text: settingsItem.name
verticalAlignment: Text.AlignVCenter
}
}
}
@@ -0,0 +1,112 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Notifications"
}
SettingSwitch {
name: "Expire notifications"
object: Config.notifs
setting: "expire"
}
Separator {
}
SettingSpinBox {
name: "Default expire timeout"
min: 0
object: Config.notifs
setting: "defaultExpireTimeout"
step: 100
}
Separator {
}
SettingSpinBox {
name: "App notification cooldown"
min: 0
object: Config.notifs
setting: "appNotifCooldown"
step: 100
}
Separator {
}
SettingSpinBox {
name: "Clear threshold"
max: 1
min: 0
object: Config.notifs
setting: "clearThreshold"
step: 0.05
}
Separator {
}
SettingSpinBox {
name: "Expand threshold"
min: 0
object: Config.notifs
setting: "expandThreshold"
}
Separator {
}
SettingSwitch {
name: "Action on click"
object: Config.notifs
setting: "actionOnClick"
}
Separator {
}
SettingSpinBox {
name: "Group preview count"
min: 1
object: Config.notifs
setting: "groupPreviewNum"
}
}
SettingsSection {
SettingsHeader {
name: "Sizes"
}
SettingSpinBox {
name: "Width"
min: 1
object: Config.notifs.sizes
setting: "width"
}
Separator {
}
SettingSpinBox {
name: "Image size"
min: 1
object: Config.notifs.sizes
setting: "image"
}
Separator {
}
SettingSpinBox {
name: "Badge size"
min: 1
object: Config.notifs.sizes
setting: "badge"
}
}
}
+77
View File
@@ -0,0 +1,77 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "On Screen Display"
}
SettingSwitch {
name: "Enable OSD"
object: Config.osd
setting: "enabled"
}
Separator {
}
SettingSpinBox {
name: "Hide delay"
min: 0
object: Config.osd
setting: "hideDelay"
step: 100
}
Separator {
}
SettingSwitch {
name: "Enable brightness OSD"
object: Config.osd
setting: "enableBrightness"
}
Separator {
}
SettingSwitch {
name: "Enable microphone OSD"
object: Config.osd
setting: "enableMicrophone"
}
Separator {
}
SettingSwitch {
name: "Brightness on all monitors"
object: Config.osd
setting: "allMonBrightness"
}
}
SettingsSection {
SettingsHeader {
name: "Sizes"
}
SettingSpinBox {
name: "Slider width"
min: 1
object: Config.osd.sizes
setting: "sliderWidth"
}
Separator {
}
SettingSpinBox {
name: "Slider height"
min: 1
object: Config.osd.sizes
setting: "sliderHeight"
}
}
}
+120
View File
@@ -0,0 +1,120 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Services"
}
SettingInput {
name: "Weather location"
object: Config.services
setting: "weatherLocation"
}
Separator {
}
SettingSwitch {
name: "Use Fahrenheit"
object: Config.services
setting: "useFahrenheit"
}
Separator {
}
SettingSwitch {
name: "Use twelve hour clock"
object: Config.services
setting: "useTwelveHourClock"
}
Separator {
}
SettingSwitch {
name: "Enable ddcutil service"
object: Config.services
setting: "ddcutilService"
}
Separator {
}
SettingInput {
name: "GPU type"
object: Config.services
setting: "gpuType"
}
}
SettingsSection {
SettingsHeader {
name: "Media"
}
SettingSpinBox {
name: "Audio increment"
max: 1
min: 0
object: Config.services
setting: "audioIncrement"
step: 0.05
}
Separator {
}
SettingSpinBox {
name: "Brightness increment"
max: 1
min: 0
object: Config.services
setting: "brightnessIncrement"
step: 0.05
}
Separator {
}
SettingSpinBox {
name: "Max volume"
max: 5
min: 0
object: Config.services
setting: "maxVolume"
step: 0.05
}
Separator {
}
SettingInput {
name: "Default player"
object: Config.services
setting: "defaultPlayer"
}
Separator {
}
SettingSpinBox {
name: "Visualizer bars"
min: 1
object: Config.services
setting: "visualizerBars"
step: 1
}
Separator {
}
SettingAliasList {
name: "Player aliases"
object: Config.services
setting: "playerAliases"
}
}
}
+26
View File
@@ -0,0 +1,26 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Sidebar"
}
SettingSwitch {
name: "Enable sidebar"
object: Config.sidebar
setting: "enabled"
}
Separator {
}
SettingSpinBox {
name: "Width"
min: 1
object: Config.sidebar.sizes
setting: "width"
}
}
}
+170
View File
@@ -0,0 +1,170 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
SettingsHeader {
name: "Utilities"
}
SettingSwitch {
name: "Enable utilities"
object: Config.utilities
setting: "enabled"
}
Separator {
}
SettingSpinBox {
name: "Max toasts"
min: 1
object: Config.utilities
setting: "maxToasts"
}
Separator {
}
SettingSpinBox {
name: "Panel width"
min: 1
object: Config.utilities.sizes
setting: "width"
}
Separator {
}
SettingSpinBox {
name: "Toast width"
min: 1
object: Config.utilities.sizes
setting: "toastWidth"
}
}
SettingsSection {
SettingsHeader {
name: "Toasts"
}
SettingSwitch {
name: "Config loaded"
object: Config.utilities.toasts
setting: "configLoaded"
}
Separator {
}
SettingSwitch {
name: "Charging changed"
object: Config.utilities.toasts
setting: "chargingChanged"
}
Separator {
}
SettingSwitch {
name: "Game mode changed"
object: Config.utilities.toasts
setting: "gameModeChanged"
}
Separator {
}
SettingSwitch {
name: "Do not disturb changed"
object: Config.utilities.toasts
setting: "dndChanged"
}
Separator {
}
SettingSwitch {
name: "Audio output changed"
object: Config.utilities.toasts
setting: "audioOutputChanged"
}
Separator {
}
SettingSwitch {
name: "Audio input changed"
object: Config.utilities.toasts
setting: "audioInputChanged"
}
Separator {
}
SettingSwitch {
name: "Caps lock changed"
object: Config.utilities.toasts
setting: "capsLockChanged"
}
Separator {
}
SettingSwitch {
name: "Num lock changed"
object: Config.utilities.toasts
setting: "numLockChanged"
}
Separator {
}
SettingSwitch {
name: "Keyboard layout changed"
object: Config.utilities.toasts
setting: "kbLayoutChanged"
}
Separator {
}
SettingSwitch {
name: "VPN changed"
object: Config.utilities.toasts
setting: "vpnChanged"
}
Separator {
}
SettingSwitch {
name: "Now playing"
object: Config.utilities.toasts
setting: "nowPlaying"
}
}
SettingsSection {
SettingsHeader {
name: "VPN"
}
SettingSwitch {
name: "Enable VPN integration"
object: Config.utilities.vpn
setting: "enabled"
}
Separator {
}
SettingStringList {
name: "Provider"
addLabel: qsTr("Add VPN provider")
object: Config.utilities.vpn
setting: "provider"
}
}
}
+72
View File
@@ -27,10 +27,26 @@ Item {
stack.push(general);
else if (currentCategory === "wallpaper")
stack.push(background);
else if (currentCategory === "bar")
stack.push(bar);
else if (currentCategory === "appearance")
stack.push(appearance);
else if (currentCategory === "lockscreen")
stack.push(lockscreen);
else if (currentCategory === "services")
stack.push(services);
else if (currentCategory === "notifications")
stack.push(notifications);
else if (currentCategory === "sidebar")
stack.push(sidebar);
else if (currentCategory === "utilities")
stack.push(utilities);
else if (currentCategory === "dashboard")
stack.push(dashboard);
else if (currentCategory === "osd")
stack.push(osd);
else if (currentCategory === "launcher")
stack.push(launcher);
}
target: root
@@ -101,10 +117,66 @@ Item {
}
}
Component {
id: bar
Cat.Bar {
}
}
Component {
id: lockscreen
Cat.Lockscreen {
}
}
Component {
id: services
Cat.Services {
}
}
Component {
id: notifications
Cat.Notifications {
}
}
Component {
id: sidebar
Cat.Sidebar {
}
}
Component {
id: utilities
Cat.Utilities {
}
}
Component {
id: dashboard
Cat.Dashboard {
}
}
Component {
id: osd
Cat.Osd {
}
}
Component {
id: launcher
Cat.Launcher {
}
}
}
@@ -0,0 +1,235 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
ColumnLayout {
id: root
required property string name
required property var object
required property string setting
function addAction() {
const list = [...root.object[root.setting]];
list.push({
name: "New Action",
icon: "bolt",
description: "",
command: [],
enabled: true,
dangerous: false
});
root.object[root.setting] = list;
Config.save();
}
function removeAction(index) {
const list = [...root.object[root.setting]];
list.splice(index, 1);
root.object[root.setting] = list;
Config.save();
}
function updateAction(index, key, value) {
const list = [...root.object[root.setting]];
const entry = list[index];
entry[key] = value;
list[index] = entry;
root.object[root.setting] = list;
Config.save();
}
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
Repeater {
model: [...root.object[root.setting]]
CustomRect {
required property int index
required property var modelData
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight + Appearance.padding.normal * 2
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.margins: Appearance.padding.normal
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.small
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: modelData.name ?? qsTr("Action")
}
IconButton {
font.pointSize: Appearance.font.size.large
icon: "delete"
type: IconButton.Tonal
onClicked: root.removeAction(index)
}
}
Separator {
}
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("Name")
}
CustomRect {
Layout.preferredHeight: 33
Layout.preferredWidth: 350
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.name ?? ""
onEditingFinished: root.updateAction(index, "name", text)
}
}
}
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("Icon")
}
CustomRect {
Layout.preferredHeight: 33
Layout.preferredWidth: 350
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.icon ?? ""
onEditingFinished: root.updateAction(index, "icon", text)
}
}
}
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("Description")
}
CustomRect {
Layout.preferredHeight: 33
Layout.preferredWidth: 350
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.description ?? ""
onEditingFinished: root.updateAction(index, "description", text)
}
}
}
StringListEditor {
Layout.fillWidth: true
addLabel: qsTr("Add command argument")
values: [...(modelData.command ?? [])]
onListEdited: function (values) {
root.updateAction(index, "command", values);
}
}
Separator {
}
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("Enabled")
}
CustomSwitch {
checked: modelData.enabled ?? true
onToggled: root.updateAction(index, "enabled", checked)
}
}
Separator {
}
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("Dangerous")
}
CustomSwitch {
checked: modelData.dangerous ?? false
onToggled: root.updateAction(index, "dangerous", checked)
}
}
}
}
}
RowLayout {
Layout.fillWidth: true
IconButton {
font.pointSize: Appearance.font.size.large
icon: "add"
onClicked: root.addAction()
}
CustomText {
Layout.fillWidth: true
text: qsTr("Add action")
}
}
}
@@ -0,0 +1,155 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
ColumnLayout {
id: root
required property string name
required property var object
required property string setting
function addAlias() {
const list = [...root.object[root.setting]];
list.push({
from: "",
to: ""
});
root.object[root.setting] = list;
Config.save();
}
function removeAlias(index) {
const list = [...root.object[root.setting]];
list.splice(index, 1);
root.object[root.setting] = list;
Config.save();
}
function updateAlias(index, key, value) {
const list = [...root.object[root.setting]];
const entry = [...list[index]];
entry[key] = value;
list[index] = entry;
root.object[root.setting] = list;
Config.save();
}
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
Repeater {
model: [...root.object[root.setting]]
Item {
required property int index
required property var modelData
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight + Appearance.padding.smaller * 2
CustomRect {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: -(Appearance.spacing.smaller / 2)
color: DynamicColors.tPalette.m3outlineVariant
implicitHeight: 1
visible: index !== 0
}
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.small
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("From")
}
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.from ?? ""
onEditingFinished: root.updateAlias(index, "from", text)
}
}
IconButton {
font.pointSize: Appearance.font.size.large
icon: "delete"
type: IconButton.Tonal
onClicked: root.removeAlias(index)
}
}
RowLayout {
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
text: qsTr("To")
}
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33
color: DynamicColors.tPalette.m3surface
radius: Appearance.rounding.small
CustomTextField {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.to ?? ""
onEditingFinished: root.updateAlias(index, "to", text)
}
}
}
}
}
}
RowLayout {
Layout.fillWidth: true
IconButton {
font.pointSize: Appearance.font.size.large
icon: "add"
onClicked: root.addAlias()
}
CustomText {
Layout.fillWidth: true
text: qsTr("Add alias")
}
}
}
@@ -0,0 +1,523 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import QtQml.Models
import qs.Components
import qs.Config
Item {
id: root
property bool dragActive: false
property real dragHeight: 0
property real dragStartX: 0
property real dragStartY: 0
property real dragX: 0
property real dragY: 0
property var draggedModelData: null
property string draggedUid: ""
property bool dropAnimating: false
required property string name
required property var object
property var pendingCommitEntries: []
required property string setting
property int uidCounter: 0
property var visualEntries: []
function beginVisualDrag(uid, modelData, item) {
const pos = item.mapToItem(root, 0, 0);
root.draggedUid = uid;
root.draggedModelData = modelData;
root.dragHeight = item.height;
root.dragStartX = pos.x;
root.dragStartY = pos.y;
root.dragX = pos.x;
root.dragY = pos.y;
root.dragActive = true;
root.dropAnimating = false;
root.pendingCommitEntries = [];
}
function commitVisualOrder(entries) {
const list = [];
for (let i = 0; i < entries.length; i++)
list.push(entries[i].entry);
root.object[root.setting] = list;
Config.save();
root.rebuildVisualEntries();
}
function endVisualDrag() {
const entries = root.visualEntries.slice();
const finalIndex = root.indexForUid(root.draggedUid);
const finalItem = listView.itemAtIndex(finalIndex);
root.dragActive = false;
if (!finalItem) {
root.pendingCommitEntries = entries;
root.finishVisualDrag();
return;
}
const pos = finalItem.mapToItem(root, 0, 0);
root.pendingCommitEntries = entries;
root.dropAnimating = true;
settleX.to = pos.x;
settleY.to = pos.y;
settleAnim.start();
}
function ensureVisualEntries() {
if (!root.dragActive && !root.dropAnimating)
root.rebuildVisualEntries();
}
function finishVisualDrag() {
const entries = root.pendingCommitEntries.slice();
root.dragActive = false;
root.dropAnimating = false;
root.draggedUid = "";
root.draggedModelData = null;
root.pendingCommitEntries = [];
root.dragHeight = 0;
root.commitVisualOrder(entries);
}
function iconForId(id) {
switch (id) {
case "workspaces":
return "dashboard";
case "audio":
return "volume_up";
case "media":
return "play_arrow";
case "resources":
return "monitoring";
case "updates":
return "system_update";
case "dash":
return "space_dashboard";
case "spacer":
return "horizontal_rule";
case "activeWindow":
return "web_asset";
case "tray":
return "widgets";
case "upower":
return "battery_full";
case "network":
return "wifi";
case "clock":
return "schedule";
case "notifBell":
return "notifications";
default:
return "drag_indicator";
}
}
function indexForUid(uid) {
for (let i = 0; i < root.visualEntries.length; i++) {
if (root.visualEntries[i].uid === uid)
return i;
}
return -1;
}
function labelForId(id) {
switch (id) {
case "workspaces":
return qsTr("Workspaces");
case "audio":
return qsTr("Audio");
case "media":
return qsTr("Media");
case "resources":
return qsTr("Resources");
case "updates":
return qsTr("Updates");
case "dash":
return qsTr("Dash");
case "spacer":
return qsTr("Spacer");
case "activeWindow":
return qsTr("Active window");
case "tray":
return qsTr("Tray");
case "upower":
return qsTr("Power");
case "network":
return qsTr("Network");
case "clock":
return qsTr("Clock");
case "notifBell":
return qsTr("Notification bell");
default:
return id;
}
}
function moveArrayItem(list, from, to) {
const next = list.slice();
const [item] = next.splice(from, 1);
next.splice(to, 0, item);
return next;
}
function previewVisualMove(from, hovered, before) {
let to = hovered + (before ? 0 : 1);
if (to > from)
to -= 1;
to = Math.max(0, Math.min(visualModel.items.count - 1, to));
if (from === to)
return;
visualModel.items.move(from, to);
root.visualEntries = root.moveArrayItem(root.visualEntries, from, to);
}
function rebuildVisualEntries() {
const entries = root.object[root.setting] ?? [];
const next = [];
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
let existing = null;
for (let j = 0; j < root.visualEntries.length; j++) {
if (root.visualEntries[j].entry === entry) {
existing = root.visualEntries[j];
break;
}
}
if (existing)
next.push(existing);
else
next.push({
uid: `entry-${root.uidCounter++}`,
entry
});
}
root.visualEntries = next;
}
function updateEntry(index, value) {
const list = [...root.object[root.setting]];
const entry = list[index];
entry.enabled = value;
list[index] = entry;
root.object[root.setting] = list;
Config.save();
root.ensureVisualEntries();
}
Layout.fillWidth: true
implicitHeight: layout.implicitHeight
Component.onCompleted: root.rebuildVisualEntries()
ParallelAnimation {
id: settleAnim
onFinished: root.finishVisualDrag()
Anim {
id: settleX
duration: Appearance.anim.durations.normal
property: "dragX"
target: root
}
Anim {
id: settleY
duration: Appearance.anim.durations.normal
property: "dragY"
target: root
}
}
ColumnLayout {
id: layout
anchors.fill: parent
spacing: Appearance.spacing.smaller
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
DelegateModel {
id: visualModel
delegate: entryDelegate
model: ScriptModel {
objectProp: "uid"
values: root.visualEntries
}
}
ListView {
id: listView
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
boundsBehavior: Flickable.StopAtBounds
clip: false
implicitHeight: contentHeight
implicitWidth: width
interactive: !(root.dragActive || root.dropAnimating)
model: visualModel
spacing: Appearance.spacing.small
add: Transition {
Anim {
properties: "opacity,scale"
to: 1
}
}
addDisplaced: Transition {
Anim {
duration: Appearance.anim.durations.normal
property: "y"
}
}
displaced: Transition {
Anim {
duration: Appearance.anim.durations.normal
property: "y"
}
}
move: Transition {
Anim {
duration: Appearance.anim.durations.normal
property: "y"
}
}
removeDisplaced: Transition {
Anim {
duration: Appearance.anim.durations.normal
property: "y"
}
}
}
}
Loader {
active: root.dragActive || root.dropAnimating
asynchronous: false
sourceComponent: Item {
Drag.active: root.dragActive
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
height: proxyRect.implicitHeight
implicitHeight: proxyRect.implicitHeight
implicitWidth: listView.width
visible: root.draggedModelData !== null
width: listView.width
x: root.dragX
y: root.dragY
z: 100
Drag.source: QtObject {
property string uid: root.draggedUid
property int visualIndex: root.indexForUid(root.draggedUid)
}
CustomRect {
id: proxyRect
color: DynamicColors.tPalette.m3surface
implicitHeight: proxyRow.implicitHeight + Appearance.padding.small * 2
implicitWidth: parent.width
opacity: 0.95
radius: Appearance.rounding.normal
width: parent.width
RowLayout {
id: proxyRow
anchors.fill: parent
anchors.margins: Appearance.padding.small
spacing: Appearance.spacing.normal
CustomRect {
color: Qt.alpha(DynamicColors.palette.m3onSurface, 0.12)
implicitHeight: 32
implicitWidth: implicitHeight
radius: Appearance.rounding.small
MaterialIcon {
anchors.centerIn: parent
color: DynamicColors.palette.m3onSurfaceVariant
text: "drag_indicator"
}
}
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
text: root.iconForId(root.draggedModelData?.entry?.id ?? "")
}
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.labelForId(root.draggedModelData?.entry?.id ?? "")
}
CustomSwitch {
checked: root.draggedModelData?.entry?.enabled ?? true
enabled: false
}
}
}
}
}
Component {
id: entryDelegate
DropArea {
id: slot
readonly property var entryData: modelData.entry
required property var modelData
readonly property string uid: modelData.uid
function previewReorder(drag) {
const source = drag.source;
if (!source || !source.uid || source.uid === slot.uid)
return;
const from = source.visualIndex;
const hovered = slot.DelegateModel.itemsIndex;
if (from < 0 || hovered < 0)
return;
root.previewVisualMove(from, hovered, drag.y < height / 2);
}
height: entryRow.implicitHeight
implicitHeight: entryRow.implicitHeight
implicitWidth: listView.width
width: ListView.view ? ListView.view.width : listView.width
onEntered: drag => previewReorder(drag)
onPositionChanged: drag => previewReorder(drag)
CustomRect {
id: entryRow
anchors.fill: parent
color: DynamicColors.tPalette.m3surface
implicitHeight: entryLayout.implicitHeight + Appearance.padding.small * 2
implicitWidth: parent.width
opacity: root.draggedUid === slot.uid ? 0 : 1
radius: Appearance.rounding.full
Behavior on opacity {
Anim {
}
}
RowLayout {
id: entryLayout
anchors.fill: parent
anchors.margins: Appearance.padding.small
spacing: Appearance.spacing.normal
CustomRect {
id: handle
color: Qt.alpha(DynamicColors.palette.m3onSurface, handleDrag.active ? 0.12 : handleHover.hovered ? 0.09 : 0.06)
implicitHeight: 32
implicitWidth: implicitHeight
radius: Appearance.rounding.full
Behavior on color {
CAnim {
}
}
MaterialIcon {
anchors.centerIn: parent
color: DynamicColors.palette.m3onSurfaceVariant
text: "drag_indicator"
}
HoverHandler {
id: handleHover
cursorShape: handleDrag.active ? Qt.ClosedHandCursor : Qt.OpenHandCursor
}
DragHandler {
id: handleDrag
enabled: true
grabPermissions: PointerHandler.CanTakeOverFromAnything
target: null
xAxis.enabled: false
yAxis.enabled: true
onActiveChanged: {
if (active) {
root.beginVisualDrag(slot.uid, slot.modelData, entryRow);
} else if (root.draggedUid === slot.uid) {
root.endVisualDrag();
}
}
onActiveTranslationChanged: {
if (!active || root.draggedUid !== slot.uid)
return;
root.dragX = root.dragStartX;
root.dragY = root.dragStartY + activeTranslation.y;
}
}
}
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
text: root.iconForId(slot.entryData.id)
}
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.labelForId(slot.entryData.id)
}
CustomSwitch {
Layout.rightMargin: Appearance.padding.small
checked: slot.entryData.enabled ?? true
onToggled: root.updateEntry(slot.DelegateModel.itemsIndex, checked)
}
}
}
}
}
}
+4 -4
View File
@@ -13,7 +13,6 @@ Item {
function formattedValue(): string {
const value = root.object[root.setting];
console.log(value);
if (value === null || value === undefined)
return "";
@@ -44,15 +43,16 @@ Item {
id: rect
Layout.preferredHeight: 33
Layout.preferredWidth: Math.max(Math.min(textField.contentWidth + Appearance.padding.normal * 3, 200), 50)
color: DynamicColors.tPalette.m3surface
radius: Appearance.rounding.small
Layout.preferredWidth: Math.max(Math.min(textField.contentWidth + Appearance.padding.normal * 2, 550), 50)
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
id: textField
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
implicitWidth: Math.min(contentWidth, 550)
text: root.formattedValue()
onEditingFinished: {
+1 -2
View File
@@ -236,8 +236,7 @@ Item {
font.pointSize: Appearance.font.size.large
icon: "add"
onClicked: console.log(button.width)
// onClicked: root.addActiveActionRequested()
onClicked: root.addActiveActionRequested()
}
CustomText {
@@ -0,0 +1,36 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
Item {
id: root
required property string name
required property string value
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
CustomText {
color: DynamicColors.palette.m3onSurfaceVariant
font.family: Appearance.font.family.mono
font.pointSize: Appearance.font.size.normal
text: root.value
}
}
}
@@ -0,0 +1,47 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
Item {
id: root
required property string name
required property var object
required property string setting
property real max: Infinity
property real min: -Infinity
property real step: 1
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CustomText {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
CustomSpinBox {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
max: root.max
min: root.min
step: root.step
value: Number(root.object[root.setting] ?? 0)
onValueModified: function (value) {
root.object[root.setting] = value;
Config.save();
}
}
}
}
@@ -18,7 +18,6 @@ Item {
function formattedValue(setting: string): string {
const value = root.object[setting];
console.log(value);
if (value === null || value === undefined)
return "";
@@ -0,0 +1,41 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
Item {
id: root
required property string name
required property var object
required property string setting
property string addLabel: qsTr("Add entry")
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
spacing: Appearance.spacing.small
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
StringListEditor {
Layout.fillWidth: true
addLabel: root.addLabel
values: [...(root.object[root.setting] ?? [])]
onListEdited: function (values) {
root.object[root.setting] = values;
Config.save();
}
}
}
}
@@ -0,0 +1,21 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
CustomRect {
id: root
required property string name
Layout.preferredHeight: 60
Layout.preferredWidth: 200
CustomText {
anchors.fill: parent
font.bold: true
font.pointSize: Appearance.font.size.large * 2
text: root.name
verticalAlignment: Text.AlignVCenter
}
}
@@ -0,0 +1,41 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
CustomFlickable {
id: root
default property alias contentData: clayout.data
contentHeight: clayout.implicitHeight
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: function (eventPoint) {
const menu = SettingsDropdowns.activeMenu;
if (!menu)
return;
const p = eventPoint.scenePosition;
if (SettingsDropdowns.hit(SettingsDropdowns.activeTrigger, p))
return;
if (SettingsDropdowns.hit(menu, p))
return;
SettingsDropdowns.closeActive();
}
}
ColumnLayout {
id: clayout
anchors.left: parent.left
anchors.right: parent.right
spacing: Appearance.spacing.small
}
}
@@ -0,0 +1,26 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
CustomRect {
id: root
default property alias contentData: layout.data
property real contentPadding: Appearance.padding.large
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight + contentPadding * 2
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal - Appearance.padding.smaller
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.margins: root.contentPadding
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
}
}
@@ -0,0 +1,107 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
ColumnLayout {
id: root
property string addLabel: qsTr("Add entry")
property var values: []
signal listEdited(var values)
function addValue() {
const list = [...root.values];
list.push("");
root.listEdited(list);
}
function removeValue(index) {
const list = [...root.values];
list.splice(index, 1);
root.listEdited(list);
}
function updateValue(index, value) {
const list = [...root.values];
list[index] = value;
root.listEdited(list);
}
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
Repeater {
model: [...root.values]
Item {
required property int index
required property var modelData
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
CustomRect {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: -(Appearance.spacing.smaller / 2)
color: DynamicColors.tPalette.m3outlineVariant
implicitHeight: 1
visible: index !== 0
}
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: String(modelData ?? "")
onEditingFinished: root.updateValue(index, text)
}
}
IconButton {
font.pointSize: Appearance.font.size.large
icon: "delete"
type: IconButton.Tonal
onClicked: root.removeValue(index)
}
}
}
}
RowLayout {
Layout.fillWidth: true
IconButton {
font.pointSize: Appearance.font.size.large
icon: "add"
onClicked: root.addValue()
}
CustomText {
Layout.fillWidth: true
text: root.addLabel
}
}
}
+2 -1
View File
@@ -28,9 +28,10 @@ Item {
root.popouts.currentName = `traymenu${root.ind}`;
root.popouts.currentCenter = Qt.binding(() => root.mapToItem(root.loader, root.implicitWidth / 2, 0).x);
root.popouts.hasCurrent = true;
if (visibilities.sidebar || visibilities.dashboard) {
if (visibilities.sidebar || visibilities.dashboard || visibilities.settings) {
visibilities.sidebar = false;
visibilities.dashboard = false;
visibilities.settings = false;
}
}
}