Files
metabuilder/qml/components/form/CSwitch.qml
johndoe6345789 5456f7eb4c feat(a11y): add Accessible roles, names, objectNames to all core QML components
Core: CButton, CIconButton, CFab, CChip, CListItem — Button roles, activeFocusOnTab
Forms: CTextField, CSelect, CCheckbox, CSwitch, CRadio, CRating — EditableText, CheckBox, ComboBox, Slider
Feedback: CAlert, CDialog, CSnackbar — AlertMessage, Dialog roles
Navigation: CTabBar — PageTabList + PageTab on delegates
Data: CAvatar, CBadge, CTable, CStatBadge, CStatusBadge — Graphic, StaticText, Table, Row
Surfaces: CCard (Pane), CAccordionItem (Button + expanded), CAppBar (ToolBar)
Progress: CProgress (ProgressBar + value), CSpinner (Animation)
Divider: CDivider (Separator)

28 files, 157 lines of a11y properties added. Zero to full coverage on core library.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:00:55 +00:00

180 lines
5.2 KiB
QML

import QtQuick
import QtQuick.Controls
import QmlComponents 1.0
/**
* CSwitch.qml - MD3 styled toggle switch
*
* MD3 spec: 52x32 pill track, 24px thumb
* (28px when pressed), animated slide and
* color transitions.
*/
Rectangle {
id: root
property bool checked: false
property alias text: label.text
property bool enabled: true
// Accessibility
Accessible.role: Accessible.CheckBox
Accessible.name: text
Accessible.checked: checked
activeFocusOnTab: true
objectName: "switch_"
+ text.toLowerCase().replace(/ /g, "_")
signal toggled(bool checked)
width: row.implicitWidth
height: 40
color: "transparent"
Row {
id: row
spacing: StyleVariables.spacingSm
anchors.verticalCenter: parent.verticalCenter
// Track + thumb container
Item {
width: 52; height: 32
anchors.verticalCenter:
parent.verticalCenter
// Track
Rectangle {
id: track
anchors.fill: parent
radius: 16
color: root.checked
? Theme.primary
: Theme.surface
border.color: root.checked
? "transparent"
: Theme.border
border.width: root.checked ? 0 : 2
opacity: root.enabled ? 1.0 : 0.38
Behavior on color {
ColorAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
Behavior on border.color {
ColorAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
// Thumb
Rectangle {
id: thumb
property int thumbSize:
mouseArea.pressed ? 28 : 24
width: thumbSize
height: thumbSize
radius: thumbSize / 2
color: root.checked
? "#ffffff" : Theme.border
y: (parent.height - height) / 2
x: root.checked
? (parent.width - width - 4)
: 4
opacity: root.enabled ? 1.0 : 0.38
// Elevation shadow for thumb
layer.enabled: true
layer.effect: null
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
Behavior on width {
NumberAnimation {
duration: 100
easing.type: Easing.OutCubic
}
}
Behavior on height {
NumberAnimation {
duration: 100
easing.type: Easing.OutCubic
}
}
Behavior on color {
ColorAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
// Hover state circle around thumb
Rectangle {
id: hoverIndicator
width: 40; height: 40
radius: 20
color: root.checked
? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b, 0.08)
: Qt.rgba(
Theme.text.r,
Theme.text.g,
Theme.text.b, 0.08)
opacity: mouseArea.containsMouse
|| mouseArea.pressed ? 1 : 0
x: thumb.x
+ (thumb.width / 2)
- (width / 2)
y: thumb.y
+ (thumb.height / 2)
- (height / 2)
Behavior on opacity {
NumberAnimation { duration: 150 }
}
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
enabled: root.enabled
cursorShape: Qt.PointingHandCursor
onClicked: {
root.checked = !root.checked;
root.toggled(root.checked);
}
}
}
Text {
id: label
text: ""
color: root.enabled
? Theme.text
: Theme.textDisabled
font.pixelSize:
StyleVariables.fontSizeSm
font.family: Theme.fontFamily
anchors.verticalCenter:
parent.verticalCenter
visible: text.length > 0
}
}
}