summaryrefslogtreecommitdiff
path: root/components/controls/ToggleButton.qml
diff options
context:
space:
mode:
Diffstat (limited to 'components/controls/ToggleButton.qml')
-rw-r--r--components/controls/ToggleButton.qml127
1 files changed, 127 insertions, 0 deletions
diff --git a/components/controls/ToggleButton.qml b/components/controls/ToggleButton.qml
new file mode 100644
index 0000000..b2c2afe
--- /dev/null
+++ b/components/controls/ToggleButton.qml
@@ -0,0 +1,127 @@
+import ".."
+import qs.components
+import qs.components.controls
+import qs.components.effects
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+StyledRect {
+ id: root
+
+ required property bool toggled
+ property string icon
+ property string label
+ property string accent: "Secondary"
+ property real iconSize: Appearance.font.size.large
+ property real horizontalPadding: Appearance.padding.large
+ property real verticalPadding: Appearance.padding.normal
+ property string tooltip: ""
+
+ property bool hovered: false
+ signal clicked
+
+ Component.onCompleted: {
+ hovered = toggleStateLayer.containsMouse;
+ }
+
+ Connections {
+ target: toggleStateLayer
+ function onContainsMouseChanged() {
+ const newHovered = toggleStateLayer.containsMouse;
+ if (hovered !== newHovered) {
+ hovered = newHovered;
+ }
+ }
+ }
+
+ Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0)
+ implicitWidth: toggleBtnInner.implicitWidth + horizontalPadding * 2
+ implicitHeight: toggleBtnIcon.implicitHeight + verticalPadding * 2
+
+ radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale)
+ color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`]
+
+ StateLayer {
+ id: toggleStateLayer
+
+ color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`]
+
+ function onClicked(): void {
+ root.clicked();
+ }
+ }
+
+ RowLayout {
+ id: toggleBtnInner
+
+ anchors.centerIn: parent
+ spacing: Appearance.spacing.normal
+
+ MaterialIcon {
+ id: toggleBtnIcon
+
+ visible: !!text
+ fill: root.toggled ? 1 : 0
+ text: root.icon
+ color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`]
+ font.pointSize: root.iconSize
+
+ Behavior on fill {
+ Anim {}
+ }
+ }
+
+ Loader {
+ asynchronous: true
+ active: !!root.label
+ visible: active
+
+ sourceComponent: StyledText {
+ text: root.label
+ color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`]
+ }
+ }
+ }
+
+ Behavior on radius {
+ Anim {
+ duration: Appearance.anim.durations.expressiveFastSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
+ }
+ }
+
+ Behavior on Layout.preferredWidth {
+ Anim {
+ duration: Appearance.anim.durations.expressiveFastSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
+ }
+ }
+
+ // Tooltip - positioned absolutely, doesn't affect layout
+ Loader {
+ id: tooltipLoader
+ active: root.tooltip !== ""
+ asynchronous: true
+ z: 10000
+ width: 0
+ height: 0
+ sourceComponent: Component {
+ Tooltip {
+ target: root
+ text: root.tooltip
+ }
+ }
+ // Completely remove from layout
+ Layout.fillWidth: false
+ Layout.fillHeight: false
+ Layout.preferredWidth: 0
+ Layout.preferredHeight: 0
+ Layout.maximumWidth: 0
+ Layout.maximumHeight: 0
+ Layout.minimumWidth: 0
+ Layout.minimumHeight: 0
+ }
+}
+