1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: MIT |
3 | |
4 | import { DemoPalette, PushButton } from "./common.slint" ; |
5 | |
6 | enum JobStatus { |
7 | Waiting, |
8 | Printing |
9 | } |
10 | |
11 | export struct PrinterQueueItem { |
12 | status: JobStatus, |
13 | progress: int, |
14 | title: string, |
15 | owner: string, |
16 | pages: int, |
17 | size: string, // number instead and format in .slint? |
18 | submission-date: string |
19 | } |
20 | |
21 | export global PrinterQueue { |
22 | in property <[PrinterQueueItem]> printer-queue: [ |
23 | { status: JobStatus.Printing, progress: 63, title: "Slint-Demo.jpeg" , owner: "info@slint.dev" , pages: 6, size: "143kb" , submission-date: "11:41 25/01/21" }, |
24 | { status: JobStatus.Waiting, title: "Adressliste.docx" , owner: "info@slint.dev" , pages: 6, size: "143kb" , submission-date: "11:41 25/01/21" }, |
25 | { status: JobStatus.Waiting, title: "210106-FinalPresentation.pdf" , owner: "info@slint.dev" , pages: 6, size: "143kb" , submission-date: "11:41 25/01/21" }, |
26 | ]; |
27 | |
28 | callback start-job(string); |
29 | callback cancel-job(int); |
30 | callback pause-job(int); |
31 | |
32 | public pure function statusString(status: JobStatus) -> string { |
33 | if (status == JobStatus.Printing) { |
34 | "PRINTING" |
35 | } else if (status == JobStatus.Waiting) { |
36 | "WAITING..." |
37 | } else { |
38 | "Unknown job status" |
39 | } |
40 | } |
41 | } |
42 | |
43 | component PrintQueueDetailsLabel inherits Text { |
44 | font-weight: 500; |
45 | color: DemoPalette.control-foreground; |
46 | horizontal-stretch: 0; |
47 | font-size: DemoPalette.base-font-size * 0.9375; |
48 | } |
49 | |
50 | component PrintQueueSeparator inherits Rectangle { |
51 | height: 1px; |
52 | border-width: 1px; |
53 | border-color: #BDC0D1; |
54 | horizontal-stretch: 2; |
55 | } |
56 | |
57 | component PrintDetails inherits GridLayout { |
58 | in property <PrinterQueueItem> queue-item; |
59 | |
60 | spacing: 3px; |
61 | |
62 | Row { |
63 | PrintQueueDetailsLabel { |
64 | text: "Owner" ; |
65 | } |
66 | |
67 | Text { |
68 | text: root.queue-item.owner; |
69 | color: DemoPalette.secondary-foreground-color; |
70 | overflow: elide; |
71 | horizontal-stretch: 1; |
72 | font-size: DemoPalette.base-font-size * 0.9375; |
73 | } |
74 | } |
75 | |
76 | Row { |
77 | PrintQueueSeparator { |
78 | colspan: 2; |
79 | } |
80 | } |
81 | |
82 | Row { |
83 | PrintQueueDetailsLabel { |
84 | text: "Pages" ; |
85 | } |
86 | |
87 | Text { |
88 | text: root.queue-item.pages; |
89 | color: DemoPalette.secondary-foreground-color; |
90 | overflow: elide; |
91 | horizontal-stretch: 1; |
92 | font-size: DemoPalette.base-font-size * 0.9375; |
93 | } |
94 | } |
95 | |
96 | Row { |
97 | PrintQueueSeparator { |
98 | colspan: 2; |
99 | } |
100 | } |
101 | |
102 | Row { |
103 | PrintQueueDetailsLabel { |
104 | text: "Size" ; |
105 | } |
106 | |
107 | Text { |
108 | text: root.queue-item.pages; |
109 | color: DemoPalette.secondary-foreground-color; |
110 | overflow: elide; |
111 | horizontal-stretch: 1; |
112 | font-size: DemoPalette.base-font-size * 0.9375; |
113 | } |
114 | } |
115 | |
116 | Row { |
117 | PrintQueueSeparator { |
118 | colspan: 2; |
119 | } |
120 | } |
121 | |
122 | Row { |
123 | PrintQueueDetailsLabel { |
124 | text: "Submitted" ; |
125 | } |
126 | |
127 | Text { |
128 | text: root.queue-item.submission-date; |
129 | color: DemoPalette.secondary-foreground-color; |
130 | overflow: elide; |
131 | horizontal-stretch: 1; |
132 | font-size: DemoPalette.base-font-size * 0.9375; |
133 | } |
134 | } |
135 | } |
136 | |
137 | component NarrowPrintQueueElement inherits Rectangle { |
138 | in property <PrinterQueueItem> queue-item; |
139 | in-out property <bool> expanded; |
140 | |
141 | private property <float> expanded-opacity: 0; |
142 | |
143 | callback cancel-job(); |
144 | |
145 | border-color: DemoPalette.control-outline-color; |
146 | border-radius: 6px; |
147 | border-width: 1px; |
148 | background: DemoPalette.printer-queue-item-background-color; |
149 | clip: true; |
150 | height: always-visible.min-height + layout.padding * 2; |
151 | |
152 | states [ |
153 | expanded when root.expanded : { |
154 | height: layout.min-height; |
155 | expanded-opacity: 1; |
156 | in { |
157 | animate height { duration: 200ms; easing: ease; } |
158 | animate expanded-opacity { duration: 200ms; } |
159 | } |
160 | out { |
161 | animate height { duration: 200ms; easing: ease; } |
162 | animate expanded-opacity { duration: 200ms; } |
163 | } |
164 | } |
165 | ] |
166 | |
167 | TouchArea { |
168 | pointer-event(ev) => { |
169 | if (ev.kind == PointerEventKind.up) { |
170 | root.expanded = !root.expanded; |
171 | } |
172 | } |
173 | } |
174 | |
175 | Rectangle { |
176 | height: 100%; |
177 | layout := VerticalLayout { |
178 | padding: root.border-radius; |
179 | spacing: 4px; |
180 | alignment: start; |
181 | |
182 | always-visible := VerticalLayout { |
183 | padding: 0; |
184 | spacing: parent.spacing; |
185 | |
186 | Text { |
187 | // TODO: text-transform: uppercase |
188 | text: { |
189 | if (root.queue-item.status == JobStatus.Printing) { |
190 | "\{root.queue-item.progress}% - \{PrinterQueue.statusString(root.queue-item.status)}" |
191 | } else { |
192 | PrinterQueue.statusString(root.queue-item.status) |
193 | } |
194 | } |
195 | color: DemoPalette.status-label-text-color; |
196 | font-size: DemoPalette.base-font-size * 0.75; |
197 | font-weight: 800; |
198 | letter-spacing: 1.26px; |
199 | } |
200 | |
201 | Text { |
202 | text: root.queue-item.title; |
203 | overflow: elide; |
204 | color: DemoPalette.text-foreground-color; |
205 | font-weight: 800; |
206 | font-size: DemoPalette.base-font-size * 1.125; |
207 | } |
208 | } |
209 | |
210 | if (root.expanded || root.expanded-opacity > 0) : PrintDetails { |
211 | padding: 0px; |
212 | padding-bottom: root.border-radius / 2; |
213 | queue-item: root.queue-item; |
214 | opacity: root.expanded-opacity; |
215 | } |
216 | |
217 | if (root.expanded || root.expanded-opacity > 0) : HorizontalLayout { |
218 | Rectangle { |
219 | horizontal-stretch: 0; |
220 | width: 10%; |
221 | } |
222 | |
223 | PushButton { |
224 | clicked => { root.cancel-job(); } |
225 | |
226 | opacity: root.expanded-opacity; |
227 | text: "Delete" ; |
228 | icon: @image-url("images/delete.svg" ); |
229 | } |
230 | |
231 | Rectangle { |
232 | horizontal-stretch: 0; |
233 | width: 10%; |
234 | } |
235 | } |
236 | } |
237 | } |
238 | } |
239 | |
240 | component NarrowPrinterQueueList inherits Flickable { |
241 | VerticalLayout { |
242 | alignment: start; |
243 | padding: 0px; |
244 | spacing: 6px; |
245 | |
246 | for queue-item[idx] in PrinterQueue.printer-queue: NarrowPrintQueueElement { |
247 | cancel-job => { |
248 | PrinterQueue.cancel-job(idx) |
249 | } |
250 | |
251 | width: root.width; |
252 | queue-item: queue-item; |
253 | } |
254 | } |
255 | } |
256 | |
257 | export component PrinterQueueView inherits Rectangle { |
258 | border-radius: 18px; |
259 | background: DemoPalette.night-mode ? DemoPalette.printer-action-background-color : #F4F6FF; |
260 | |
261 | VerticalLayout { |
262 | padding: 6px; |
263 | spacing: 6px; |
264 | |
265 | queue-list := NarrowPrinterQueueList { } |
266 | } |
267 | } |
268 | |