1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: MIT |
3 | |
4 | import { SpinBox, Button, CheckBox, Slider, GroupBox, StandardListView } from "std-widgets.slint" ; |
5 | import { Label, Page, Preview } from "common.slint" ; |
6 | import { CopyPage } from "copy_page.slint" ; |
7 | import { FaxPage } from "fax_page.slint" ; |
8 | import { PrintPage } from "print_page.slint" ; |
9 | import { SettingsPage } from "settings_page.slint" ; |
10 | |
11 | component TopPanel inherits Rectangle { |
12 | in-out property <int> active-page: 0; |
13 | |
14 | callback quit(); |
15 | |
16 | background: white; |
17 | |
18 | HorizontalLayout { |
19 | alignment: center; |
20 | Text { |
21 | text: "PrintMachine" ; |
22 | color: root.active-page == 0 ? black : #0000; |
23 | font-size: root.width * 5%; |
24 | horizontal-alignment: center; |
25 | vertical-alignment: center; |
26 | |
27 | animate color { duration: 200ms; } |
28 | } |
29 | Text { |
30 | text: "2000" ; |
31 | color: root.active-page == 0 ? #918e8c : #0000; |
32 | font-size: root.width * 5%; |
33 | horizontal-alignment: center; |
34 | vertical-alignment: center; |
35 | |
36 | animate color { duration: 200ms; } |
37 | |
38 | } |
39 | } |
40 | power-button := Image { |
41 | x: parent.width - self.width - 20px; |
42 | y: (parent.height - self.height) / 2; |
43 | source: @image-url("images/power.svg" ); |
44 | width: 5%; |
45 | height: self.width; |
46 | |
47 | TouchArea { |
48 | clicked => { |
49 | root.quit(); |
50 | } |
51 | } |
52 | } |
53 | } |
54 | |
55 | struct InkLevel { |
56 | color: color, |
57 | level: float, |
58 | } |
59 | |
60 | export component MainWindow inherits Window { |
61 | /// Note that this property is overwritten in the .cpp and .rs code. |
62 | /// The data is only in this file so it looks good in the viewer |
63 | in-out property <[InkLevel]> ink-levels: [ |
64 | {color: #0ff, level: 60%}, |
65 | {color: #ff0, level: 80%}, |
66 | {color: #f0f, level: 70%}, |
67 | {color: #000, level: 30%}, |
68 | ]; |
69 | /// Aliased to the fax number in the fax page |
70 | in-out property <string> fax-number; |
71 | in-out property <int> active-page: 0; |
72 | |
73 | callback quit(); |
74 | callback fax-number-erase; |
75 | callback fax-send; |
76 | |
77 | /// That's just a default implementation for the viewer, but the .cpp and .rs code |
78 | /// overwrite that to erase only the last character |
79 | fax-number-erase => { root.fax-number = "" ; } |
80 | |
81 | width: 800px; |
82 | height: 600px; |
83 | title: "Slint printer demo" ; |
84 | |
85 | panel := TopPanel { |
86 | quit => { root.quit(); } |
87 | |
88 | y: 0; |
89 | active-page: root.active-page; |
90 | width: 100%; |
91 | height: 12.5%; |
92 | } |
93 | |
94 | for page-info[idx] in [ |
95 | { color: #1ac80a, text: "Copy" , img-small: @image-url("images/replicate.svg" ) }, |
96 | { color: #00c889, text: "Fax" , img-small: @image-url("images/laptop.svg" ) }, |
97 | { color: #00bbc8, text: "Print" , img-small: @image-url("images/printer.svg" ) }, |
98 | { color: #009dc8, text: "Settings" , img-small: @image-url("images/list.svg" ) }, |
99 | ] : Rectangle { |
100 | property <length> w: root.width / 5; |
101 | |
102 | width: self.w; |
103 | height: root.height / 3; |
104 | y: root.height / 4; |
105 | x: idx * (self.w + (root.width - self.w*4) / 5) + (root.width - self.w*4)/5; |
106 | border-radius: 25px; |
107 | background: page-info.color; |
108 | |
109 | animate x, y, height, width, background, border-radius { |
110 | duration: 300ms; |
111 | easing: ease-in-out; |
112 | } |
113 | |
114 | states [ |
115 | active when root.active-page == idx + 1: { |
116 | x: 0phx; |
117 | y: 0phx; |
118 | height: root.height * 12.5%; |
119 | width: root.width; |
120 | border-radius: 0px; |
121 | img.x: root.height * 12.5%; |
122 | img.width: root.height * 10%; |
123 | img.height: root.height * 10%; |
124 | text.y: 0phx; |
125 | } |
126 | pressed when root.active-page == 0 && touch.pressed : { |
127 | w: root.width / 5 + 6px; |
128 | height: root.height / 3 + 6px ; |
129 | y: root.height / 4 - 3px; |
130 | } |
131 | invisible when root.active-page > 0 && root.active-page != idx + 1 : { |
132 | color: transparent; |
133 | // FIXME: should probably hide the entire item under with z-ordering |
134 | img.y: 1000000000px; |
135 | text.color: #0000; |
136 | } |
137 | ] |
138 | |
139 | img := Image { |
140 | y: 5px; |
141 | x: (w - (root.width / 6.25)) / 2; |
142 | width: root.width / 6.25; |
143 | height: root.height / 4.68; |
144 | source: page-info.img-small; |
145 | |
146 | animate width, height, x, y { |
147 | duration: 300ms; |
148 | easing: ease-in-out; |
149 | } |
150 | } |
151 | |
152 | text := Text { |
153 | y: root.height / 10; |
154 | x: 5px; |
155 | width: 100%; |
156 | height: 100%; |
157 | horizontal-alignment: center; |
158 | vertical-alignment: center; |
159 | text: page-info.text; |
160 | font-size: 28px; |
161 | |
162 | animate x, y { |
163 | duration: 300ms; |
164 | easing: ease-in-out; |
165 | } |
166 | } |
167 | touch := TouchArea { |
168 | clicked => { |
169 | if (root.active-page == 0) { |
170 | root.active-page = idx + 1; |
171 | } |
172 | } |
173 | } |
174 | } |
175 | |
176 | if (root.active-page != 0) : Rectangle { |
177 | x:0;y:0; |
178 | width: self.height; |
179 | height: 12.5%; |
180 | |
181 | Text { |
182 | width: 100%; |
183 | height: 100%; |
184 | text: "←" ; |
185 | color: white; |
186 | font-size: root.height / 10; |
187 | horizontal-alignment: center; |
188 | vertical-alignment: center; |
189 | } |
190 | |
191 | TouchArea { |
192 | clicked => { root.active-page = 0; } |
193 | } |
194 | } |
195 | |
196 | |
197 | Rectangle { |
198 | property <bool> full-screen; |
199 | |
200 | width: root.width / 5; |
201 | height: root.height / 5; |
202 | x: root.width - self.width - 20px; |
203 | y: root.height - self.height - 20px; |
204 | background: #eee; |
205 | |
206 | states [ |
207 | full-screen when self.full-screen : { |
208 | width: root.width - 35px; |
209 | height: 7/8 * root.height - 40px ; |
210 | } |
211 | ] |
212 | animate width, height { duration: 200ms; easing: ease; } |
213 | |
214 | HorizontalLayout { |
215 | spacing: 10px; |
216 | padding: 10px; |
217 | |
218 | for color-info[idx] in root.ink-levels : Rectangle { |
219 | background: white; |
220 | |
221 | Rectangle { |
222 | width: parent.width; |
223 | height: parent.height * color-info.level; |
224 | y: parent.height - self.height; |
225 | background: color-info.color; |
226 | |
227 | states [ |
228 | inactive when root.active-page != 0 : { |
229 | height: 0phx; |
230 | out { |
231 | animate height { duration: 750ms; easing: ease-in-out; } |
232 | } |
233 | } |
234 | ] |
235 | |
236 | } |
237 | } |
238 | } |
239 | |
240 | TouchArea { |
241 | clicked => { |
242 | if (root.active-page == 0) { |
243 | parent.full-screen = !parent.full-screen; |
244 | } |
245 | } |
246 | } |
247 | } |
248 | |
249 | CopyPage { |
250 | height: root.height - root.height / 8; |
251 | width: 100%; |
252 | y: root.height; |
253 | |
254 | states [ |
255 | active when root.active-page == 1: { |
256 | y: root.height / 8; |
257 | } |
258 | ] |
259 | } |
260 | |
261 | FaxPage { |
262 | fax-number-erase => { root.fax-number-erase(); } |
263 | fax-send => { root.fax-send(); } |
264 | |
265 | height: root.height - root.height / 8; |
266 | width: 100%; |
267 | y: root.height; |
268 | fax-number <=> root.fax-number; |
269 | |
270 | states [ |
271 | active when root.active-page == 2: { |
272 | y: root.height / 8; |
273 | } |
274 | ] |
275 | } |
276 | |
277 | PrintPage { |
278 | height: root.height - root.height / 8; |
279 | width: 100%; |
280 | y: root.height; |
281 | |
282 | states [ |
283 | active when root.active-page == 3: { |
284 | y: root.height / 8; |
285 | } |
286 | ] |
287 | } |
288 | |
289 | SettingsPage { |
290 | height: root.height - root.height / 8; |
291 | width: 100%; |
292 | y: root.height; |
293 | |
294 | states [ |
295 | active when root.active-page == 4: { |
296 | y: root.height / 8; |
297 | } |
298 | ] |
299 | } |
300 | } |
301 | |