1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3
4struct ButtonColors {
5 base: color,
6 pressed: color,
7 hovered: color,
8}
9
10export global DemoPalette {
11 // Color of the home/settings/ink buttons on the left side bar
12 out property <color> active-page-icon-color: root.night-mode ? #6284FF : #122F7B;
13 out property <color> inactive-page-icon-color: #BDC0D1;
14 out property <color> main-background: #0E133F;
15 out property <color> neutral-box: #BDC0D1;
16 out property <color> page-background-color: root.night-mode ? #122F7B : white;
17 out property <color> text-foreground-color: root.night-mode ? #F4F6FF : black;
18 out property <color> secondary-foreground-color: root.night-mode ? #C1C3CA : #6C6E7A;
19 out property <color> printer-action-background-color: root.night-mode ? root.main-background : white;
20 out property <color> printer-queue-item-background-color: root.page-background-color;
21 out property <color> status-label-text-color: root.night-mode ? #F1FF98 : #6284FF;
22
23 // Color used for the border / outline of items that can be clicked on, such as the
24 // "Print"/"Scan" buttons, the printer queue items (for expansion) or controls such
25 // as the combo box or spin box.
26 out property <color> control-outline-color: #FFBF63;
27 out property <color> control-secondary: #6284FF;
28 out property <color> control-foreground: root.night-mode ? white : #122F7B; // FIXME: the night mode color was not part of the design
29 out property <color> primary-push-button-base: #6284FF;
30 out property <ButtonColors> primary-push-button-colors: {
31 base: root.primary-push-button-base,
32 pressed: root.primary-push-button-base.darker(40%),
33 hovered: root.primary-push-button-base.darker(20%),
34 };
35 out property <color> secondary-push-button-base: #FFBF63;
36 out property <ButtonColors> secondary-push-button-colors: {
37 base: root.secondary-push-button-base,
38 pressed: root.secondary-push-button-base.darker(40%),
39 hovered: root.secondary-push-button-base.darker(20%),
40 };
41 out property <color> push-button-text-color: white;
42 out property <length> base-font-size: 12px;
43 in-out property <bool> night-mode: false;
44}
45
46export component Page inherits Rectangle {
47 in property <string> header <=> h.text;
48 in property <bool> has-back-button: false;
49
50 callback back;
51
52 background: DemoPalette.page-background-color;
53
54 TouchArea {} // protect underneath controls
55
56 if (root.has-back-button) : Image {
57 source: @image-url("images/back.svg");
58 image-fit: contain;
59 colorize: DemoPalette.control-secondary;
60 y: h.y + (h.height - self.height) / 2;
61 x: 5px;
62 width: 14px;
63 height: 24px;
64
65 TouchArea {
66 pointer-event(ev) => {
67 if (ev.kind == PointerEventKind.up) {
68 root.back()
69 }
70 }
71 width: 400%;
72 height: 200%;
73 x: (parent.width - self.width) / 2;
74 y: (parent.height - self.height) / 2;
75 }
76 }
77
78 h := Text {
79 font-weight: 900;
80 font-size: DemoPalette.base-font-size * 1.75;
81 color: DemoPalette.text-foreground-color;
82 y: 23px - self.font-size;
83 x: root.has-back-button ? 30px + 16px : 0px;
84
85 // Allow clicking on the title as well to get back easier when just
86 // using fingers on a small screen.
87 if (root.has-back-button) : TouchArea {
88 pointer-event(ev) => {
89 if (ev.kind == PointerEventKind.up) {
90 root.back()
91 }
92 }
93 }
94 }
95}
96export component Label inherits Text {
97 color: DemoPalette.text-foreground-color;
98 vertical-alignment: center;
99 font-weight: 700;
100 vertical-stretch: 0;
101}
102
103component SquareButton inherits Rectangle {
104 in property <image> img;
105
106 callback clicked;
107
108 border-radius: 3px;
109 border-width: 2px;
110 border-color: DemoPalette.control-outline-color;
111
112 touch := TouchArea {
113 pointer-event(ev) => {
114 if (ev.kind == PointerEventKind.up) {
115 root.clicked()
116 }
117 }
118
119 x: -4px;
120 y: -4px;
121 width: parent.width + 8px;
122 height: parent.height + 8px;
123 }
124
125 Image {
126 height: 12px;
127 width: 12px;
128 x: (parent.width - self.width)/2;
129 y: (parent.height - self.height)/2;
130 source <=> root.img;
131 image-fit: contain;
132 colorize: DemoPalette.control-secondary;
133 }
134}
135
136export component SpinBox inherits Rectangle {
137 in property <int> minimum;
138 in property <int> maximum: 100;
139 in-out property <int> value;
140
141 height: 32px;
142
143 HorizontalLayout {
144 spacing: 12px;
145 padding: 0;
146
147 SquareButton {
148 clicked => {
149 if (root.value > root.minimum) {
150 root.value -= 1;
151 }
152 }
153
154 width: root.height - parent.padding * 2;
155 img: @image-url("images/minus.svg");
156 }
157
158 Rectangle {
159 border-radius: 3px;
160 border-width: 2px;
161 border-color: DemoPalette.control-outline-color;
162
163 Text {
164 width: 100%;
165 height: 100%;
166 vertical-alignment: center;
167 horizontal-alignment: center;
168 text: root.value;
169 color: DemoPalette.control-foreground;
170 }
171 }
172
173 SquareButton {
174 clicked => {
175 if (root.value < root.maximum) {
176 root.value += 1;
177 }
178 }
179
180 width: root.height - parent.padding * 2;
181 img: @image-url("images/plus.svg");
182 }
183 }
184}
185
186export component ComboBox inherits Rectangle {
187 in property <[string]> choices;
188 in-out property <string> value;
189
190 border-radius: 3px;
191 border-width: 2px;
192 border-color: DemoPalette.control-outline-color;
193 height: 32px;
194 min-width: label.x + label.width + i.width;
195 horizontal-stretch: 1; // Work around #2284
196
197 label := Text {
198 vertical-alignment: center;
199 horizontal-alignment: left;
200 text <=> root.value;
201 color: DemoPalette.control-foreground;
202 height: 100%;
203 x: 12px;
204 }
205
206 i := Image {
207 source: @image-url("images/down.svg");
208 colorize: DemoPalette.control-secondary;
209 height: 40%;
210 width: self.height;
211 image-fit: contain;
212 x: parent.width - self.width - self.y;
213 y: (parent.height - self.height)/2;
214 }
215
216 TouchArea {
217 pointer-event(ev) => {
218 if (ev.kind == PointerEventKind.up) {
219 popup.show()
220 }
221 }
222
223 width: 100%;
224 height: 100%;
225 }
226
227 popup := PopupWindow {
228 x: 0;
229 y: root.height;
230 width: root.width;
231
232 Rectangle {
233 background: DemoPalette.page-background-color;
234 border-radius: 3px;
235 border-width: 2px;
236 border-color: DemoPalette.control-outline-color;
237 }
238
239 VerticalLayout {
240 spacing: 6px;
241 padding: 3px;
242
243 for value[idx] in root.choices: Rectangle {
244 border-radius: 3px;
245 background: item-area.has-hover ? DemoPalette.primary-push-button-colors.hovered : #0000;
246
247 HorizontalLayout {
248 Text {
249 text: value;
250 color: item-area.has-hover ? DemoPalette.push-button-text-color : DemoPalette.text-foreground-color;
251 font-size: DemoPalette.base-font-size;
252 }
253 }
254
255 item-area := TouchArea {
256 clicked => {
257 root.value = value;
258 }
259 }
260 }
261 }
262 }
263}
264
265export component CheckBox inherits Rectangle {
266 in property <string> text;
267 in-out property <bool> checked;
268
269 height: 32px;
270
271 HorizontalLayout {
272 spacing: 12px;
273 padding: 0;
274
275 SquareButton {
276 clicked => { root.checked = !root.checked; }
277
278 width: root.height - parent.padding * 2;
279 img: root.checked ? @image-url("images/check.svg") : @image-url("");
280 }
281
282 if root.text != "" : Text {
283 text <=> root.text;
284 vertical-alignment: center;
285 horizontal-alignment: center;
286 color: DemoPalette.control-foreground;
287 horizontal-stretch: 1;
288 }
289 }
290
291 TouchArea {
292 pointer-event(ev) => {
293 if (ev.kind == PointerEventKind.up) {
294 root.checked = !root.checked;
295 }
296 }
297 }
298}
299
300export component PushButton inherits Rectangle {
301
302 in property <string> text <=> label.text;
303 in property <image> icon <=> img.source;
304 in property <bool> primary: true;
305 out property <bool> pressed: touch-area.pressed;
306 out property <ButtonColors> colors: root.primary ? DemoPalette.primary-push-button-colors : DemoPalette.secondary-push-button-colors;
307
308 callback clicked;
309
310 border-radius: 13.5px;
311 background: root.pressed ? root.colors.pressed : (touch-area.has-hover ? root.colors.hovered : root.colors.base);
312 horizontal-stretch: 1;
313
314 HorizontalLayout {
315 padding-top: 5px;
316 padding-bottom: 5px;
317 padding-left: parent.border-radius;
318 padding-right: parent.border-radius;
319
320 img := Image {
321 horizontal-stretch: 0;
322 colorize: DemoPalette.push-button-text-color;
323 image-fit: contain;
324 width: 17px;
325 }
326
327 label := Text {
328 font-weight: 900;
329 font-size: DemoPalette.base-font-size * 0.975;
330 color: DemoPalette.push-button-text-color;
331 horizontal-alignment: center;
332 vertical-alignment: center;
333 }
334 }
335
336 touch-area := TouchArea {
337 pointer-event(ev) => {
338 if (ev.kind == PointerEventKind.up) {
339 root.clicked()
340 }
341 }
342 }
343}
344