slint/internal/compiler/widgets/fluent/switch.slint
Olivier Goffart 2f57a4df35 Switch: ensure that the min-width contains the text
Currently, the min-with don't account for the text.
That means that, for example, the switch on the top bar of the gallery,
get the text to overflow which doesn't look good by default
2025-08-22 16:18:46 +02:00

137 lines
4.6 KiB
Text

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { FluentFontSettings, FluentPalette } from "styling.slint";
import { FocusBorder } from "components.slint";
export component Switch {
in property <bool> enabled: true;
in property <string> text;
in-out property <bool> checked;
out property <bool> has-focus: focus-scope.has-focus;
callback toggled;
private property <color> text-color: FluentPalette.foreground;
function toggle-checked() {
if(!root.enabled) {
return;
}
root.checked = !root.checked;
root.toggled();
}
min-width: max(40px, layout.min-width);
min-height: max(20px, layout.min-height);
vertical-stretch: 0;
horizontal-stretch: 0;
accessible-enabled: root.enabled;
accessible-label: root.text;
accessible-checkable: true;
accessible-checked <=> root.checked;
accessible-role: switch;
accessible-action-default => {
root.checked = !root.checked;
root.toggled();
}
forward-focus: focus-scope;
states [
disabled when !root.enabled : {
rail.background: root.checked ? FluentPalette.accent-disabled : transparent;
rail.border-color: FluentPalette.control-strong-stroke-disabled;
thumb.background: FluentPalette.text-disabled;
root.text-color: FluentPalette.text-disabled;
thumb.background: root.checked ? FluentPalette.text-accent-foreground-disabled : FluentPalette.text-secondary;
}
pressed when touch-area.pressed : {
rail.background: root.checked ? FluentPalette.tertiary-accent-background : FluentPalette.control-alt-quartiary;
thumb.width: 17px;
thumb.height: 14px;
thumb.border-width: root.checked ? 1px : 0;
thumb.background: root.checked ? FluentPalette.accent-foreground : FluentPalette.text-secondary;
}
hover when touch-area.has-hover : {
rail.background: root.checked ? FluentPalette.secondary-accent-background : FluentPalette.control-alt-tertiary;
thumb.width: 14px;
thumb.border-width: root.checked ? 1px : 0;
thumb.background: root.checked ? FluentPalette.accent-foreground : FluentPalette.text-secondary;
}
selected when root.checked : {
rail.background: FluentPalette.accent-background;
thumb.border-width: 1px;
thumb.border-color: FluentPalette.circle-border;
thumb.background: FluentPalette.accent-foreground;
}
]
layout := HorizontalLayout {
spacing: 12px;
VerticalLayout {
alignment: center;
Rectangle {
width: 40px;
height: 20px;
rail := Rectangle {
border-radius: 10px;
border-width: root.checked ? 0 : 1px;
border-color: FluentPalette.control-strong-stroke;
background: FluentPalette.control-alt-secondary;
}
thumb := Rectangle {
x: root.checked ? parent.width - self.width - 4px : 4px;
y: (parent.height - self.height) / 2;
width: 12px;
height: self.width;
border-radius: self.height / 2;
background: FluentPalette.text-secondary;
border-color: FluentPalette.circle-border;
animate background, width { duration: 150ms; easing: linear; }
}
// focus border
if root.has-focus && root.enabled : FocusBorder {
border-radius: rail.border-radius;
}
}
}
if (root.text != "") : Text {
text: root.text;
color: root.text-color;
font-size: FluentFontSettings.body.font-size;
font-weight: FluentFontSettings.body.font-weight;
vertical-alignment: center;
horizontal-alignment: left;
}
}
touch-area := TouchArea {
enabled <=> root.enabled;
clicked => {
root.toggle-checked();
}
}
focus-scope := FocusScope {
x:0;
width: 0px; // Do not react on clicks
enabled <=> root.enabled;
key-pressed(event) => {
if (event.text == " " || event.text == "\n") {
root.toggle-checked();
return accept;
}
return reject;
}
}
}