Skip to main content

fui/node/
mod.rs

1use crate::bindings::ui;
2use crate::drawing::DrawContext;
3use crate::event::{
4    FocusChangedEventArgs, GestureEventArgs, KeyEventArgs, LongPressEventArgs, PointerEventArgs,
5    PointerType, SelectionChangedEventArgs, TextChangedEventArgs, WheelEventArgs,
6    DEFAULT_LONG_PRESS_MINIMUM_DURATION_MS, DEFAULT_LONG_PRESS_MOVEMENT_TOLERANCE,
7};
8use crate::ffi::{
9    AlignItems, AlignSelf, BorderStyle, CursorStyle, FlexDirection, FlexWrap, GridUnit,
10    HandleValue, ImageSamplingKind, JustifyContent, NodeType, ObjectFit, Orientation, PositionType,
11    SemanticCheckedState, SemanticRole, TextAlign, TextOverflow, TextVerticalAlign, Unit,
12    Visibility,
13};
14use crate::theme;
15use crate::transitions::NodeTransitions;
16use crate::typography::{FontFamily, FontStack, FontStyle, FontWeight};
17use std::any::Any;
18use std::cell::RefCell;
19use std::rc::{Rc, Weak};
20
21mod core;
22mod custom_drawable;
23mod flex_box;
24mod grid;
25mod helpers;
26mod image;
27mod presenter_host_style;
28mod scroll_bar;
29mod scroll_box;
30mod scroll_state;
31mod scroll_view;
32mod svg_node;
33mod text_node;
34mod virtual_list;
35
36#[doc(hidden)]
37pub use core::NodeRef;
38pub use core::{ContextMenuEventArgs, Node, NodeHandle};
39pub(crate) use core::{WeakFlexBox, WeakNodeRef};
40pub use custom_drawable::{CustomDrawable, DrawableInvalidator};
41pub use flex_box::{Border, FlexBox, GradientStop};
42pub use grid::{Grid, GridTrack};
43pub(crate) use helpers::*;
44pub use helpers::{
45    auto, column, custom_drawable, fill, flex_box, grid, image, pct, portal, px, row, scroll_box,
46    scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Length,
47};
48pub use image::ImageNode;
49pub(crate) use presenter_host_style::HostStyleLayers;
50pub use presenter_host_style::{Corners, EdgeInsets, PresenterHostStyle, Shadow};
51pub use scroll_bar::{ScrollBar, ScrollBarStyle, ScrollBarVisibility};
52pub use scroll_box::ScrollBox;
53pub use scroll_state::ScrollState;
54pub use scroll_view::ScrollView;
55pub use svg_node::SvgNode;
56pub use text_node::TextNode;
57pub use virtual_list::VirtualList;
58
59pub type Image = ImageNode;
60pub type Portal = FlexBox;
61pub type Svg = SvgNode;
62pub type Text = TextNode;
63
64pub trait HasFlexBoxRoot {
65    fn flex_box_root(&self) -> &FlexBox;
66
67    #[doc(hidden)]
68    fn set_flex_box_surface_width(&self, value: f32, unit: Unit) {
69        self.flex_box_root().width(value, unit);
70    }
71
72    #[doc(hidden)]
73    fn set_flex_box_surface_height(&self, value: f32, unit: Unit) {
74        self.flex_box_root().height(value, unit);
75    }
76
77    #[doc(hidden)]
78    fn append_flex_box_surface_child(&self, child: NodeRef) {
79        self.flex_box_root()
80            .retained_node_ref()
81            .append_child_ref(&child);
82    }
83}
84
85pub trait ThemeBindable: Sized + 'static {
86    #[doc(hidden)]
87    fn theme_binding_node(&self) -> NodeRef;
88
89    #[doc(hidden)]
90    fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>>;
91
92    fn bind_theme(&self, handler: impl Fn(&Self, crate::theme::Theme) + 'static) -> &Self {
93        let target = self.weak_theme_target();
94        let guard = crate::theme::subscribe(move |theme| {
95            if let Some(control) = target() {
96                handler(&control, theme);
97            }
98        });
99        self.theme_binding_node().retain_attachment(Rc::new(guard));
100        self
101    }
102}
103
104impl HasFlexBoxRoot for FlexBox {
105    fn flex_box_root(&self) -> &FlexBox {
106        self
107    }
108}
109
110impl ThemeBindable for FlexBox {
111    fn theme_binding_node(&self) -> NodeRef {
112        self.retained_node_ref()
113    }
114
115    fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
116        let weak = self.downgrade();
117        Box::new(move || weak.upgrade())
118    }
119}
120
121pub trait HasTextNode {
122    fn text_node(&self) -> &TextNode;
123
124    #[doc(hidden)]
125    fn set_text_surface_content(&self, content: String) {
126        self.text_node().text(content);
127    }
128
129    #[doc(hidden)]
130    fn set_text_surface_font_stack(&self, stack: FontStack, size: f32) {
131        self.text_node().font_stack(stack, size);
132    }
133
134    #[doc(hidden)]
135    fn set_text_surface_font_family(&self, family: FontFamily) {
136        self.text_node().font_family(family);
137    }
138
139    #[doc(hidden)]
140    fn set_text_surface_font_weight(&self, weight: FontWeight) {
141        self.text_node().font_weight(weight);
142    }
143
144    #[doc(hidden)]
145    fn set_text_surface_font_style(&self, style: FontStyle) {
146        self.text_node().font_style(style);
147    }
148
149    #[doc(hidden)]
150    fn set_text_surface_font_size(&self, size: f32) {
151        self.text_node().font_size(size);
152    }
153
154    #[doc(hidden)]
155    fn set_text_surface_color(&self, color: u32) {
156        self.text_node().text_color(color);
157    }
158}
159
160pub trait TextLayoutSurface: HasTextNode {
161    fn width(&self, width: f32, unit: Unit) -> &Self {
162        self.text_node().width(width, unit);
163        self
164    }
165
166    fn height(&self, height: f32, unit: Unit) -> &Self {
167        self.text_node().height(height, unit);
168        self
169    }
170
171    fn width_len(&self, length: Length) -> &Self {
172        let (value, unit) = length;
173        self.text_node().width(value, unit);
174        self
175    }
176
177    fn height_len(&self, length: Length) -> &Self {
178        let (value, unit) = length;
179        self.text_node().height(value, unit);
180        self
181    }
182
183    fn fill_width(&self) -> &Self {
184        self.text_node().fill_width();
185        self
186    }
187
188    fn fill_height(&self) -> &Self {
189        self.text_node().fill_height();
190        self
191    }
192
193    fn fill_size(&self) -> &Self {
194        self.text_node().fill_size();
195        self
196    }
197
198    fn fill_width_percent(&self, percent: f32) -> &Self {
199        self.text_node().fill_width_percent(percent);
200        self
201    }
202
203    fn fill_height_percent(&self, percent: f32) -> &Self {
204        self.text_node().fill_height_percent(percent);
205        self
206    }
207
208    fn min_width(&self, value: f32, unit: Unit) -> &Self {
209        self.text_node().min_width(value, unit);
210        self
211    }
212
213    fn max_width(&self, value: f32, unit: Unit) -> &Self {
214        self.text_node().max_width(value, unit);
215        self
216    }
217
218    fn min_height(&self, value: f32, unit: Unit) -> &Self {
219        self.text_node().min_height(value, unit);
220        self
221    }
222
223    fn max_height(&self, value: f32, unit: Unit) -> &Self {
224        self.text_node().max_height(value, unit);
225        self
226    }
227
228    fn text_align(&self, align: TextAlign) -> &Self {
229        self.text_node().text_align(align);
230        self
231    }
232
233    fn text_vertical_align(&self, align: TextVerticalAlign) -> &Self {
234        self.text_node().text_vertical_align(align);
235        self
236    }
237
238    fn text_limits(&self, max_chars: i32, max_lines: i32) -> &Self {
239        self.text_node().text_limits(max_chars, max_lines);
240        self
241    }
242
243    fn max_lines(&self, max_lines: i32) -> &Self {
244        self.text_node().max_lines(max_lines);
245        self
246    }
247
248    fn wrapping(&self, wrap: bool) -> &Self {
249        self.text_node().wrapping(wrap);
250        self
251    }
252
253    fn text_overflow(&self, overflow: TextOverflow) -> &Self {
254        self.text_node().text_overflow(overflow);
255        self
256    }
257
258    fn text_overflow_fade(&self, horizontal: bool, vertical: bool) -> &Self {
259        self.text_node().text_overflow_fade(horizontal, vertical);
260        self
261    }
262}
263
264impl<T: HasTextNode> TextLayoutSurface for T {}
265
266pub trait TextContentSurface: HasTextNode {
267    fn text(&self, content: impl Into<String>) -> &Self {
268        self.set_text_surface_content(content.into());
269        self
270    }
271
272    fn content(&self) -> String {
273        self.text_node().content()
274    }
275}
276
277impl<T: HasTextNode> TextContentSurface for T {}
278
279pub trait TextTypographySurface: HasTextNode {
280    fn font_stack(&self, stack: FontStack, size: f32) -> &Self {
281        self.set_text_surface_font_stack(stack, size);
282        self
283    }
284
285    fn font_family(&self, family: FontFamily) -> &Self {
286        self.set_text_surface_font_family(family);
287        self
288    }
289
290    fn font_weight(&self, weight: FontWeight) -> &Self {
291        self.set_text_surface_font_weight(weight);
292        self
293    }
294
295    fn font_style(&self, style: FontStyle) -> &Self {
296        self.set_text_surface_font_style(style);
297        self
298    }
299
300    fn font_size(&self, size: f32) -> &Self {
301        self.set_text_surface_font_size(size);
302        self
303    }
304
305    fn line_height(&self, line_height: f32) -> &Self {
306        self.text_node().line_height(line_height);
307        self
308    }
309
310    fn text_color(&self, color: u32) -> &Self {
311        self.set_text_surface_color(color);
312        self
313    }
314}
315
316impl<T: HasTextNode> TextTypographySurface for T {}
317
318pub trait TextSelectionSurface: HasTextNode {
319    fn uses_default_selection_behavior(&self) -> bool {
320        self.text_node().uses_default_selection_behavior()
321    }
322
323    fn is_selectable_text(&self) -> bool {
324        self.text_node().is_selectable_text()
325    }
326
327    fn selection_start(&self) -> u32 {
328        self.text_node().selection_start()
329    }
330
331    fn selection_end(&self) -> u32 {
332        self.text_node().selection_end()
333    }
334
335    fn selectable(&self, selectable: bool) -> &Self {
336        self.text_node().selectable(selectable);
337        self
338    }
339
340    fn selection_color(&self, color: u32) -> &Self {
341        self.text_node().selection_color(color);
342        self
343    }
344
345    fn selection_range(&self, start: u32, end: u32) -> &Self {
346        self.text_node().selection_range(start, end);
347        self
348    }
349
350    fn caret_color(&self, color: u32) -> &Self {
351        self.text_node().caret_color(color);
352        self
353    }
354}
355
356impl<T: HasTextNode> TextSelectionSurface for T {}
357
358pub trait TextEditingSurface: HasTextNode {
359    fn is_editable_text(&self) -> bool {
360        self.text_node().is_editable_text()
361    }
362
363    fn editable(&self, editable: bool) -> &Self {
364        self.text_node().editable(editable);
365        self
366    }
367
368    fn obscured(&self, obscured: bool) -> &Self {
369        self.text_node().obscured(obscured);
370        self
371    }
372}
373
374impl<T: HasTextNode> TextEditingSurface for T {}
375
376pub trait TextEventSurface: HasTextNode {
377    fn on_text_changed(&self, handler: impl Fn(TextChangedEventArgs) + 'static) -> &Self {
378        self.text_node().on_text_changed(handler);
379        self
380    }
381
382    fn on_selection_changed(&self, handler: impl Fn(SelectionChangedEventArgs) + 'static) -> &Self {
383        self.text_node().on_selection_changed(handler);
384        self
385    }
386}
387
388impl<T: HasTextNode> TextEventSurface for T {}
389
390pub trait TextSurface:
391    TextLayoutSurface
392    + TextContentSurface
393    + TextTypographySurface
394    + TextSelectionSurface
395    + TextEditingSurface
396    + TextEventSurface
397{
398}
399
400impl<T> TextSurface for T where
401    T: TextLayoutSurface
402        + TextContentSurface
403        + TextTypographySurface
404        + TextSelectionSurface
405        + TextEditingSurface
406        + TextEventSurface
407{
408}
409
410impl HasTextNode for TextNode {
411    fn text_node(&self) -> &TextNode {
412        self
413    }
414}
415
416pub trait LayoutSurface {
417    #[doc(hidden)]
418    fn layout_surface_root(&self) -> &FlexBox;
419
420    #[doc(hidden)]
421    fn set_layout_surface_width(&self, value: f32, unit: Unit);
422
423    #[doc(hidden)]
424    fn set_layout_surface_height(&self, value: f32, unit: Unit);
425
426    fn width(&self, width: f32, unit: Unit) -> &Self {
427        self.set_layout_surface_width(width, unit);
428        self
429    }
430
431    fn width_len(&self, length: Length) -> &Self {
432        let (value, unit) = length;
433        self.set_layout_surface_width(value, unit);
434        self
435    }
436
437    fn height(&self, height: f32, unit: Unit) -> &Self {
438        self.set_layout_surface_height(height, unit);
439        self
440    }
441
442    fn height_len(&self, length: Length) -> &Self {
443        let (value, unit) = length;
444        self.set_layout_surface_height(value, unit);
445        self
446    }
447
448    fn fill_width(&self) -> &Self {
449        self.layout_surface_root().fill_width();
450        self
451    }
452
453    fn fill_height(&self) -> &Self {
454        self.layout_surface_root().fill_height();
455        self
456    }
457
458    fn fill_size(&self) -> &Self {
459        self.layout_surface_root().fill_size();
460        self
461    }
462
463    fn fill_width_percent(&self, percent: f32) -> &Self {
464        self.layout_surface_root().fill_width_percent(percent);
465        self
466    }
467
468    fn fill_height_percent(&self, percent: f32) -> &Self {
469        self.layout_surface_root().fill_height_percent(percent);
470        self
471    }
472
473    fn min_width(&self, value: f32, unit: Unit) -> &Self {
474        self.layout_surface_root().min_width(value, unit);
475        self
476    }
477
478    fn min_width_len(&self, length: Length) -> &Self {
479        self.layout_surface_root().min_width_len(length);
480        self
481    }
482
483    fn max_width(&self, value: f32, unit: Unit) -> &Self {
484        self.layout_surface_root().max_width(value, unit);
485        self
486    }
487
488    fn max_width_len(&self, length: Length) -> &Self {
489        self.layout_surface_root().max_width_len(length);
490        self
491    }
492
493    fn min_height(&self, value: f32, unit: Unit) -> &Self {
494        self.layout_surface_root().min_height(value, unit);
495        self
496    }
497
498    fn min_height_len(&self, length: Length) -> &Self {
499        self.layout_surface_root().min_height_len(length);
500        self
501    }
502
503    fn max_height(&self, value: f32, unit: Unit) -> &Self {
504        self.layout_surface_root().max_height(value, unit);
505        self
506    }
507
508    fn max_height_len(&self, length: Length) -> &Self {
509        self.layout_surface_root().max_height_len(length);
510        self
511    }
512
513    fn margin(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
514        self.layout_surface_root().margin(left, top, right, bottom);
515        self
516    }
517
518    fn position_type(&self, position_type: PositionType) -> &Self {
519        self.layout_surface_root().position_type(position_type);
520        self
521    }
522
523    fn position_absolute(&self) -> &Self {
524        self.layout_surface_root()
525            .position_type(PositionType::Absolute);
526        self
527    }
528
529    fn position(&self, left: f32, top: f32) -> &Self {
530        self.layout_surface_root().position(left, top);
531        self
532    }
533}
534
535impl<T: HasFlexBoxRoot> LayoutSurface for T {
536    fn layout_surface_root(&self) -> &FlexBox {
537        self.flex_box_root()
538    }
539
540    fn set_layout_surface_width(&self, value: f32, unit: Unit) {
541        self.set_flex_box_surface_width(value, unit);
542    }
543
544    fn set_layout_surface_height(&self, value: f32, unit: Unit) {
545        self.set_flex_box_surface_height(value, unit);
546    }
547}
548
549pub trait BoxStyleSurface {
550    #[doc(hidden)]
551    fn box_style_surface_root(&self) -> &FlexBox;
552
553    fn interactive(&self, interactive: bool) -> &Self {
554        self.box_style_surface_root().interactive(interactive);
555        self
556    }
557
558    fn padding(&self, left: f32, top: f32, right: f32, bottom: f32) -> &Self {
559        self.box_style_surface_root()
560            .padding(left, top, right, bottom);
561        self
562    }
563
564    fn clear_padding(&self) -> &Self {
565        self.box_style_surface_root().clear_padding();
566        self
567    }
568
569    fn corner_radius(&self, radius: f32) -> &Self {
570        self.box_style_surface_root().corner_radius(radius);
571        self
572    }
573
574    fn clear_corners(&self) -> &Self {
575        self.box_style_surface_root().clear_corners();
576        self
577    }
578
579    fn corners(&self, tl: f32, tr: f32, br: f32, bl: f32) -> &Self {
580        self.box_style_surface_root().corners(tl, tr, br, bl);
581        self
582    }
583
584    fn border(&self, width: f32, color: u32) -> &Self {
585        self.box_style_surface_root().border(width, color);
586        self
587    }
588
589    fn border_config(&self, border: Border) -> &Self {
590        self.box_style_surface_root().border_config(border);
591        self
592    }
593
594    fn clear_border(&self) -> &Self {
595        self.box_style_surface_root().clear_border();
596        self
597    }
598
599    fn bg_color(&self, color: u32) -> &Self {
600        self.box_style_surface_root().bg_color(color);
601        self
602    }
603
604    fn clear_bg_color(&self) -> &Self {
605        self.box_style_surface_root().clear_bg_color();
606        self
607    }
608
609    fn opacity(&self, value: f32) -> &Self {
610        self.box_style_surface_root().opacity(value);
611        self
612    }
613
614    fn clear_opacity(&self) -> &Self {
615        self.box_style_surface_root().clear_opacity();
616        self
617    }
618
619    fn blur(&self, sigma: f32) -> &Self {
620        self.box_style_surface_root().blur(sigma);
621        self
622    }
623
624    fn drop_shadow(
625        &self,
626        color: u32,
627        offset_x: f32,
628        offset_y: f32,
629        blur_sigma: f32,
630        spread: f32,
631    ) -> &Self {
632        self.box_style_surface_root()
633            .drop_shadow(color, offset_x, offset_y, blur_sigma, spread);
634        self
635    }
636
637    fn clear_drop_shadow(&self) -> &Self {
638        self.box_style_surface_root().clear_drop_shadow();
639        self
640    }
641
642    fn background_blur(&self, sigma: f32) -> &Self {
643        self.box_style_surface_root().background_blur(sigma);
644        self
645    }
646
647    fn linear_gradient(
648        &self,
649        start_x: f32,
650        start_y: f32,
651        end_x: f32,
652        end_y: f32,
653        offsets: Vec<f32>,
654        colors: Vec<u32>,
655    ) -> &Self {
656        self.box_style_surface_root()
657            .linear_gradient(start_x, start_y, end_x, end_y, offsets, colors);
658        self
659    }
660
661    fn linear_gradient_stops(
662        &self,
663        start_x: f32,
664        start_y: f32,
665        end_x: f32,
666        end_y: f32,
667        stops: Vec<GradientStop>,
668    ) -> &Self {
669        self.box_style_surface_root()
670            .linear_gradient_stops(start_x, start_y, end_x, end_y, stops);
671        self
672    }
673
674    fn transitions(&self, transitions: Option<NodeTransitions>) -> &Self {
675        self.box_style_surface_root().transitions(transitions);
676        self
677    }
678
679    fn clip_to_bounds(&self, clip: bool) -> &Self {
680        self.box_style_surface_root().clip_to_bounds(clip);
681        self
682    }
683}
684
685impl<T: HasFlexBoxRoot> BoxStyleSurface for T {
686    fn box_style_surface_root(&self) -> &FlexBox {
687        self.flex_box_root()
688    }
689}
690
691pub trait FlexLayoutSurface {
692    #[doc(hidden)]
693    fn flex_layout_surface_root(&self) -> &FlexBox;
694
695    fn flex_direction(&self, direction: FlexDirection) -> &Self {
696        self.flex_layout_surface_root().flex_direction(direction);
697        self
698    }
699
700    fn flex_basis(&self, basis: f32) -> &Self {
701        self.flex_layout_surface_root().flex_basis(basis);
702        self
703    }
704
705    fn justify_content(&self, justify: JustifyContent) -> &Self {
706        self.flex_layout_surface_root().justify_content(justify);
707        self
708    }
709
710    fn clear_justify_content(&self) -> &Self {
711        self.flex_layout_surface_root().clear_justify_content();
712        self
713    }
714
715    fn align_items(&self, align: AlignItems) -> &Self {
716        self.flex_layout_surface_root().align_items(align);
717        self
718    }
719
720    fn clear_align_items(&self) -> &Self {
721        self.flex_layout_surface_root().clear_align_items();
722        self
723    }
724
725    fn align_self(&self, align: AlignSelf) -> &Self {
726        self.flex_layout_surface_root().align_self(align);
727        self
728    }
729
730    fn flex_wrap(&self, wrap: FlexWrap) -> &Self {
731        self.flex_layout_surface_root().flex_wrap(wrap);
732        self
733    }
734}
735
736impl<T: HasFlexBoxRoot> FlexLayoutSurface for T {
737    fn flex_layout_surface_root(&self) -> &FlexBox {
738        self.flex_box_root()
739    }
740}
741
742/// Fluent retained-child composition for FlexBox-backed nodes and controls.
743///
744/// Composed controls may install presenter-owned children before user content;
745/// `child` and `children` append without replacing those presenter children.
746/// A caller can remove a child it owns through [`Node::remove_child`] without
747/// disturbing the control-owned prefix. Controls with a distinct public content
748/// surface override the hidden append adapter to match their FUI-AS counterpart.
749pub trait ChildContainerSurface {
750    #[doc(hidden)]
751    fn append_surface_child(&self, child: NodeRef);
752
753    fn child<T: Node>(&self, child: &T) -> &Self {
754        self.append_surface_child(child.retained_node_ref());
755        self
756    }
757
758    fn children<I, C>(&self, children: I) -> &Self
759    where
760        I: IntoIterator<Item = C>,
761        C: Into<Child>,
762    {
763        for child in children {
764            self.append_surface_child(child.into().node_ref);
765        }
766        self
767    }
768}
769
770impl<T: HasFlexBoxRoot> ChildContainerSurface for T {
771    fn append_surface_child(&self, child: NodeRef) {
772        self.append_flex_box_surface_child(child);
773    }
774}
775
776pub trait FlexBoxSurface:
777    LayoutSurface + BoxStyleSurface + FlexLayoutSurface + ChildContainerSurface
778{
779}
780
781impl<T> FlexBoxSurface for T where
782    T: LayoutSurface + BoxStyleSurface + FlexLayoutSurface + ChildContainerSurface
783{
784}
785
786#[derive(Clone)]
787pub struct Child {
788    pub(crate) node_ref: NodeRef,
789}
790
791impl Child {
792    pub fn from_node<T: Node>(value: &T) -> Self {
793        Self {
794            node_ref: value.retained_node_ref(),
795        }
796    }
797}
798
799impl<T: Node> From<T> for Child {
800    fn from(value: T) -> Self {
801        Self {
802            node_ref: value.retained_node_ref(),
803        }
804    }
805}