1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4import { FluentFontSettings, FluentPalette, Icons } from "styling.slint";
5import { FocusBorder } from "components.slint";
6
7export component CheckBox {
8 in property <string> text;
9 in property <bool> enabled <=> touch-area.enabled;
10 out property <bool> has-focus: focus-scope.has-focus;
11 in-out property <bool> checked;
12
13 callback toggled;
14
15 private property <color> text-color: FluentPalette.foreground;
16
17 min-height: max(18px, layout.min-height);
18 accessible-checkable: true;
19 accessible-enabled: root.enabled;
20 accessible-label: root.text;
21 accessible-checked <=> root.checked;
22 accessible-role: checkbox;
23 accessible-action-default => {
24 root.checked = !root.checked;
25 root.toggled();
26 }
27 forward-focus: focus-scope;
28
29 states [
30 disabled when !root.enabled : {
31 border.border-color: FluentPalette.control-strong-stroke-disabled;
32 background.background: root.checked ? FluentPalette.accent-disabled : FluentPalette.control-alt-disabled;
33 icon.colorize: FluentPalette.text-accent-foreground-disabled;
34 root.text-color: FluentPalette.text-disabled;
35 }
36 pressed when touch-area.pressed : {
37 border.border-color: FluentPalette.control-strong-stroke-disabled;
38 background.background: root.checked ? FluentPalette.tertiary-accent-background : FluentPalette.control-alt-quartiary;
39 icon.colorize: FluentPalette.text-accent-foreground-secondary;
40 }
41 hover when touch-area.has-hover : {
42 background.background: root.checked ? FluentPalette.secondary-accent-background : FluentPalette.control-alt-tertiary;
43 }
44 checked when root.checked && root.enabled : {
45 background.background: FluentPalette.accent-background;
46 }
47 ]
48
49 animate text-color { duration: 200ms; }
50
51 layout := HorizontalLayout {
52 spacing: 12px;
53
54 background := Rectangle {
55 width: 18px;
56 height: self.width;
57 y: (parent.height - self.height) / 2;
58 background: FluentPalette.control-alt-secondary;
59 border-radius: 2px;
60
61 animate background, border-color { duration: 150ms; }
62
63 border := Rectangle {
64 border-color: FluentPalette.control-strong-stroke;
65 border-width: root.checked ? 0 : 1px;
66 border-radius: parent.border-radius;
67 }
68
69 icon := Image {
70 image-fit: contain;
71 visible: root.checked;
72 source: Icons.check-mark;
73 colorize: FluentPalette.accent-foreground;
74 width: 12px;
75 accessible-role: none;
76
77 animate colorize { duration: 150ms; }
78 }
79 }
80
81 if root.text != "" : Text {
82 text: root.text;
83 color: root.text-color;
84 font-size: FluentFontSettings.body.font-size;
85 font-weight: FluentFontSettings.body.font-weight;
86 vertical-alignment: center;
87 horizontal-alignment: left;
88 }
89 }
90
91 touch-area := TouchArea {
92 clicked => {
93 if (root.enabled) {
94 root.checked = !root.checked;
95 root.toggled();
96 }
97 }
98 }
99
100 focus-scope := FocusScope {
101 x: 0;
102 width: 0; // Do not react on clicks
103 enabled <=> root.enabled;
104
105 key-pressed(event) => {
106 if (event.text == " " || event.text == "\n") {
107 touch-area.clicked();
108 return accept;
109 }
110 return reject;
111 }
112 }
113
114 // focus border
115 if root.has-focus && root.enabled : FocusBorder {
116 border-radius: 4px;
117 }
118}
119