rg3d_ui/
lib.rs

1//! Extendable, retained mode, graphics API agnostic UI library.
2//!
3//! See examples here - <https://github.com/mrDIMAS/rusty-shooter/blob/master/src/menu.rs>
4
5#![forbid(unsafe_code)]
6#![allow(irrefutable_let_patterns)]
7#![allow(clippy::float_cmp)]
8#![allow(clippy::upper_case_acronyms)]
9#![allow(clippy::from_over_into)]
10#![allow(clippy::new_without_default)]
11
12#[macro_use]
13extern crate lazy_static;
14
15pub use rg3d_core as core;
16
17pub mod border;
18pub mod brush;
19pub mod button;
20pub mod canvas;
21pub mod check_box;
22pub mod color;
23pub mod curve;
24pub mod decorator;
25pub mod dock;
26pub mod draw;
27pub mod dropdown_list;
28pub mod expander;
29pub mod file_browser;
30pub mod formatted_text;
31pub mod grid;
32pub mod image;
33pub mod inspector;
34pub mod list_view;
35pub mod menu;
36pub mod message;
37pub mod messagebox;
38pub mod numeric;
39pub mod popup;
40pub mod progress_bar;
41pub mod range;
42pub mod rect;
43pub mod scroll_bar;
44pub mod scroll_panel;
45pub mod scroll_viewer;
46pub mod stack_panel;
47pub mod tab_control;
48pub mod text;
49pub mod text_box;
50pub mod tree;
51pub mod ttf;
52pub mod utils;
53pub mod vec;
54pub mod vector_image;
55pub mod widget;
56pub mod window;
57pub mod wrap_panel;
58
59use crate::{
60    brush::Brush,
61    canvas::Canvas,
62    core::{
63        algebra::Vector2,
64        color::Color,
65        math::{clampf, Rect},
66        pool::{Handle, Pool},
67        scope_profile,
68    },
69    draw::{CommandTexture, Draw, DrawingContext},
70    message::{
71        ButtonState, CursorIcon, KeyboardModifiers, MessageDirection, MouseButton, OsEvent,
72        UiMessage,
73    },
74    popup::{Placement, PopupMessage},
75    ttf::{Font, SharedFont},
76    widget::{Widget, WidgetBuilder, WidgetMessage},
77};
78use copypasta::ClipboardContext;
79use fxhash::{FxHashMap, FxHashSet};
80use std::{
81    any::{Any, TypeId},
82    cell::Cell,
83    collections::VecDeque,
84    fmt::Debug,
85    ops::{Deref, DerefMut, Index, IndexMut},
86    sync::{
87        mpsc::{self, Receiver, Sender, TryRecvError},
88        Arc, Mutex,
89    },
90};
91
92// TODO: Make this part of UserInterface struct.
93pub const COLOR_DARKEST: Color = Color::opaque(20, 20, 20);
94pub const COLOR_DARKER: Color = Color::opaque(30, 30, 30);
95pub const COLOR_DARK: Color = Color::opaque(40, 40, 40);
96pub const COLOR_PRIMARY: Color = Color::opaque(50, 50, 50);
97pub const COLOR_LIGHT: Color = Color::opaque(65, 65, 65);
98pub const COLOR_LIGHTER: Color = Color::opaque(80, 80, 80);
99pub const COLOR_LIGHTEST: Color = Color::opaque(95, 95, 95);
100pub const COLOR_BRIGHT: Color = Color::opaque(130, 130, 130);
101pub const COLOR_BRIGHT_BLUE: Color = Color::opaque(80, 118, 178);
102pub const COLOR_TEXT: Color = Color::opaque(220, 220, 220);
103pub const COLOR_FOREGROUND: Color = Color::WHITE;
104
105pub const BRUSH_DARKEST: Brush = Brush::Solid(COLOR_DARKEST);
106pub const BRUSH_DARKER: Brush = Brush::Solid(COLOR_DARKER);
107pub const BRUSH_DARK: Brush = Brush::Solid(COLOR_DARK);
108pub const BRUSH_PRIMARY: Brush = Brush::Solid(COLOR_PRIMARY);
109pub const BRUSH_LIGHT: Brush = Brush::Solid(COLOR_LIGHT);
110pub const BRUSH_LIGHTER: Brush = Brush::Solid(COLOR_LIGHTER);
111pub const BRUSH_LIGHTEST: Brush = Brush::Solid(COLOR_LIGHTEST);
112pub const BRUSH_BRIGHT: Brush = Brush::Solid(COLOR_BRIGHT);
113pub const BRUSH_BRIGHT_BLUE: Brush = Brush::Solid(COLOR_BRIGHT_BLUE);
114pub const BRUSH_TEXT: Brush = Brush::Solid(COLOR_TEXT);
115pub const BRUSH_FOREGROUND: Brush = Brush::Solid(COLOR_FOREGROUND);
116
117#[derive(Copy, Clone, PartialEq, Debug)]
118pub enum HorizontalAlignment {
119    Stretch,
120    Left,
121    Center,
122    Right,
123}
124
125#[derive(Copy, Clone, PartialEq, Debug)]
126pub enum VerticalAlignment {
127    Stretch,
128    Top,
129    Center,
130    Bottom,
131}
132
133#[derive(Copy, Clone, PartialEq, Debug)]
134pub struct Thickness {
135    pub left: f32,
136    pub top: f32,
137    pub right: f32,
138    pub bottom: f32,
139}
140
141impl Default for Thickness {
142    fn default() -> Self {
143        Self::uniform(0.0)
144    }
145}
146
147#[derive(Copy, Clone, Debug, PartialEq)]
148pub enum Orientation {
149    Vertical,
150    Horizontal,
151}
152
153impl Thickness {
154    pub fn zero() -> Self {
155        Self {
156            left: 0.0,
157            top: 0.0,
158            right: 0.0,
159            bottom: 0.0,
160        }
161    }
162
163    pub fn uniform(v: f32) -> Self {
164        Self {
165            left: v,
166            top: v,
167            right: v,
168            bottom: v,
169        }
170    }
171
172    pub fn bottom(v: f32) -> Self {
173        Self {
174            left: 0.0,
175            top: 0.0,
176            right: 0.0,
177            bottom: v,
178        }
179    }
180
181    pub fn top(v: f32) -> Self {
182        Self {
183            left: 0.0,
184            top: v,
185            right: 0.0,
186            bottom: 0.0,
187        }
188    }
189
190    pub fn left(v: f32) -> Self {
191        Self {
192            left: v,
193            top: 0.0,
194            right: 0.0,
195            bottom: 0.0,
196        }
197    }
198
199    pub fn right(v: f32) -> Self {
200        Self {
201            left: 0.0,
202            top: 0.0,
203            right: v,
204            bottom: 0.0,
205        }
206    }
207
208    pub fn offset(&self) -> Vector2<f32> {
209        Vector2::new(self.left, self.top)
210    }
211
212    /// Returns margin for each axis.
213    pub fn axes_margin(&self) -> Vector2<f32> {
214        Vector2::new(self.left + self.right, self.top + self.bottom)
215    }
216}
217
218type NodeHandle = Handle<UiNode>;
219
220#[derive(Default)]
221pub struct NodeHandleMapping {
222    hash_map: FxHashMap<NodeHandle, NodeHandle>,
223}
224
225impl NodeHandleMapping {
226    pub fn add_mapping(&mut self, old: Handle<UiNode>, new: Handle<UiNode>) {
227        self.hash_map.insert(old, new);
228    }
229
230    pub fn resolve(&self, old: &mut Handle<UiNode>) {
231        // None handles aren't mapped.
232        if old.is_some() {
233            if let Some(clone) = self.hash_map.get(old) {
234                *old = *clone;
235            }
236        }
237    }
238
239    pub fn resolve_cell(&self, old: &mut Cell<Handle<UiNode>>) {
240        // None handles aren't mapped.
241        if old.get().is_some() {
242            if let Some(clone) = self.hash_map.get(&old.get()) {
243                old.set(*clone)
244            }
245        }
246    }
247
248    pub fn resolve_slice(&self, slice: &mut [Handle<UiNode>]) {
249        for item in slice {
250            self.resolve(item);
251        }
252    }
253}
254
255pub trait BaseControl: 'static {
256    fn as_any(&self) -> &dyn Any;
257
258    fn as_any_mut(&mut self) -> &mut dyn Any;
259
260    fn clone_boxed(&self) -> Box<dyn Control>;
261}
262
263impl<T: Any + Clone + 'static + Control> BaseControl for T {
264    fn as_any(&self) -> &dyn Any {
265        self
266    }
267
268    fn as_any_mut(&mut self) -> &mut dyn Any {
269        self
270    }
271
272    fn clone_boxed(&self) -> Box<dyn Control> {
273        Box::new(self.clone())
274    }
275}
276
277/// Trait for all UI controls in library.
278pub trait Control: BaseControl + Deref<Target = Widget> + DerefMut {
279    /// Allows a widget to provide access to inner components. For example you can build your custom
280    /// MyTree widget using engine's Tree widget as a base. The engine needs to know whether the custom
281    /// widget is actually extends functionality of some existing widget.
282    ///
283    /// # Implementation
284    ///
285    /// It should at least return `Some(self)` for `type_id == TypeId::of::<Self>`.
286    fn query_component(&self, type_id: TypeId) -> Option<&dyn Any>;
287
288    fn resolve(&mut self, _node_map: &NodeHandleMapping) {}
289
290    fn on_remove(&self, _sender: &Sender<UiMessage>) {}
291
292    fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
293        scope_profile!();
294
295        self.deref().measure_override(ui, available_size)
296    }
297
298    fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
299        scope_profile!();
300
301        self.deref().arrange_override(ui, final_size)
302    }
303
304    fn draw(&self, _drawing_context: &mut DrawingContext) {}
305
306    fn update(&mut self, _dt: f32, _sender: &Sender<UiMessage>) {}
307
308    /// Performs event-specific actions. Must call widget.handle_message()!
309    ///
310    /// # Notes
311    ///
312    /// Do *not* try to borrow node by `self_handle` in UI - at this moment node has been moved
313    /// out of pool and attempt of borrowing will cause panic! `self_handle` should be used only
314    /// to check if event came from/for this node or to capture input on node.
315    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage);
316
317    /// Used to react to a message (by producing another message) that was posted outside of current
318    /// hierarchy. In other words this method is used when you need to "peek" a message before it'll
319    /// be passed into bubbling router. Most common use case is to catch messages from popups: popup
320    /// in 99.9% cases is a child of root canvas and it **won't** receive a message from a its *logical*
321    /// parent during bubbling message routing. For example `preview_message` used in a dropdown list:
322    /// dropdown list has two separate parts - a field with selected value and a popup for all possible
323    /// options. Visual parent of the popup in this case is the root canvas, but logical parent is the
324    /// dropdown list. Because of this fact, the field won't receive any messages from popup, to solve
325    /// this we use `preview_message`. This method is much more restrictive - it does not allow you to
326    /// modify a node and ui, you can either *request* changes by sending a message or use internal
327    /// mutability (`Cell`, `RefCell`, etc).
328    ///
329    /// ## Important notes
330    ///
331    /// Due to performance reasons, you **must** set `.with_preview_messages(true)` in widget builder to
332    /// force library to call `preview_message`!
333    ///
334    /// The order of execution of this method is undefined! There is no guarantee that it will be called
335    /// hierarchically as widgets connected.
336    fn preview_message(&self, _ui: &UserInterface, _message: &mut UiMessage) {
337        // This method is optional.
338    }
339
340    /// Provides a way to respond to OS specific events. Can be useful to detect if a key or mouse
341    /// button was pressed. This method significantly differs from `handle_message` because os events
342    /// are not dispatched - they'll be passed to this method in any case.
343    ///
344    /// ## Important notes
345    ///
346    /// Due to performance reasons, you **must** set `.with_handle_os_messages(true)` in widget builder to
347    /// force library to call `handle_os_event`!
348    fn handle_os_event(
349        &mut self,
350        _self_handle: Handle<UiNode>,
351        _ui: &mut UserInterface,
352        _event: &OsEvent,
353    ) {
354    }
355}
356
357pub struct DragContext {
358    is_dragging: bool,
359    drag_node: Handle<UiNode>,
360    click_pos: Vector2<f32>,
361    drag_preview: Handle<UiNode>,
362}
363
364impl Default for DragContext {
365    fn default() -> Self {
366        Self {
367            is_dragging: false,
368            drag_node: Default::default(),
369            click_pos: Vector2::new(0.0, 0.0),
370            drag_preview: Default::default(),
371        }
372    }
373}
374
375#[derive(Copy, Clone, Debug, Eq, PartialEq)]
376pub struct MouseState {
377    left: ButtonState,
378    right: ButtonState,
379    middle: ButtonState,
380    // TODO Add rest of buttons
381}
382
383impl Default for MouseState {
384    fn default() -> Self {
385        Self {
386            left: ButtonState::Released,
387            right: ButtonState::Released,
388            middle: ButtonState::Released,
389        }
390    }
391}
392
393pub struct UiNode(pub Box<dyn Control>);
394
395impl Deref for UiNode {
396    type Target = dyn Control;
397
398    fn deref(&self) -> &Self::Target {
399        self.0.deref()
400    }
401}
402
403impl DerefMut for UiNode {
404    fn deref_mut(&mut self) -> &mut Self::Target {
405        self.0.deref_mut()
406    }
407}
408
409impl UiNode {
410    pub fn new<T: Control>(widget: T) -> Self {
411        Self(Box::new(widget))
412    }
413
414    pub fn cast<T: Control>(&self) -> Option<&T> {
415        self.0.as_any().downcast_ref::<T>()
416    }
417
418    pub fn cast_mut<T: Control>(&mut self) -> Option<&mut T> {
419        self.0.as_any_mut().downcast_mut::<T>()
420    }
421}
422
423pub struct BuildContext<'a> {
424    ui: &'a mut UserInterface,
425}
426
427impl<'a> BuildContext<'a> {
428    pub fn add_node(&mut self, node: UiNode) -> Handle<UiNode> {
429        self.ui.add_node(node)
430    }
431
432    pub fn link(&mut self, child: Handle<UiNode>, parent: Handle<UiNode>) {
433        self.ui.link_nodes_internal(child, parent, false)
434    }
435
436    pub fn copy(&mut self, node: Handle<UiNode>) -> Handle<UiNode> {
437        self.ui.copy_node(node)
438    }
439}
440
441impl<'a> Index<Handle<UiNode>> for BuildContext<'a> {
442    type Output = UiNode;
443
444    fn index(&self, index: Handle<UiNode>) -> &Self::Output {
445        &self.ui.nodes[index]
446    }
447}
448
449impl<'a> IndexMut<Handle<UiNode>> for BuildContext<'a> {
450    fn index_mut(&mut self, index: Handle<UiNode>) -> &mut Self::Output {
451        &mut self.ui.nodes[index]
452    }
453}
454
455#[derive(Copy, Clone)]
456pub struct RestrictionEntry {
457    /// Handle to UI node to which picking must be restricted to.
458    pub handle: Handle<UiNode>,
459
460    /// A flag that tells UI to stop iterating over picking stack.
461    /// There are two use cases: chain of menus (popups) and set of modal windows. In case of
462    /// menus you need to restrict picking to an entire chain, but leave possibility to select
463    /// any menu in the chain. In case of multiple modal windows you need to restrict picking
464    /// individually per window, not allowing to pick anything behind modal window, but still
465    /// save restrictions in the entire chain of modal windows so if topmost closes, restriction
466    /// will be on previous one and so on.
467    pub stop: bool,
468}
469
470struct TooltipEntry {
471    tooltip: Handle<UiNode>,
472    /// Time remaining until this entry should disappear (in seconds).
473    time: f32,
474    /// Maximum time that it should be kept for
475    /// This is stored here as well, because when hovering
476    /// over the tooltip, we don't know the time it should stay for and
477    /// so we use this to refresh the timer.
478    max_time: f32,
479}
480impl TooltipEntry {
481    fn new(tooltip: Handle<UiNode>, time: f32) -> TooltipEntry {
482        Self {
483            tooltip,
484            time,
485            max_time: time,
486        }
487    }
488
489    fn decrease(&mut self, amount: f32) {
490        self.time -= amount;
491    }
492
493    fn should_display(&self) -> bool {
494        self.time > 0.0
495    }
496}
497
498#[derive(Debug)]
499enum LayoutEvent {
500    MeasurementInvalidated(Handle<UiNode>),
501    ArrangementInvalidated(Handle<UiNode>),
502    VisibilityChanged(Handle<UiNode>),
503}
504
505pub struct UserInterface {
506    screen_size: Vector2<f32>,
507    nodes: Pool<UiNode>,
508    drawing_context: DrawingContext,
509    visual_debug: bool,
510    root_canvas: Handle<UiNode>,
511    picked_node: Handle<UiNode>,
512    prev_picked_node: Handle<UiNode>,
513    captured_node: Handle<UiNode>,
514    keyboard_focus_node: Handle<UiNode>,
515    cursor_position: Vector2<f32>,
516    receiver: Receiver<UiMessage>,
517    sender: Sender<UiMessage>,
518    stack: Vec<Handle<UiNode>>,
519    picking_stack: Vec<RestrictionEntry>,
520    bubble_queue: VecDeque<Handle<UiNode>>,
521    drag_context: DragContext,
522    mouse_state: MouseState,
523    keyboard_modifiers: KeyboardModifiers,
524    cursor_icon: CursorIcon,
525    active_tooltip: Option<TooltipEntry>,
526    preview_set: FxHashSet<Handle<UiNode>>,
527    clipboard: Option<ClipboardContext>,
528    layout_events_receiver: Receiver<LayoutEvent>,
529    layout_events_sender: Sender<LayoutEvent>,
530    need_update_global_transform: bool,
531}
532
533lazy_static! {
534    pub static ref DEFAULT_FONT: SharedFont = {
535        let font_bytes = std::include_bytes!("./built_in_font.ttf").to_vec();
536        let font = Font::from_memory(font_bytes, 16.0, Font::default_char_set()).unwrap();
537        Arc::new(Mutex::new(font)).into()
538    };
539}
540
541fn draw_node(
542    nodes: &Pool<UiNode>,
543    node_handle: Handle<UiNode>,
544    drawing_context: &mut DrawingContext,
545) {
546    scope_profile!();
547
548    let node = &nodes[node_handle];
549    if !node.is_globally_visible() {
550        return;
551    }
552
553    // Crawl up on tree and check if current bounds are intersects with every screen bound
554    // of parents chain. This is needed because some control can move their children outside of
555    // their bounds (like scroll viewer, etc.) and single intersection test of parent bounds with
556    // current bounds is not enough.
557    let bounds = node.screen_bounds();
558    let mut parent = node.parent();
559    while parent.is_some() {
560        let parent_node = nodes.borrow(parent);
561        if !parent_node.screen_bounds().intersects(bounds) {
562            return;
563        }
564        parent = parent_node.parent();
565    }
566
567    let start_index = drawing_context.get_commands().len();
568
569    let pushed = if !is_node_enabled(nodes, node_handle) {
570        drawing_context.push_opacity(0.4);
571        true
572    } else if let Some(opacity) = node.opacity() {
573        drawing_context.push_opacity(opacity);
574        true
575    } else {
576        false
577    };
578
579    node.draw(drawing_context);
580
581    let end_index = drawing_context.get_commands().len();
582    for i in start_index..end_index {
583        node.command_indices.borrow_mut().push(i);
584    }
585
586    // Continue on children
587    for &child_node in node.children().iter() {
588        // Do not continue render of top-most nodes - they'll be rendered in separate pass.
589        if !nodes[child_node].is_draw_on_top() {
590            draw_node(nodes, child_node, drawing_context);
591        }
592    }
593
594    if pushed {
595        drawing_context.pop_opacity();
596    }
597}
598
599fn is_node_enabled(nodes: &Pool<UiNode>, handle: Handle<UiNode>) -> bool {
600    let root_node = &nodes[handle];
601    let mut enabled = root_node.enabled();
602    let mut parent = root_node.parent();
603    while parent.is_some() {
604        let node = &nodes[parent];
605        if !node.enabled() {
606            enabled = false;
607            break;
608        }
609        parent = node.parent();
610    }
611    enabled
612}
613
614impl UserInterface {
615    pub fn new(screen_size: Vector2<f32>) -> UserInterface {
616        let (sender, receiver) = mpsc::channel();
617        let (layout_events_sender, layout_events_receiver) = mpsc::channel();
618        let mut ui = UserInterface {
619            screen_size,
620            sender,
621            receiver,
622            visual_debug: false,
623            captured_node: Handle::NONE,
624            root_canvas: Handle::NONE,
625            nodes: Pool::new(),
626            cursor_position: Vector2::new(0.0, 0.0),
627            drawing_context: DrawingContext::new(),
628            picked_node: Handle::NONE,
629            prev_picked_node: Handle::NONE,
630            keyboard_focus_node: Handle::NONE,
631            stack: Default::default(),
632            picking_stack: Default::default(),
633            bubble_queue: Default::default(),
634            drag_context: Default::default(),
635            mouse_state: Default::default(),
636            keyboard_modifiers: Default::default(),
637            cursor_icon: Default::default(),
638            active_tooltip: Default::default(),
639            preview_set: Default::default(),
640            clipboard: ClipboardContext::new().ok(),
641            layout_events_receiver,
642            layout_events_sender,
643            need_update_global_transform: Default::default(),
644        };
645        ui.root_canvas = ui.add_node(UiNode::new(Canvas::new(WidgetBuilder::new().build())));
646        ui
647    }
648
649    pub fn keyboard_modifiers(&self) -> KeyboardModifiers {
650        self.keyboard_modifiers
651    }
652
653    pub fn build_ctx(&mut self) -> BuildContext<'_> {
654        BuildContext { ui: self }
655    }
656
657    #[inline]
658    pub fn capture_mouse(&mut self, node: Handle<UiNode>) -> bool {
659        if self.captured_node.is_none() {
660            self.captured_node = node;
661            true
662        } else {
663            false
664        }
665    }
666
667    #[inline]
668    pub fn release_mouse_capture(&mut self) {
669        self.captured_node = Handle::NONE;
670    }
671
672    #[inline]
673    pub fn get_drawing_context(&self) -> &DrawingContext {
674        &self.drawing_context
675    }
676
677    #[inline]
678    pub fn get_drawing_context_mut(&mut self) -> &mut DrawingContext {
679        &mut self.drawing_context
680    }
681
682    pub fn is_node_enabled(&self, handle: Handle<UiNode>) -> bool {
683        is_node_enabled(&self.nodes, handle)
684    }
685
686    fn update_global_visibility(&mut self, from: Handle<UiNode>) {
687        scope_profile!();
688
689        self.stack.clear();
690        self.stack.push(from);
691        while let Some(node_handle) = self.stack.pop() {
692            let (widget, parent) = self
693                .nodes
694                .try_borrow_dependant_mut(node_handle, |n| n.parent());
695
696            if let Some(widget) = widget {
697                self.stack.extend_from_slice(widget.children());
698
699                let visibility = if let Some(parent) = parent {
700                    widget.visibility() && parent.is_globally_visible()
701                } else {
702                    widget.visibility()
703                };
704
705                if widget.prev_global_visibility != visibility {
706                    let _ = self
707                        .layout_events_sender
708                        .send(LayoutEvent::MeasurementInvalidated(node_handle));
709                    let _ = self
710                        .layout_events_sender
711                        .send(LayoutEvent::ArrangementInvalidated(node_handle));
712                }
713
714                widget.set_global_visibility(visibility);
715            }
716        }
717    }
718
719    fn update_transform(&mut self) {
720        scope_profile!();
721
722        self.stack.clear();
723        self.stack.push(self.root_canvas);
724        while let Some(node_handle) = self.stack.pop() {
725            let (widget, parent) = self
726                .nodes
727                .try_borrow_dependant_mut(node_handle, |n| n.parent());
728
729            let widget = widget.unwrap();
730
731            if widget.is_globally_visible() {
732                self.stack.extend_from_slice(widget.children());
733
734                let screen_position = if let Some(parent) = parent {
735                    widget.actual_local_position() + parent.screen_position()
736                } else {
737                    widget.actual_local_position()
738                };
739
740                widget.screen_position = screen_position;
741            }
742        }
743    }
744
745    pub fn screen_size(&self) -> Vector2<f32> {
746        self.screen_size
747    }
748
749    fn handle_layout_events(&mut self) {
750        fn invalidate_recursive_up(
751            nodes: &Pool<UiNode>,
752            node: Handle<UiNode>,
753            callback: fn(&UiNode),
754        ) {
755            if let Some(node_ref) = nodes.try_borrow(node) {
756                (callback)(node_ref);
757                if node_ref.parent().is_some() {
758                    invalidate_recursive_up(nodes, node_ref.parent(), callback);
759                }
760            }
761        }
762
763        while let Ok(layout_event) = self.layout_events_receiver.try_recv() {
764            match layout_event {
765                LayoutEvent::MeasurementInvalidated(node) => {
766                    invalidate_recursive_up(&self.nodes, node, |node_ref| {
767                        node_ref.measure_valid.set(false)
768                    });
769                }
770                LayoutEvent::ArrangementInvalidated(node) => {
771                    invalidate_recursive_up(&self.nodes, node, |node_ref| {
772                        node_ref.arrange_valid.set(false)
773                    });
774                    self.need_update_global_transform = true;
775                }
776                LayoutEvent::VisibilityChanged(node) => {
777                    self.update_global_visibility(node);
778                }
779            }
780        }
781    }
782
783    pub fn update(&mut self, screen_size: Vector2<f32>, dt: f32) {
784        scope_profile!();
785
786        self.screen_size = screen_size;
787
788        self.handle_layout_events();
789
790        self.measure_node(self.root_canvas, screen_size);
791        self.arrange_node(
792            self.root_canvas,
793            &Rect::new(0.0, 0.0, screen_size.x, screen_size.y),
794        );
795
796        if self.need_update_global_transform {
797            self.update_transform();
798            self.need_update_global_transform = false;
799        }
800
801        let sender = self.sender.clone();
802        for node in self.nodes.iter_mut() {
803            node.update(dt, &sender)
804        }
805
806        self.update_tooltips(dt);
807
808        if !self.drag_context.is_dragging {
809            // Try to fetch new cursor icon starting from current picked node. Traverse
810            // tree up until cursor with different value is found.
811            self.cursor_icon = CursorIcon::default();
812            let mut handle = self.picked_node;
813            while handle.is_some() {
814                let node = &self.nodes[handle];
815                if let Some(cursor) = node.cursor() {
816                    self.cursor_icon = cursor;
817                    break;
818                }
819                handle = node.parent();
820            }
821        }
822    }
823
824    pub fn cursor(&self) -> CursorIcon {
825        self.cursor_icon
826    }
827
828    pub fn draw(&mut self) -> &DrawingContext {
829        scope_profile!();
830
831        self.calculate_clip_bounds(
832            self.root_canvas,
833            Rect::new(0.0, 0.0, self.screen_size.x, self.screen_size.y),
834        );
835        self.drawing_context.clear();
836
837        for node in self.nodes.iter_mut() {
838            node.command_indices.borrow_mut().clear();
839        }
840
841        // Draw everything except top-most nodes.
842        draw_node(&self.nodes, self.root_canvas, &mut self.drawing_context);
843
844        // Render top-most nodes in separate pass.
845        // TODO: This may give weird results because of invalid nesting.
846        self.stack.clear();
847        self.stack.push(self.root());
848        while let Some(node_handle) = self.stack.pop() {
849            let node = &self.nodes[node_handle];
850            if node.is_draw_on_top() {
851                draw_node(&self.nodes, node_handle, &mut self.drawing_context);
852            }
853            for &child in node.children() {
854                self.stack.push(child);
855            }
856        }
857
858        // Debug info rendered on top of other.
859        if self.visual_debug {
860            if self.picked_node.is_some() {
861                let bounds = self.nodes.borrow(self.picked_node).screen_bounds();
862                self.drawing_context.push_rect(&bounds, 1.0);
863                self.drawing_context.commit(
864                    bounds,
865                    Brush::Solid(Color::WHITE),
866                    CommandTexture::None,
867                    None,
868                );
869            }
870
871            if self.keyboard_focus_node.is_some() {
872                let bounds = self.nodes.borrow(self.keyboard_focus_node).screen_bounds();
873                self.drawing_context.push_rect(&bounds, 1.0);
874                self.drawing_context.commit(
875                    bounds,
876                    Brush::Solid(Color::GREEN),
877                    CommandTexture::None,
878                    None,
879                );
880            }
881        }
882
883        &self.drawing_context
884    }
885
886    pub fn clipboard(&self) -> Option<&ClipboardContext> {
887        self.clipboard.as_ref()
888    }
889
890    pub fn clipboard_mut(&mut self) -> Option<&mut ClipboardContext> {
891        self.clipboard.as_mut()
892    }
893
894    pub fn arrange_node(&self, handle: Handle<UiNode>, final_rect: &Rect<f32>) -> bool {
895        scope_profile!();
896
897        let node = self.node(handle);
898
899        if node.is_arrange_valid() && node.prev_arrange.get() == *final_rect {
900            return false;
901        }
902
903        if node.visibility() {
904            node.prev_arrange.set(*final_rect);
905
906            let margin = node.margin().axes_margin();
907
908            let mut size = Vector2::new(
909                (final_rect.w() - margin.x).max(0.0),
910                (final_rect.h() - margin.y).max(0.0),
911            );
912
913            let available_size = size;
914
915            if node.horizontal_alignment() != HorizontalAlignment::Stretch {
916                size.x = size.x.min(node.desired_size().x - margin.x);
917            }
918            if node.vertical_alignment() != VerticalAlignment::Stretch {
919                size.y = size.y.min(node.desired_size().y - margin.y);
920            }
921
922            if node.width() > 0.0 {
923                size.x = node.width();
924            }
925            if node.height() > 0.0 {
926                size.y = node.height();
927            }
928
929            size = node.arrange_override(self, size);
930
931            size.x = size.x.min(final_rect.w());
932            size.y = size.y.min(final_rect.h());
933
934            let mut origin = final_rect.position + node.margin().offset();
935
936            match node.horizontal_alignment() {
937                HorizontalAlignment::Center | HorizontalAlignment::Stretch => {
938                    origin.x += (available_size.x - size.x) * 0.5;
939                }
940                HorizontalAlignment::Right => origin.x += available_size.x - size.x,
941                _ => (),
942            }
943
944            match node.vertical_alignment() {
945                VerticalAlignment::Center | VerticalAlignment::Stretch => {
946                    origin.y += (available_size.y - size.y) * 0.5;
947                }
948                VerticalAlignment::Bottom => origin.y += available_size.y - size.y,
949                _ => (),
950            }
951
952            node.commit_arrange(origin, size);
953        }
954
955        true
956    }
957
958    pub fn measure_node(&self, handle: Handle<UiNode>, available_size: Vector2<f32>) -> bool {
959        scope_profile!();
960
961        let node = self.node(handle);
962
963        if node.is_measure_valid() && node.prev_measure.get() == available_size {
964            return false;
965        }
966
967        if node.visibility() {
968            node.prev_measure.set(available_size);
969
970            let axes_margin = node.margin().axes_margin();
971            let mut inner_size = available_size - axes_margin;
972            inner_size.x = inner_size.x.max(0.0);
973            inner_size.y = inner_size.y.max(0.0);
974
975            let mut size = Vector2::new(
976                if node.width() > 0.0 {
977                    node.width()
978                } else {
979                    inner_size.x
980                },
981                if node.height() > 0.0 {
982                    node.height()
983                } else {
984                    inner_size.y
985                },
986            );
987
988            size.x = clampf(size.x, node.min_size().x, node.max_size().x);
989            size.y = clampf(size.y, node.min_size().y, node.max_size().y);
990
991            let mut desired_size = node.measure_override(self, size);
992
993            if !node.width().is_nan() {
994                desired_size.x = node.width();
995            }
996            if !node.height().is_nan() {
997                desired_size.y = node.height();
998            }
999
1000            desired_size.x = clampf(desired_size.x, node.min_size().x, node.max_size().x);
1001            desired_size.y = clampf(desired_size.y, node.min_size().y, node.max_size().y);
1002
1003            desired_size += axes_margin;
1004
1005            desired_size.x = desired_size.x.min(available_size.x);
1006            desired_size.y = desired_size.y.min(available_size.y);
1007
1008            node.commit_measure(desired_size);
1009        } else {
1010            node.commit_measure(Vector2::new(0.0, 0.0));
1011        }
1012
1013        true
1014    }
1015
1016    fn is_node_clipped(&self, node_handle: Handle<UiNode>, pt: Vector2<f32>) -> bool {
1017        scope_profile!();
1018
1019        let mut clipped = true;
1020
1021        let widget = self.nodes.borrow(node_handle);
1022
1023        if widget.is_globally_visible() {
1024            clipped = !widget.screen_bounds().contains(pt);
1025
1026            if !clipped {
1027                for command_index in widget.command_indices.borrow().iter() {
1028                    if let Some(command) = self.drawing_context.get_commands().get(*command_index) {
1029                        if let Some(geometry) = command.clipping_geometry.as_ref() {
1030                            if geometry.is_contains_point(pt) {
1031                                clipped = false;
1032                                break;
1033                            }
1034                        }
1035                    }
1036                }
1037            }
1038
1039            // Point can be clipped by parent's clipping geometry.
1040            if !widget.parent().is_none() && !clipped {
1041                clipped |= self.is_node_clipped(widget.parent(), pt);
1042            }
1043        }
1044
1045        clipped
1046    }
1047
1048    fn is_node_contains_point(&self, node_handle: Handle<UiNode>, pt: Vector2<f32>) -> bool {
1049        scope_profile!();
1050
1051        let widget = self.nodes.borrow(node_handle);
1052
1053        if !widget.is_globally_visible() {
1054            return false;
1055        }
1056
1057        if !self.is_node_clipped(node_handle, pt) {
1058            for command_index in widget.command_indices.borrow().iter() {
1059                if let Some(command) = self.drawing_context.get_commands().get(*command_index) {
1060                    if self.drawing_context.is_command_contains_point(command, pt) {
1061                        return true;
1062                    }
1063                }
1064            }
1065        }
1066
1067        false
1068    }
1069
1070    fn pick_node(
1071        &self,
1072        node_handle: Handle<UiNode>,
1073        pt: Vector2<f32>,
1074        level: &mut i32,
1075    ) -> Handle<UiNode> {
1076        scope_profile!();
1077
1078        let widget = self.nodes.borrow(node_handle);
1079
1080        if !widget.is_hit_test_visible()
1081            || !widget.enabled()
1082            || !widget.screen_bounds().intersects(Rect {
1083                position: Default::default(),
1084                size: self.screen_size,
1085            })
1086        {
1087            return Handle::NONE;
1088        }
1089
1090        let (mut picked, mut topmost_picked_level) = if self.is_node_contains_point(node_handle, pt)
1091        {
1092            (node_handle, *level)
1093        } else {
1094            (Handle::NONE, 0)
1095        };
1096
1097        for child_handle in widget.children() {
1098            *level += 1;
1099            let picked_child = self.pick_node(*child_handle, pt, level);
1100            if picked_child.is_some() && *level > topmost_picked_level {
1101                topmost_picked_level = *level;
1102                picked = picked_child;
1103            }
1104        }
1105
1106        picked
1107    }
1108
1109    pub fn cursor_position(&self) -> Vector2<f32> {
1110        self.cursor_position
1111    }
1112
1113    pub fn hit_test(&self, pt: Vector2<f32>) -> Handle<UiNode> {
1114        scope_profile!();
1115
1116        if self.nodes.is_valid_handle(self.captured_node) {
1117            self.captured_node
1118        } else if self.picking_stack.is_empty() {
1119            // We're not restricted to any node, just start from root.
1120            let mut level = 0;
1121            self.pick_node(self.root_canvas, pt, &mut level)
1122        } else {
1123            // We have some picking restriction chain.
1124            // Go over picking stack and try each entry. This will help with picking
1125            // in a series of popups, especially in menus where may be many open popups
1126            // at the same time.
1127            for root in self.picking_stack.iter().rev() {
1128                if self.nodes.is_valid_handle(root.handle) {
1129                    let mut level = 0;
1130                    let picked = self.pick_node(root.handle, pt, &mut level);
1131                    if picked.is_some() {
1132                        return picked;
1133                    }
1134                }
1135                if root.stop {
1136                    break;
1137                }
1138            }
1139            Handle::NONE
1140        }
1141    }
1142
1143    /// Searches a node down on tree starting from give root that matches a criteria
1144    /// defined by a given func.
1145    pub fn find_by_criteria_down<Func>(
1146        &self,
1147        node_handle: Handle<UiNode>,
1148        func: &Func,
1149    ) -> Handle<UiNode>
1150    where
1151        Func: Fn(&UiNode) -> bool,
1152    {
1153        let node = self.nodes.borrow(node_handle);
1154
1155        if func(node) {
1156            return node_handle;
1157        }
1158
1159        for child_handle in node.children() {
1160            let result = self.find_by_criteria_down(*child_handle, func);
1161
1162            if result.is_some() {
1163                return result;
1164            }
1165        }
1166
1167        Handle::NONE
1168    }
1169
1170    /// Searches a node up on tree starting from given root that matches a criteria
1171    /// defined by a given func.
1172    pub fn find_by_criteria_up<Func>(
1173        &self,
1174        node_handle: Handle<UiNode>,
1175        func: Func,
1176    ) -> Handle<UiNode>
1177    where
1178        Func: Fn(&UiNode) -> bool,
1179    {
1180        let node = self.nodes.borrow(node_handle);
1181
1182        if func(node) {
1183            return node_handle;
1184        }
1185
1186        if node.parent().is_some() {
1187            self.find_by_criteria_up(node.parent(), func)
1188        } else {
1189            Handle::NONE
1190        }
1191    }
1192
1193    /// Checks if specified node is a child of some other node on `root_handle`. This method
1194    /// is useful to understand if some event came from some node down by tree.
1195    pub fn is_node_child_of(
1196        &self,
1197        node_handle: Handle<UiNode>,
1198        root_handle: Handle<UiNode>,
1199    ) -> bool {
1200        self.nodes
1201            .borrow(root_handle)
1202            .has_descendant(node_handle, self)
1203    }
1204
1205    /// Recursively calculates clipping bounds for every node.
1206    fn calculate_clip_bounds(&self, node: Handle<UiNode>, parent_bounds: Rect<f32>) {
1207        let node = &self.nodes[node];
1208        node.clip_bounds
1209            .set(node.screen_bounds().clip_by(parent_bounds));
1210        for &child in node.children() {
1211            self.calculate_clip_bounds(child, node.clip_bounds.get());
1212        }
1213    }
1214
1215    /// Checks if specified node is a direct child of some other node on `root_handle`.
1216    pub fn is_node_direct_child_of(
1217        &self,
1218        node_handle: Handle<UiNode>,
1219        root_handle: Handle<UiNode>,
1220    ) -> bool {
1221        for child_handle in self.nodes.borrow(root_handle).children() {
1222            if *child_handle == node_handle {
1223                return true;
1224            }
1225        }
1226        false
1227    }
1228
1229    /// Searches a node by name up on tree starting from given root node.
1230    pub fn find_by_name_up(&self, node_handle: Handle<UiNode>, name: &str) -> Handle<UiNode> {
1231        self.find_by_criteria_up(node_handle, |node| node.name() == name)
1232    }
1233
1234    /// Searches a node by name down on tree starting from given root node.
1235    pub fn find_by_name_down(&self, node_handle: Handle<UiNode>, name: &str) -> Handle<UiNode> {
1236        self.find_by_criteria_down(node_handle, &|node| node.name() == name)
1237    }
1238
1239    /// Searches a node by name up on tree starting from given root node and tries to borrow it if exists.
1240    pub fn borrow_by_name_up(&self, start_node_handle: Handle<UiNode>, name: &str) -> &UiNode {
1241        self.nodes
1242            .borrow(self.find_by_name_up(start_node_handle, name))
1243    }
1244
1245    /// Searches a node by name down on tree starting from given root node and tries to borrow it if exists.
1246    pub fn borrow_by_name_down(&self, start_node_handle: Handle<UiNode>, name: &str) -> &UiNode {
1247        self.nodes
1248            .borrow(self.find_by_name_down(start_node_handle, name))
1249    }
1250
1251    /// Searches for a node up on tree that satisfies some criteria and then borrows
1252    /// shared reference.
1253    ///
1254    /// # Panics
1255    ///
1256    /// It will panic if there no node that satisfies given criteria.
1257    pub fn borrow_by_criteria_up<Func>(
1258        &self,
1259        start_node_handle: Handle<UiNode>,
1260        func: Func,
1261    ) -> &UiNode
1262    where
1263        Func: Fn(&UiNode) -> bool,
1264    {
1265        self.nodes
1266            .borrow(self.find_by_criteria_up(start_node_handle, func))
1267    }
1268
1269    pub fn try_borrow_by_criteria_up<Func>(
1270        &self,
1271        start_node_handle: Handle<UiNode>,
1272        func: Func,
1273    ) -> Option<&UiNode>
1274    where
1275        Func: Fn(&UiNode) -> bool,
1276    {
1277        self.nodes
1278            .try_borrow(self.find_by_criteria_up(start_node_handle, func))
1279    }
1280
1281    pub fn try_borrow_by_type_up<T>(
1282        &self,
1283        node_handle: Handle<UiNode>,
1284    ) -> Option<(Handle<UiNode>, &T)>
1285    where
1286        T: Control,
1287    {
1288        let node = self.nodes.borrow(node_handle);
1289
1290        let casted = node.cast::<T>();
1291        if let Some(casted) = casted {
1292            return Some((node_handle, casted));
1293        }
1294
1295        if node.parent().is_some() {
1296            self.try_borrow_by_type_up(node.parent())
1297        } else {
1298            None
1299        }
1300    }
1301
1302    /// Returns instance of message sender which can be used to push messages into queue
1303    /// from other threads.
1304    pub fn sender(&self) -> Sender<UiMessage> {
1305        self.sender.clone()
1306    }
1307
1308    pub fn send_message(&self, message: UiMessage) {
1309        self.sender.send(message).unwrap()
1310    }
1311
1312    // Puts node at the end of children list of a parent node.
1313    //
1314    // # Notes
1315    //
1316    // Node will be topmost *only* on same hierarchy level! So if you have a floating
1317    // window (for example) and a window embedded into some other control (yes this is
1318    // possible) then floating window won't be the topmost.
1319    fn make_topmost(&mut self, node: Handle<UiNode>) {
1320        let parent = self.node(node).parent();
1321        if parent.is_some() {
1322            let parent = &mut self.nodes[parent];
1323            parent.remove_child(node);
1324            parent.add_child(node, false);
1325        }
1326    }
1327
1328    fn bubble_message(&mut self, message: &mut UiMessage) {
1329        scope_profile!();
1330
1331        // Dispatch event using bubble strategy. Bubble routing means that message will go
1332        // from specified destination up on tree to tree root.
1333        // Gather chain of nodes from source to root.
1334        self.bubble_queue.clear();
1335        self.bubble_queue.push_back(message.destination());
1336        let mut parent = self.nodes[message.destination()].parent();
1337        while parent.is_some() && self.nodes.is_valid_handle(parent) {
1338            self.bubble_queue.push_back(parent);
1339            parent = self.nodes[parent].parent();
1340        }
1341
1342        while let Some(handle) = self.bubble_queue.pop_front() {
1343            let (ticket, mut node) = self.nodes.take_reserve(handle);
1344            node.handle_routed_message(self, message);
1345            self.nodes.put_back(ticket, node);
1346        }
1347    }
1348
1349    /// Extracts UI event one-by-one from common queue. Each extracted event will go to *all*
1350    /// available nodes first and only then will be moved outside of this method. This is one
1351    /// of most important methods which must be called each frame of your game loop, otherwise
1352    /// UI will not respond to any kind of events and simply speaking will just not work.
1353    pub fn poll_message(&mut self) -> Option<UiMessage> {
1354        match self.receiver.try_recv() {
1355            Ok(mut message) => {
1356                // Destination node may be destroyed at the time we receive message,
1357                // we have to discard such messages.
1358                if !self.nodes.is_valid_handle(message.destination()) {
1359                    return None;
1360                }
1361
1362                if message.need_perform_layout() {
1363                    self.update(self.screen_size, 0.0);
1364                }
1365
1366                for &handle in self.preview_set.iter() {
1367                    if let Some(node_ref) = self.nodes.try_borrow(handle) {
1368                        node_ref.preview_message(self, &mut message);
1369                    }
1370                }
1371
1372                self.bubble_message(&mut message);
1373
1374                if let Some(msg) = message.data::<WidgetMessage>() {
1375                    match msg {
1376                        WidgetMessage::ZIndex(_) => {
1377                            // Keep order of children of a parent node of a node that changed z-index
1378                            // the same as z-index of children.
1379                            let parent = self.node(message.destination()).parent();
1380                            if parent.is_some() {
1381                                self.stack.clear();
1382                                for child in self.nodes.borrow(parent).children() {
1383                                    self.stack.push(*child);
1384                                }
1385
1386                                let nodes = &mut self.nodes;
1387                                self.stack.sort_by(|a, b| {
1388                                    let z_a = nodes.borrow(*a).z_index();
1389                                    let z_b = nodes.borrow(*b).z_index();
1390                                    z_a.cmp(&z_b)
1391                                });
1392
1393                                let parent = self.nodes.borrow_mut(parent);
1394                                parent.clear_children();
1395                                for child in self.stack.iter() {
1396                                    parent.add_child(*child, false);
1397                                }
1398                            }
1399                        }
1400                        WidgetMessage::TopMost => {
1401                            if message.destination().is_some() {
1402                                self.make_topmost(message.destination());
1403                            }
1404                        }
1405                        WidgetMessage::Unlink => {
1406                            if message.destination().is_some() {
1407                                self.unlink_node(message.destination());
1408
1409                                let node = &self.nodes[message.destination()];
1410                                let new_position = node.screen_position;
1411                                self.send_message(WidgetMessage::desired_position(
1412                                    message.destination(),
1413                                    MessageDirection::ToWidget,
1414                                    new_position,
1415                                ));
1416                            }
1417                        }
1418                        &WidgetMessage::LinkWith(parent) => {
1419                            if message.destination().is_some() {
1420                                self.link_nodes_internal(message.destination(), parent, false);
1421                            }
1422                        }
1423                        &WidgetMessage::LinkWithReverse(parent) => {
1424                            if message.destination().is_some() {
1425                                self.link_nodes_internal(message.destination(), parent, true);
1426                            }
1427                        }
1428                        WidgetMessage::Remove => {
1429                            if message.destination().is_some() {
1430                                self.remove_node(message.destination());
1431                            }
1432                        }
1433                        WidgetMessage::Center => {
1434                            if message.destination().is_some() {
1435                                let node = self.node(message.destination());
1436                                let size = node.actual_size();
1437                                let parent = node.parent();
1438                                let parent_size = if parent.is_some() {
1439                                    if parent == self.root_canvas {
1440                                        self.screen_size
1441                                    } else {
1442                                        self.node(parent).actual_size()
1443                                    }
1444                                } else {
1445                                    self.screen_size
1446                                };
1447
1448                                self.send_message(WidgetMessage::desired_position(
1449                                    message.destination(),
1450                                    MessageDirection::ToWidget,
1451                                    (parent_size - size).scale(0.5),
1452                                ));
1453                            }
1454                        }
1455                        WidgetMessage::MouseDown { button, .. } => {
1456                            if *button == MouseButton::Right {
1457                                if let Some(picked) = self.nodes.try_borrow(self.picked_node) {
1458                                    // Get the context menu from the current node or aa parent node
1459                                    let (context_menu, target) = if picked.context_menu().is_some()
1460                                    {
1461                                        (picked.context_menu(), self.picked_node)
1462                                    } else {
1463                                        let parent_handle = picked.find_by_criteria_up(self, |n| {
1464                                            n.context_menu().is_some()
1465                                        });
1466
1467                                        if let Some(parent) = self.nodes.try_borrow(parent_handle) {
1468                                            (parent.context_menu(), parent_handle)
1469                                        } else {
1470                                            (Handle::NONE, Handle::NONE)
1471                                        }
1472                                    };
1473
1474                                    // Display context menu
1475                                    if context_menu.is_some() {
1476                                        self.send_message(PopupMessage::placement(
1477                                            context_menu,
1478                                            MessageDirection::ToWidget,
1479                                            Placement::Cursor(target),
1480                                        ));
1481                                        self.send_message(PopupMessage::open(
1482                                            context_menu,
1483                                            MessageDirection::ToWidget,
1484                                        ));
1485                                    }
1486                                }
1487                            }
1488                        }
1489                        _ => {}
1490                    }
1491                }
1492
1493                Some(message)
1494            }
1495            Err(e) => match e {
1496                TryRecvError::Empty => None,
1497                TryRecvError::Disconnected => unreachable!(),
1498            },
1499        }
1500    }
1501
1502    fn show_tooltip(&self, tooltip: Handle<UiNode>) {
1503        self.send_message(WidgetMessage::visibility(
1504            tooltip,
1505            MessageDirection::ToWidget,
1506            true,
1507        ));
1508        self.send_message(WidgetMessage::topmost(tooltip, MessageDirection::ToWidget));
1509        self.send_message(WidgetMessage::desired_position(
1510            tooltip,
1511            MessageDirection::ToWidget,
1512            self.cursor_position() + Vector2::new(0.0, 16.0),
1513        ));
1514    }
1515
1516    fn replace_or_update_tooltip(&mut self, tooltip: Handle<UiNode>, time: f32) {
1517        if let Some(entry) = self.active_tooltip.as_mut() {
1518            if entry.tooltip == tooltip {
1519                // Keep current visible.
1520                entry.time = time;
1521            } else {
1522                let old_tooltip = entry.tooltip;
1523
1524                entry.tooltip = tooltip;
1525                self.show_tooltip(tooltip);
1526
1527                // Hide previous.
1528                self.send_message(WidgetMessage::visibility(
1529                    old_tooltip,
1530                    MessageDirection::ToWidget,
1531                    false,
1532                ));
1533            }
1534        } else {
1535            self.show_tooltip(tooltip);
1536            self.active_tooltip = Some(TooltipEntry::new(tooltip, time));
1537        }
1538    }
1539
1540    /// Find any tooltips that are being hovered and activate them.
1541    /// As well, update their time.
1542    fn update_tooltips(&mut self, dt: f32) {
1543        let sender = &self.sender;
1544        if let Some(entry) = self.active_tooltip.as_mut() {
1545            entry.decrease(dt);
1546            if !entry.should_display() {
1547                // This uses sender directly since we're currently mutably borrowing
1548                // visible_tooltips
1549                sender
1550                    .send(WidgetMessage::visibility(
1551                        entry.tooltip,
1552                        MessageDirection::ToWidget,
1553                        false,
1554                    ))
1555                    .unwrap();
1556
1557                self.active_tooltip = None;
1558            }
1559        }
1560
1561        // Check for hovering over a widget with a tooltip, or hovering over a tooltip.
1562        let mut handle = self.picked_node;
1563        while let Some(node) = self.nodes.try_borrow(handle) {
1564            // Get the parent to avoid the problem with having a immutable access here and a
1565            // mutable access later
1566            let parent = node.parent();
1567
1568            if node.tooltip().is_some() {
1569                // They have a tooltip, we stop here and use that.
1570                let tooltip = node.tooltip();
1571                let tooltip_time = node.tooltip_time();
1572                self.replace_or_update_tooltip(tooltip, tooltip_time);
1573                break;
1574            } else if let Some(entry) = self.active_tooltip.as_mut() {
1575                if entry.tooltip == handle {
1576                    // The current node was a tooltip.
1577                    // We refresh the timer back to the stored max time.
1578                    entry.time = entry.max_time;
1579                    break;
1580                }
1581            }
1582
1583            handle = parent;
1584        }
1585    }
1586
1587    pub fn captured_node(&self) -> Handle<UiNode> {
1588        self.captured_node
1589    }
1590
1591    /// Translates raw window event into some specific UI message. This is one of the
1592    /// most important methods of UI. You must call it each time you received a message
1593    /// from a window.
1594    pub fn process_os_event(&mut self, event: &OsEvent) -> bool {
1595        let mut event_processed = false;
1596
1597        match event {
1598            &OsEvent::MouseInput { button, state, .. } => {
1599                match button {
1600                    MouseButton::Left => self.mouse_state.left = state,
1601                    MouseButton::Right => self.mouse_state.right = state,
1602                    MouseButton::Middle => self.mouse_state.middle = state,
1603                    _ => {}
1604                }
1605
1606                match state {
1607                    ButtonState::Pressed => {
1608                        self.picked_node = self.hit_test(self.cursor_position);
1609
1610                        // Try to find draggable node in hierarchy starting from picked node.
1611                        if self.picked_node.is_some() {
1612                            self.stack.clear();
1613                            self.stack.push(self.picked_node);
1614                            while let Some(handle) = self.stack.pop() {
1615                                let node = &self.nodes[handle];
1616                                if node.is_drag_allowed() {
1617                                    self.drag_context.drag_node = handle;
1618                                    self.stack.clear();
1619                                    break;
1620                                } else if node.parent().is_some() {
1621                                    self.stack.push(node.parent());
1622                                }
1623                            }
1624                            self.drag_context.click_pos = self.cursor_position;
1625                        }
1626
1627                        if self.keyboard_focus_node != self.picked_node {
1628                            if self.keyboard_focus_node.is_some() {
1629                                self.send_message(WidgetMessage::lost_focus(
1630                                    self.keyboard_focus_node,
1631                                    MessageDirection::FromWidget,
1632                                ));
1633                            }
1634
1635                            self.keyboard_focus_node = self.picked_node;
1636
1637                            if self.keyboard_focus_node.is_some() {
1638                                self.send_message(WidgetMessage::got_focus(
1639                                    self.keyboard_focus_node,
1640                                    MessageDirection::FromWidget,
1641                                ));
1642                            }
1643                        }
1644
1645                        if self.picked_node.is_some() {
1646                            self.send_message(WidgetMessage::mouse_down(
1647                                self.picked_node,
1648                                MessageDirection::FromWidget,
1649                                self.cursor_position,
1650                                button,
1651                            ));
1652                            event_processed = true;
1653                        }
1654                    }
1655                    ButtonState::Released => {
1656                        if self.picked_node.is_some() {
1657                            if self.drag_context.is_dragging {
1658                                self.drag_context.is_dragging = false;
1659                                self.cursor_icon = CursorIcon::Default;
1660
1661                                // Try to find node with drop allowed in hierarchy starting from picked node.
1662                                self.stack.clear();
1663                                self.stack.push(self.picked_node);
1664                                while let Some(handle) = self.stack.pop() {
1665                                    let node = &self.nodes[handle];
1666                                    if node.is_drop_allowed() {
1667                                        self.send_message(WidgetMessage::drop(
1668                                            handle,
1669                                            MessageDirection::FromWidget,
1670                                            self.drag_context.drag_node,
1671                                        ));
1672                                        self.stack.clear();
1673                                        break;
1674                                    } else if node.parent().is_some() {
1675                                        self.stack.push(node.parent());
1676                                    }
1677                                }
1678                            }
1679                            self.drag_context.drag_node = Handle::NONE;
1680                            if self.nodes.is_valid_handle(self.drag_context.drag_preview) {
1681                                self.remove_node(self.drag_context.drag_preview);
1682                                self.drag_context.drag_preview = Default::default();
1683                            }
1684
1685                            self.send_message(WidgetMessage::mouse_up(
1686                                self.picked_node,
1687                                MessageDirection::FromWidget,
1688                                self.cursor_position,
1689                                button,
1690                            ));
1691                            event_processed = true;
1692                        }
1693                    }
1694                }
1695            }
1696            OsEvent::CursorMoved { position } => {
1697                self.cursor_position = *position;
1698                self.picked_node = self.hit_test(self.cursor_position);
1699
1700                if !self.drag_context.is_dragging
1701                    && self.mouse_state.left == ButtonState::Pressed
1702                    && self.picked_node.is_some()
1703                    && self.drag_context.drag_node.is_some()
1704                    && (self.drag_context.click_pos - *position).norm() > 5.0
1705                {
1706                    self.drag_context.drag_preview =
1707                        self.copy_node_with_limit(self.drag_context.drag_node, Some(30));
1708                    self.nodes[self.drag_context.drag_preview].set_opacity(Some(0.5));
1709
1710                    self.drag_context.is_dragging = true;
1711
1712                    self.send_message(WidgetMessage::drag_started(
1713                        self.picked_node,
1714                        MessageDirection::FromWidget,
1715                        self.drag_context.drag_node,
1716                    ));
1717
1718                    self.cursor_icon = CursorIcon::Crosshair;
1719                }
1720
1721                if self.drag_context.is_dragging
1722                    && self.nodes.is_valid_handle(self.drag_context.drag_preview)
1723                {
1724                    self.send_message(WidgetMessage::desired_position(
1725                        self.drag_context.drag_preview,
1726                        MessageDirection::ToWidget,
1727                        *position,
1728                    ));
1729                }
1730
1731                // Fire mouse leave for previously picked node
1732                if self.picked_node != self.prev_picked_node && self.prev_picked_node.is_some() {
1733                    let prev_picked_node = self.nodes.borrow_mut(self.prev_picked_node);
1734                    if prev_picked_node.is_mouse_directly_over {
1735                        prev_picked_node.is_mouse_directly_over = false;
1736                        self.send_message(WidgetMessage::mouse_leave(
1737                            self.prev_picked_node,
1738                            MessageDirection::FromWidget,
1739                        ));
1740                    }
1741                }
1742
1743                if self.picked_node.is_some() {
1744                    let picked_node = self.nodes.borrow_mut(self.picked_node);
1745                    if !picked_node.is_mouse_directly_over {
1746                        picked_node.is_mouse_directly_over = true;
1747                        self.send_message(WidgetMessage::mouse_enter(
1748                            self.picked_node,
1749                            MessageDirection::FromWidget,
1750                        ));
1751                    }
1752
1753                    // Fire mouse move
1754                    self.send_message(WidgetMessage::mouse_move(
1755                        self.picked_node,
1756                        MessageDirection::FromWidget,
1757                        self.cursor_position,
1758                        self.mouse_state,
1759                    ));
1760
1761                    if self.drag_context.is_dragging {
1762                        self.send_message(WidgetMessage::drag_over(
1763                            self.picked_node,
1764                            MessageDirection::FromWidget,
1765                            self.drag_context.drag_node,
1766                        ));
1767                    }
1768
1769                    event_processed = true;
1770                }
1771            }
1772            OsEvent::MouseWheel(_, y) => {
1773                if self.picked_node.is_some() {
1774                    self.send_message(WidgetMessage::mouse_wheel(
1775                        self.picked_node,
1776                        MessageDirection::FromWidget,
1777                        self.cursor_position,
1778                        *y,
1779                    ));
1780
1781                    event_processed = true;
1782                }
1783            }
1784            OsEvent::KeyboardInput { button, state } => {
1785                if self.keyboard_focus_node.is_some() {
1786                    self.send_message(match state {
1787                        ButtonState::Pressed => WidgetMessage::key_down(
1788                            self.keyboard_focus_node,
1789                            MessageDirection::FromWidget,
1790                            *button,
1791                        ),
1792                        ButtonState::Released => WidgetMessage::key_up(
1793                            self.keyboard_focus_node,
1794                            MessageDirection::FromWidget,
1795                            *button,
1796                        ),
1797                    });
1798
1799                    event_processed = true;
1800                }
1801            }
1802            OsEvent::Character(unicode) => {
1803                if self.keyboard_focus_node.is_some() {
1804                    self.send_message(WidgetMessage::text(
1805                        self.keyboard_focus_node,
1806                        MessageDirection::FromWidget,
1807                        *unicode,
1808                    ));
1809
1810                    event_processed = true;
1811                }
1812            }
1813            &OsEvent::KeyboardModifiers(modifiers) => {
1814                // TODO: Is message needed for focused node?
1815                self.keyboard_modifiers = modifiers;
1816            }
1817        }
1818
1819        self.prev_picked_node = self.picked_node;
1820
1821        for i in 0..self.nodes.get_capacity() {
1822            let handle = self.nodes.handle_from_index(i);
1823
1824            if let Some(node_ref) = self.nodes.try_borrow(handle) {
1825                if node_ref.handle_os_events {
1826                    let (ticket, mut node) = self.nodes.take_reserve(handle);
1827
1828                    node.handle_os_event(handle, self, event);
1829
1830                    self.nodes.put_back(ticket, node);
1831                }
1832            }
1833        }
1834
1835        event_processed
1836    }
1837
1838    pub fn nodes(&self) -> &Pool<UiNode> {
1839        &self.nodes
1840    }
1841
1842    pub fn root(&self) -> Handle<UiNode> {
1843        self.root_canvas
1844    }
1845
1846    pub fn add_node(&mut self, mut node: UiNode) -> Handle<UiNode> {
1847        let children = node.children().to_vec();
1848        node.clear_children();
1849        let node_handle = self.nodes.spawn(node);
1850        if self.root_canvas.is_some() {
1851            self.link_nodes_internal(node_handle, self.root_canvas, false);
1852        }
1853        for child in children {
1854            self.link_nodes_internal(child, node_handle, false)
1855        }
1856        let node = self.nodes[node_handle].deref_mut();
1857        node.layout_events_sender = Some(self.layout_events_sender.clone());
1858        if node.preview_messages {
1859            self.preview_set.insert(node_handle);
1860        }
1861        node.handle = node_handle;
1862        node_handle
1863    }
1864
1865    pub fn push_picking_restriction(&mut self, restriction: RestrictionEntry) {
1866        if let Some(top) = self.top_picking_restriction() {
1867            assert_ne!(top.handle, restriction.handle);
1868        }
1869        self.picking_stack.push(restriction);
1870    }
1871
1872    pub fn remove_picking_restriction(&mut self, node: Handle<UiNode>) {
1873        if let Some(pos) = self.picking_stack.iter().position(|h| h.handle == node) {
1874            self.picking_stack.remove(pos);
1875        }
1876    }
1877
1878    pub fn picking_restriction_stack(&self) -> &[RestrictionEntry] {
1879        &self.picking_stack
1880    }
1881
1882    /// Removes all picking restrictions.
1883    pub fn drop_picking_restrictions(&mut self) {
1884        self.picking_stack.clear();
1885    }
1886
1887    pub fn top_picking_restriction(&self) -> Option<RestrictionEntry> {
1888        self.picking_stack.last().cloned()
1889    }
1890
1891    /// Use WidgetMessage::remove(...) to remove node.
1892    fn remove_node(&mut self, node: Handle<UiNode>) {
1893        self.unlink_node_internal(node);
1894
1895        let mut tooltips = Vec::new();
1896        let sender = self.sender.clone();
1897        let mut stack = vec![node];
1898        while let Some(handle) = stack.pop() {
1899            if self.prev_picked_node == handle {
1900                self.prev_picked_node = Handle::NONE;
1901            }
1902            if self.picked_node == handle {
1903                self.picked_node = Handle::NONE;
1904            }
1905            if self.captured_node == handle {
1906                self.captured_node = Handle::NONE;
1907            }
1908            if self.keyboard_focus_node == handle {
1909                self.keyboard_focus_node = Handle::NONE;
1910            }
1911            self.remove_picking_restriction(handle);
1912
1913            let node_ref = self.nodes.borrow(handle);
1914            stack.extend_from_slice(node_ref.children());
1915
1916            // We also must delete tooltips, since they're not in the tree of the widget they
1917            // won't be deleted automatically.
1918            if node_ref.tooltip().is_some() {
1919                tooltips.push(node_ref.tooltip());
1920            }
1921
1922            // Notify node that it is about to be deleted so it will have a chance to remove
1923            // other widgets (like popups).
1924            node_ref.on_remove(&sender);
1925
1926            self.nodes.free(handle);
1927        }
1928
1929        for tooltip in tooltips {
1930            self.remove_node(tooltip);
1931        }
1932
1933        self.preview_set.remove(&node);
1934    }
1935
1936    /// Links specified child with specified parent.
1937    #[inline]
1938    fn link_nodes_internal(
1939        &mut self,
1940        child_handle: Handle<UiNode>,
1941        parent_handle: Handle<UiNode>,
1942        in_front: bool,
1943    ) {
1944        assert_ne!(child_handle, parent_handle);
1945        self.unlink_node_internal(child_handle);
1946        self.nodes[child_handle].set_parent(parent_handle);
1947        self.nodes[parent_handle].add_child(child_handle, in_front);
1948    }
1949
1950    /// Unlinks specified node from its parent, so node will become root.
1951    #[inline]
1952    fn unlink_node_internal(&mut self, node_handle: Handle<UiNode>) {
1953        // Replace parent handle of child
1954        let node = self.nodes.borrow_mut(node_handle);
1955        let parent_handle = node.parent();
1956        if parent_handle.is_some() {
1957            node.set_parent(Handle::NONE);
1958
1959            // Remove child from parent's children list
1960            self.nodes[parent_handle].remove_child(node_handle);
1961        }
1962    }
1963
1964    /// Unlinks specified node from its parent and attaches back to root canvas.
1965    ///
1966    /// Use [WidgetMessage::remove](enum.WidgetMessage.html#method.remove) to unlink
1967    /// a node at runtime!
1968    #[inline]
1969    fn unlink_node(&mut self, node_handle: Handle<UiNode>) {
1970        self.unlink_node_internal(node_handle);
1971        self.link_nodes_internal(node_handle, self.root_canvas, false);
1972    }
1973
1974    #[inline]
1975    pub fn node(&self, node_handle: Handle<UiNode>) -> &UiNode {
1976        self.nodes.borrow(node_handle)
1977    }
1978
1979    #[inline]
1980    pub fn try_get_node(&self, node_handle: Handle<UiNode>) -> Option<&UiNode> {
1981        self.nodes.try_borrow(node_handle)
1982    }
1983
1984    pub fn copy_node(&mut self, node: Handle<UiNode>) -> Handle<UiNode> {
1985        let mut map = NodeHandleMapping::default();
1986
1987        let root = self.copy_node_recursive(node, &mut map);
1988
1989        for &node_handle in map.hash_map.values() {
1990            self.nodes[node_handle].resolve(&map);
1991        }
1992
1993        root
1994    }
1995
1996    fn copy_node_recursive(
1997        &mut self,
1998        node_handle: Handle<UiNode>,
1999        map: &mut NodeHandleMapping,
2000    ) -> Handle<UiNode> {
2001        let node = self.nodes.borrow(node_handle);
2002        let mut cloned = UiNode(node.clone_boxed());
2003
2004        let mut cloned_children = Vec::new();
2005        for child in node.children().to_vec() {
2006            cloned_children.push(self.copy_node_recursive(child, map));
2007        }
2008
2009        cloned.set_children(cloned_children);
2010        let copy_handle = self.add_node(cloned);
2011        map.add_mapping(node_handle, copy_handle);
2012        copy_handle
2013    }
2014
2015    pub fn copy_node_with_limit(
2016        &mut self,
2017        node: Handle<UiNode>,
2018        limit: Option<usize>,
2019    ) -> Handle<UiNode> {
2020        let mut map = NodeHandleMapping::default();
2021        let mut counter = 0;
2022
2023        let root = self.copy_node_recursive_with_limit(node, &mut map, limit, &mut counter);
2024
2025        for &node_handle in map.hash_map.values() {
2026            self.nodes[node_handle].resolve(&map);
2027        }
2028
2029        root
2030    }
2031
2032    fn copy_node_recursive_with_limit(
2033        &mut self,
2034        node_handle: Handle<UiNode>,
2035        map: &mut NodeHandleMapping,
2036        limit: Option<usize>,
2037        counter: &mut usize,
2038    ) -> Handle<UiNode> {
2039        if let Some(limit) = limit {
2040            if *counter >= limit {
2041                return Default::default();
2042            }
2043        }
2044
2045        let node = self.nodes.borrow(node_handle);
2046        let mut cloned = UiNode(node.clone_boxed());
2047
2048        let mut cloned_children = Vec::new();
2049        for child in node.children().to_vec() {
2050            let cloned_child = self.copy_node_recursive_with_limit(child, map, limit, counter);
2051            if cloned_child.is_some() {
2052                cloned_children.push(cloned_child);
2053            } else {
2054                break;
2055            }
2056        }
2057
2058        cloned.set_children(cloned_children);
2059        let copy_handle = self.add_node(cloned);
2060        map.add_mapping(node_handle, copy_handle);
2061
2062        *counter += 1;
2063
2064        copy_handle
2065    }
2066}
2067
2068#[cfg(test)]
2069mod test {
2070    use crate::{
2071        border::BorderBuilder,
2072        core::algebra::Vector2,
2073        message::MessageDirection,
2074        widget::{WidgetBuilder, WidgetMessage},
2075        UserInterface,
2076    };
2077
2078    #[test]
2079    fn center() {
2080        let screen_size = Vector2::new(1000.0, 1000.0);
2081        let widget_size = Vector2::new(100.0, 100.0);
2082        let mut ui = UserInterface::new(screen_size);
2083        let widget = BorderBuilder::new(
2084            WidgetBuilder::new()
2085                .with_width(widget_size.x)
2086                .with_height(widget_size.y),
2087        )
2088        .build(&mut ui.build_ctx());
2089        ui.update(screen_size, 0.0); // Make sure layout was calculated.
2090        ui.send_message(WidgetMessage::center(widget, MessageDirection::ToWidget));
2091        while ui.poll_message().is_some() {}
2092        ui.update(screen_size, 0.0);
2093        let expected_position = (screen_size - widget_size).scale(0.5);
2094        let actual_position = ui.node(widget).actual_local_position();
2095        assert_eq!(actual_position, expected_position);
2096    }
2097}