pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls import QtQuick.Layouts import qs.services import qs.modules.common import qs.modules.common.widgets import qs.modules.common.functions ComboBox { id: root property string buttonIcon: "" property real buttonRadius: height / 2 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.popup.visible) ? root.colBackgroundActive : root.hovered ? root.colBackgroundHover : root.colBackground Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } } indicator: MaterialSymbol { x: root.width - width - 16 y: root.height / 2 - height / 2 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 { 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 || (root.currentIndex >= 0 && typeof root.model[root.currentIndex] === 'object' && root.model[root.currentIndex]?.icon) visible: active sourceComponent: MaterialSymbol { text: { if (root.currentIndex >= 0 && typeof root.model[root.currentIndex] === 'object' && root.model[root.currentIndex]?.icon) { return root.model[root.currentIndex].icon; } return 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: 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 : ColorUtils.transparentize(Appearance.colors.colSurfaceContainerHigh) Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } } contentItem: RowLayout { spacing: 8 anchors.leftMargin: 12 anchors.rightMargin: 12 Loader { Layout.alignment: Qt.AlignVCenter 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 } } } 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 } } } } popup: Popup { y: root.height + 4 width: root.width height: Math.min(listView.contentHeight + topPadding + bottomPadding, 300) padding: 8 enter: Transition { NumberAnimation { property: "opacity" from: 0 to: 1 duration: 150 easing.type: Easing.OutCubic } } exit: Transition { NumberAnimation { property: "opacity" from: 1 to: 0 duration: 100 easing.type: Easing.InCubic } } background: Item { StyledRectangularShadow { target: popupBackground } Rectangle { id: popupBackground anchors.fill: parent radius: Appearance.rounding.normal color: Appearance.colors.colSurfaceContainerHigh } } contentItem: StyledListView { id: listView clip: true implicitHeight: contentHeight spacing: 2 model: root.popup.visible ? root.delegateModel : null currentIndex: root.highlightedIndex ScrollIndicator.vertical: ScrollIndicator {} } } }