1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//! Off-UI-thread native file pickers -- the ONE place `rfd::FileDialog` is ever
//! constructed anywhere in this app, so no picker dialog ever blocks the UI
//! thread.
//!
//! Generalizes `gui::editor::native_io`'s own `pick_file`/`PickKind`
//! (that module moved its own dialogs off the UI thread, but left every other
//! module's `rfd` call untouched -- see this module's own handoff note) into
//! one shared worker every picker in the app goes through:
//! [`pick`] shows [`PickerRequest`]'s dialog on a background thread (never the
//! UI thread) and delivers the result to a continuation on the UI thread via
//! `Weak::upgrade_in_event_loop`, plus a `#[cfg(test)]` hook
//! ([`set_test_pick_answer`]) so a test can inject a chosen path (or a
//! cancellation) with no real OS dialog and no spawned thread.
//!
//! # Why a request enum/struct, not a caller-supplied `rfd::FileDialog` builder
//!
//! A closure like `impl FnOnce() -> rfd::FileDialog` would still need `rfd::`
//! written out at every call site to build one, defeating the point of having
//! a single construction site to grep for. Every
//! picker's own shape (open/save/folder, filters, starting directory, default
//! file name) is instead plain data ([`PickerRequest`]), and only [`pick`]
//! itself (via the private [`build_dialog`]) ever turns that into a real
//! `rfd::FileDialog`.
//!
//! # `gui::editor::native_io`
//!
//! That module's own `pick_file`/`PickKind` are kept (not removed) as a thin
//! wrapper over [`pick`]/[`PickerRequest`] -- see that module's own doc
//! comment on `pick_file` for why: five call sites there already build a
//! `PickKind` value and thread a continuation through it, and none of that
//! shape needs to change now that the picker itself lives here instead.
//!
//! # Every `rfd`-using dialog in this app goes through here
//!
//! `gui::render::camera_lighting::setup_environment_map_callbacks`'s
//! `on_pick_hdr_file` and `gui::remote::worker_callbacks::setup_cert_dir_picker_callback`'s
//! `on_pick_cert_dir` are the two dialogs whose own Slint callback signature had
//! to change to reach this module: both were Slint callbacks that
//! RETURNED their result directly into a property assignment
//! (`root.env_map_path = root.pick_hdr_file(root.env_map_path)`,
//! `root.form_cert_dir = RemoteWorkerModel.pick_cert_dir(root.form_cert_dir)`)
//! -- Slint has no way to await a value-returning callback, so neither could
//! move here while their own signatures stayed value-returning. Both callbacks
//! are void now (`ui/models/settings.slint`/`ui/models/remote_worker.slint`), and each
//! dialog (`settings_dialog.slint`'s `env_map_path`,
//! `remote_worker_dialog.slint`'s `form_cert_dir` via a new
//! `RemoteWorkerModel.picked_cert_dir` property and `changed` handler) is
//! filled from the completion continuation this module hands back on the UI
//! thread instead -- so both now build their `PickerRequest` and call [`pick`]
//! exactly like every other caller.
use crateMainWindow;
use ;
use ;
/// One filter row a picker offers -- a label plus the extensions (no leading
/// dot) it accepts. Mirrors `rfd::FileDialog::add_filter`'s own two
/// parameters exactly; [`build_and_show`] is the only place this is ever
/// turned into a real one.
///
/// Owned (`String`/`Vec<String>`), not `&'static str`/`&'static [&'static str]`:
/// most of this app's own filters ARE `'static` literals (a fixed extension
/// like `"asc"`), but at least one real caller
/// (`gui::library::detail::export_diagram_file_via_source`) needs a filter
/// built from a RUNTIME string (an attachment's own file extension, not known
/// until the attachment is picked) -- a `'static`-only field would force that
/// caller to leak memory (`Box::leak`) just to satisfy the type, once per
/// click, for no real benefit over an owned `String` a `PickerRequest` already
/// gets dropped after one use anyway.
pub
/// Which native dialog [`pick`] should show.
pub
/// Everything one native dialog needs, as plain data -- every
/// `rfd::FileDialog` builder method this app's own dialogs use, named as a
/// field instead of a method call. See the module
/// doc comment for why this exists at all (not a caller-supplied
/// `rfd::FileDialog` builder closure).
pub
/// [`set_test_pick_answer`]'s own stashed answer -- a one-field wrapper around
/// `Option<PathBuf>` (the picker's own "cancelled or picked" result) purely so
/// the OUTER "is a test answer stashed at all" state can be a single-level
/// `Option`, not `Option<Option<PathBuf>>` (`clippy::option_option`) -- the
/// same shape `gui::editor::native_io::TestPickAnswer` uses.
;
/// A stashed [`pick`] continuation -- named purely to keep [`PENDING_PICKS`]'s
/// own type under clippy's `type_complexity` lint.
type PickContinuation = ;
thread_local!
/// Test-only: see [`TEST_PICK_ANSWER`]'s own doc comment.
pub
/// Pure precedence check, split out of [`pick`] purely so a test can exercise
/// the hook without a live `MainWindow`: `Some` (consuming the stashed answer)
/// when a test has stubbed one, `None` otherwise (the ordinary "show a real
/// picker" path).
/// Turns a [`PickerRequest`] into a real `rfd::FileDialog` and shows it,
/// returning the chosen path (`None` on cancel/dismiss) -- the ONLY function
/// in this app that constructs one. Always called from a background thread
/// (see [`pick`]), never the UI thread.
/// The one entry point every native file/folder picker in this app uses: shows
/// `request`'s dialog on a background thread (never the UI thread) and
/// delivers the result (`None` on cancel/dismiss) to `on_done` on the UI
/// thread via `Weak::upgrade_in_event_loop`. The caller's own state must never
/// be borrowed across a call to this function -- pick first, then borrow,
/// never the other way around (the same discipline `gui::editor::native_io`'s
/// own former `pick_file` doc comment already established). `on_done` silently
/// never runs if the window closed while the picker was open, the same
/// convention every worker in this crate follows.
pub