feat: use button base component

This commit is contained in:
2 * r + 2 * t 2026-05-02 18:50:58 +10:00
parent 5c1158018b
commit 17281a66a5
7 changed files with 38 additions and 154 deletions

View file

@ -3,75 +3,37 @@ import Caelestia.Config
import qs.components
import qs.services
StyledRect {
ButtonBase {
id: root
enum Type {
Filled,
Tonal,
Text
}
property alias icon: label.text
property bool checked
property bool toggle
property real padding: type === IconButton.Text ? Tokens.padding.extraSmall / 2 : Tokens.padding.small
property alias font: label.fontStyle
property int type: IconButton.Filled
property bool disabled
property bool isRound
readonly property alias label: label
readonly property alias pressed: stateLayer.pressed
readonly property alias hovered: stateLayer.containsMouse
padding: type === IconButton.Text ? Tokens.padding.extraSmall / 2 : Tokens.padding.small
property alias stateLayer: stateLayer
property alias label: label
property alias radiusAnim: radiusAnim
property bool internalChecked
property color activeColour: type === IconButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
property color inactiveColour: {
if (!toggle && type === IconButton.Filled)
activeColour: type === IconButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
inactiveColour: {
if (!isToggle && type === IconButton.Filled)
return Colours.palette.m3primary;
return type === IconButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer;
}
property color activeOnColour: type === IconButton.Filled ? Colours.palette.m3onPrimary : type === IconButton.Tonal ? Colours.palette.m3onSecondary : Colours.palette.m3primary
property color inactiveOnColour: {
if (!toggle && type === IconButton.Filled)
activeOnColour: type === IconButton.Filled ? Colours.palette.m3onPrimary : type === IconButton.Tonal ? Colours.palette.m3onSecondary : Colours.palette.m3primary
inactiveOnColour: {
if (!isToggle && type === IconButton.Filled)
return Colours.palette.m3onPrimary;
return type === IconButton.Tonal ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurfaceVariant;
}
property color disabledColour: Qt.alpha(Colours.palette.m3onSurface, 0.1)
property color disabledOnColour: Qt.alpha(Colours.palette.m3onSurface, 0.38)
signal clicked
onCheckedChanged: internalChecked = checked
radius: stateLayer.pressed ? Tokens.rounding.small : internalChecked ? Tokens.rounding.medium : isRound ? implicitHeight / 2 * Math.min(1, Tokens.rounding.scale) : Tokens.rounding.large
color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour
implicitWidth: implicitHeight
implicitHeight: label.implicitHeight + padding * 2
StateLayer {
id: stateLayer
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
disabled: root.disabled
onClicked: {
if (root.toggle)
root.internalChecked = !root.internalChecked;
root.clicked();
}
}
MaterialIcon {
id: label
anchors.centerIn: parent
color: root.disabled ? root.disabledOnColour : root.internalChecked ? root.activeOnColour : root.inactiveOnColour
fill: !root.toggle || root.internalChecked ? 1 : 0
color: root.onColour
fontStyle: root.font
fill: !root.isToggle || root.internalChecked ? 1 : 0
Behavior on fill {
Anim {
@ -79,12 +41,4 @@ StyledRect {
}
}
}
Behavior on radius {
Anim {
id: radiusAnim
type: Anim.DefaultEffects
}
}
}

View file

@ -4,55 +4,23 @@ import Caelestia.Config
import qs.components
import qs.services
StyledRect {
ButtonBase {
id: root
enum Type {
Filled,
Tonal,
Text
}
property alias icon: iconLabel.text
property alias text: label.text
property bool checked
property bool toggle
property real horizontalPadding: Tokens.padding.medium
property real verticalPadding: Tokens.padding.small
property alias font: label.font
property int type: IconTextButton.Filled
property alias stateLayer: stateLayer
property alias iconLabel: iconLabel
property alias label: label
readonly property alias iconLabel: iconLabel
readonly property alias label: label
property bool internalChecked
property color activeColour: type === IconTextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
property color inactiveColour: type === IconTextButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer
property color activeOnColour: type === IconTextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary
property color inactiveOnColour: type === IconTextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer
signal clicked
onCheckedChanged: internalChecked = checked
radius: internalChecked ? Tokens.rounding.medium : implicitHeight / 2 * Math.min(1, Tokens.rounding.scale)
color: type === IconTextButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour
activeColour: type === IconTextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
inactiveColour: type === IconTextButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer
activeOnColour: type === IconTextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary
inactiveOnColour: type === IconTextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer
implicitWidth: row.implicitWidth + horizontalPadding * 2
implicitHeight: row.implicitHeight + verticalPadding * 2
StateLayer {
id: stateLayer
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
onClicked: {
if (root.toggle)
root.internalChecked = !root.internalChecked;
root.clicked();
}
}
RowLayout {
id: row
@ -64,7 +32,7 @@ StyledRect {
Layout.alignment: Qt.AlignVCenter
Layout.topMargin: Math.round(fontInfo.pointSize * 0.0575)
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
color: root.onColour
fill: root.internalChecked ? 1 : 0
Behavior on fill {
@ -79,11 +47,7 @@ StyledRect {
Layout.alignment: Qt.AlignVCenter
Layout.topMargin: -Math.round(iconLabel.fontInfo.pointSize * 0.0575)
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
color: root.onColour
}
}
Behavior on radius {
Anim {}
}
}

View file

@ -3,75 +3,41 @@ import Caelestia.Config
import qs.components
import qs.services
StyledRect {
ButtonBase {
id: root
enum Type {
Filled,
Tonal,
Text
}
property alias text: label.text
property bool checked
property bool toggle
property real horizontalPadding: Tokens.padding.medium
property real verticalPadding: Tokens.padding.small
property alias font: label.font
property int type: TextButton.Filled
readonly property alias label: label
property alias stateLayer: stateLayer
property alias label: label
horizontalPadding: Tokens.padding.medium
verticalPadding: Tokens.padding.small
property bool internalChecked
property color activeColour: type === TextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
property color inactiveColour: {
if (!toggle && type === TextButton.Filled)
activeColour: type === TextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
inactiveColour: {
if (!isToggle && type === TextButton.Filled)
return Colours.palette.m3primary;
return type === TextButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer;
}
property color activeOnColour: {
activeOnColour: {
if (type === TextButton.Text)
return Colours.palette.m3primary;
return type === TextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary;
}
property color inactiveOnColour: {
if (!toggle && type === TextButton.Filled)
inactiveOnColour: {
if (!isToggle && type === TextButton.Filled)
return Colours.palette.m3onPrimary;
if (type === TextButton.Text)
return Colours.palette.m3primary;
return type === TextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer;
}
signal clicked
onCheckedChanged: internalChecked = checked
radius: internalChecked ? Tokens.rounding.medium : implicitHeight / 2 * Math.min(1, Tokens.rounding.scale)
color: type === TextButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour
implicitWidth: label.implicitWidth + horizontalPadding * 2
implicitHeight: label.implicitHeight + verticalPadding * 2
StateLayer {
id: stateLayer
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
onClicked: {
if (root.toggle)
root.internalChecked = !root.internalChecked;
root.clicked();
}
}
StyledText {
id: label
anchors.centerIn: parent
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
}
Behavior on radius {
Anim {}
color: root.onColour
}
}

View file

@ -63,7 +63,7 @@ StyledRect {
Layout.fillWidth: true
text: modelData.label
checked: _checked
toggle: false
isToggle: false
type: TextButton.Tonal
// Create binding in Component.onCompleted

View file

@ -266,7 +266,7 @@ Item {
PlayerControl {
icon: Players.active?.isPlaying ? "pause" : "play_arrow"
label.animate: true
toggle: true
isToggle: true
padding: Tokens.padding.extraSmall / 2
checked: Players.active?.isPlaying ?? false
font: Tokens.font.icon.builders.large.scale(1.5).build()

View file

@ -256,7 +256,7 @@ StyledRect {
IconButton {
label.animate: true
icon: Recorder.paused ? "play_arrow" : "pause"
toggle: true
isToggle: true
checked: Recorder.paused
type: IconButton.Tonal
font: Tokens.font.icon.large

View file

@ -114,7 +114,7 @@ StyledRect {
delegate: Toggle {
icon: "settings"
inactiveOnColour: Colours.palette.m3onSurfaceVariant
toggle: false
isToggle: false
onClicked: {
root.visibilities.utilities = false;
root.popouts.detach("network");
@ -143,7 +143,7 @@ StyledRect {
icon: "vpn_key"
checked: VPN.connected && VPN.status.state !== "needs-auth" && VPN.status.state !== "error"
enabled: !VPN.connecting
toggle: VPN.status.state !== "needs-auth" && VPN.status.state !== "error"
isToggle: VPN.status.state !== "needs-auth" && VPN.status.state !== "error"
inactiveOnColour: Colours.palette.m3onSurfaceVariant
onClicked: VPN.toggle()
}
@ -157,7 +157,7 @@ StyledRect {
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? Tokens.padding.large : internalChecked ? Tokens.padding.small : 0)
radius: stateLayer.pressed ? Tokens.rounding.medium / 2 : internalChecked ? Tokens.rounding.medium : Tokens.rounding.large
inactiveColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
toggle: true
isToggle: true
radiusAnim.duration: Tokens.anim.durations.expressiveFastSpatial
radiusAnim.easing: Tokens.anim.expressiveFastSpatial