From fb1b5db2796d07f2f458642a0c6a2b0d23e038c8 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 04:25:21 +0300 Subject: [PATCH 01/30] Add dropdown button for language --- .../common/widgets/LanguageDropdownButton.qml | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml new file mode 100644 index 000000000..98db62580 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml @@ -0,0 +1,179 @@ +import QtQuick +import QtQuick.Layouts +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions + +ColumnLayout { + id: root + Layout.fillWidth: true + spacing: 4 + + property list options: [] + property var currentValue: null + + signal selected(var newValue) + + function getCurrentDisplayName() { + for (let i = 0; i < options.length; i++) { + if (options[i].value === currentValue) { + return options[i].displayName; + } + } + return "Select language"; + } + + GroupButton { + id: dropdownButton + Layout.fillWidth: true + buttonRadius: height / 2 + buttonRadiusPressed: height / 2 + leftRadius: height / 2 + rightRadius: height / 2 + horizontalPadding: 16 + verticalPadding: 10 + colBackground: Appearance.colors.colSecondaryContainer + colBackgroundHover: Appearance.colors.colSecondaryContainerHover + colBackgroundActive: Appearance.colors.colSecondaryContainerActive + + contentItem: RowLayout { + spacing: 8 + + MaterialSymbol { + Layout.alignment: Qt.AlignVCenter + text: "language" + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colOnSecondaryContainer + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + color: Appearance.colors.colOnSecondaryContainer + text: root.getCurrentDisplayName() + } + + MaterialSymbol { + Layout.alignment: Qt.AlignVCenter + text: dropdownPopup.visible ? "arrow_drop_up" : "arrow_drop_down" + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colOnSecondaryContainer + + Behavior on text { + enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined + } + } + } + + onClicked: { + dropdownPopup.visible = !dropdownPopup.visible; + } + } + + Item { + id: dropdownPopup + visible: false + Layout.fillWidth: true + implicitHeight: visible ? Math.min(optionColumn.implicitHeight + 16, 300) : 0 + clip: true + + Rectangle { + anchors.fill: parent + radius: Appearance.rounding.normal + color: Appearance.colors.colSurfaceContainerHigh + border.width: 1 + border.color: Appearance.colors.colOutline + + Flickable { + id: scrollView + anchors.fill: parent + anchors.margins: 8 + contentHeight: optionColumn.implicitHeight + clip: true + + ColumnLayout { + id: optionColumn + width: parent.width + spacing: 2 + + Repeater { + model: root.options + + delegate: GroupButton { + id: optionButton + required property var modelData + required property int index + Layout.fillWidth: true + + buttonText: modelData.displayName + toggled: modelData.value === root.currentValue + buttonRadius: Appearance.rounding.small + buttonRadiusPressed: Appearance.rounding.small + leftRadius: Appearance.rounding.small + rightRadius: Appearance.rounding.small + horizontalPadding: 12 + verticalPadding: 8 + colBackground: "transparent" + colBackgroundHover: Appearance.colors.colSecondaryContainerHover + colBackgroundActive: Appearance.colors.colSecondaryContainerActive + colBackgroundToggled: Appearance.colors.colPrimary + colBackgroundToggledHover: Appearance.colors.colPrimaryHover + colBackgroundToggledActive: Appearance.colors.colPrimaryActive + + contentItem: RowLayout { + spacing: 8 + + MaterialSymbol { + Layout.alignment: Qt.AlignVCenter + text: "check" + iconSize: Appearance.font.pixelSize.normal + color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + opacity: optionButton.toggled ? 1 : 0 + + Behavior on opacity { + enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined + NumberAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + text: optionButton.buttonText + } + } + + onClicked: { + root.selected(modelData.value); + dropdownPopup.visible = false; + } + } + } + } + } + } + + Behavior on implicitHeight { + enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined + NumberAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + + opacity: visible ? 1 : 0 + + Behavior on opacity { + enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined + NumberAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + } +} From 5504bd3f095198aaf8e7f5726f4d1e2c99989667 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 04:25:59 +0300 Subject: [PATCH 02/30] switch selection array to language dropdown --- dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml index c2ea1f930..b4ea73a5a 100644 --- a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml @@ -137,7 +137,7 @@ ContentPage { title: Translation.tr("Interface Language") tooltip: Translation.tr("Select the language for the user interface.\n\"Auto\" will use your system's locale.") - ConfigSelectionArray { + LanguageDropdownButton { id: languageSelector currentValue: Config.options.language.ui onSelected: newValue => { From 6b0572975fc99f736d90c686e53d1b5149a4ec98 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 19:06:41 +0300 Subject: [PATCH 03/30] make dropdown options like a overlay --- .../modules/common/widgets/DropdownButton.qml | 264 ++++++++++++++++++ .../common/widgets/LanguageDropdownButton.qml | 179 ------------ .../ii/modules/settings/GeneralConfig.qml | 3 +- 3 files changed, 266 insertions(+), 180 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml delete mode 100644 dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml new file mode 100644 index 000000000..8443a1fa0 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml @@ -0,0 +1,264 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions + +Item { + id: root + implicitWidth: dropdownButton.implicitWidth + implicitHeight: dropdownButton.implicitHeight + + property list options: [] + property var currentValue: null + + property string buttonText: "" + property string buttonIcon: "" + property string placeholder: "Select..." + property Component buttonContent: null + + property Component itemDelegate: null + property real maxPopupHeight: 300 + property real popupWidth: dropdownButton.width + + property real buttonRadius: dropdownButton.height / 2 + property color buttonBackground: Appearance.colors.colSecondaryContainer + property color buttonBackgroundHover: Appearance.colors.colSecondaryContainerHover + property color buttonBackgroundActive: Appearance.colors.colSecondaryContainerActive + + property bool popupVisible: false + + signal selected(var newValue) + + function findWindowRoot() { + var p = root.parent; + while (p && p.parent) { + p = p.parent; + } + return p || root.parent; + } + + function getGlobalPosition() { + var windowRoot = findWindowRoot(); + if (windowRoot) { + return root.mapToItem(windowRoot, 0, 0); + } + return { + x: 0, + y: 0 + }; + } + + function getCurrentDisplayName() { + for (let i = 0; i < options.length; i++) { + if (options[i].value === currentValue) { + return options[i].displayName; + } + } + return placeholder; + } + + GroupButton { + id: dropdownButton + anchors.fill: parent + buttonRadius: root.buttonRadius + buttonRadiusPressed: root.buttonRadius + leftRadius: root.buttonRadius + rightRadius: root.buttonRadius + horizontalPadding: 16 + verticalPadding: 10 + colBackground: root.buttonBackground + colBackgroundHover: root.buttonBackgroundHover + colBackgroundActive: root.buttonBackgroundActive + + contentItem: Loader { + sourceComponent: root.buttonContent || defaultButtonContent + } + + onClicked: { + root.popupVisible = !root.popupVisible; + } + } + + Component { + id: defaultButtonContent + + RowLayout { + spacing: 8 + + Loader { + Layout.alignment: Qt.AlignVCenter + active: root.buttonIcon.length > 0 + visible: active + sourceComponent: MaterialSymbol { + text: root.buttonIcon + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colOnSecondaryContainer + } + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + color: Appearance.colors.colOnSecondaryContainer + text: root.buttonText || root.getCurrentDisplayName() + } + + MaterialSymbol { + Layout.alignment: Qt.AlignVCenter + text: root.popupVisible ? "arrow_drop_up" : "arrow_drop_down" + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colOnSecondaryContainer + } + } + } + + Rectangle { + id: scrim + visible: root.popupVisible + parent: root.findWindowRoot() + anchors.fill: parent + color: "transparent" + z: 999 + + MouseArea { + anchors.fill: parent + onClicked: { + root.popupVisible = false; + } + } + } + + Rectangle { + id: popupContent + visible: root.popupVisible + z: 1000 + + parent: root.findWindowRoot() + + width: root.popupWidth + height: Math.min(optionColumn.implicitHeight + 16, root.maxPopupHeight) + + radius: Appearance.rounding.normal + color: Appearance.colors.colSurfaceContainerHigh + border.width: 1 + border.color: Appearance.colors.colOutline + + Flickable { + id: scrollView + anchors.fill: parent + anchors.margins: 8 + contentHeight: optionColumn.implicitHeight + clip: true + + ColumnLayout { + id: optionColumn + width: scrollView.width + spacing: 2 + + Repeater { + model: root.options + + delegate: Loader { + id: itemLoader + required property var modelData + required property int index + Layout.fillWidth: true + + sourceComponent: root.itemDelegate || defaultItemDelegate + + onLoaded: { + if (item) { + item.modelData = Qt.binding(() => modelData); + item.index = Qt.binding(() => index); + } + } + } + } + } + } + + opacity: visible ? 1 : 0 + scale: visible ? 1 : 0.95 + transformOrigin: Item.Top + + Behavior on opacity { + NumberAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + + Behavior on scale { + NumberAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + + Behavior on height { + NumberAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + } + + Component { + id: defaultItemDelegate + + GroupButton { + id: optionButton + property var modelData + property int index + + buttonText: modelData?.displayName || "" + toggled: modelData?.value === root.currentValue + buttonRadius: Appearance.rounding.small + buttonRadiusPressed: Appearance.rounding.small + leftRadius: Appearance.rounding.small + rightRadius: Appearance.rounding.small + horizontalPadding: 12 + verticalPadding: 8 + colBackground: "transparent" + colBackgroundHover: Appearance.colors.colSecondaryContainerHover + colBackgroundActive: Appearance.colors.colSecondaryContainerActive + colBackgroundToggled: Appearance.colors.colPrimary + colBackgroundToggledHover: Appearance.colors.colPrimaryHover + colBackgroundToggledActive: Appearance.colors.colPrimaryActive + + contentItem: RowLayout { + spacing: 8 + + MaterialSymbol { + Layout.alignment: Qt.AlignVCenter + text: "check" + iconSize: Appearance.font.pixelSize.normal + color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + opacity: optionButton.toggled ? 1 : 0 + + Behavior on opacity { + NumberAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + text: optionButton.buttonText + } + } + + onClicked: { + root.selected(modelData.value); + root.popupVisible = false; + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml deleted file mode 100644 index 98db62580..000000000 --- a/dots/.config/quickshell/ii/modules/common/widgets/LanguageDropdownButton.qml +++ /dev/null @@ -1,179 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.services -import qs.modules.common -import qs.modules.common.widgets -import qs.modules.common.functions - -ColumnLayout { - id: root - Layout.fillWidth: true - spacing: 4 - - property list options: [] - property var currentValue: null - - signal selected(var newValue) - - function getCurrentDisplayName() { - for (let i = 0; i < options.length; i++) { - if (options[i].value === currentValue) { - return options[i].displayName; - } - } - return "Select language"; - } - - GroupButton { - id: dropdownButton - Layout.fillWidth: true - buttonRadius: height / 2 - buttonRadiusPressed: height / 2 - leftRadius: height / 2 - rightRadius: height / 2 - horizontalPadding: 16 - verticalPadding: 10 - colBackground: Appearance.colors.colSecondaryContainer - colBackgroundHover: Appearance.colors.colSecondaryContainerHover - colBackgroundActive: Appearance.colors.colSecondaryContainerActive - - contentItem: RowLayout { - spacing: 8 - - MaterialSymbol { - Layout.alignment: Qt.AlignVCenter - text: "language" - iconSize: Appearance.font.pixelSize.larger - color: Appearance.colors.colOnSecondaryContainer - } - - StyledText { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - color: Appearance.colors.colOnSecondaryContainer - text: root.getCurrentDisplayName() - } - - MaterialSymbol { - Layout.alignment: Qt.AlignVCenter - text: dropdownPopup.visible ? "arrow_drop_up" : "arrow_drop_down" - iconSize: Appearance.font.pixelSize.larger - color: Appearance.colors.colOnSecondaryContainer - - Behavior on text { - enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined - } - } - } - - onClicked: { - dropdownPopup.visible = !dropdownPopup.visible; - } - } - - Item { - id: dropdownPopup - visible: false - Layout.fillWidth: true - implicitHeight: visible ? Math.min(optionColumn.implicitHeight + 16, 300) : 0 - clip: true - - Rectangle { - anchors.fill: parent - radius: Appearance.rounding.normal - color: Appearance.colors.colSurfaceContainerHigh - border.width: 1 - border.color: Appearance.colors.colOutline - - Flickable { - id: scrollView - anchors.fill: parent - anchors.margins: 8 - contentHeight: optionColumn.implicitHeight - clip: true - - ColumnLayout { - id: optionColumn - width: parent.width - spacing: 2 - - Repeater { - model: root.options - - delegate: GroupButton { - id: optionButton - required property var modelData - required property int index - Layout.fillWidth: true - - buttonText: modelData.displayName - toggled: modelData.value === root.currentValue - buttonRadius: Appearance.rounding.small - buttonRadiusPressed: Appearance.rounding.small - leftRadius: Appearance.rounding.small - rightRadius: Appearance.rounding.small - horizontalPadding: 12 - verticalPadding: 8 - colBackground: "transparent" - colBackgroundHover: Appearance.colors.colSecondaryContainerHover - colBackgroundActive: Appearance.colors.colSecondaryContainerActive - colBackgroundToggled: Appearance.colors.colPrimary - colBackgroundToggledHover: Appearance.colors.colPrimaryHover - colBackgroundToggledActive: Appearance.colors.colPrimaryActive - - contentItem: RowLayout { - spacing: 8 - - MaterialSymbol { - Layout.alignment: Qt.AlignVCenter - text: "check" - iconSize: Appearance.font.pixelSize.normal - color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - opacity: optionButton.toggled ? 1 : 0 - - Behavior on opacity { - enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - } - - StyledText { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - text: optionButton.buttonText - } - } - - onClicked: { - root.selected(modelData.value); - dropdownPopup.visible = false; - } - } - } - } - } - } - - Behavior on implicitHeight { - enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - - opacity: visible ? 1 : 0 - - Behavior on opacity { - enabled: Appearance.animation.elementMoveFast.numberAnimation !== undefined - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - } -} diff --git a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml index b4ea73a5a..e9430a14b 100644 --- a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml @@ -137,8 +137,9 @@ ContentPage { title: Translation.tr("Interface Language") tooltip: Translation.tr("Select the language for the user interface.\n\"Auto\" will use your system's locale.") - LanguageDropdownButton { + DropdownButton { id: languageSelector + buttonIcon: "language" currentValue: Config.options.language.ui onSelected: newValue => { Config.options.language.ui = newValue; From 6fa417a4c1853776a123c63011a7951b07b8b458 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 19:09:41 +0300 Subject: [PATCH 04/30] fix the positioning problem --- .../ii/modules/common/widgets/DropdownButton.qml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml index 8443a1fa0..92aec88c6 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml @@ -131,6 +131,20 @@ Item { } } + Timer { + id: positionTracker + interval: 8 // is this smooth enough? + repeat: true + running: root.popupVisible + onTriggered: { + if (popupContent.visible) { + var pos = root.getGlobalPosition(); + popupContent.x = pos.x; + popupContent.y = pos.y + root.height + 4; + } + } + } + Rectangle { id: popupContent visible: root.popupVisible From 9cf2aa83a1ca0a4232307d1d4b09ea1f65d6a629 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 19:13:52 +0300 Subject: [PATCH 05/30] better border --- .../quickshell/ii/modules/common/widgets/DropdownButton.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml index 92aec88c6..8676f9e05 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml @@ -157,8 +157,6 @@ Item { radius: Appearance.rounding.normal color: Appearance.colors.colSurfaceContainerHigh - border.width: 1 - border.color: Appearance.colors.colOutline Flickable { id: scrollView From 3f1b5bba956854248d94187f3abd577e8f0d8aca Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 19:19:59 +0300 Subject: [PATCH 06/30] fix some auto resizing issue on items --- .../quickshell/ii/modules/common/widgets/DropdownButton.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml index 8676f9e05..f6063dab6 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml @@ -21,7 +21,6 @@ Item { property Component itemDelegate: null property real maxPopupHeight: 300 - property real popupWidth: dropdownButton.width property real buttonRadius: dropdownButton.height / 2 property color buttonBackground: Appearance.colors.colSecondaryContainer @@ -152,7 +151,7 @@ Item { parent: root.findWindowRoot() - width: root.popupWidth + width: Math.max(dropdownButton.width, optionColumn.implicitWidth + 16) height: Math.min(optionColumn.implicitHeight + 16, root.maxPopupHeight) radius: Appearance.rounding.normal @@ -162,12 +161,13 @@ Item { id: scrollView anchors.fill: parent anchors.margins: 8 + contentWidth: optionColumn.implicitWidth contentHeight: optionColumn.implicitHeight clip: true ColumnLayout { id: optionColumn - width: scrollView.width + width: Math.max(implicitWidth, scrollView.width) spacing: 2 Repeater { From 8b5a783c1ff2fec642389add18e00a9a3396f837 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 20:12:08 +0300 Subject: [PATCH 07/30] Added StyledComboBox --- .../modules/common/widgets/StyledComboBox.qml | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml new file mode 100644 index 000000000..ae90c8432 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -0,0 +1,136 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.services +import qs.modules.common +import qs.modules.common.widgets + +ComboBox { + id: root + + property string buttonIcon: "" + property real buttonRadius: height / 2 + property color buttonBackground: Appearance.colors.colSecondaryContainer + property color buttonBackgroundHover: Appearance.colors.colSecondaryContainerHover + property color buttonBackgroundActive: Appearance.colors.colSecondaryContainerActive + + implicitHeight: 40 + Layout.fillWidth: true + + background: Rectangle { + radius: root.buttonRadius + color: root.down ? root.buttonBackgroundActive : root.hovered ? root.buttonBackgroundHover : root.buttonBackground + + Behavior on color { + ColorAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + } + + contentItem: Item { + implicitWidth: buttonLayout.implicitWidth + implicitHeight: buttonLayout.implicitHeight + + RowLayout { + id: buttonLayout + anchors.fill: parent + spacing: 8 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + Loader { + Layout.alignment: Qt.AlignVCenter + active: root.buttonIcon.length > 0 + visible: active + sourceComponent: MaterialSymbol { + text: root.buttonIcon + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colOnSecondaryContainer + } + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + color: Appearance.colors.colOnSecondaryContainer + text: root.displayText + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + } + } + + delegate: ItemDelegate { + id: itemDelegate + width: root.width + height: 40 + + required property var model + required property int index + + background: Rectangle { + radius: Appearance.rounding.small + color: root.currentIndex === itemDelegate.index ? Appearance.colors.colPrimary : itemDelegate.down ? Appearance.colors.colSecondaryContainerActive : itemDelegate.hovered ? Appearance.colors.colSecondaryContainerHover : "transparent" + + Behavior on color { + ColorAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + } + + contentItem: RowLayout { + spacing: 8 + anchors.leftMargin: 12 + anchors.rightMargin: 12 + + MaterialSymbol { + Layout.alignment: Qt.AlignVCenter + text: "check" + iconSize: Appearance.font.pixelSize.normal + color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + opacity: root.currentIndex === itemDelegate.index ? 1 : 0 + + Behavior on opacity { + NumberAnimation { + duration: 150 + easing.type: Easing.OutCubic + } + } + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + text: itemDelegate.model[root.textRole] + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + } + } + + popup: Popup { + y: root.height + 4 + width: root.width + implicitHeight: Math.min(contentItem.implicitHeight, 300) + padding: 8 + + background: Rectangle { + radius: Appearance.rounding.normal + color: Appearance.colors.colSurfaceContainerHigh + } + + contentItem: ListView { + clip: true + implicitHeight: contentHeight + model: root.popup.visible ? root.delegateModel : null + currentIndex: root.highlightedIndex + + ScrollIndicator.vertical: ScrollIndicator {} + } + } +} From c7c38bf0b103b699ef2ec6dbc06a6353fc7eade6 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 20:12:30 +0300 Subject: [PATCH 08/30] Switch from DropdownButton to StyledComboBox --- .../ii/modules/settings/GeneralConfig.qml | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml index e9430a14b..34d3c0781 100644 --- a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml @@ -128,7 +128,7 @@ ContentPage { } } } - + ContentSection { icon: "language" title: Translation.tr("Language") @@ -137,14 +137,12 @@ ContentPage { title: Translation.tr("Interface Language") tooltip: Translation.tr("Select the language for the user interface.\n\"Auto\" will use your system's locale.") - DropdownButton { + StyledComboBox { id: languageSelector buttonIcon: "language" - currentValue: Config.options.language.ui - onSelected: newValue => { - Config.options.language.ui = newValue; - } - options: [ + textRole: "displayName" + + model: [ { displayName: Translation.tr("Auto (System)"), value: "auto" @@ -154,14 +152,26 @@ ContentPage { displayName: lang, value: lang }; - }) - ] + })] + + Component.onCompleted: { + for (let i = 0; i < model.length; i++) { + if (model[i].value === Config.options.language.ui) { + currentIndex = i; + break; + } + } + } + + onActivated: index => { + Config.options.language.ui = model[index].value; + } } } ContentSubsection { title: Translation.tr("Generate translation with Gemini") tooltip: Translation.tr("You'll need to enter your Gemini API key first.\nType /key on the sidebar for instructions.") - + ConfigRow { MaterialTextArea { id: localeInput @@ -196,7 +206,7 @@ ContentPage { ContentSubsectionLabel { text: Translation.tr("AI") } - + ConfigSelectionArray { currentValue: Config.options.policies.ai onSelected: newValue => { @@ -279,7 +289,7 @@ ContentPage { } } } - + ContentSection { icon: "nest_clock_farsight_analog" title: Translation.tr("Time") @@ -310,7 +320,6 @@ ContentPage { } Config.options.time.format = newValue; - } options: [ { From 9209ca8216a47f0c6851aa91bd00229560e9d2ec Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 21:25:59 +0300 Subject: [PATCH 09/30] fix item list size calculation to fit all items in list --- .../quickshell/ii/modules/common/widgets/StyledComboBox.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index ae90c8432..97424647e 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -116,7 +116,7 @@ ComboBox { popup: Popup { y: root.height + 4 width: root.width - implicitHeight: Math.min(contentItem.implicitHeight, 300) + height: Math.min(listView.contentHeight + topPadding + bottomPadding, 300) padding: 8 background: Rectangle { @@ -125,6 +125,7 @@ ComboBox { } contentItem: ListView { + id: listView clip: true implicitHeight: contentHeight model: root.popup.visible ? root.delegateModel : null From 4c5bc1974862d6ecc73262932f13c5df348dfee3 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 21:31:24 +0300 Subject: [PATCH 10/30] correct item corner radius --- .../quickshell/ii/modules/common/widgets/StyledComboBox.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 97424647e..8f564a1a5 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -64,13 +64,14 @@ ComboBox { delegate: ItemDelegate { id: itemDelegate - width: root.width + width: ListView.view ? ListView.view.width : root.width height: 40 required property var model required property int index background: Rectangle { + anchors.fill: parent radius: Appearance.rounding.small color: root.currentIndex === itemDelegate.index ? Appearance.colors.colPrimary : itemDelegate.down ? Appearance.colors.colSecondaryContainerActive : itemDelegate.hovered ? Appearance.colors.colSecondaryContainerHover : "transparent" From 225e03b0a3957f0b303ddd0015272348f8fa51e0 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 21:35:37 +0300 Subject: [PATCH 11/30] remove check mark it looks better without check mark --- .../ii/modules/common/widgets/StyledComboBox.qml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 8f564a1a5..cab4a23a6 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -88,21 +88,6 @@ ComboBox { anchors.leftMargin: 12 anchors.rightMargin: 12 - MaterialSymbol { - Layout.alignment: Qt.AlignVCenter - text: "check" - iconSize: Appearance.font.pixelSize.normal - color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - opacity: root.currentIndex === itemDelegate.index ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - StyledText { Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter From a2ae9497df2ce9c5e11f440976cb9245c62506a5 Mon Sep 17 00:00:00 2001 From: Pico Date: Sat, 8 Nov 2025 23:55:16 +0300 Subject: [PATCH 12/30] fix language selector index binding --- .../quickshell/ii/modules/settings/GeneralConfig.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml index 34d3c0781..67ad2f9c1 100644 --- a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml @@ -154,13 +154,13 @@ ContentPage { }; })] - Component.onCompleted: { + currentIndex: { for (let i = 0; i < model.length; i++) { if (model[i].value === Config.options.language.ui) { - currentIndex = i; - break; + return i; } } + return 0; } onActivated: index => { From fa6a4e85436a089345cd0a92ae52181a9b54f840 Mon Sep 17 00:00:00 2001 From: Pico Date: Sun, 9 Nov 2025 00:11:12 +0300 Subject: [PATCH 13/30] spice it up with smooth animations --- .../modules/common/widgets/StyledComboBox.qml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index cab4a23a6..6bebd6667 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -105,6 +105,40 @@ ComboBox { height: Math.min(listView.contentHeight + topPadding + bottomPadding, 300) padding: 8 + enter: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "height" + from: 0 + to: popup.height + duration: 200 + easing.type: Easing.OutCubic + } + } + + exit: Transition { + NumberAnimation { + property: "opacity" + from: 1 + to: 0 + duration: 150 + easing.type: Easing.InCubic + } + NumberAnimation { + property: "height" + from: popup.height + to: 0 + duration: 150 + easing.type: Easing.InCubic + } + } + background: Rectangle { radius: Appearance.rounding.normal color: Appearance.colors.colSurfaceContainerHigh From 96e4ca10959a94c948c4b8c8b31528193bb0cbad Mon Sep 17 00:00:00 2001 From: Pico Date: Sun, 9 Nov 2025 00:23:44 +0300 Subject: [PATCH 14/30] remove height animation to prevent jump on reposition Height animation breaks when popup auto repositions from down to up. Simple fade animation works smoothly regardless of direction. --- .../modules/common/widgets/StyledComboBox.qml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 6bebd6667..4910c0d49 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -110,14 +110,7 @@ ComboBox { property: "opacity" from: 0 to: 1 - duration: 200 - easing.type: Easing.OutCubic - } - NumberAnimation { - property: "height" - from: 0 - to: popup.height - duration: 200 + duration: 150 easing.type: Easing.OutCubic } } @@ -127,14 +120,7 @@ ComboBox { property: "opacity" from: 1 to: 0 - duration: 150 - easing.type: Easing.InCubic - } - NumberAnimation { - property: "height" - from: popup.height - to: 0 - duration: 150 + duration: 100 easing.type: Easing.InCubic } } From eafe9f7217ea889a6160737e2f69b5828e7f09c0 Mon Sep 17 00:00:00 2001 From: Pico Date: Sun, 9 Nov 2025 00:26:42 +0300 Subject: [PATCH 15/30] Delete DropDownButton we don't need DropDownButton anymore --- .../modules/common/widgets/DropdownButton.qml | 276 ------------------ 1 file changed, 276 deletions(-) delete mode 100644 dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml deleted file mode 100644 index f6063dab6..000000000 --- a/dots/.config/quickshell/ii/modules/common/widgets/DropdownButton.qml +++ /dev/null @@ -1,276 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.services -import qs.modules.common -import qs.modules.common.widgets -import qs.modules.common.functions - -Item { - id: root - implicitWidth: dropdownButton.implicitWidth - implicitHeight: dropdownButton.implicitHeight - - property list options: [] - property var currentValue: null - - property string buttonText: "" - property string buttonIcon: "" - property string placeholder: "Select..." - property Component buttonContent: null - - property Component itemDelegate: null - property real maxPopupHeight: 300 - - property real buttonRadius: dropdownButton.height / 2 - property color buttonBackground: Appearance.colors.colSecondaryContainer - property color buttonBackgroundHover: Appearance.colors.colSecondaryContainerHover - property color buttonBackgroundActive: Appearance.colors.colSecondaryContainerActive - - property bool popupVisible: false - - signal selected(var newValue) - - function findWindowRoot() { - var p = root.parent; - while (p && p.parent) { - p = p.parent; - } - return p || root.parent; - } - - function getGlobalPosition() { - var windowRoot = findWindowRoot(); - if (windowRoot) { - return root.mapToItem(windowRoot, 0, 0); - } - return { - x: 0, - y: 0 - }; - } - - function getCurrentDisplayName() { - for (let i = 0; i < options.length; i++) { - if (options[i].value === currentValue) { - return options[i].displayName; - } - } - return placeholder; - } - - GroupButton { - id: dropdownButton - anchors.fill: parent - buttonRadius: root.buttonRadius - buttonRadiusPressed: root.buttonRadius - leftRadius: root.buttonRadius - rightRadius: root.buttonRadius - horizontalPadding: 16 - verticalPadding: 10 - colBackground: root.buttonBackground - colBackgroundHover: root.buttonBackgroundHover - colBackgroundActive: root.buttonBackgroundActive - - contentItem: Loader { - sourceComponent: root.buttonContent || defaultButtonContent - } - - onClicked: { - root.popupVisible = !root.popupVisible; - } - } - - Component { - id: defaultButtonContent - - RowLayout { - spacing: 8 - - Loader { - Layout.alignment: Qt.AlignVCenter - active: root.buttonIcon.length > 0 - visible: active - sourceComponent: MaterialSymbol { - text: root.buttonIcon - iconSize: Appearance.font.pixelSize.larger - color: Appearance.colors.colOnSecondaryContainer - } - } - - StyledText { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - color: Appearance.colors.colOnSecondaryContainer - text: root.buttonText || root.getCurrentDisplayName() - } - - MaterialSymbol { - Layout.alignment: Qt.AlignVCenter - text: root.popupVisible ? "arrow_drop_up" : "arrow_drop_down" - iconSize: Appearance.font.pixelSize.larger - color: Appearance.colors.colOnSecondaryContainer - } - } - } - - Rectangle { - id: scrim - visible: root.popupVisible - parent: root.findWindowRoot() - anchors.fill: parent - color: "transparent" - z: 999 - - MouseArea { - anchors.fill: parent - onClicked: { - root.popupVisible = false; - } - } - } - - Timer { - id: positionTracker - interval: 8 // is this smooth enough? - repeat: true - running: root.popupVisible - onTriggered: { - if (popupContent.visible) { - var pos = root.getGlobalPosition(); - popupContent.x = pos.x; - popupContent.y = pos.y + root.height + 4; - } - } - } - - Rectangle { - id: popupContent - visible: root.popupVisible - z: 1000 - - parent: root.findWindowRoot() - - width: Math.max(dropdownButton.width, optionColumn.implicitWidth + 16) - height: Math.min(optionColumn.implicitHeight + 16, root.maxPopupHeight) - - radius: Appearance.rounding.normal - color: Appearance.colors.colSurfaceContainerHigh - - Flickable { - id: scrollView - anchors.fill: parent - anchors.margins: 8 - contentWidth: optionColumn.implicitWidth - contentHeight: optionColumn.implicitHeight - clip: true - - ColumnLayout { - id: optionColumn - width: Math.max(implicitWidth, scrollView.width) - spacing: 2 - - Repeater { - model: root.options - - delegate: Loader { - id: itemLoader - required property var modelData - required property int index - Layout.fillWidth: true - - sourceComponent: root.itemDelegate || defaultItemDelegate - - onLoaded: { - if (item) { - item.modelData = Qt.binding(() => modelData); - item.index = Qt.binding(() => index); - } - } - } - } - } - } - - opacity: visible ? 1 : 0 - scale: visible ? 1 : 0.95 - transformOrigin: Item.Top - - Behavior on opacity { - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - - Behavior on scale { - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Component { - id: defaultItemDelegate - - GroupButton { - id: optionButton - property var modelData - property int index - - buttonText: modelData?.displayName || "" - toggled: modelData?.value === root.currentValue - buttonRadius: Appearance.rounding.small - buttonRadiusPressed: Appearance.rounding.small - leftRadius: Appearance.rounding.small - rightRadius: Appearance.rounding.small - horizontalPadding: 12 - verticalPadding: 8 - colBackground: "transparent" - colBackgroundHover: Appearance.colors.colSecondaryContainerHover - colBackgroundActive: Appearance.colors.colSecondaryContainerActive - colBackgroundToggled: Appearance.colors.colPrimary - colBackgroundToggledHover: Appearance.colors.colPrimaryHover - colBackgroundToggledActive: Appearance.colors.colPrimaryActive - - contentItem: RowLayout { - spacing: 8 - - MaterialSymbol { - Layout.alignment: Qt.AlignVCenter - text: "check" - iconSize: Appearance.font.pixelSize.normal - color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - opacity: optionButton.toggled ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - StyledText { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - color: optionButton.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - text: optionButton.buttonText - } - } - - onClicked: { - root.selected(modelData.value); - root.popupVisible = false; - } - } - } -} From d8bcf2ed5984c8d2e1e0e0edec2d72c55744e8e2 Mon Sep 17 00:00:00 2001 From: Pico Date: Sun, 9 Nov 2025 01:41:00 +0300 Subject: [PATCH 16/30] added symbol (icon) support to items --- .../modules/common/widgets/StyledComboBox.qml | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 4910c0d49..75bb76f28 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -42,10 +42,15 @@ ComboBox { Loader { Layout.alignment: Qt.AlignVCenter - active: root.buttonIcon.length > 0 + active: root.buttonIcon.length > 0 || (root.currentIndex >= 0 && root.model[root.currentIndex]?.icon) visible: active sourceComponent: MaterialSymbol { - text: root.buttonIcon + text: { + if (root.currentIndex >= 0 && root.model[root.currentIndex]?.icon) { + return root.model[root.currentIndex].icon; + } + return root.buttonIcon; + } iconSize: Appearance.font.pixelSize.larger color: Appearance.colors.colOnSecondaryContainer } @@ -88,13 +93,36 @@ ComboBox { anchors.leftMargin: 12 anchors.rightMargin: 12 - StyledText { - Layout.fillWidth: true + Loader { Layout.alignment: Qt.AlignVCenter - color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - text: itemDelegate.model[root.textRole] - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter + Layout.preferredHeight: Appearance.font.pixelSize.larger + active: itemDelegate.model.icon && itemDelegate.model.icon.length > 0 + visible: active + sourceComponent: Item { + implicitWidth: icon.implicitWidth + implicitHeight: Appearance.font.pixelSize.larger + MaterialSymbol { + id: icon + anchors.centerIn: parent + text: itemDelegate.model.icon + iconSize: Appearance.font.pixelSize.larger + color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + } + } + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: Appearance.font.pixelSize.larger + + StyledText { + anchors.centerIn: parent + width: parent.width + color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + text: itemDelegate.model[root.textRole] + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } } } } @@ -134,6 +162,7 @@ ComboBox { id: listView clip: true implicitHeight: contentHeight + spacing: 2 model: root.popup.visible ? root.delegateModel : null currentIndex: root.highlightedIndex From c64f3a01222f4d178410db3e43f281455c8e2a90 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:18:37 +0100 Subject: [PATCH 17/30] combobox: make color names more consistent with other buttons --- .../ii/modules/common/widgets/StyledComboBox.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 75bb76f28..150dbc249 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -10,16 +10,16 @@ ComboBox { property string buttonIcon: "" property real buttonRadius: height / 2 - property color buttonBackground: Appearance.colors.colSecondaryContainer - property color buttonBackgroundHover: Appearance.colors.colSecondaryContainerHover - property color buttonBackgroundActive: Appearance.colors.colSecondaryContainerActive + property color colBackground: Appearance.colors.colSecondaryContainer + property color colBackgroundHover: Appearance.colors.colSecondaryContainerHover + property color colBackgroundActive: Appearance.colors.colSecondaryContainerActive implicitHeight: 40 Layout.fillWidth: true background: Rectangle { radius: root.buttonRadius - color: root.down ? root.buttonBackgroundActive : root.hovered ? root.buttonBackgroundHover : root.buttonBackground + color: root.down ? root.colBackgroundActive : root.hovered ? root.colBackgroundHover : root.colBackground Behavior on color { ColorAnimation { From 6f19e1cdd68604d6dae1514f3d3c28611fdf7e83 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:21:50 +0100 Subject: [PATCH 18/30] styledcombobox: use predefined color anim --- .../ii/modules/common/widgets/StyledComboBox.qml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 150dbc249..0c0209295 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -22,10 +22,7 @@ ComboBox { color: root.down ? root.colBackgroundActive : root.hovered ? root.colBackgroundHover : root.colBackground Behavior on color { - ColorAnimation { - duration: 150 - easing.type: Easing.OutCubic - } + animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } } @@ -81,10 +78,7 @@ ComboBox { color: root.currentIndex === itemDelegate.index ? Appearance.colors.colPrimary : itemDelegate.down ? Appearance.colors.colSecondaryContainerActive : itemDelegate.hovered ? Appearance.colors.colSecondaryContainerHover : "transparent" Behavior on color { - ColorAnimation { - duration: 150 - easing.type: Easing.OutCubic - } + animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } } From 6f61782c8f5a52e5f81fa1bd30a0a990de54a557 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:26:53 +0100 Subject: [PATCH 19/30] styledcombobox: fix some warnings, use styledlistview --- .../quickshell/ii/modules/common/widgets/StyledComboBox.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 0c0209295..c7ce67539 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -152,7 +153,7 @@ ComboBox { color: Appearance.colors.colSurfaceContainerHigh } - contentItem: ListView { + contentItem: StyledListView { id: listView clip: true implicitHeight: contentHeight From 86aab5b1fdd06efd524df9bacb06d48ff73baacd Mon Sep 17 00:00:00 2001 From: Pico Date: Fri, 14 Nov 2025 00:51:07 +0300 Subject: [PATCH 20/30] replace for loop with findIndex --- .../quickshell/ii/modules/settings/GeneralConfig.qml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml index 67ad2f9c1..6b83f9cf9 100644 --- a/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/GeneralConfig.qml @@ -155,12 +155,8 @@ ContentPage { })] currentIndex: { - for (let i = 0; i < model.length; i++) { - if (model[i].value === Config.options.language.ui) { - return i; - } - } - return 0; + const index = model.findIndex(item => item.value === Config.options.language.ui); + return index !== -1 ? index : 0; } onActivated: index => { From bda5422ccc36a7c5de898e0b23c52eb1770f0c07 Mon Sep 17 00:00:00 2001 From: Pico Date: Fri, 14 Nov 2025 01:03:53 +0300 Subject: [PATCH 21/30] use triangle instead of the up/down arrows --- .../ii/modules/common/widgets/StyledComboBox.qml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index c7ce67539..9ba03bd9f 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -27,6 +27,14 @@ ComboBox { } } + indicator: MaterialSymbol { + x: root.width - width - 16 + y: root.height / 2 - height / 2 + text: "arrow_drop_down" + iconSize: Appearance.font.pixelSize.larger + color: Appearance.colors.colOnSecondaryContainer + } + contentItem: Item { implicitWidth: buttonLayout.implicitWidth implicitHeight: buttonLayout.implicitHeight From 2362c2ab3f31a90af5f75cdd25019820753dfccb Mon Sep 17 00:00:00 2001 From: Pico Date: Fri, 14 Nov 2025 01:08:47 +0300 Subject: [PATCH 22/30] fixed some undefined warnings --- .../ii/modules/common/widgets/StyledComboBox.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 9ba03bd9f..16c48f749 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -48,11 +48,11 @@ ComboBox { Loader { Layout.alignment: Qt.AlignVCenter - active: root.buttonIcon.length > 0 || (root.currentIndex >= 0 && root.model[root.currentIndex]?.icon) + active: root.buttonIcon.length > 0 || (root.currentIndex >= 0 && typeof root.model[root.currentIndex] === 'object' && root.model[root.currentIndex]?.icon) visible: active sourceComponent: MaterialSymbol { text: { - if (root.currentIndex >= 0 && root.model[root.currentIndex]?.icon) { + if (root.currentIndex >= 0 && typeof root.model[root.currentIndex] === 'object' && root.model[root.currentIndex]?.icon) { return root.model[root.currentIndex].icon; } return root.buttonIcon; @@ -99,7 +99,7 @@ ComboBox { Loader { Layout.alignment: Qt.AlignVCenter Layout.preferredHeight: Appearance.font.pixelSize.larger - active: itemDelegate.model.icon && itemDelegate.model.icon.length > 0 + active: typeof itemDelegate.model === 'object' && itemDelegate.model?.icon?.length > 0 visible: active sourceComponent: Item { implicitWidth: icon.implicitWidth @@ -107,7 +107,7 @@ ComboBox { MaterialSymbol { id: icon anchors.centerIn: parent - text: itemDelegate.model.icon + text: itemDelegate.model?.icon ?? "" iconSize: Appearance.font.pixelSize.larger color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer } From 21c51119614342c101749f7c92656b1c03dc44c8 Mon Sep 17 00:00:00 2001 From: Pico Date: Fri, 14 Nov 2025 01:15:18 +0300 Subject: [PATCH 23/30] added shadow to items list --- .../ii/modules/common/widgets/StyledComboBox.qml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 16c48f749..6ae65984e 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -156,9 +156,17 @@ ComboBox { } } - background: Rectangle { - radius: Appearance.rounding.normal - color: Appearance.colors.colSurfaceContainerHigh + background: Item { + StyledRectangularShadow { + target: popupBackground + } + + Rectangle { + id: popupBackground + anchors.fill: parent + radius: Appearance.rounding.normal + color: Appearance.colors.colSurfaceContainerHigh + } } contentItem: StyledListView { From 3e554426549c002653b3e4d5d80b44fd245b23ba Mon Sep 17 00:00:00 2001 From: Pico Date: Fri, 14 Nov 2025 01:21:09 +0300 Subject: [PATCH 24/30] replace color:"transparent" with transparentize --- .../quickshell/ii/modules/common/widgets/StyledComboBox.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 6ae65984e..5b9da31e2 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import qs.services import qs.modules.common import qs.modules.common.widgets +import qs.modules.common.functions ComboBox { id: root @@ -84,7 +85,7 @@ ComboBox { background: Rectangle { anchors.fill: parent radius: Appearance.rounding.small - color: root.currentIndex === itemDelegate.index ? Appearance.colors.colPrimary : itemDelegate.down ? Appearance.colors.colSecondaryContainerActive : itemDelegate.hovered ? Appearance.colors.colSecondaryContainerHover : "transparent" + color: root.currentIndex === itemDelegate.index ? Appearance.colors.colPrimary : itemDelegate.down ? Appearance.colors.colSecondaryContainerActive : itemDelegate.hovered ? Appearance.colors.colSecondaryContainerHover : ColorUtils.transparentize(Appearance.colors.colSurfaceContainerHigh) Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) From 7049dda7de632ddc0fd6e9bc3091e0e482efe9b1 Mon Sep 17 00:00:00 2001 From: Pico Date: Fri, 14 Nov 2025 01:26:38 +0300 Subject: [PATCH 25/30] fixed button contrast when triggered --- .../quickshell/ii/modules/common/widgets/StyledComboBox.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 5b9da31e2..a7ab3e9a5 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -21,7 +21,7 @@ ComboBox { background: Rectangle { radius: root.buttonRadius - color: root.down ? root.colBackgroundActive : root.hovered ? root.colBackgroundHover : root.colBackground + color: (root.down && !root.popup.visible) ? root.colBackgroundActive : root.hovered ? root.colBackgroundHover : root.colBackground Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) From a135b09ec72a9b95cc118ec48d2617f8a44875de Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:35:24 +0100 Subject: [PATCH 26/30] styledcombobox: make dropdown arrow nicer --- .../ii/modules/common/widgets/StyledComboBox.qml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index a7ab3e9a5..944aaf8c1 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -31,9 +31,14 @@ ComboBox { indicator: MaterialSymbol { x: root.width - width - 16 y: root.height / 2 - height / 2 - text: "arrow_drop_down" + text: "keyboard_arrow_down" iconSize: Appearance.font.pixelSize.larger color: Appearance.colors.colOnSecondaryContainer + + rotation: root.popup.visible ? 180 : 0 + Behavior on rotation { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } } contentItem: Item { From b97c2d1d4da1e7b468badea79f32f6bb9ca7509e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:38:39 +0100 Subject: [PATCH 27/30] styledcombobox: pointing hand cursor shape --- .../ii/modules/common/widgets/StyledComboBox.qml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 944aaf8c1..1909ad40c 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -26,6 +26,12 @@ ComboBox { Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } } indicator: MaterialSymbol { @@ -95,6 +101,12 @@ ComboBox { Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } } contentItem: RowLayout { From 1495669a60dce6f852cc6d365614e6a15173ae58 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:40:02 +0100 Subject: [PATCH 28/30] styledcombobox: remove dupe scrollbar --- .../quickshell/ii/modules/common/widgets/StyledComboBox.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 1909ad40c..8775715bb 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -194,8 +194,6 @@ ComboBox { spacing: 2 model: root.popup.visible ? root.delegateModel : null currentIndex: root.highlightedIndex - - ScrollIndicator.vertical: ScrollIndicator {} } } } From 18c264a85e02c6c2d963e13d132283a7d9c97593 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:44:21 +0100 Subject: [PATCH 29/30] make menu fade anim not arbitrary --- .../modules/common/widgets/StyledComboBox.qml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 8775715bb..5db02e448 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -155,22 +155,22 @@ ComboBox { padding: 8 enter: Transition { - NumberAnimation { - property: "opacity" - from: 0 + PropertyAnimation { + properties: "opacity" to: 1 - duration: 150 - easing.type: Easing.OutCubic + duration: Appearance.animation.elementMoveFast.duration + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve } } exit: Transition { - NumberAnimation { - property: "opacity" - from: 1 + PropertyAnimation { + properties: "opacity" to: 0 - duration: 100 - easing.type: Easing.InCubic + duration: Appearance.animation.elementMoveFast.duration + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve } } From 4878f7dbb14bddecf61114a1dbcb812abf27de6d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 22 Nov 2025 16:07:10 +0100 Subject: [PATCH 30/30] combobox: update color mappings --- .../modules/common/widgets/StyledComboBox.qml | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml index 5db02e448..18add2cc3 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledComboBox.qml @@ -88,15 +88,27 @@ ComboBox { delegate: ItemDelegate { id: itemDelegate width: ListView.view ? ListView.view.width : root.width - height: 40 + implicitHeight: 40 required property var model required property int index + property color color: { + if (root.currentIndex === itemDelegate.index) { + if (itemDelegate.down) return Appearance.colors.colSecondaryContainerActive; + if (itemDelegate.hovered) return Appearance.colors.colSecondaryContainerHover; + return Appearance.colors.colSecondaryContainer; + } else { + if (itemDelegate.down) return Appearance.colors.colLayer3Active; + if (itemDelegate.hovered) return Appearance.colors.colLayer3Hover; + return ColorUtils.transparentize(Appearance.colors.colLayer3); + } + } + property color colText: (root.currentIndex === itemDelegate.index) ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnLayer3 background: Rectangle { anchors.fill: parent radius: Appearance.rounding.small - color: root.currentIndex === itemDelegate.index ? Appearance.colors.colPrimary : itemDelegate.down ? Appearance.colors.colSecondaryContainerActive : itemDelegate.hovered ? Appearance.colors.colSecondaryContainerHover : ColorUtils.transparentize(Appearance.colors.colSurfaceContainerHigh) + color: itemDelegate.color Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) @@ -119,31 +131,28 @@ ComboBox { Layout.preferredHeight: Appearance.font.pixelSize.larger active: typeof itemDelegate.model === 'object' && itemDelegate.model?.icon?.length > 0 visible: active + sourceComponent: Item { implicitWidth: icon.implicitWidth implicitHeight: Appearance.font.pixelSize.larger + MaterialSymbol { id: icon anchors.centerIn: parent text: itemDelegate.model?.icon ?? "" iconSize: Appearance.font.pixelSize.larger - color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + color: itemDelegate.colText } } } - Item { + StyledText { Layout.fillWidth: true Layout.preferredHeight: Appearance.font.pixelSize.larger - - StyledText { - anchors.centerIn: parent - width: parent.width - color: root.currentIndex === itemDelegate.index ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer - text: itemDelegate.model[root.textRole] - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - } + color: itemDelegate.colText + text: itemDelegate.model[root.textRole] + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter } } }