@effindomv2/fui-rs 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/COMMERCIAL.md +7 -0
  2. package/Cargo.toml +34 -0
  3. package/LICENSE.md +9 -0
  4. package/README.md +88 -0
  5. package/package.json +54 -0
  6. package/scripts/build.sh +227 -0
  7. package/scripts/check-runtime-dependency.sh +41 -0
  8. package/scripts/framework-host-services.ts +40 -0
  9. package/scripts/generate-host-events.ts +17 -0
  10. package/scripts/generate-host-services.ts +28 -0
  11. package/scripts/hostgen/common.ts +73 -0
  12. package/scripts/hostgen/registry.ts +159 -0
  13. package/scripts/hostgen/rust-host-events.ts +171 -0
  14. package/scripts/hostgen/rust-host-services.ts +257 -0
  15. package/src/animation.rs +625 -0
  16. package/src/app.rs +324 -0
  17. package/src/assets.rs +572 -0
  18. package/src/bindings/mod.rs +1 -0
  19. package/src/bindings/ui.rs +705 -0
  20. package/src/bitmap.rs +317 -0
  21. package/src/bridge_callbacks.rs +242 -0
  22. package/src/context_menu_manager.rs +332 -0
  23. package/src/controls/anti_selection_area.rs +54 -0
  24. package/src/controls/button.rs +542 -0
  25. package/src/controls/checkbox.rs +372 -0
  26. package/src/controls/combobox.rs +1574 -0
  27. package/src/controls/context_menu.rs +1367 -0
  28. package/src/controls/control_template_set.rs +46 -0
  29. package/src/controls/control_tokens.rs +596 -0
  30. package/src/controls/dialog.rs +590 -0
  31. package/src/controls/dropdown.rs +1010 -0
  32. package/src/controls/form.rs +229 -0
  33. package/src/controls/internal/button_presenter.rs +142 -0
  34. package/src/controls/internal/checkbox_indicator_presenter.rs +210 -0
  35. package/src/controls/internal/dropdown_chevron_presenter.rs +134 -0
  36. package/src/controls/internal/dropdown_field_presenter.rs +269 -0
  37. package/src/controls/internal/dropdown_option_row_presenter.rs +184 -0
  38. package/src/controls/internal/mod.rs +13 -0
  39. package/src/controls/internal/pressable_indicator_presenter.rs +26 -0
  40. package/src/controls/internal/pressable_labeled_control.rs +492 -0
  41. package/src/controls/internal/radio_indicator_presenter.rs +208 -0
  42. package/src/controls/internal/selectable_popup_list.rs +597 -0
  43. package/src/controls/internal/slider_presenter.rs +282 -0
  44. package/src/controls/internal/switch_indicator_presenter.rs +235 -0
  45. package/src/controls/internal/text_input_core.rs +1074 -0
  46. package/src/controls/internal/text_input_presenter.rs +108 -0
  47. package/src/controls/mod.rs +235 -0
  48. package/src/controls/nav_link.rs +395 -0
  49. package/src/controls/popup.rs +191 -0
  50. package/src/controls/progress_bar.rs +287 -0
  51. package/src/controls/radio_button.rs +348 -0
  52. package/src/controls/radio_group.rs +283 -0
  53. package/src/controls/selection_area.rs +82 -0
  54. package/src/controls/shared.rs +68 -0
  55. package/src/controls/slider.rs +701 -0
  56. package/src/controls/switch.rs +293 -0
  57. package/src/controls/templating.rs +49 -0
  58. package/src/controls/tests.rs +3905 -0
  59. package/src/controls/text_area.rs +207 -0
  60. package/src/controls/text_input.rs +192 -0
  61. package/src/debug.rs +146 -0
  62. package/src/drag_drop.rs +424 -0
  63. package/src/drag_gesture.rs +258 -0
  64. package/src/drawing.rs +385 -0
  65. package/src/event.rs +1603 -0
  66. package/src/external_drop.rs +467 -0
  67. package/src/fetch.rs +500 -0
  68. package/src/ffi.rs +3542 -0
  69. package/src/file.rs +1677 -0
  70. package/src/focus_adorner.rs +307 -0
  71. package/src/focus_visibility.rs +121 -0
  72. package/src/frame_scheduler.rs +159 -0
  73. package/src/frame_signal.rs +64 -0
  74. package/src/generated/ffi.rs +798 -0
  75. package/src/generated/framework_host_services.rs +74 -0
  76. package/src/generated/mod.rs +2 -0
  77. package/src/host_services.rs +162 -0
  78. package/src/image_sampling.rs +78 -0
  79. package/src/keyboard_scroll.rs +137 -0
  80. package/src/keyboard_scroll_tracker.rs +385 -0
  81. package/src/lib.rs +547 -0
  82. package/src/logger.rs +56 -0
  83. package/src/mobile_text_selection_toolbar.rs +1034 -0
  84. package/src/navigation.rs +48 -0
  85. package/src/node/core.rs +2210 -0
  86. package/src/node/custom_drawable.rs +149 -0
  87. package/src/node/flex_box.rs +874 -0
  88. package/src/node/grid.rs +304 -0
  89. package/src/node/helpers.rs +442 -0
  90. package/src/node/image.rs +506 -0
  91. package/src/node/mod.rs +315 -0
  92. package/src/node/scroll_bar.rs +845 -0
  93. package/src/node/scroll_box.rs +514 -0
  94. package/src/node/scroll_state.rs +121 -0
  95. package/src/node/scroll_view.rs +557 -0
  96. package/src/node/svg_node.rs +474 -0
  97. package/src/node/text_node.rs +633 -0
  98. package/src/node/virtual_list.rs +678 -0
  99. package/src/panic_hook.rs +36 -0
  100. package/src/persisted.rs +274 -0
  101. package/src/platform.rs +556 -0
  102. package/src/popup_presenter.rs +344 -0
  103. package/src/selection_handle_adorner.rs +838 -0
  104. package/src/signal.rs +134 -0
  105. package/src/text.rs +1065 -0
  106. package/src/theme.rs +571 -0
  107. package/src/timers.rs +106 -0
  108. package/src/tool_tip.rs +167 -0
  109. package/src/tool_tip_manager.rs +691 -0
  110. package/src/transitions.rs +41 -0
  111. package/src/typography.rs +520 -0
  112. package/src/viewport.rs +108 -0
  113. package/src/worker.rs +308 -0
  114. package/src/worker_job.rs +82 -0
  115. package/src/worker_runtime.rs +172 -0
