forked from Shinonome/dots-hyprland
fancier dropdown (#2397)
This commit is contained in:
@@ -1,15 +1,208 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
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
|
||||
|
||||
Material.theme: Material.System
|
||||
Material.accent: Appearance.m3colors.m3primary
|
||||
Material.primary: Appearance.m3colors.m3primary
|
||||
Material.background: Appearance.m3colors.m3surface
|
||||
Material.foreground: Appearance.m3colors.m3onSurface
|
||||
Material.containerStyle: Material.Outlined
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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: itemDelegate.color
|
||||
|
||||
Behavior on color {
|
||||
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
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: itemDelegate.colText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Appearance.font.pixelSize.larger
|
||||
color: itemDelegate.colText
|
||||
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 {
|
||||
PropertyAnimation {
|
||||
properties: "opacity"
|
||||
to: 1
|
||||
duration: Appearance.animation.elementMoveFast.duration
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
PropertyAnimation {
|
||||
properties: "opacity"
|
||||
to: 0
|
||||
duration: Appearance.animation.elementMoveFast.duration
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ ContentPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ContentSection {
|
||||
icon: "language"
|
||||
title: Translation.tr("Language")
|
||||
@@ -137,13 +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.")
|
||||
|
||||
ConfigSelectionArray {
|
||||
StyledComboBox {
|
||||
id: languageSelector
|
||||
currentValue: Config.options.language.ui
|
||||
onSelected: newValue => {
|
||||
Config.options.language.ui = newValue;
|
||||
}
|
||||
options: [
|
||||
buttonIcon: "language"
|
||||
textRole: "displayName"
|
||||
|
||||
model: [
|
||||
{
|
||||
displayName: Translation.tr("Auto (System)"),
|
||||
value: "auto"
|
||||
@@ -153,14 +152,22 @@ ContentPage {
|
||||
displayName: lang,
|
||||
value: lang
|
||||
};
|
||||
})
|
||||
]
|
||||
})]
|
||||
|
||||
currentIndex: {
|
||||
const index = model.findIndex(item => item.value === Config.options.language.ui);
|
||||
return index !== -1 ? index : 0;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -195,7 +202,7 @@ ContentPage {
|
||||
ContentSubsectionLabel {
|
||||
text: Translation.tr("AI")
|
||||
}
|
||||
|
||||
|
||||
ConfigSelectionArray {
|
||||
currentValue: Config.options.policies.ai
|
||||
onSelected: newValue => {
|
||||
@@ -278,7 +285,7 @@ ContentPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ContentSection {
|
||||
icon: "nest_clock_farsight_analog"
|
||||
title: Translation.tr("Time")
|
||||
@@ -309,7 +316,6 @@ ContentPage {
|
||||
}
|
||||
|
||||
Config.options.time.format = newValue;
|
||||
|
||||
}
|
||||
options: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user