1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial |
3 | |
4 | // cSpell: ignore Heade |
5 | |
6 | import { Button, ComboBox, ListView, ScrollView, VerticalBox } from "std-widgets.slint" ; |
7 | import { ComponentList, ComponentListItem } from "component-list.slint" ; |
8 | import { DrawArea, DrawAreaMode, Selection } from "draw-area.slint" ; |
9 | import { HeaderBar } from "header-bar.slint" ; |
10 | import { Diagnostics, DiagnosticsOverlay } from "diagnostics-overlay.slint" ; |
11 | |
12 | export { Diagnostics } |
13 | |
14 | export component PreviewUi inherits Window { |
15 | in property <[ComponentListItem]> known-components; |
16 | in property <[Diagnostics]> diagnostics; |
17 | in property <[Selection]> selections; |
18 | in property <[string]> known-styles; |
19 | in property <bool> experimental: false; |
20 | in property <bool> show-preview-ui: true; |
21 | in property <component-factory> preview-area; |
22 | in property <string> status-text; |
23 | in-out property <string> current-style; |
24 | out property <bool> design-mode; |
25 | |
26 | pure callback can-drop(/* component_type */ string, /* x */ length, /* y */ length) -> bool; |
27 | callback drop(/* component_type */ string, /* x */ length, /* y */ length); |
28 | callback selected-element-update-geometry(/* x */ length, /* y */ length, /* width */ length, /* height */ length); |
29 | callback selected-element-delete(); |
30 | callback select-at(/* x */ length, /* y */ length, /* enter_component? */ bool); |
31 | callback select-behind(/* x */ length, /* y */ length, /* enter_component* */ bool, /* reverse */ bool); |
32 | callback show-document(/* url */ string, /* line */ int, /* column */ int); |
33 | callback style-changed(); |
34 | callback reselect(); |
35 | callback unselect(); |
36 | |
37 | property <length> border: 20px; |
38 | property <length> side-bar-width: 200px; |
39 | |
40 | title: "Slint Live-Preview" ; |
41 | icon: @image-url("assets/slint-logo-small-light.png" ); |
42 | |
43 | VerticalLayout { |
44 | if (!show-preview-ui): no-ui-drawing-rect := Rectangle { |
45 | VerticalLayout { |
46 | ComponentContainer { |
47 | component-factory <=> root.preview-area; |
48 | } |
49 | } |
50 | |
51 | // Diagnostics overlay: |
52 | DiagnosticsOverlay { |
53 | width: 100%; |
54 | height: 100%; |
55 | diagnostics <=> root.diagnostics; |
56 | show-document(url, line, column) => { |
57 | root.show-document(url, line, column); |
58 | } |
59 | } |
60 | } |
61 | if (show-preview-ui): Rectangle { |
62 | VerticalLayout { |
63 | HeaderBar { |
64 | vertical-stretch: 0.0; |
65 | |
66 | height: self.preferred-height; |
67 | |
68 | pick-button := Button { |
69 | text: @tr("Design Mode" ); |
70 | checkable: true; |
71 | checked <=> root.design-mode; |
72 | clicked() => { |
73 | key-handler.focus(); |
74 | } |
75 | } |
76 | |
77 | Text { |
78 | text: @tr("Style:" ); |
79 | vertical-alignment: center; |
80 | } |
81 | |
82 | style-select := ComboBox { |
83 | model: root.known-styles; |
84 | current-value <=> current-style; |
85 | selected(value) => { |
86 | root.style-changed(); |
87 | } |
88 | } |
89 | |
90 | Text { |
91 | text: root.status-text; |
92 | vertical-alignment: center; |
93 | } |
94 | } |
95 | |
96 | HorizontalLayout { |
97 | left-sidebar := Rectangle { |
98 | VerticalBox { |
99 | ComponentList { |
100 | known-components <=> root.known-components; |
101 | preview-area-position-x: draw-area.preview-area-position-x; |
102 | preview-area-position-y: draw-area.preview-area-position-y; |
103 | preview-area-width: draw-area.preview-area-width; |
104 | preview-area-height: draw-area.preview-area-height; |
105 | |
106 | can-drop(c, x, y) => { |
107 | return root.can-drop(c, x, y); |
108 | } |
109 | drop(c, x, y) => { |
110 | root.drop(c, x, y); |
111 | } |
112 | } |
113 | } |
114 | |
115 | states [ |
116 | visible when !pick-button.checked: { |
117 | width: 0px; |
118 | } |
119 | hidden when pick-button.checked: { |
120 | width: root.side-bar-width; |
121 | } |
122 | ] |
123 | } |
124 | |
125 | draw-area := DrawArea { |
126 | design-mode <=> root.design-mode; |
127 | diagnostics <=> root.diagnostics; |
128 | preview-area <=> root.preview-area; |
129 | selections <=> root.selections; |
130 | |
131 | select-at(x, y, enter_component) => { |
132 | root.select-at(x, y, enter_component); |
133 | } |
134 | selected-element-update-geometry(x, y, w, h) => { |
135 | root.selected-element-update-geometry(x, y, w, h); |
136 | } |
137 | selected-element-delete() => { |
138 | root.selected-element-delete(); |
139 | } |
140 | select-behind(x, y, stay_in_file, reverse) => { |
141 | root.select-behind(x, y, stay_in_file, reverse); |
142 | } |
143 | show-document(url, line, column) => { |
144 | root.show-document(url, line, column); |
145 | } |
146 | unselect() => { |
147 | root.unselect(); |
148 | } |
149 | reselect() => { |
150 | root.reselect(); |
151 | } |
152 | } |
153 | |
154 | preferred-width: draw-area.preferred-width + root.side-bar-width/* for left-side-bar */; |
155 | } |
156 | } |
157 | |
158 | key-handler := FocusScope { |
159 | enabled: draw-area.mode == DrawAreaMode.designing; |
160 | |
161 | key-released(event) => { |
162 | if event.text == Key.Delete { |
163 | // This `if` should not be necessary, but without it |
164 | // we do trigger deletion of Elements while errors |
165 | // are on screen. |
166 | if draw-area.mode == DrawAreaMode.designing { |
167 | root.selected-element-delete(); |
168 | } |
169 | return accept; |
170 | } |
171 | reject |
172 | } |
173 | } |
174 | } |
175 | } |
176 | } |
177 | |