@@ -0,0 +1,395 @@
1
+ use super::*;
2
+ use crate::bindings::ui;
3
+ use crate::event::PointerType;
4
+ use crate::ffi::{CursorStyle, HandleValue, SemanticRole};
5
+ use crate::navigation;
6
+ use crate::node::{text, NodeHandle, NodeRef, WeakFlexBox};
7
+ use crate::platform;
8
+ use crate::signal::SubscriptionGuard;
9
+ use crate::theme::{current_theme, subscribe};
10
+ use crate::{focus_adorner, focus_visibility};
11
+ use std::cell::{Cell, RefCell};
12
+ use std::rc::Rc;
13
+
14
+ thread_local! {
15
+ static ACTIVE_PREVIEW_OWNER: Cell<u64> = const { Cell::new(HandleValue::Invalid as u64) };
16
+ }
17
+
18
+ fn is_primary_activation_pointer(event: &PointerEventArgs) -> bool {
19
+ event.button == 0
20
+ || event.pointer_type == PointerType::Touch
21
+ || event.pointer_type == PointerType::Pen
22
+ }
23
+
24
+ #[derive(Clone, Debug, PartialEq, Eq)]
25
+ pub struct NavigateEventArgs {
26
+ pub path: String,
27
+ }
28
+
29
+ type NavigateCallback = Rc<dyn Fn(NavigateEventArgs)>;
30
+
31
+ #[derive(Clone)]
32
+ pub struct NavLink {
33
+ root: FlexBox,
34
+ label: TextNode,
35
+ href: Rc<RefCell<String>>,
36
+ open_in_new_tab: Rc<Cell<bool>>,
37
+ navigate: Rc<RefCell<Option<NavigateCallback>>>,
38
+ hovered: Rc<Cell<bool>>,
39
+ focused: Rc<Cell<bool>>,
40
+ pointer_pressed: Rc<Cell<bool>>,
41
+ pointer_pressed_open_in_new_tab: Rc<Cell<bool>>,
42
+ enter_pressed: Rc<Cell<bool>>,
43
+ enter_pressed_open_in_new_tab: Rc<Cell<bool>>,
44
+ preview_pinned_for_context_menu: Rc<Cell<bool>>,
45
+ theme_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
46
+ focus_visibility_guard: Rc<RefCell<Option<SubscriptionGuard>>>,
47
+ }
48
+
49
+ impl NavLink {
50
+ pub fn new(href: impl Into<String>) -> Self {
51
+ let href = href.into();
52
+ Self::with_label(href.clone(), href)
53
+ }
54
+
55
+ pub fn with_label(href: impl Into<String>, label: impl Into<String>) -> Self {
56
+ let href = href.into();
57
+ let label = label.into();
58
+ let root = row();
59
+ let label_node = text(&label);
60
+ let theme = current_theme();
61
+ label_node
62
+ .font_family(theme.fonts.body_family.clone())
63
+ .font_size(15.0)
64
+ .text_color(theme.colors.accent)
65
+ .cursor(CursorStyle::Pointer);
66
+ root.justify_content(JustifyContent::Start)
67
+ .align_items(AlignItems::Center)
68
+ .interactive(true)
69
+ .focusable(true, 0)
70
+ .cursor(CursorStyle::Pointer)
71
+ .semantic_role(SemanticRole::Link)
72
+ .semantic_label(label)
73
+ .reflect_semantic_disabled_from_enabled()
74
+ .child(&label_node);
75
+ root.retained_node_ref()
76
+ .set_link_url_for_routing(Some(href.clone()));
77
+
78
+ let link = Self {
79
+ root,
80
+ label: label_node,
81
+ href: Rc::new(RefCell::new(href)),
82
+ open_in_new_tab: Rc::new(Cell::new(false)),
83
+ navigate: Rc::new(RefCell::new(None)),
84
+ hovered: Rc::new(Cell::new(false)),
85
+ focused: Rc::new(Cell::new(false)),
86
+ pointer_pressed: Rc::new(Cell::new(false)),
87
+ pointer_pressed_open_in_new_tab: Rc::new(Cell::new(false)),
88
+ enter_pressed: Rc::new(Cell::new(false)),
89
+ enter_pressed_open_in_new_tab: Rc::new(Cell::new(false)),
90
+ preview_pinned_for_context_menu: Rc::new(Cell::new(false)),
91
+ theme_guard: Rc::new(RefCell::new(None)),
92
+ focus_visibility_guard: Rc::new(RefCell::new(None)),
93
+ };
94
+ let node_ref = link.root.retained_node_ref();
95
+ let pin_target = link.event_target();
96
+ let release_target = link.event_target();
97
+ node_ref.set_link_preview_handlers_for_routing(
98
+ Some(Rc::new(move || {
99
+ pin_target.pin_preview_for_context_menu();
100
+ })),
101
+ Some(Rc::new(move || {
102
+ release_target.release_preview_for_context_menu();
103
+ })),
104
+ );
105
+ link.install_subscriptions();
106
+ link.bind_events();
107
+ link.sync_visual_state();
108
+ link.sync_focus_chrome();
109
+ link
110
+ }
111
+
112
+ fn bind_events(&self) {
113
+ let target = self.event_target();
114
+ self.root.on_pointer_enter(move |_event| {
115
+ target.hovered.set(true);
116
+ target.sync_visual_state();
117
+ target.show_preview();
118
+ });
119
+ let target = self.event_target();
120
+ self.root.on_pointer_leave(move |_event| {
121
+ target.hovered.set(false);
122
+ target.pointer_pressed.set(false);
123
+ target.pointer_pressed_open_in_new_tab.set(false);
124
+ target.sync_visual_state();
125
+ if !target.focused.get() && !target.preview_pinned_for_context_menu.get() {
126
+ target.hide_preview();
127
+ }
128
+ });
129
+ let target = self.event_target();
130
+ self.root.on_pointer_down(move |event| {
131
+ if !is_primary_activation_pointer(event) {
132
+ target.pointer_pressed.set(false);
133
+ target.pointer_pressed_open_in_new_tab.set(false);
134
+ return;
135
+ }
136
+ target.pointer_pressed.set(true);
137
+ target
138
+ .pointer_pressed_open_in_new_tab
139
+ .set(target.should_open_in_new_tab(event.modifiers));
140
+ event.handled = true;
141
+ });
142
+ let target = self.event_target();
143
+ self.root.on_pointer_up(move |event| {
144
+ if target.pointer_pressed.replace(false) && is_primary_activation_pointer(event) {
145
+ let open_in_new_tab = target.pointer_pressed_open_in_new_tab.get()
146
+ || target.should_open_in_new_tab(event.modifiers);
147
+ target.activate(open_in_new_tab);
148
+ event.handled = true;
149
+ }
150
+ target.pointer_pressed_open_in_new_tab.set(false);
151
+ });
152
+ let target = self.event_target();
153
+ self.root.on_key_down(move |event| {
154
+ if !target.should_handle_enter_key(event.modifiers) || event.key != "Enter" {
155
+ return;
156
+ }
157
+ if target.enter_pressed.get() {
158
+ event.handled = true;
159
+ return;
160
+ }
161
+ target.enter_pressed.set(true);
162
+ target
163
+ .enter_pressed_open_in_new_tab
164
+ .set(target.should_open_in_new_tab(event.modifiers));
165
+ event.handled = true;
166
+ });
167
+ let target = self.event_target();
168
+ self.root.on_key_up(move |event| {
169
+ if !target.should_handle_enter_key(event.modifiers) || event.key != "Enter" {
170
+ return;
171
+ }
172
+ if target.enter_pressed.replace(false) {
173
+ let open_in_new_tab = target.enter_pressed_open_in_new_tab.get()
174
+ || target.should_open_in_new_tab(event.modifiers);
175
+ target.activate(open_in_new_tab);
176
+ event.handled = true;
177
+ }
178
+ target.enter_pressed_open_in_new_tab.set(false);
179
+ });
180
+ let target = self.event_target();
181
+ self.root.on_focus_changed(move |event| {
182
+ target.focused.set(event.focused);
183
+ if !event.focused {
184
+ target.enter_pressed.set(false);
185
+ target.enter_pressed_open_in_new_tab.set(false);
186
+ }
187
+ target.sync_focus_chrome();
188
+ if event.focused {
189
+ target.show_preview();
190
+ } else if !target.hovered.get() && !target.preview_pinned_for_context_menu.get() {
191
+ target.hide_preview();
192
+ }
193
+ });
194
+ }
195
+
196
+ fn install_subscriptions(&self) {
197
+ let target = self.event_target();
198
+ *self.theme_guard.borrow_mut() = Some(subscribe(move |_theme| {
199
+ target.sync_visual_state();
200
+ target.sync_focus_chrome();
201
+ }));
202
+ let target = self.event_target();
203
+ *self.focus_visibility_guard.borrow_mut() =
204
+ Some(focus_visibility::subscribe(move |_visible| {
205
+ target.sync_focus_chrome();
206
+ }));
207
+ }
208
+
209
+ fn event_target(&self) -> NavLinkEventTarget {
210
+ NavLinkEventTarget {
211
+ weak_root: self.root.downgrade(),
212
+ label: self.label.retained_node_ref(),
213
+ href: self.href.clone(),
214
+ open_in_new_tab: self.open_in_new_tab.clone(),
215
+ navigate: self.navigate.clone(),
216
+ hovered: self.hovered.clone(),
217
+ focused: self.focused.clone(),
218
+ pointer_pressed: self.pointer_pressed.clone(),
219
+ pointer_pressed_open_in_new_tab: self.pointer_pressed_open_in_new_tab.clone(),
220
+ enter_pressed: self.enter_pressed.clone(),
221
+ enter_pressed_open_in_new_tab: self.enter_pressed_open_in_new_tab.clone(),
222
+ preview_pinned_for_context_menu: self.preview_pinned_for_context_menu.clone(),
223
+ }
224
+ }
225
+
226
+ pub fn href(&self) -> String {
227
+ self.href.borrow().clone()
228
+ }
229
+
230
+ pub fn href_to(&self, href: impl Into<String>) -> &Self {
231
+ let href = href.into();
232
+ *self.href.borrow_mut() = href.clone();
233
+ self.root
234
+ .retained_node_ref()
235
+ .set_link_url_for_routing(Some(href));
236
+ if self.focused.get() || self.hovered.get() || self.preview_pinned_for_context_menu.get() {
237
+ self.event_target().show_preview();
238
+ }
239
+ self
240
+ }
241
+
242
+ pub fn text(&self, value: impl Into<String>) -> &Self {
243
+ let value = value.into();
244
+ self.label.text(value.clone());
245
+ self.root.semantic_label(value);
246
+ self
247
+ }
248
+
249
+ pub fn open_in_new_tab(&self, open: bool) -> &Self {
250
+ self.open_in_new_tab.set(open);
251
+ self
252
+ }
253
+
254
+ pub fn on_navigate(&self, handler: impl Fn(NavigateEventArgs) + 'static) -> &Self {
255
+ *self.navigate.borrow_mut() = Some(Rc::new(handler));
256
+ self
257
+ }
258
+
259
+ fn sync_visual_state(&self) {
260
+ self.event_target().sync_visual_state();
261
+ }
262
+
263
+ fn sync_focus_chrome(&self) {
264
+ self.event_target().sync_focus_chrome();
265
+ }
266
+ }
267
+
268
+ impl Node for NavLink {
269
+ fn retained_node_ref(&self) -> NodeRef {
270
+ self.root.retained_node_ref()
271
+ }
272
+
273
+ fn build_self(&self) {
274
+ self.root.build_self();
275
+ }
276
+ }
277
+
278
+ impl HasFlexBoxRoot for NavLink {
279
+ fn flex_box_root(&self) -> &FlexBox {
280
+ &self.root
281
+ }
282
+ }
283
+
284
+ #[derive(Clone)]
285
+ struct NavLinkEventTarget {
286
+ weak_root: WeakFlexBox,
287
+ label: NodeRef,
288
+ href: Rc<RefCell<String>>,
289
+ open_in_new_tab: Rc<Cell<bool>>,
290
+ navigate: Rc<RefCell<Option<NavigateCallback>>>,
291
+ hovered: Rc<Cell<bool>>,
292
+ focused: Rc<Cell<bool>>,
293
+ pointer_pressed: Rc<Cell<bool>>,
294
+ pointer_pressed_open_in_new_tab: Rc<Cell<bool>>,
295
+ enter_pressed: Rc<Cell<bool>>,
296
+ enter_pressed_open_in_new_tab: Rc<Cell<bool>>,
297
+ preview_pinned_for_context_menu: Rc<Cell<bool>>,
298
+ }
299
+
300
+ impl NavLinkEventTarget {
301
+ fn is_enabled(&self) -> bool {
302
+ self.weak_root
303
+ .upgrade()
304
+ .map(|root| root.retained_node_ref().is_enabled_for_routing())
305
+ .unwrap_or(false)
306
+ }
307
+
308
+ fn activate(&self, open_in_new_tab: bool) {
309
+ let href = self.href.borrow().clone();
310
+ navigation::navigate_to(&href, open_in_new_tab);
311
+ if let Some(callback) = self.navigate.borrow().clone() {
312
+ callback(NavigateEventArgs { path: href });
313
+ }
314
+ }
315
+
316
+ fn should_open_in_new_tab(&self, modifiers: u32) -> bool {
317
+ self.open_in_new_tab.get() || platform::has_primary_shortcut_modifier(modifiers)
318
+ }
319
+
320
+ fn should_handle_enter_key(&self, modifiers: u32) -> bool {
321
+ self.is_enabled() && (modifiers == 0 || platform::has_primary_shortcut_modifier(modifiers))
322
+ }
323
+
324
+ fn show_preview(&self) {
325
+ let Some(root) = self.weak_root.upgrade() else {
326
+ return;
327
+ };
328
+ let handle = root.handle().raw();
329
+ if handle == HandleValue::Invalid as u64 {
330
+ return;
331
+ }
332
+ let href = self.href.borrow().clone();
333
+ let bytes = href.as_bytes();
334
+ unsafe {
335
+ crate::ffi::fui_show_url_preview(
336
+ if bytes.is_empty() {
337
+ 0
338
+ } else {
339
+ bytes.as_ptr() as usize
340
+ },
341
+ bytes.len() as u32,
342
+ )
343
+ };
344
+ ACTIVE_PREVIEW_OWNER.with(|owner| owner.set(handle));
345
+ }
346
+
347
+ fn hide_preview(&self) {
348
+ let Some(root) = self.weak_root.upgrade() else {
349
+ return;
350
+ };
351
+ let handle = root.handle().raw();
352
+ if !ACTIVE_PREVIEW_OWNER.with(|owner| owner.get() == handle) {
353
+ return;
354
+ }
355
+ ACTIVE_PREVIEW_OWNER.with(|owner| owner.set(HandleValue::Invalid as u64));
356
+ unsafe { crate::ffi::fui_hide_url_preview() };
357
+ }
358
+
359
+ fn pin_preview_for_context_menu(&self) {
360
+ self.preview_pinned_for_context_menu.set(true);
361
+ self.show_preview();
362
+ }
363
+
364
+ fn release_preview_for_context_menu(&self) {
365
+ if !self.preview_pinned_for_context_menu.replace(false) {
366
+ return;
367
+ }
368
+ if !self.hovered.get() && !self.focused.get() {
369
+ self.hide_preview();
370
+ }
371
+ }
372
+
373
+ fn sync_visual_state(&self) {
374
+ let color = if self.hovered.get() {
375
+ current_theme().colors.accent_hovered
376
+ } else {
377
+ current_theme().colors.accent
378
+ };
379
+ let label = &self.label;
380
+ if label.handle() != NodeHandle::INVALID {
381
+ ui::set_text_color(label.handle().raw(), color);
382
+ }
383
+ }
384
+
385
+ fn sync_focus_chrome(&self) {
386
+ let Some(root) = self.weak_root.upgrade() else {
387
+ return;
388
+ };
389
+ if self.focused.get() && self.is_enabled() && focus_visibility::keyboard_focus_visible() {
390
+ focus_adorner::show_standard(&root, current_theme().spacing.sm);
391
+ return;
392
+ }
393
+ focus_adorner::hide_owner(&root);
394
+ }
395
+ }
@@ -0,0 +1,191 @@
1
+ use super::*;
2
+ use crate::ffi::{FlexDirection, PositionType, Unit};
3
+ use crate::node::{portal, Border, Child};
4
+ use crate::popup_presenter::{PopupPlacement, PopupPresenter};
5
+ use std::cell::Cell;
6
+
7
+ #[derive(Clone)]
8
+ pub struct Popup {
9
+ root: FlexBox,
10
+ surface_node: FlexBox,
11
+ presenter: PopupPresenter,
12
+ dismiss_on_backdrop_click: Rc<Cell<bool>>,
13
+ }
14
+
15
+ impl Default for Popup {
16
+ fn default() -> Self {
17
+ Self::new()
18
+ }
19
+ }
20
+
21
+ impl Popup {
22
+ pub fn new() -> Self {
23
+ let root = portal();
24
+ let surface_node = flex_box();
25
+ surface_node
26
+ .position_type(PositionType::Absolute)
27
+ .flex_direction(FlexDirection::Column);
28
+ let presenter = PopupPresenter::new(root.clone(), surface_node.clone());
29
+ root.position_type(PositionType::Absolute)
30
+ .position(0.0, 0.0)
31
+ .width(100.0, Unit::Percent)
32
+ .height(100.0, Unit::Percent);
33
+ let dismiss_on_backdrop_click = Rc::new(Cell::new(true));
34
+ let dismiss_flag = dismiss_on_backdrop_click.clone();
35
+ let presenter_target = presenter.event_target();
36
+ presenter
37
+ .overlay_node()
38
+ .interactive(true)
39
+ .on_click(move |_event| {
40
+ if dismiss_flag.get() {
41
+ presenter_target.hide();
42
+ }
43
+ });
44
+ Self {
45
+ root,
46
+ surface_node,
47
+ presenter,
48
+ dismiss_on_backdrop_click,
49
+ }
50
+ }
51
+
52
+ pub fn is_open(&self) -> bool {
53
+ self.presenter.is_open()
54
+ }
55
+
56
+ pub fn surface(&self) -> FlexBox {
57
+ self.surface_node.clone()
58
+ }
59
+
60
+ pub fn placement(&self, value: PopupPlacement) -> &Self {
61
+ self.presenter.placement(value);
62
+ self
63
+ }
64
+
65
+ pub fn edge_padding(&self, value: f32) -> &Self {
66
+ self.presenter.edge_padding(value);
67
+ self
68
+ }
69
+
70
+ pub fn anchor_gap(&self, value: f32) -> &Self {
71
+ self.presenter.anchor_gap(value);
72
+ self
73
+ }
74
+
75
+ pub fn dismiss_on_backdrop_click(&self, flag: bool) -> &Self {
76
+ self.dismiss_on_backdrop_click.set(flag);
77
+ self
78
+ }
79
+
80
+ pub fn backdrop_color(&self, color: u32) -> &Self {
81
+ self.presenter.backdrop_color(color);
82
+ self
83
+ }
84
+
85
+ pub fn background_blur(&self, sigma: f32) -> &Self {
86
+ self.presenter.background_blur(sigma);
87
+ self
88
+ }
89
+
90
+ pub fn child<T: Node>(&self, node: &T) -> &Self {
91
+ self.surface_node.child(node);
92
+ self
93
+ }
94
+
95
+ pub fn children<I, C>(&self, nodes: I) -> &Self
96
+ where
97
+ I: IntoIterator<Item = C>,
98
+ C: Into<Child>,
99
+ {
100
+ for node in nodes {
101
+ self.surface_node
102
+ .retained_node_ref()
103
+ .append_child_ref(&node.into().node_ref);
104
+ }
105
+ self
106
+ }
107
+
108
+ pub fn panel_color(&self, color: u32) -> &Self {
109
+ self.surface_node.bg_color(color);
110
+ self
111
+ }
112
+
113
+ pub fn panel_background_blur(&self, sigma: f32) -> &Self {
114
+ self.surface_node.background_blur(sigma);
115
+ self
116
+ }
117
+
118
+ pub fn panel_corner_radius(&self, radius: f32) -> &Self {
119
+ self.surface_node.corner_radius(radius);
120
+ self
121
+ }
122
+
123
+ pub fn panel_border(&self, width: f32, color: u32) -> &Self {
124
+ self.surface_node.border(width, color);
125
+ self
126
+ }
127
+
128
+ pub fn panel_border_config(&self, border: Border) -> &Self {
129
+ self.surface_node.border_config(border);
130
+ self
131
+ }
132
+
133
+ pub fn panel_shadow(
134
+ &self,
135
+ color: u32,
136
+ offset_x: f32,
137
+ offset_y: f32,
138
+ blur_sigma: f32,
139
+ spread: f32,
140
+ ) -> &Self {
141
+ self.surface_node
142
+ .drop_shadow(color, offset_x, offset_y, blur_sigma, spread);
143
+ self
144
+ }
145
+
146
+ pub fn show_anchored(
147
+ &self,
148
+ anchor_x: f32,
149
+ anchor_y: f32,
150
+ anchor_width: f32,
151
+ anchor_height: f32,
152
+ width: f32,
153
+ height: f32,
154
+ ) {
155
+ self.surface_node.width(width, Unit::Pixel);
156
+ self.surface_node.height(height, Unit::Pixel);
157
+ self.presenter.show_anchored(
158
+ anchor_x,
159
+ anchor_y,
160
+ anchor_width,
161
+ anchor_height,
162
+ width,
163
+ height,
164
+ );
165
+ }
166
+
167
+ pub fn show_at_point(&self, x: f32, y: f32, width: f32, height: f32) {
168
+ self.surface_node.width(width, Unit::Pixel);
169
+ self.surface_node.height(height, Unit::Pixel);
170
+ self.presenter.show_at_point(x, y, width, height);
171
+ }
172
+
173
+ pub fn hide(&self) {
174
+ self.presenter.hide();
175
+ }
176
+ }
177
+
178
+ impl Node for Popup {
179
+ fn retained_node_ref(&self) -> NodeRef {
180
+ self.root.retained_node_ref()
181
+ }
182
+
183
+ fn build_self(&self) {
184
+ self.root.build_self();
185
+ }
186
+
187
+ fn dispose(&self) {
188
+ self.presenter.dispose();
189
+ self.root.dispose();
190
+ }
191
+ }