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