Skip to main content

fyrox_ui/
lib.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Extendable, retained mode, graphics API agnostic UI library with lots (35+) of built-in widgets, HiDPI support,
22//! rich layout system and many more.
23//!
24//! ## Basic Concepts
25//!
26//! FyroxUI is quite a complex UI library and before using it, you should understand basic concepts of it. Especially,
27//! if you're got used to immediate-mode UIs.
28//!
29//! ### Stateful
30//!
31//! **Stateful UI* means that we can create and destroy widgets when we need to, it is the opposite approach of
32//! **immediate-mode** or **stateless UIs** when you don't have long-lasting state for your widgets
33//! (usually stateless UI holds its state only for one or few frames).
34//!
35//! Stateful UI is much more powerful and flexible, it allows you to have a complex layout system without having to
36//! create hacks to create complex layout as you'd do in immediate-mode UIs. It is also much faster in terms of
37//! performance. Stateful UI is a must for complex user interfaces that requires rich layout and high performance.
38//!
39//! ### Node-based architecture
40//!
41//! Every user interface could be represented as a set of small blocks that have hierarchical bonding between each
42//! other. For example, a button could be represented using two parts: a background and a foreground. Usually the background
43//! is just a simple rectangle (either a vector or bitmap), and a foreground is a text. The text (the foreground widget)
44//! is a child object of the rectangle (the background widget). These two widgets form another, more complex widget that
45//! we call button.
46//!
47//! Such approach allows us to modify the look of the button as we wish, we can create a button with image background,
48//! or with any vector image, or even other widgets. The foreground can be anything too, it can also contain its own
49//! complex hierarchy, like a pair of an icon with a text and so on.
50//!
51//! ### Composition
52//!
53//! Every widget in the engine uses composition to build more complex widgets. All widgets (and respective builders) contain
54//! `Widget` instance inside, it provides basic functionality for the widget such as layout information, hierarchy, default
55//! foreground and background brushes (their usage depends on derived widget), render and layout transform, and so on.
56//!
57//! ### Message passing
58//!
59//! The engine uses message passing mechanism for UI logic. What does that mean? Let's see at the button from the
60//! previous section and imagine we want to change its text. To do that, we need to explicitly "tell" the button's text
61//! widget to change its content to something new. This is done by sending a message to the widget.
62//!
63//! There are no "classic" callbacks to handle various types of messages, which may come from widgets. Instead, you should write
64//! your own message dispatcher where you'll handle all messages. Why so? At first - decoupling, in this case business logic
65//! is decoupled from the UI. You just receive messages one-by-one and do specific logic. The next reason is that any
66//! callback would require context capturing which could be somewhat restrictive - since you need to share context with the
67//! UI, it would force you to wrap it in `Rc<RefCell<...>>`/`Arc<Mutex<...>>`.
68//!
69//! ### Message routing strategies
70//!
71//! Message passing mechanism works in pair with various routing strategies that allows you to define how the message
72//! will "travel" across the tree of nodes.
73//!
74//! 1. Bubble - a message starts its way from a widget and goes up on hierarchy until it reaches the root node of the hierarchy.
75//! Nodes that lie outside that path won't receive the message. This is the most important message routing strategy that
76//! is used for **every** node by default.
77//! 2. Direct - a message passed directly to every node that is capable of handle it. There is actual routing in this
78//! case. Direct routing is used in rare cases when you need to catch a message outside its normal "bubble" route. It is **off**
79//! by default for every widget, but can be enabled on a per-widget instance basis.
80//!
81//! ## Widgets Overview
82//!
83//! The following subsections explains how to use every widget built into FyroxUI. We will order them by primary function to
84//! help introduce them to new users.
85//!
86//! ### Containers
87//!
88//! The Container widgets' primary purpose is to contain other widgets. They are mostly used as a tool to lay out the UI in
89//! visually different ways.
90//!
91//! * [`stack_panel::StackPanel`]: The Stack Panel arranges widgets in a linear fashion, either vertically or horizontally
92//! depending on how it's setup.
93//! * [`wrap_panel::WrapPanel`]: The Wrap Panel arranges widgets in a linear fashion, but if it overflows, the widgets are
94//! continued adjacent to the first line. Can arrange widgets either vertically or horizontally depending on how its setup.
95//! * [`grid::Grid`]: The Grid arranges widgets into rows and columns with given size constraints.
96//! * [`Canvas`]: The Canvas arranges widgets at their desired positions; it has infinite size and does not restrict
97//! their children's widgets' position and size.
98//! * [`window::Window`]: The Window holds other widgets in a panel that can be configured at setup to be move-able,
99//! expanded and contracted via user input, exited, and have a displayed label. The window has a title bar to assist with these
100//! features.
101//! * [`messagebox::MessageBox`]: The Message Box is a Window that has been streamlined to show standard confirmation/information
102//! dialogues, for example, closing a document with unsaved changes. It has a title, some text, and a fixed set of buttons (Yes, No,
103//! Cancel in different combinations).
104//! * [`menu::Menu`]: The Menu is a root container for Menu Items, an example could be a menu strip with File, Edit, View, etc
105//! items.
106//! * [`popup::Popup`]: The Popup is a panel that locks input to its content while it is open. A simple example of it could be a
107//! context menu.
108//! * [`scroll_viewer::ScrollViewer`]: The ScrollViewer is a wrapper for Scroll Panel that adds two scroll bars to it.
109//! * [`scroll_panel::ScrollPanel`]: The Scroll Panel is a panel that allows you to apply some offset to children widgets. It
110//! is used to create "scrollable" area in conjunction with the Scroll Viewer.
111//! * [`expander::Expander`]: The Expander handles hiding and showing multiple panels of widgets in an according style UI element.
112//! Multiple panels can be shown or hidden at any time based on user input.
113//! * [`tab_control::TabControl`]: The Tab Control handles hiding several panels of widgets, only showing the one that the user
114//! has selected.
115//! * [`dock::DockingManager`]: The Docking manager allows you to dock windows and hold them in-place.
116//! * [`tree::Tree`]: The Tree allows you to create views for hierarchical data.
117//! * [`screen::Screen`]: The Screen widgets always has its bounds match the current screen size,
118//! thus making it possible to create widget hierarchy that always fits the screen bounds.
119//!
120//!
121//! ### Visual
122//!
123//! The Visual widgets' primary purpose is to provide the user feedback generally without the user directly interacting with them.
124//!
125//! * [`text::Text`]: The Text widget is used to display a string to the user.
126//! * [`image::Image`]: The Image widget is used to display a pixel image to the user.
127//! * [`vector_image::VectorImage`]: The Vector Image is used to render vector instructions as a graphical element.
128//! * [`rect::RectEditor`]: The Rect allows you to specify numeric values for X, Y, Width, and Height of a rectangle.
129//! * [`progress_bar::ProgressBar`]: The Progress Bar shows a bar whose fill state can be adjusted to indicate visually how full
130//! something is, for example, how close to 100% is a loading process.
131//! * [`decorator::Decorator`]: The Decorator is used to style any widget. It has support for different styles depending on various
132//! events like mouse hover or click.
133//! * [`border::Border`]: The Border widget is used in conjunction with the Decorator widget to provide configurable boarders to
134//! any widget for styling purposes.
135//!
136//! ### Controls
137//!
138//! Control widgets' primary purpose is to provide users with interactable UI elements to control some aspect of the program.
139//!
140//! * [`button::Button`]: The Button provides a press-able control that can contain other UI elements, for example, a Text
141//! or Image Widget.
142//! * [`check_box::CheckBox`]: The Checkbox is a toggle-able control that can contain other UI elements, for example, a Text
143//! or Image Widget.
144//! * [`text_box::TextBox`]: The Text Box is a control that allows the editing of text.
145//! * [`scroll_bar::ScrollBar`]: The Scroll Bar provides a scroll bar like control that can be used on its own as a data input or with
146//! certain other widgets to provide content scrolling capabilities.
147//! * [`numeric::NumericUpDown`]: The Numeric Field provides the ability to adjust a number via increment and decrement buttons or direct
148//! input. The number can be constrained to remain inside a specific range or have a specific step.
149//! * [`range::RangeEditor`]: The Range allows the user to edit a numeric range - specify its beginning and end values.
150//! * [`list_view::ListView`]: The List View provides a control where users can select from a list of items.
151//! * [`dropdown_list::DropdownList`]: The Drop-down List is a control which shows the currently selected item and provides a drop-down
152//! list to select an item.
153//! * [`file_browser::FileBrowser`]: The File Browser is a tree view of the file system allowing the user to select a file or folder.
154//! * [`curve::CurveEditor`]: The CurveEditor allows editing parametric curves - adding points, and setting up transitions (constant,
155//! linear, cubic) between them.
156//! * [`inspector::Inspector`]: The Inspector automatically creates and handles the input of UI elements based on a populated Inspector
157//! Context given to it, allowing the user to adjust values of a variety of models without manually creating UI for each type.
158//!
159//! ## Examples
160//!
161//! A simple usage example could be the following code:
162//!
163//! ```rust
164//! use fyrox_ui::{
165//!     button::{ButtonBuilder, ButtonMessage},
166//!     core::algebra::Vector2,
167//!     widget::WidgetBuilder,
168//!     UserInterface,
169//! };
170//!
171//! // Create the UI first.
172//! let mut ui = UserInterface::new(Vector2::new(1024.0, 768.0));
173//!
174//! // Add some widgets.
175//! let button = ButtonBuilder::new(WidgetBuilder::new())
176//!     .with_text("Click Me!")
177//!     .build(&mut ui.build_ctx());
178//!
179//! // Poll the messages coming from the widgets and react to them.
180//! while let Some(message) = ui.poll_message() {
181//!     if let Some(ButtonMessage::Click) = message.data() {
182//!         if message.destination() == button {
183//!             println!("The button was clicked!");
184//!         }
185//!     }
186//! }
187//! ```
188//!
189//! **Important**: This example **does not** include any drawing or OS event processing! It is because this
190//! crate is OS- and GAPI-agnostic and does not create native OS windows and cannot draw anything on screen.
191//! For more specific examples, please see `examples` of the crate.
192//!
193//! ## Keyboard Focus
194//!
195//! Widgets can receive keyboard events, but only one widget at a time can have the keyboard focus.
196//! The focused widget is automatically highlighted by the UI library using a rounded rectangle of
197//! bright-blue color. Such highlighting can be disabled by setting a [`Style::BRUSH_HIGHLIGHT`]
198//! property at the root style of your [`UserInterface`] instance.
199//!
200//! ```rust
201//! use fyrox_core::color::Color;
202//! use fyrox_ui::brush::Brush;
203//! use fyrox_ui::style::Style;
204//! use fyrox_ui::UserInterface;
205//!
206//! fn disable_highlighting(ui: &mut UserInterface) {
207//!     ui.style().data_ref().set(Style::BRUSH_HIGHLIGHT, Brush::Solid(Color::TRANSPARENT));
208//! }
209//! ```
210
211#![forbid(unsafe_code)]
212#![allow(irrefutable_let_patterns)]
213#![allow(clippy::float_cmp)]
214#![allow(clippy::upper_case_acronyms)]
215#![allow(clippy::from_over_into)]
216#![allow(clippy::new_without_default)]
217#![allow(clippy::too_many_arguments)]
218#![allow(clippy::type_complexity)]
219#![allow(clippy::doc_lazy_continuation)]
220#![allow(clippy::mutable_key_type)]
221#![allow(mismatched_lifetime_syntaxes)]
222
223pub use bbcode::*;
224pub use copypasta;
225pub use fyrox_core as core;
226use message::TouchPhase;
227
228pub mod absm;
229mod alignment;
230pub mod animation;
231mod bbcode;
232pub mod bit;
233pub mod border;
234pub mod brush;
235mod build;
236pub mod button;
237pub mod canvas;
238pub mod check_box;
239pub mod color;
240mod control;
241pub mod curve;
242pub mod decorator;
243pub mod dock;
244pub mod draw;
245pub mod dropdown_list;
246pub mod dropdown_menu;
247pub mod expander;
248pub mod file_browser;
249pub mod font;
250pub mod formatted_text;
251pub mod grid;
252pub mod image;
253pub mod input;
254pub mod inspector;
255pub mod key;
256pub mod list_view;
257pub mod loader;
258pub mod log;
259pub mod matrix;
260pub mod menu;
261pub mod message;
262pub mod messagebox;
263pub mod navigation;
264pub mod nine_patch;
265mod node;
266pub mod numeric;
267pub mod path;
268pub mod popup;
269pub mod progress_bar;
270pub mod range;
271pub mod rect;
272pub mod resources;
273pub mod screen;
274pub mod scroll_bar;
275pub mod scroll_panel;
276pub mod scroll_viewer;
277pub mod searchbar;
278pub mod selector;
279pub mod stack_panel;
280pub mod style;
281pub mod tab_control;
282pub mod test;
283pub mod text;
284pub mod text_box;
285mod thickness;
286pub mod thumb;
287pub mod toggle;
288pub mod tree;
289pub mod utils;
290pub mod uuid;
291pub mod vec;
292pub mod vector_image;
293pub mod widget;
294pub mod window;
295pub mod wrap_panel;
296
297use crate::{
298    brush::Brush,
299    canvas::Canvas,
300    constructor::WidgetConstructorContainer,
301    container::WidgetContainer,
302    core::{
303        algebra::{Matrix3, Vector2},
304        color::Color,
305        futures::future::join_all,
306        log::Log,
307        math::Rect,
308        parking_lot::Mutex,
309        pool::{Handle, ObjectOrVariant, Pool, Ticket},
310        reflect::prelude::*,
311        uuid::{uuid, Uuid},
312        uuid_provider,
313        visitor::prelude::*,
314        SafeLock, TypeUuidProvider,
315    },
316    draw::{CommandTexture, Draw, DrawingContext},
317    font::{FontResource, BUILT_IN_FONT},
318    message::{
319        ButtonState, CursorIcon, KeyboardModifiers, MessageDirection, MouseButton, OsEvent,
320        UiMessage,
321    },
322    message::{DeliveryMode, MessageData, RoutingStrategy},
323    popup::{Placement, PopupMessage},
324    style::{
325        resource::{StyleResource, StyleResourceExt},
326        Style, DEFAULT_STYLE,
327    },
328    widget::{Widget, WidgetBuilder, WidgetMaterial, WidgetMessage},
329};
330use copypasta::ClipboardContext;
331use fxhash::{FxHashMap, FxHashSet};
332pub use fyrox_animation as generic_animation;
333use fyrox_graph::{NodeHandleMap, NodeMapping, PrefabData, SceneGraph, SceneGraphNode};
334use fyrox_resource::{
335    io::{FsResourceIo, ResourceIo},
336    manager::ResourceManager,
337    untyped::UntypedResource,
338    Resource, ResourceData,
339};
340use fyrox_texture::TextureResource;
341use serde::{Deserialize, Serialize};
342use std::{
343    any::TypeId,
344    cell::{Ref, RefCell, RefMut},
345    collections::{btree_set::BTreeSet, hash_map::Entry, VecDeque},
346    error::Error,
347    fmt::{Debug, Formatter, Write},
348    ops::{Deref, DerefMut, Index, IndexMut},
349    path::Path,
350    sync::{
351        mpsc::{self, Receiver, Sender},
352        Arc,
353    },
354};
355use strum_macros::{AsRefStr, EnumString, VariantNames};
356
357pub use alignment::*;
358pub use build::*;
359pub use control::*;
360use fyrox_core::algebra::Point2;
361use fyrox_core::dyntype::{DynTypeConstructorContainer, DynTypeContainer};
362use fyrox_core::pool::PoolError;
363pub use fyrox_texture as texture;
364pub use node::*;
365pub use thickness::*;
366
367#[derive(Default, Clone, Reflect, Debug)]
368pub(crate) struct RcUiNodeHandleInner {
369    handle: Handle<UiNode>,
370    #[reflect(hidden)]
371    sender: Option<Sender<UiMessage>>,
372}
373
374impl Visit for RcUiNodeHandleInner {
375    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
376        self.handle.visit(name, visitor)?;
377
378        if visitor.is_reading() {
379            self.sender = Some(
380                visitor
381                    .blackboard
382                    .get::<Sender<UiMessage>>()
383                    .expect("Ui message sender must be provided for correct deserialization!")
384                    .clone(),
385            );
386        }
387
388        Ok(())
389    }
390}
391
392impl Drop for RcUiNodeHandleInner {
393    fn drop(&mut self) {
394        if let Some(sender) = self.sender.as_ref() {
395            let _ = sender.send(UiMessage::for_widget(self.handle, WidgetMessage::Remove));
396        } else {
397            Log::warn(format!(
398                "There's no message sender for shared handle {}. The object \
399            won't be destroyed.",
400                self.handle
401            ))
402        }
403    }
404}
405
406/// Reference counted handle to a widget. It is used to automatically destroy the widget it points
407/// to when the reference counter reaches zero. Its main usage in the library is to store handles
408/// to context menus that could be shared across multiple widgets.
409#[derive(Clone, Default, Visit, Reflect, TypeUuidProvider)]
410#[type_uuid(id = "9111a53b-05dc-4c75-aab1-71d5b1c93311")]
411pub struct RcUiNodeHandle(Arc<Mutex<RcUiNodeHandleInner>>);
412
413impl Debug for RcUiNodeHandle {
414    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
415        let handle = self.0.safe_lock().handle;
416
417        writeln!(
418            f,
419            "RcUiNodeHandle - {}:{} with {} uses",
420            handle.index(),
421            handle.generation(),
422            Arc::strong_count(&self.0)
423        )
424    }
425}
426
427impl PartialEq for RcUiNodeHandle {
428    fn eq(&self, other: &Self) -> bool {
429        let a = self.0.safe_lock().handle;
430        let b = other.0.safe_lock().handle;
431        a == b
432    }
433}
434
435impl RcUiNodeHandle {
436    /// Creates a new reference counted widget handle.
437    #[inline]
438    pub fn new(handle: Handle<impl ObjectOrVariant<UiNode>>, sender: Sender<UiMessage>) -> Self {
439        Self(Arc::new(Mutex::new(RcUiNodeHandleInner {
440            handle: handle.to_base(),
441            sender: Some(sender),
442        })))
443    }
444
445    /// Returns the inner handle.
446    #[inline]
447    pub fn handle(&self) -> Handle<UiNode> {
448        self.0.safe_lock().handle
449    }
450}
451
452/// Orientation of something.
453#[derive(
454    Copy,
455    Clone,
456    Debug,
457    PartialEq,
458    Eq,
459    Visit,
460    Reflect,
461    Default,
462    Serialize,
463    Deserialize,
464    AsRefStr,
465    EnumString,
466    VariantNames,
467)]
468pub enum Orientation {
469    /// Vertical orientation. This is default value.
470    #[default]
471    Vertical,
472    /// Horizontal orientation.
473    Horizontal,
474}
475
476uuid_provider!(Orientation = "1c6ad1b0-3f4c-48be-87dd-6929cb3577bf");
477
478#[derive(Default, Clone)]
479pub struct NodeStatistics(pub FxHashMap<&'static str, isize>);
480
481impl NodeStatistics {
482    pub fn new(ui: &UserInterface) -> NodeStatistics {
483        let mut statistics = Self::default();
484        for node in ui.nodes.iter() {
485            statistics
486                .0
487                .entry(BaseControl::type_name(&*node.0))
488                .and_modify(|counter| *counter += 1)
489                .or_insert(1);
490        }
491        statistics
492    }
493
494    fn unite_type_names(&self, prev_stats: &NodeStatistics) -> BTreeSet<&'static str> {
495        let mut union = BTreeSet::default();
496        for stats in [self, prev_stats] {
497            for &type_name in stats.0.keys() {
498                union.insert(type_name);
499            }
500        }
501        union
502    }
503
504    fn count_of(&self, type_name: &str) -> isize {
505        self.0.get(type_name).cloned().unwrap_or_default()
506    }
507
508    pub fn print_diff(&self, prev_stats: &NodeStatistics, show_unchanged: bool) {
509        println!("**** Diff UI Node Statistics ****");
510        for type_name in self.unite_type_names(prev_stats) {
511            let count = self.count_of(type_name);
512            let prev_count = prev_stats.count_of(type_name);
513            let delta = count - prev_count;
514            if delta != 0 || show_unchanged {
515                println!("{type_name}: \x1b[93m{delta}\x1b[0m");
516            }
517        }
518    }
519
520    pub fn print_changed(&self, prev_stats: &NodeStatistics) {
521        println!("**** Changed UI Node Statistics ****");
522        for type_name in self.unite_type_names(prev_stats) {
523            let count = self.count_of(type_name);
524            let prev_count = prev_stats.count_of(type_name);
525            if count - prev_count != 0 {
526                println!("{type_name}: \x1b[93m{count}\x1b[0m");
527            }
528        }
529    }
530}
531
532#[derive(Visit, Reflect, Debug, Clone)]
533pub struct DragContext {
534    pub is_dragging: bool,
535    pub drag_node: Handle<UiNode>,
536    pub click_pos: Vector2<f32>,
537    pub drag_preview: Handle<UiNode>,
538}
539
540impl Default for DragContext {
541    fn default() -> Self {
542        Self {
543            is_dragging: false,
544            drag_node: Default::default(),
545            click_pos: Vector2::new(0.0, 0.0),
546            drag_preview: Default::default(),
547        }
548    }
549}
550
551#[derive(Copy, Clone, Debug, Eq, PartialEq, Visit, Reflect)]
552pub struct MouseState {
553    pub left: ButtonState,
554    pub right: ButtonState,
555    pub middle: ButtonState,
556    // TODO Add rest of buttons
557}
558
559impl Default for MouseState {
560    fn default() -> Self {
561        Self {
562            left: ButtonState::Released,
563            right: ButtonState::Released,
564            middle: ButtonState::Released,
565        }
566    }
567}
568
569#[derive(Copy, Clone, Visit, Reflect, Debug, Default)]
570pub struct RestrictionEntry {
571    /// Handle to UI node to which picking must be restricted to.
572    pub handle: Handle<UiNode>,
573
574    /// A flag that tells the UI to stop iterating over picking stack.
575    /// There are two use cases: chain of menus (popups) and set of modal windows. In case of
576    ///  menus, you need to restrict picking to an entire chain, but leave the possibility to select
577    /// any menu in the chain. In the case of multiple modal windows, you need to restrict picking
578    /// individually per window, not allowing to pick anything behind modal window, but still
579    /// save restrictions in the entire chain of modal windows, so if topmost closes, restriction
580    /// will be on the previous one and so on.
581    pub stop: bool,
582}
583
584#[derive(Clone, Debug)]
585pub struct TooltipEntry {
586    pub tooltip: RcUiNodeHandle,
587    pub appear_timer: f32,
588    pub shown: bool,
589    /// Time remaining until this entry should disappear (in seconds).
590    pub disappear_timer: f32,
591    /// The Maximum time that it should be kept for
592    /// This is stored here as well, because when hovering
593    /// over the tooltip, we don't know the time it should stay for, and
594    /// so we use this to refresh the timer.
595    pub max_time: f32,
596}
597
598impl TooltipEntry {
599    fn new(tooltip: RcUiNodeHandle, appear_timeout: f32, disappear_timeout: f32) -> TooltipEntry {
600        Self {
601            tooltip,
602            appear_timer: appear_timeout,
603            shown: false,
604            disappear_timer: disappear_timeout,
605            max_time: disappear_timeout,
606        }
607    }
608}
609
610#[derive(Debug)]
611pub enum LayoutEvent {
612    MeasurementInvalidated(Handle<UiNode>),
613    ArrangementInvalidated(Handle<UiNode>),
614    VisualInvalidated(Handle<UiNode>),
615    VisibilityChanged(Handle<UiNode>),
616    ZIndexChanged(Handle<UiNode>),
617    TransformChanged(Handle<UiNode>),
618}
619
620#[derive(Clone, Debug, Visit, Reflect, Default)]
621struct DoubleClickEntry {
622    timer: f32,
623    click_count: u32,
624}
625
626struct Clipboard(Option<RefCell<ClipboardContext>>);
627
628impl Debug for Clipboard {
629    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
630        write!(f, "Clipboard")
631    }
632}
633
634#[derive(Default, Debug, Clone)]
635struct WidgetMethodsRegistry {
636    preview_message: FxHashSet<Handle<UiNode>>,
637    on_update: FxHashSet<Handle<UiNode>>,
638    handle_os_event: FxHashSet<Handle<UiNode>>,
639}
640
641impl WidgetMethodsRegistry {
642    fn register<T: Control + ?Sized>(&mut self, node: &T) {
643        let node_handle = node.handle();
644
645        if node.preview_messages && !self.preview_message.insert(node_handle) {
646            Log::warn(format!(
647                "Widget {node_handle} `preview_message` method is already registered!"
648            ));
649        }
650        if node.handle_os_events && !self.handle_os_event.insert(node_handle) {
651            Log::warn(format!(
652                "Widget {node_handle} `handle_os_event` method is already registered!"
653            ));
654        }
655        if node.need_update && !self.on_update.insert(node_handle) {
656            Log::warn(format!(
657                "Widget {node_handle} `on_update` method is already registered!"
658            ));
659        }
660    }
661
662    fn unregister<T: Control + ?Sized>(&mut self, node: &T) {
663        let node_handle = node.handle();
664
665        self.preview_message.remove(&node_handle);
666        self.on_update.remove(&node_handle);
667        self.handle_os_event.remove(&node_handle);
668    }
669}
670
671/// A set of switches that allows you to disable a particular step of UI update pipeline.
672#[derive(Clone, PartialEq, Eq, Default)]
673pub struct UiUpdateSwitches {
674    /// A set of nodes that will be updated, everything else won't be updated.
675    pub node_overrides: Option<FxHashSet<Handle<UiNode>>>,
676}
677
678pub type WidgetPool = Pool<UiNode, WidgetContainer>;
679
680#[derive(Default, Debug, Clone, Reflect, Visit)]
681pub enum RenderMode {
682    /// The UI will be re-rendered on every frame. This is the default behavior.
683    #[default]
684    EveryFrame,
685    /// The UI will be re-rendered only if there was any message with [`MessageDirection::ToWidget`]
686    /// sent to it. This option can be useful for offscreen rending of a user interface that changes
687    /// infrequently.
688    OnChanges,
689}
690
691#[derive(Reflect)]
692pub struct UserInterface {
693    screen_size: Vector2<f32>,
694    nodes: WidgetPool,
695    #[reflect(hidden)]
696    pub drawing_context: DrawingContext,
697    visual_debug: bool,
698    root_canvas: Handle<UiNode>,
699    picked_node: Handle<UiNode>,
700    prev_picked_node: Handle<UiNode>,
701    captured_node: Handle<UiNode>,
702    keyboard_focus_node: Handle<UiNode>,
703    cursor_position: Vector2<f32>,
704    pub style: StyleResource,
705    #[reflect(hidden)]
706    receiver: Receiver<UiMessage>,
707    #[reflect(hidden)]
708    sender: Sender<UiMessage>,
709    stack: Vec<Handle<UiNode>>,
710    picking_stack: Vec<RestrictionEntry>,
711    #[reflect(hidden)]
712    bubble_queue: VecDeque<Handle<UiNode>>,
713    drag_context: DragContext,
714    mouse_state: MouseState,
715    keyboard_modifiers: KeyboardModifiers,
716    cursor_icon: CursorIcon,
717    #[reflect(hidden)]
718    active_tooltip: Option<TooltipEntry>,
719    #[reflect(hidden)]
720    methods_registry: WidgetMethodsRegistry,
721    #[reflect(hidden)]
722    clipboard: Clipboard,
723    #[reflect(hidden)]
724    layout_events_receiver: Receiver<LayoutEvent>,
725    #[reflect(hidden)]
726    layout_events_sender: Sender<LayoutEvent>,
727    #[reflect(hidden)]
728    z_index_update_set: FxHashSet<Handle<UiNode>>,
729    #[reflect(hidden)]
730    pub default_font: FontResource,
731    #[reflect(hidden)]
732    double_click_entries: FxHashMap<MouseButton, DoubleClickEntry>,
733    pub double_click_time_slice: f32,
734    pub tooltip_appear_delay: f32,
735    pub standard_material: WidgetMaterial,
736    /// Optional render target of the user interface. The UI will be rendered in such target with
737    /// and the target size will be set to the screen size of the user interface.
738    pub render_target: Option<TextureResource>,
739    /// Render mode of the user interface. See [`RenderMode`] docs for more info.
740    pub render_mode: RenderMode,
741    /// A flag that indicates that the UI should be rendered. It is only taken into account if
742    /// the render mode is set to [`RenderMode::OnChanges`].
743    pub need_render: bool,
744    pub user_data: DynTypeContainer,
745}
746
747impl Debug for UserInterface {
748    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
749        f.debug_struct("UserInterface")
750            .field("screen_size", &self.screen_size)
751            .field("drawing_context", &self.drawing_context)
752            .field("visual_debug", &self.visual_debug)
753            .field("root_canvas", &self.root_canvas)
754            .field("picked_node", &self.picked_node)
755            .field("prev_picked_node", &self.prev_picked_node)
756            .field("captured_node", &self.captured_node)
757            .field("keyboard_focus_node", &self.keyboard_focus_node)
758            .field("cursor_position", &self.cursor_position)
759            .field("style", &self.style)
760            .field("receiver", &self.receiver)
761            .field("sender", &self.sender)
762            .field("stack", &self.stack)
763            .field("picking_stack", &self.picking_stack)
764            .field("bubble_queue", &self.bubble_queue)
765            .field("drag_context", &self.drag_context)
766            .field("mouse_state", &self.mouse_state)
767            .field("keyboard_modifiers", &self.keyboard_modifiers)
768            .field("cursor_icon", &self.cursor_icon)
769            .field("active_tooltip", &self.active_tooltip)
770            .field("methods_registry", &self.methods_registry)
771            .field("clipboard", &self.clipboard)
772            .field("layout_events_receiver", &self.layout_events_receiver)
773            .field("layout_events_sender", &self.layout_events_sender)
774            .field("z_index_update_set", &self.z_index_update_set)
775            .field("default_font", &self.default_font)
776            .field("double_click_entries", &self.double_click_entries)
777            .field("double_click_time_slice", &self.double_click_time_slice)
778            .field("tooltip_appear_delay", &self.tooltip_appear_delay)
779            .field("standard_material", &self.standard_material)
780            .field("render_target", &self.render_target)
781            .field("render_mode", &self.render_mode)
782            .field("need_render", &self.need_render)
783            .field("user_data", &self.user_data)
784            .finish()?;
785        f.write_char('\n')?;
786        f.write_str(&self.summary())
787    }
788}
789
790impl Visit for UserInterface {
791    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
792        let mut region = visitor.enter_region(name)?;
793
794        if region.is_reading() {
795            self.nodes.clear();
796            self.root_canvas = Handle::NONE;
797            self.methods_registry = Default::default();
798        }
799
800        self.screen_size.visit("ScreenSize", &mut region)?;
801        self.nodes.visit("Nodes", &mut region)?;
802        self.visual_debug.visit("VisualDebug", &mut region)?;
803        self.root_canvas.visit("RootCanvas", &mut region)?;
804        self.picked_node.visit("PickedNode", &mut region)?;
805        self.prev_picked_node.visit("PrevPickedNode", &mut region)?;
806        self.captured_node.visit("CapturedNode", &mut region)?;
807        self.keyboard_focus_node
808            .visit("KeyboardFocusNode", &mut region)?;
809        self.cursor_position.visit("CursorPosition", &mut region)?;
810        self.picking_stack.visit("PickingStack", &mut region)?;
811        self.drag_context.visit("DragContext", &mut region)?;
812        self.mouse_state.visit("MouseState", &mut region)?;
813        self.keyboard_modifiers
814            .visit("KeyboardModifiers", &mut region)?;
815        self.cursor_icon.visit("CursorIcon", &mut region)?;
816        self.double_click_time_slice
817            .visit("DoubleClickTimeSlice", &mut region)?;
818        self.tooltip_appear_delay
819            .visit("TooltipAppearDelay", &mut region)?;
820        self.standard_material
821            .visit("StandardMaterial", &mut region)?;
822        self.render_mode.visit("RenderMode", &mut region)?;
823        Log::verify(self.user_data.visit("UserData", &mut region));
824
825        if region.is_reading() {
826            for node in self.nodes.iter() {
827                self.methods_registry.register(node.deref());
828            }
829        }
830
831        Ok(())
832    }
833}
834
835impl Clone for UserInterface {
836    fn clone(&self) -> Self {
837        let (sender, receiver) = mpsc::channel();
838        let (layout_events_sender, layout_events_receiver) = mpsc::channel();
839        let mut nodes = Pool::new();
840        for (handle, node) in self.nodes.pair_iter() {
841            let mut clone = node.clone_boxed();
842            clone.layout_events_sender = Some(layout_events_sender.clone());
843            nodes.spawn_at_handle(handle, UiNode(clone)).unwrap();
844        }
845
846        Self {
847            screen_size: self.screen_size,
848            nodes,
849            drawing_context: self.drawing_context.clone(),
850            visual_debug: self.visual_debug,
851            root_canvas: self.root_canvas,
852            picked_node: self.picked_node,
853            prev_picked_node: self.prev_picked_node,
854            captured_node: self.captured_node,
855            keyboard_focus_node: self.keyboard_focus_node,
856            cursor_position: self.cursor_position,
857            style: DEFAULT_STYLE.resource.clone(),
858            receiver,
859            sender,
860            stack: self.stack.clone(),
861            picking_stack: self.picking_stack.clone(),
862            bubble_queue: self.bubble_queue.clone(),
863            drag_context: self.drag_context.clone(),
864            mouse_state: self.mouse_state,
865            keyboard_modifiers: self.keyboard_modifiers,
866            cursor_icon: self.cursor_icon,
867            active_tooltip: self.active_tooltip.clone(),
868            methods_registry: self.methods_registry.clone(),
869            clipboard: Clipboard(ClipboardContext::new().ok().map(RefCell::new)),
870            layout_events_receiver,
871            layout_events_sender,
872            z_index_update_set: self.z_index_update_set.clone(),
873            default_font: self.default_font.clone(),
874            double_click_entries: self.double_click_entries.clone(),
875            double_click_time_slice: self.double_click_time_slice,
876            tooltip_appear_delay: self.tooltip_appear_delay,
877            standard_material: Default::default(),
878            render_target: None,
879            render_mode: Default::default(),
880            need_render: self.need_render,
881            user_data: self.user_data.clone(),
882        }
883    }
884}
885
886impl Default for UserInterface {
887    fn default() -> Self {
888        Self::new(Vector2::new(100.0, 100.0))
889    }
890}
891
892#[inline(always)]
893fn invalidate_recursive_up(
894    nodes: &Pool<UiNode, WidgetContainer>,
895    node: Handle<UiNode>,
896    callback: fn(&UiNode),
897) {
898    if let Ok(node_ref) = nodes.try_borrow(node) {
899        callback(node_ref);
900        if node_ref.parent().is_some() {
901            invalidate_recursive_up(nodes, node_ref.parent(), callback);
902        }
903    }
904}
905
906#[derive(Default)]
907pub struct UiContainer {
908    pool: Pool<UserInterface>,
909}
910
911impl UiContainer {
912    /// Creates a new user interface container.
913    pub fn new() -> Self {
914        Self::default()
915    }
916
917    /// Returns a reference to the first user interface in the container. Panics, if the container
918    /// is empty.
919    pub fn first(&self) -> &UserInterface {
920        self.pool
921            .first_ref()
922            .expect("The container must have at least one user interface.")
923    }
924
925    /// Returns a reference to the first user interface in the container. Panics, if the container
926    /// is empty.
927    pub fn first_mut(&mut self) -> &mut UserInterface {
928        self.pool
929            .first_mut()
930            .expect("The container must have at least one user interface.")
931    }
932
933    /// Return true if given handle is valid and "points" to "alive" user interface.
934    pub fn is_valid_handle(&self, handle: Handle<UserInterface>) -> bool {
935        self.pool.is_valid_handle(handle)
936    }
937
938    /// Returns pair iterator which yields (handle, user_interface_ref) pairs.
939    pub fn pair_iter(&self) -> impl Iterator<Item = (Handle<UserInterface>, &UserInterface)> {
940        self.pool.pair_iter()
941    }
942
943    /// Returns pair iterator which yields (handle, user_interface_ref) pairs.
944    pub fn pair_iter_mut(
945        &mut self,
946    ) -> impl Iterator<Item = (Handle<UserInterface>, &mut UserInterface)> {
947        self.pool.pair_iter_mut()
948    }
949
950    /// Tries to borrow a user interface using its handle.
951    pub fn try_get(&self, handle: Handle<UserInterface>) -> Result<&UserInterface, PoolError> {
952        self.pool.try_borrow(handle)
953    }
954
955    /// Tries to borrow a user interface using its handle.
956    pub fn try_get_mut(
957        &mut self,
958        handle: Handle<UserInterface>,
959    ) -> Result<&mut UserInterface, PoolError> {
960        self.pool.try_borrow_mut(handle)
961    }
962
963    /// Creates new iterator over user interfaces in container.
964    #[inline]
965    pub fn iter(&self) -> impl Iterator<Item = &UserInterface> {
966        self.pool.iter()
967    }
968
969    /// Creates new mutable iterator over user interfaces in container.
970    #[inline]
971    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut UserInterface> {
972        self.pool.iter_mut()
973    }
974
975    /// Adds a new user interface into the container.
976    #[inline]
977    pub fn add(&mut self, scene: UserInterface) -> Handle<UserInterface> {
978        self.pool.spawn(scene)
979    }
980
981    /// Removes all user interfaces from container.
982    #[inline]
983    pub fn clear(&mut self) {
984        self.pool.clear()
985    }
986
987    /// Removes the given user interface from the container. The user interface will be destroyed
988    /// immediately.
989    #[inline]
990    pub fn remove(&mut self, handle: Handle<UserInterface>) {
991        self.pool.free(handle);
992    }
993
994    /// Takes a user interface from the container and transfers ownership to caller. You must either
995    /// put the user interface back using ticket or call `forget_ticket` to make memory used by the
996    /// user interface vacant again.
997    pub fn take_reserve(
998        &mut self,
999        handle: Handle<UserInterface>,
1000    ) -> (Ticket<UserInterface>, UserInterface) {
1001        self.pool.take_reserve(handle)
1002    }
1003
1004    /// Puts a user interface back to the container using its ticket.
1005    pub fn put_back(
1006        &mut self,
1007        ticket: Ticket<UserInterface>,
1008        scene: UserInterface,
1009    ) -> Handle<UserInterface> {
1010        self.pool.put_back(ticket, scene)
1011    }
1012
1013    /// Forgets ticket of a user interface, making place at which ticket points, vacant again.
1014    pub fn forget_ticket(&mut self, ticket: Ticket<UserInterface>) {
1015        self.pool.forget_ticket(ticket)
1016    }
1017}
1018
1019impl<T: ObjectOrVariant<UiNode>> Index<Handle<T>> for UserInterface {
1020    type Output = T;
1021
1022    #[inline]
1023    fn index(&self, index: Handle<T>) -> &Self::Output {
1024        self.try_get(index).unwrap()
1025    }
1026}
1027
1028impl<T: ObjectOrVariant<UiNode>> IndexMut<Handle<T>> for UserInterface {
1029    #[inline]
1030    fn index_mut(&mut self, index: Handle<T>) -> &mut Self::Output {
1031        self.try_get_mut(index).unwrap()
1032    }
1033}
1034
1035impl Index<Handle<UserInterface>> for UiContainer {
1036    type Output = UserInterface;
1037
1038    #[inline]
1039    fn index(&self, index: Handle<UserInterface>) -> &Self::Output {
1040        &self.pool[index]
1041    }
1042}
1043
1044impl IndexMut<Handle<UserInterface>> for UiContainer {
1045    #[inline]
1046    fn index_mut(&mut self, index: Handle<UserInterface>) -> &mut Self::Output {
1047        &mut self.pool[index]
1048    }
1049}
1050
1051fn is_on_screen(node: &UiNode, nodes: &Pool<UiNode, WidgetContainer>) -> bool {
1052    // Crawl up on tree and check if current bounds are intersects with every screen bound
1053    // of parents chain. This is needed because some control can move their children outside
1054    // their bounds (like scroll viewer, etc.) and single intersection test of parent bounds with
1055    // current bounds is not enough.
1056    let bounds = node.clip_bounds();
1057    let mut parent = node.parent();
1058    while parent.is_some() {
1059        let parent_node = nodes.borrow(parent);
1060        if !parent_node.clip_bounds().intersects(bounds) {
1061            return false;
1062        }
1063        parent = parent_node.parent();
1064    }
1065    true
1066}
1067
1068fn draw_node(
1069    nodes: &Pool<UiNode, WidgetContainer>,
1070    node_handle: Handle<UiNode>,
1071    drawing_context: &mut DrawingContext,
1072    mut enabled: bool,
1073) {
1074    let node = &nodes[node_handle];
1075    if node.visual_valid.get() {
1076        return;
1077    }
1078
1079    enabled &= node.enabled();
1080
1081    let pushed = if !enabled {
1082        drawing_context.push_opacity(0.4);
1083        true
1084    } else if let Some(opacity) = node.opacity() {
1085        drawing_context.push_opacity(opacity);
1086        true
1087    } else {
1088        false
1089    };
1090
1091    drawing_context.transform_stack.push(node.visual_transform);
1092
1093    // Draw
1094    {
1095        node.draw(drawing_context);
1096        drawing_context
1097            .copy_render_data_and_clear(&mut node.render_data_set.borrow_mut().draw_result);
1098    }
1099
1100    // Continue on children
1101    for &child_node in node.children().iter() {
1102        draw_node(nodes, child_node, drawing_context, enabled);
1103    }
1104
1105    // Post draw.
1106    {
1107        node.post_draw(drawing_context);
1108
1109        drawing_context
1110            .copy_render_data_and_clear(&mut node.render_data_set.borrow_mut().post_draw_result);
1111    }
1112
1113    drawing_context.transform_stack.pop();
1114
1115    if pushed {
1116        drawing_context.pop_opacity();
1117    }
1118
1119    node.visual_valid.set(true);
1120}
1121
1122#[derive(Debug)]
1123pub struct SubGraph {
1124    pub root: (Ticket<UiNode>, UiNode),
1125
1126    pub descendants: Vec<(Ticket<UiNode>, UiNode)>,
1127
1128    pub parent: Handle<UiNode>,
1129}
1130
1131fn remap_handles(old_new_mapping: &NodeHandleMap<UiNode>, ui: &mut UserInterface) {
1132    // Iterate over instantiated nodes and remap handles.
1133    for (_, &new_node_handle) in old_new_mapping.inner().iter() {
1134        old_new_mapping.remap_handles(
1135            &mut ui.nodes[new_node_handle],
1136            &[TypeId::of::<UntypedResource>()],
1137        );
1138    }
1139}
1140
1141struct VisualTransformUpdateData {
1142    roots: FxHashSet<Handle<UiNode>>,
1143    visited: Vec<bool>,
1144}
1145
1146pub struct PollResult {
1147    pub processed_messages: usize,
1148    pub message: Option<UiMessage>,
1149}
1150
1151impl UserInterface {
1152    pub fn new(screen_size: Vector2<f32>) -> UserInterface {
1153        let (sender, receiver) = mpsc::channel();
1154        Self::new_with_channel(sender, receiver, screen_size)
1155    }
1156
1157    pub fn new_with_channel(
1158        sender: Sender<UiMessage>,
1159        receiver: Receiver<UiMessage>,
1160        screen_size: Vector2<f32>,
1161    ) -> UserInterface {
1162        let (layout_events_sender, layout_events_receiver) = mpsc::channel();
1163        let style = DEFAULT_STYLE.resource.clone();
1164        let mut ui = UserInterface {
1165            screen_size,
1166            sender,
1167            receiver,
1168            visual_debug: false,
1169            captured_node: Handle::NONE,
1170            root_canvas: Handle::NONE,
1171            nodes: Pool::new(),
1172            cursor_position: Vector2::new(0.0, 0.0),
1173            drawing_context: DrawingContext::new(style.clone()),
1174            picked_node: Handle::NONE,
1175            prev_picked_node: Handle::NONE,
1176            style,
1177            keyboard_focus_node: Handle::NONE,
1178            stack: Default::default(),
1179            picking_stack: Default::default(),
1180            bubble_queue: Default::default(),
1181            drag_context: Default::default(),
1182            mouse_state: Default::default(),
1183            keyboard_modifiers: Default::default(),
1184            cursor_icon: Default::default(),
1185            active_tooltip: Default::default(),
1186            methods_registry: Default::default(),
1187            clipboard: Clipboard(ClipboardContext::new().ok().map(RefCell::new)),
1188            layout_events_receiver,
1189            layout_events_sender,
1190            z_index_update_set: Default::default(),
1191            default_font: BUILT_IN_FONT.resource(),
1192            double_click_entries: Default::default(),
1193            double_click_time_slice: 0.5, // 500 ms is standard in most operating systems.
1194            tooltip_appear_delay: 0.55,
1195            standard_material: Default::default(),
1196            render_target: None,
1197            render_mode: Default::default(),
1198            need_render: true,
1199            user_data: Default::default(),
1200        };
1201        let root_node = UiNode::new(Canvas {
1202            widget: WidgetBuilder::new().build(&ui.build_ctx()),
1203        });
1204        ui.root_canvas = ui.add_node(root_node);
1205        ui.keyboard_focus_node = ui.root_canvas;
1206        ui
1207    }
1208
1209    fn recursive_summary(&self, indent: usize, current: Handle<UiNode>, result: &mut String) {
1210        for _ in 0..indent {
1211            result.push_str("  ");
1212        }
1213        let Ok(node) = self.try_get(current) else {
1214            use std::fmt::Write;
1215            writeln!(result, "{}: Failed to get", current).unwrap();
1216            return;
1217        };
1218        result.push_str(&node.summary());
1219        result.push('\n');
1220        for child in node.children() {
1221            self.recursive_summary(indent + 1, *child, result);
1222        }
1223    }
1224
1225    pub fn set_tooltip_appear_delay(&mut self, appear_delay: f32) {
1226        self.tooltip_appear_delay = appear_delay;
1227    }
1228
1229    pub fn tooltip_appear_delay(&self) -> f32 {
1230        self.tooltip_appear_delay
1231    }
1232
1233    pub fn active_tooltip(&self) -> Option<&TooltipEntry> {
1234        self.active_tooltip.as_ref()
1235    }
1236
1237    pub fn keyboard_modifiers(&self) -> KeyboardModifiers {
1238        self.keyboard_modifiers
1239    }
1240
1241    pub fn build_ctx(&mut self) -> BuildContext<'_> {
1242        self.into()
1243    }
1244
1245    #[inline]
1246    pub fn capture_mouse(&mut self, node: Handle<impl ObjectOrVariant<UiNode>>) -> bool {
1247        let node = node.to_base();
1248        if self.captured_node.is_none() {
1249            self.captured_node = node;
1250            true
1251        } else {
1252            false
1253        }
1254    }
1255
1256    #[inline]
1257    pub fn release_mouse_capture(&mut self) {
1258        self.captured_node = Handle::NONE;
1259    }
1260
1261    #[inline]
1262    pub fn is_node_enabled(&self, mut handle: Handle<UiNode>) -> bool {
1263        while let Ok(node) = self.nodes.try_get(handle) {
1264            if !node.enabled() {
1265                return false;
1266            }
1267            handle = node.parent();
1268        }
1269        true
1270    }
1271
1272    fn update_global_visibility(&mut self, from: Handle<UiNode>) {
1273        self.stack.clear();
1274        self.stack.push(from);
1275        while let Some(node_handle) = self.stack.pop() {
1276            let (widget, parent) = self
1277                .nodes
1278                .try_borrow_dependant_mut(node_handle, |n| n.parent());
1279
1280            if let Ok(widget) = widget {
1281                self.stack.extend_from_slice(widget.children());
1282
1283                let visibility = if let Ok(parent) = parent {
1284                    widget.visibility() && parent.is_globally_visible()
1285                } else {
1286                    widget.visibility()
1287                };
1288
1289                if widget.prev_global_visibility != visibility {
1290                    let _ = self
1291                        .layout_events_sender
1292                        .send(LayoutEvent::MeasurementInvalidated(node_handle));
1293                    let _ = self
1294                        .layout_events_sender
1295                        .send(LayoutEvent::ArrangementInvalidated(node_handle));
1296                }
1297
1298                widget.set_global_visibility(visibility);
1299            }
1300        }
1301    }
1302
1303    fn update_visual_transform(&mut self, from: Handle<UiNode>) {
1304        invalidate_recursive_up(&self.nodes, from, |n| n.visual_valid.set(false));
1305
1306        self.stack.clear();
1307        self.stack.push(from);
1308        while let Some(node_handle) = self.stack.pop() {
1309            let (widget, parent) = self
1310                .nodes
1311                .try_borrow_dependant_mut(node_handle, |n| n.parent());
1312
1313            if let Ok(widget) = widget {
1314                if widget.is_globally_visible() {
1315                    self.stack.extend_from_slice(widget.children());
1316
1317                    let mut layout_transform = *widget.layout_transform();
1318
1319                    layout_transform[6] = widget.actual_local_position().x;
1320                    layout_transform[7] = widget.actual_local_position().y;
1321
1322                    let visual_transform = if let Ok(parent) = parent {
1323                        parent.visual_transform() * layout_transform * widget.render_transform()
1324                    } else {
1325                        layout_transform * widget.render_transform()
1326                    };
1327
1328                    let old_transform =
1329                        std::mem::replace(&mut widget.visual_transform, visual_transform);
1330                    widget.on_visual_transform_changed(&old_transform, &visual_transform);
1331                    widget.visual_valid.set(false);
1332                }
1333            }
1334        }
1335    }
1336
1337    pub fn screen_size(&self) -> Vector2<f32> {
1338        self.screen_size
1339    }
1340
1341    pub fn set_screen_size(&mut self, screen_size: Vector2<f32>) {
1342        self.screen_size = screen_size;
1343    }
1344
1345    fn handle_layout_events(&mut self, data: &mut VisualTransformUpdateData) {
1346        while let Ok(layout_event) = self.layout_events_receiver.try_recv() {
1347            match layout_event {
1348                LayoutEvent::MeasurementInvalidated(node) => {
1349                    invalidate_recursive_up(&self.nodes, node, |node_ref| {
1350                        node_ref.measure_valid.set(false);
1351                    });
1352                }
1353                LayoutEvent::ArrangementInvalidated(node) => {
1354                    invalidate_recursive_up(&self.nodes, node, |node_ref| {
1355                        node_ref.arrange_valid.set(false);
1356                    });
1357                }
1358                LayoutEvent::VisualInvalidated(node) => {
1359                    invalidate_recursive_up(&self.nodes, node, |node_ref| {
1360                        node_ref.visual_valid.set(false);
1361                    });
1362                }
1363                LayoutEvent::VisibilityChanged(node) => {
1364                    self.update_global_visibility(node);
1365                }
1366                LayoutEvent::ZIndexChanged(node) => {
1367                    if let Ok(node_ref) = self.nodes.try_borrow(node) {
1368                        // Z index affects the location of the node in its parent's children list.
1369                        // Hash set will remove duplicate requests of z-index updates, thus improving
1370                        // performance.
1371                        self.z_index_update_set.insert(node_ref.parent);
1372                    }
1373                }
1374                LayoutEvent::TransformChanged(node) => {
1375                    let is_visited = &mut data.visited[node.index() as usize];
1376
1377                    if *is_visited {
1378                        continue;
1379                    }
1380
1381                    *is_visited = true;
1382
1383                    data.roots.insert(node);
1384
1385                    // Mark the entire hierarchy as visited.
1386                    fn traverse_recursive(
1387                        graph: &UserInterface,
1388                        from: Handle<UiNode>,
1389                        func: &mut impl FnMut(Handle<UiNode>),
1390                    ) {
1391                        func(from);
1392                        if let Ok(node) = graph.try_get_node(from) {
1393                            for &child in node.children() {
1394                                traverse_recursive(graph, child, func)
1395                            }
1396                        }
1397                    }
1398
1399                    traverse_recursive(self, node, &mut |h| {
1400                        data.visited[h.index() as usize] = true;
1401
1402                        // Remove a descendant from the list of potential roots.
1403                        if h != node && data.roots.contains(&h) {
1404                            data.roots.remove(&h);
1405                        }
1406                    })
1407                }
1408            }
1409        }
1410
1411        // Do z-index sorting.
1412        for node_handle in self.z_index_update_set.drain() {
1413            invalidate_recursive_up(&self.nodes, node_handle, |node_ref| {
1414                node_ref.visual_valid.set(false);
1415            });
1416
1417            let mbc = self.nodes.begin_multi_borrow();
1418            if let Ok(mut node) = mbc.try_get_mut(node_handle) {
1419                node.children.sort_by_key(|handle| {
1420                    mbc.try_get(*handle).map(|c| *c.z_index).unwrap_or_default()
1421                });
1422            };
1423        }
1424    }
1425
1426    pub fn invalidate_layout(&mut self) {
1427        for node in self.nodes.iter_mut() {
1428            node.invalidate_layout();
1429        }
1430    }
1431
1432    pub fn update_layout(&mut self, screen_size: Vector2<f32>) {
1433        self.screen_size = screen_size;
1434
1435        let mut data = VisualTransformUpdateData {
1436            roots: Default::default(),
1437            visited: vec![false; self.nodes.get_capacity() as usize],
1438        };
1439
1440        self.handle_layout_events(&mut data);
1441
1442        self.measure_node(self.root_canvas, screen_size);
1443        self.arrange_node(
1444            self.root_canvas,
1445            &Rect::new(0.0, 0.0, screen_size.x, screen_size.y),
1446        );
1447
1448        // Arrange step may produce changes that affects visual transform.
1449        self.handle_layout_events(&mut data);
1450
1451        for root in data.roots {
1452            self.update_visual_transform(root);
1453
1454            // Recalculate clip bounds, because they depend on the visual transform.
1455            if let Ok(root_ref) = self.try_get_node(root) {
1456                self.calculate_clip_bounds(
1457                    root,
1458                    self.try_get_node(root_ref.parent())
1459                        .ok()
1460                        .map(|c| c.clip_bounds())
1461                        .unwrap_or_else(|| {
1462                            Rect::new(0.0, 0.0, self.screen_size.x, self.screen_size.y)
1463                        }),
1464                );
1465            }
1466        }
1467    }
1468
1469    pub fn update(&mut self, screen_size: Vector2<f32>, dt: f32, switches: &UiUpdateSwitches) {
1470        for entry in self.double_click_entries.values_mut() {
1471            entry.timer -= dt;
1472        }
1473
1474        self.update_layout(screen_size);
1475
1476        if let Some(node_overrides) = switches.node_overrides.as_ref() {
1477            for &handle in node_overrides.iter() {
1478                let (ticket, mut node) = self.nodes.take_reserve(handle);
1479                node.update(dt, self);
1480                self.nodes.put_back(ticket, node);
1481            }
1482        } else {
1483            let update_subs = std::mem::take(&mut self.methods_registry.on_update);
1484            for &handle in update_subs.iter() {
1485                let (ticket, mut node) = self.nodes.take_reserve(handle);
1486                node.update(dt, self);
1487                self.nodes.put_back(ticket, node);
1488            }
1489            self.methods_registry.on_update = update_subs;
1490        }
1491
1492        self.update_tooltips(dt);
1493
1494        // Try to fetch new cursor icon starting from the current picked node. Traverse
1495        // tree up until cursor with different value is found.
1496        self.cursor_icon = CursorIcon::default();
1497        let mut handle = self.picked_node;
1498        while handle.is_some() {
1499            let node = &self.nodes[handle];
1500            if self.drag_context.is_dragging {
1501                if handle != self.drag_context.drag_node {
1502                    if node.accepts_drop(self.drag_context.drag_node, self) {
1503                        self.cursor_icon = CursorIcon::Crosshair;
1504                        break;
1505                    } else {
1506                        self.cursor_icon = CursorIcon::NoDrop;
1507                    }
1508                }
1509            } else if let Some(cursor) = node.cursor() {
1510                self.cursor_icon = cursor;
1511                break;
1512            }
1513            handle = node.parent();
1514        }
1515
1516        self.draw();
1517    }
1518
1519    pub fn style(&self) -> &StyleResource {
1520        &self.style
1521    }
1522
1523    pub fn set_style(&mut self, style: StyleResource) {
1524        self.style = style;
1525
1526        fn notify_depth_first(node: Handle<UiNode>, ui: &UserInterface) {
1527            if let Ok(node_ref) = ui.try_get_node(node) {
1528                for child in node_ref.children.iter() {
1529                    notify_depth_first(*child, ui);
1530                }
1531
1532                ui.send(node, WidgetMessage::Style(ui.style.clone()));
1533            }
1534        }
1535
1536        notify_depth_first(self.root_canvas, self);
1537    }
1538
1539    pub fn cursor(&self) -> CursorIcon {
1540        self.cursor_icon
1541    }
1542
1543    pub fn set_time(&mut self, elapsed_time: f32) {
1544        self.drawing_context.elapsed_time = elapsed_time;
1545    }
1546
1547    fn draw(&mut self) {
1548        self.drawing_context.clear();
1549        draw_node(
1550            &self.nodes,
1551            self.root_canvas,
1552            &mut self.drawing_context,
1553            true,
1554        );
1555
1556        // Merge all render data from all the widgets.
1557        fn merge_recursively<F>(
1558            node_handle: Handle<UiNode>,
1559            nodes: &Pool<UiNode, WidgetContainer>,
1560            drawing_context: &mut DrawingContext,
1561            filter: &mut F,
1562        ) where
1563            F: FnMut(&UiNode) -> bool,
1564        {
1565            let node = &nodes[node_handle];
1566
1567            if !filter(node) {
1568                return;
1569            }
1570
1571            if !node.is_globally_visible() || !is_on_screen(node, nodes) {
1572                return;
1573            }
1574
1575            assert!(node.visual_valid.get());
1576
1577            drawing_context.append(&node.render_data_set.borrow().draw_result);
1578
1579            for child in node.children() {
1580                merge_recursively(*child, nodes, drawing_context, filter);
1581            }
1582
1583            drawing_context.append(&node.render_data_set.borrow().post_draw_result);
1584        }
1585
1586        self.drawing_context.clear();
1587
1588        let mut topmost_nodes = Vec::new();
1589        merge_recursively(
1590            self.root_canvas,
1591            &self.nodes,
1592            &mut self.drawing_context,
1593            &mut |node| {
1594                // Skip topmost nodes. They'll be merged in a separate pass to be rendered on top.
1595                if node.is_draw_on_top() {
1596                    topmost_nodes.push(node.handle);
1597                    false
1598                } else {
1599                    true
1600                }
1601            },
1602        );
1603
1604        for topmost_node in topmost_nodes.drain(..) {
1605            merge_recursively(
1606                topmost_node,
1607                &self.nodes,
1608                &mut self.drawing_context,
1609                &mut |_| true,
1610            );
1611        }
1612
1613        // Debug info rendered on top of others.
1614        if self.visual_debug {
1615            if self.picked_node.is_some() {
1616                let bounds = self.nodes.borrow(self.picked_node).screen_bounds();
1617                self.drawing_context.push_rect(&bounds, 1.0);
1618                self.drawing_context.commit(
1619                    bounds,
1620                    Brush::Solid(Color::WHITE),
1621                    CommandTexture::None,
1622                    &self.standard_material,
1623                    None,
1624                );
1625            }
1626
1627            if self.keyboard_focus_node.is_some() {
1628                let bounds = self.nodes.borrow(self.keyboard_focus_node).screen_bounds();
1629                self.drawing_context.push_rect(&bounds, 1.0);
1630                self.drawing_context.commit(
1631                    bounds,
1632                    Brush::Solid(Color::GREEN),
1633                    CommandTexture::None,
1634                    &self.standard_material,
1635                    None,
1636                );
1637            }
1638        }
1639
1640        if let Ok(keyboard_focus_node) = self.nodes.try_borrow(self.keyboard_focus_node) {
1641            if keyboard_focus_node.global_visibility
1642                && keyboard_focus_node.accepts_input
1643                && is_on_screen(keyboard_focus_node, &self.nodes)
1644            {
1645                let bounds = keyboard_focus_node
1646                    .screen_bounds()
1647                    .clip_by(keyboard_focus_node.clip_bounds())
1648                    .unwrap_or_default()
1649                    .inflate(1.0, 1.0);
1650                self.drawing_context.push_rounded_rect(&bounds, 1.0, 2.0, 6);
1651                self.drawing_context.commit(
1652                    bounds,
1653                    self.style.get_or_default(Style::BRUSH_HIGHLIGHT),
1654                    CommandTexture::None,
1655                    &self.standard_material,
1656                    None,
1657                );
1658            }
1659        }
1660    }
1661
1662    pub fn clipboard(&self) -> Option<Ref<ClipboardContext>> {
1663        self.clipboard.0.as_ref().map(|v| v.borrow())
1664    }
1665
1666    pub fn clipboard_mut(&self) -> Option<RefMut<ClipboardContext>> {
1667        self.clipboard.0.as_ref().map(|v| v.borrow_mut())
1668    }
1669
1670    pub fn arrange_node(
1671        &self,
1672        handle: Handle<impl ObjectOrVariant<UiNode>>,
1673        final_rect: &Rect<f32>,
1674    ) -> bool {
1675        let handle = handle.to_base();
1676        let node = self.node(handle);
1677
1678        if node.is_arrange_valid() && node.prev_arrange.get() == *final_rect {
1679            return false;
1680        }
1681
1682        if node.visibility() {
1683            node.prev_arrange.set(*final_rect);
1684
1685            let margin = node.margin().axes_margin();
1686
1687            let mut size = Vector2::new(
1688                (final_rect.w() - margin.x).max(0.0),
1689                (final_rect.h() - margin.y).max(0.0),
1690            );
1691
1692            let available_size = size;
1693
1694            if node.horizontal_alignment() != HorizontalAlignment::Stretch {
1695                size.x = size.x.min(node.desired_size().x - margin.x);
1696            }
1697            if node.vertical_alignment() != VerticalAlignment::Stretch {
1698                size.y = size.y.min(node.desired_size().y - margin.y);
1699            }
1700
1701            if node.width() > 0.0 {
1702                size.x = node.width();
1703            }
1704            if node.height() > 0.0 {
1705                size.y = node.height();
1706            }
1707
1708            size = transform_size(size, node.layout_transform());
1709
1710            if !node.ignore_layout_rounding {
1711                size.x = size.x.ceil();
1712                size.y = size.y.ceil();
1713            }
1714
1715            size = node.arrange_override(self, size);
1716
1717            size.x = size.x.min(final_rect.w());
1718            size.y = size.y.min(final_rect.h());
1719
1720            let transformed_rect =
1721                Rect::new(0.0, 0.0, size.x, size.y).transform(node.layout_transform());
1722
1723            size = transformed_rect.size;
1724
1725            let mut origin =
1726                final_rect.position - transformed_rect.position + node.margin().offset();
1727
1728            match node.horizontal_alignment() {
1729                HorizontalAlignment::Center | HorizontalAlignment::Stretch => {
1730                    origin.x += (available_size.x - size.x) * 0.5;
1731                }
1732                HorizontalAlignment::Right => origin.x += available_size.x - size.x,
1733                _ => (),
1734            }
1735
1736            match node.vertical_alignment() {
1737                VerticalAlignment::Center | VerticalAlignment::Stretch => {
1738                    origin.y += (available_size.y - size.y) * 0.5;
1739                }
1740                VerticalAlignment::Bottom => origin.y += available_size.y - size.y,
1741                _ => (),
1742            }
1743
1744            if !node.ignore_layout_rounding {
1745                origin.x = origin.x.floor();
1746                origin.y = origin.y.floor();
1747            }
1748
1749            node.commit_arrange(origin, size);
1750        }
1751
1752        true
1753    }
1754
1755    pub fn measure_node(
1756        &self,
1757        handle: Handle<impl ObjectOrVariant<UiNode>>,
1758        available_size: Vector2<f32>,
1759    ) -> bool {
1760        let handle = handle.to_base();
1761        let node = self.node(handle);
1762
1763        if node.is_measure_valid() && node.prev_measure.get() == available_size {
1764            return false;
1765        }
1766
1767        if node.visibility() {
1768            node.prev_measure.set(available_size);
1769
1770            let axes_margin = node.margin().axes_margin();
1771            let mut inner_size = available_size - axes_margin;
1772            inner_size.x = inner_size.x.max(0.0);
1773            inner_size.y = inner_size.y.max(0.0);
1774
1775            let mut size = Vector2::new(
1776                if node.width() > 0.0 {
1777                    node.width()
1778                } else {
1779                    inner_size.x
1780                },
1781                if node.height() > 0.0 {
1782                    node.height()
1783                } else {
1784                    inner_size.y
1785                },
1786            );
1787
1788            size = transform_size(size, node.layout_transform());
1789
1790            if size.x.is_finite() {
1791                size.x = size.x.clamp(node.min_size().x, node.max_size().x);
1792            }
1793            if size.y.is_finite() {
1794                size.y = size.y.clamp(node.min_size().y, node.max_size().y);
1795            }
1796
1797            let mut desired_size = node.measure_override(self, size);
1798
1799            desired_size = Rect::new(0.0, 0.0, desired_size.x, desired_size.y)
1800                .transform(node.layout_transform())
1801                .size;
1802
1803            if !node.width().is_nan() {
1804                desired_size.x = node.width();
1805            }
1806            if !node.height().is_nan() {
1807                desired_size.y = node.height();
1808            }
1809
1810            desired_size.x = desired_size.x.clamp(node.min_size().x, node.max_size().x);
1811            desired_size.y = desired_size.y.clamp(node.min_size().y, node.max_size().y);
1812
1813            desired_size += axes_margin;
1814
1815            if node.ignore_layout_rounding {
1816                desired_size.x = desired_size.x.min(available_size.x);
1817                desired_size.y = desired_size.y.min(available_size.y);
1818            } else {
1819                desired_size.x = desired_size.x.min(available_size.x).ceil();
1820                desired_size.y = desired_size.y.min(available_size.y).ceil();
1821            }
1822
1823            node.commit_measure(desired_size);
1824        } else {
1825            node.commit_measure(Vector2::new(0.0, 0.0));
1826        }
1827
1828        true
1829    }
1830
1831    fn is_node_clipped(&self, node_handle: Handle<UiNode>, pt: Vector2<f32>) -> bool {
1832        let mut clipped = true;
1833
1834        let widget = self.nodes.borrow(node_handle);
1835        let render_data_set = widget.render_data_set.borrow();
1836
1837        if widget.is_globally_visible() {
1838            clipped = !widget.clip_bounds().contains(pt);
1839
1840            if !clipped {
1841                // TODO: Use post draw as well.
1842                for command in render_data_set.draw_result.command_buffer.iter() {
1843                    if let Some(geometry) = command.clipping_geometry.as_ref() {
1844                        if geometry.is_contains_point(pt) {
1845                            clipped = false;
1846                            break;
1847                        }
1848                    }
1849                }
1850            }
1851
1852            // Point can be clipped by parent's clipping geometry.
1853            if !widget.parent().is_none() && !clipped {
1854                clipped |= self.is_node_clipped(widget.parent(), pt);
1855            }
1856        }
1857
1858        clipped
1859    }
1860
1861    fn is_node_contains_point(
1862        &self,
1863        node_handle: Handle<UiNode>,
1864        screen_space_pt: Vector2<f32>,
1865    ) -> bool {
1866        let widget = self.nodes.borrow(node_handle);
1867
1868        // Transform the probe position into the local space of the widget.
1869        let local_space_pt = widget
1870            .visual_transform()
1871            .try_inverse()
1872            .unwrap_or_default()
1873            .transform_point(&Point2::from(screen_space_pt))
1874            .coords;
1875
1876        if !widget.is_globally_visible() {
1877            return false;
1878        }
1879
1880        let render_data_set = widget.render_data_set.borrow();
1881
1882        if !self.is_node_clipped(node_handle, screen_space_pt) {
1883            // TODO: Use post draw as well.
1884            for command in render_data_set.draw_result.command_buffer.iter() {
1885                if render_data_set
1886                    .draw_result
1887                    .is_command_contains_point(command, local_space_pt)
1888                {
1889                    return true;
1890                }
1891            }
1892        }
1893
1894        false
1895    }
1896
1897    fn pick_node(
1898        &self,
1899        node_handle: Handle<UiNode>,
1900        pt: Vector2<f32>,
1901        level: &mut i32,
1902    ) -> Handle<UiNode> {
1903        let widget = self.nodes.borrow(node_handle);
1904
1905        if !widget.is_hit_test_visible()
1906            || !widget.enabled()
1907            || !widget.clip_bounds().intersects(Rect {
1908                position: Default::default(),
1909                size: self.screen_size,
1910            })
1911        {
1912            return Handle::NONE;
1913        }
1914
1915        let (mut picked, mut topmost_picked_level) = if self.is_node_contains_point(node_handle, pt)
1916        {
1917            (node_handle, *level)
1918        } else {
1919            (Handle::NONE, 0)
1920        };
1921
1922        for child_handle in widget.children() {
1923            *level += 1;
1924            let picked_child = self.pick_node(*child_handle, pt, level);
1925            if picked_child.is_some() && *level > topmost_picked_level {
1926                topmost_picked_level = *level;
1927                picked = picked_child;
1928            }
1929        }
1930
1931        picked
1932    }
1933
1934    /// Cursor position in screen space coordinate system.
1935    pub fn cursor_position(&self) -> Vector2<f32> {
1936        self.cursor_position
1937    }
1938
1939    pub fn hit_test_unrestricted(&self, pt: Vector2<f32>) -> Handle<UiNode> {
1940        // We're not restricted to any node, just start from root.
1941        let mut level = 0;
1942        self.pick_node(self.root_canvas, pt, &mut level)
1943    }
1944
1945    pub fn hit_test(&self, pt: Vector2<f32>) -> Handle<UiNode> {
1946        if self.nodes.is_valid_handle(self.captured_node) {
1947            self.captured_node
1948        } else if self.picking_stack.is_empty() {
1949            self.hit_test_unrestricted(pt)
1950        } else {
1951            // We have some picking restriction chain.
1952            // Go over picking stack and try each entry. This will help with picking
1953            // in a series of popups, especially in menus where there may be many open popups
1954            // at the same time.
1955            for root in self.picking_stack.iter().rev() {
1956                if self.nodes.is_valid_handle(root.handle) {
1957                    let mut level = 0;
1958                    let picked = self.pick_node(root.handle, pt, &mut level);
1959                    if picked.is_some() {
1960                        return picked;
1961                    }
1962                }
1963                if root.stop {
1964                    break;
1965                }
1966            }
1967            Handle::NONE
1968        }
1969    }
1970
1971    /// Checks if specified node is a child of some other node on `root_handle`. This method
1972    /// is useful to understand if some event came from some node down by tree.
1973    pub fn is_node_child_of(
1974        &self,
1975        node_handle: Handle<impl ObjectOrVariant<UiNode>>,
1976        root_handle: Handle<impl ObjectOrVariant<UiNode>>,
1977    ) -> bool {
1978        self.nodes
1979            .borrow(root_handle.to_base())
1980            .has_descendant(node_handle.to_base(), self)
1981    }
1982
1983    /// Checks if the specified node is a descendant of the hierarchy defined by a `root_handle` or
1984    /// the given handles are equal.
1985    pub fn has_descendant_or_equal(
1986        &self,
1987        node_handle: Handle<impl ObjectOrVariant<UiNode>>,
1988        root_handle: Handle<impl ObjectOrVariant<UiNode>>,
1989    ) -> bool {
1990        root_handle.to_base() == node_handle.to_base()
1991            || self.is_node_child_of(node_handle, root_handle)
1992    }
1993
1994    /// Recursively calculates clipping bounds for every node.
1995    fn calculate_clip_bounds(&self, node: Handle<UiNode>, parent_bounds: Rect<f32>) {
1996        let node = &self.nodes[node];
1997
1998        let screen_bounds = if *node.clip_to_bounds {
1999            node.screen_bounds()
2000        } else {
2001            Rect::new(0.0, 0.0, self.screen_size.x, self.screen_size.y)
2002        };
2003
2004        node.clip_bounds.set(
2005            screen_bounds
2006                .clip_by(parent_bounds)
2007                .unwrap_or(screen_bounds),
2008        );
2009
2010        for &child in node.children() {
2011            self.calculate_clip_bounds(child, node.clip_bounds.get());
2012        }
2013    }
2014
2015    /// Returns instance of message sender which can be used to push messages into queue
2016    /// from other threads.
2017    pub fn sender(&self) -> Sender<UiMessage> {
2018        self.sender.clone()
2019    }
2020
2021    pub fn send_message(&self, message: UiMessage) {
2022        self.sender.send(message).unwrap()
2023    }
2024
2025    pub fn try_send_response(&self, message: &UiMessage) -> bool {
2026        if message.is_sync() || message.direction() == MessageDirection::FromWidget {
2027            false
2028        } else {
2029            self.send_message(message.reverse());
2030            true
2031        }
2032    }
2033
2034    pub fn send_messages<const N: usize>(&self, messages: [UiMessage; N]) {
2035        for message in messages {
2036            self.send_message(message)
2037        }
2038    }
2039
2040    pub fn send(&self, handle: Handle<impl ObjectOrVariant<UiNode>>, data: impl MessageData) {
2041        self.sender
2042            .send(
2043                UiMessage::with_data(data)
2044                    .with_destination(handle.transmute())
2045                    .with_direction(MessageDirection::ToWidget),
2046            )
2047            .unwrap()
2048    }
2049
2050    pub fn send_handled(
2051        &self,
2052        handle: Handle<impl ObjectOrVariant<UiNode>>,
2053        data: impl MessageData,
2054    ) {
2055        self.sender
2056            .send(
2057                UiMessage::with_data(data)
2058                    .with_destination(handle.transmute())
2059                    .with_direction(MessageDirection::ToWidget)
2060                    .with_handled(true),
2061            )
2062            .unwrap()
2063    }
2064
2065    pub fn send_sync(&self, handle: Handle<impl ObjectOrVariant<UiNode>>, data: impl MessageData) {
2066        self.sender
2067            .send(
2068                UiMessage::with_data(data)
2069                    .with_destination(handle.transmute())
2070                    .with_direction(MessageDirection::ToWidget)
2071                    .with_delivery_mode(DeliveryMode::SyncOnly),
2072            )
2073            .unwrap()
2074    }
2075
2076    pub fn send_with_flags<T: MessageData>(
2077        &self,
2078        handle: Handle<impl ObjectOrVariant<UiNode>>,
2079        flags: u64,
2080        data: T,
2081    ) {
2082        self.sender
2083            .send(
2084                UiMessage::with_data(data)
2085                    .with_destination(handle.transmute())
2086                    .with_direction(MessageDirection::ToWidget)
2087                    .with_flags(flags),
2088            )
2089            .unwrap()
2090    }
2091
2092    pub fn send_many<const N: usize, T: MessageData>(
2093        &self,
2094        handle: Handle<impl ObjectOrVariant<UiNode>>,
2095        payload: [T; N],
2096    ) {
2097        for data in payload {
2098            self.send(handle, data)
2099        }
2100    }
2101
2102    pub fn send_sync_many<const N: usize, T: MessageData>(
2103        &self,
2104        handle: Handle<impl ObjectOrVariant<UiNode>>,
2105        payload: [T; N],
2106    ) {
2107        for data in payload {
2108            self.send_sync(handle, data)
2109        }
2110    }
2111
2112    pub fn post<T: MessageData>(&self, handle: Handle<impl ObjectOrVariant<UiNode>>, data: T) {
2113        self.sender
2114            .send(
2115                UiMessage::with_data(data)
2116                    .with_destination(handle.transmute())
2117                    .with_direction(MessageDirection::FromWidget),
2118            )
2119            .unwrap()
2120    }
2121
2122    pub fn post_many<const N: usize, T: MessageData>(
2123        &self,
2124        handle: Handle<impl ObjectOrVariant<UiNode>>,
2125        payload: [T; N],
2126    ) {
2127        for data in payload {
2128            self.post(handle, data)
2129        }
2130    }
2131
2132    // Puts node at the end of children list of a parent node.
2133    //
2134    // # Notes
2135    //
2136    // Node will be topmost *only* on the same hierarchy level! So if you have a floating
2137    // window (for example) and a window embedded into some other control (yes, this is
2138    // possible), then the floating window won't be the topmost.
2139    fn make_topmost(&mut self, node: Handle<UiNode>) {
2140        let parent = self.node(node).parent();
2141        if parent.is_some() {
2142            let parent = &mut self.nodes[parent];
2143            parent.remove_child(node);
2144            parent.add_child(node, false);
2145        }
2146    }
2147
2148    fn make_lowermost(&mut self, node: Handle<UiNode>) {
2149        let parent = self.node(node).parent();
2150        if parent.is_some() {
2151            let parent = &mut self.nodes[parent];
2152            parent.remove_child(node);
2153            parent.add_child(node, true);
2154        }
2155    }
2156
2157    fn bubble_message(&mut self, message: &mut UiMessage) {
2158        // Dispatch event using bubble strategy. Bubble routing means that message will go
2159        // from specified destination up on tree to tree root.
2160        // Gather chain of nodes from source to root.
2161        self.bubble_queue.clear();
2162        self.bubble_queue.push_back(message.destination());
2163        let mut parent = self.nodes[message.destination()].parent();
2164        while parent.is_some() && self.nodes.is_valid_handle(parent) {
2165            self.bubble_queue.push_back(parent);
2166            parent = self.nodes[parent].parent();
2167        }
2168
2169        while let Some(handle) = self.bubble_queue.pop_front() {
2170            let (ticket, mut node) = self.nodes.take_reserve(handle);
2171            node.handle_routed_message(self, message);
2172            self.nodes.put_back(ticket, node);
2173        }
2174    }
2175
2176    /// Extracts UI event one-by-one from common queue. Each extracted event will go to *all*
2177    /// available nodes first and only then will be moved outside of this method. This is one
2178    ///  of the most important methods which must be called each frame of your game loop, otherwise
2179    /// the UI will not respond to any kind of events and simply speaking will just not work.
2180    ///
2181    /// # Routing Scheme
2182    ///
2183    /// The following scheme shows the full routing procedure for a single method call.
2184    ///
2185    /// ```text
2186    ///
2187    ///     poll_message                                                          return message;
2188    ///           │                   Discard Message                                    ▲
2189    ///           ├─────────────────────────────◄───────────────────────────┐            │
2190    ///           │                                                         │   Delivery │
2191    ///           │                                                         │   Mode     │
2192    /// ┌─────────▼─────────┐  ┌─────────────────────────────────────┐      │    ┌───────┼──────┐
2193    /// │Message            │  │ Destination                         │      │    │ Full Cycle?  │
2194    /// │Queue              │  │ Widget Sub-Tree                     │      │    ├──────────────┤
2195    /// │   ┌───────────┐   │  │                                     │      └────┼ Sync Only?   │
2196    /// │   │  Message  │   │  │ Bubble Routing                      │           └───────▲──────┘
2197    /// │   └───────────┘   │  │ ┌─────────────────────────────────┐ │                   │
2198    /// │   ┌───────────┐   │  │ │   Root::handle_routed_message   ├─┼─────────►─────────┤
2199    /// │   │  Message  │   │  │ └────────────────▲────────────────┘ │                   │
2200    /// │   └───────────┘   │  │                 ...                 │                   │
2201    /// │        ...        │  │ ┌────────────────┼────────────────┐ │                   │
2202    /// │   ┌───────────┐   │  │ │  Parent::handle_routed_message  │ │                   │
2203    /// │   │  Message  │   │  │ └────────────────▲────────────────┘ │                   │
2204    /// │   └───────────┘   │  │                  │                  │                   │
2205    /// │   ┌───────────┐   │  │ ┌────────────────┼────────────────┐ │  Direct Routing   │
2206    /// │   │  Message  │   │  │ │  Widget::handle_routed_message  │ │  ┌────────────────┼────────────────┐
2207    /// │   └─────────┬─┘   │  │ └────────────────▲────────────────┘ │  │  Widget::handle_routed_message  │
2208    /// └─────────────┼─────┘  └──────────────────┼──────────────────┘  └────────────────▲────────────────┘
2209    ///               │                           │                                      │
2210    ///     pop_front │                  Routing  │                                      │
2211    ///               │                  Strategy │                                      │
2212    /// ┌─────────────┼───────────────┐   ┌──────────────────┐                           │
2213    /// │Preview Set  │               │   │ Bubble Routing?  │                           │
2214    /// │ ┌───────────▼─────────────┐ │   ├──────────────────┤                           │
2215    /// │ │ Widget::preview_message │ │   │ Direct Routing?  ├───────────────────────────┘
2216    /// │ └───────────┬─────────────┘ │   └──────────────────┘
2217    /// │             │               │           │
2218    /// │ ┌───────────▼─────────────┐ │           │
2219    /// │ │ Widget::preview_message │ │           │
2220    /// │ └───────────┬─────────────┘ │           │
2221    /// │             │               │           │
2222    /// │ ┌───────────▼─────────────┐ │           │
2223    /// │ │ Widget::preview_message─┼─┼───────────┘
2224    /// │ └─────────────────────────┘ │ To destination
2225    /// └─────────────────────────────┘ widget
2226    /// ```
2227    ///
2228    /// Keep in mind, that any number of widget may produce some other messages during this method
2229    /// call. These messages will be put at the end of the queue.
2230    ///
2231    /// # Returns
2232    ///
2233    /// This method returns a [`PollResult`] with processed message number and the last processed message
2234    /// that has [`DeliveryMode::FullCycle`]. See the diagram above for the explanation.
2235    pub fn poll_message_queue(&mut self) -> PollResult {
2236        let mut poll_result = PollResult {
2237            processed_messages: 0,
2238            message: None,
2239        };
2240
2241        while let Ok(message) = self.receiver.try_recv() {
2242            poll_result.processed_messages += 1;
2243            if let Some(message) = self.poll_single_message(message) {
2244                poll_result.message = Some(message);
2245                break;
2246            }
2247        }
2248
2249        poll_result
2250    }
2251
2252    /// Same as [`Self::poll_message_queue`], but discards the number of processed message the last
2253    /// processed message that has [`DeliveryMode::FullCycle`].
2254    pub fn poll_message(&mut self) -> Option<UiMessage> {
2255        self.poll_message_queue().message
2256    }
2257
2258    fn poll_single_message(&mut self, mut message: UiMessage) -> Option<UiMessage> {
2259        // The Destination node may be destroyed at the time we receive message,
2260        // we have skip processing of such messages.
2261        if !self.nodes.is_valid_handle(message.destination()) {
2262            return Some(message);
2263        }
2264
2265        if let RenderMode::OnChanges = self.render_mode {
2266            self.need_render = true;
2267        }
2268
2269        if message.need_perform_layout() {
2270            self.update_layout(self.screen_size);
2271        }
2272
2273        for &handle in self.methods_registry.preview_message.iter() {
2274            if let Ok(node_ref) = self.nodes.try_borrow(handle) {
2275                node_ref.preview_message(self, &mut message);
2276            }
2277        }
2278
2279        match message.routing_strategy {
2280            RoutingStrategy::BubbleUp => self.bubble_message(&mut message),
2281            RoutingStrategy::Direct => {
2282                let (ticket, mut node) = self.nodes.take_reserve(message.destination());
2283                node.handle_routed_message(self, &mut message);
2284                self.nodes.put_back(ticket, node);
2285            }
2286        }
2287
2288        if let Some(msg) = message.data::<WidgetMessage>() {
2289            match msg {
2290                WidgetMessage::Focus => {
2291                    if self.nodes.is_valid_handle(message.destination())
2292                        && message.direction() == MessageDirection::ToWidget
2293                    {
2294                        self.request_focus(message.destination());
2295                    }
2296                }
2297                WidgetMessage::Unfocus => {
2298                    if self.nodes.is_valid_handle(message.destination())
2299                        && message.direction() == MessageDirection::ToWidget
2300                    {
2301                        self.request_focus(self.root_canvas);
2302                    }
2303                }
2304                WidgetMessage::Topmost => {
2305                    if self.nodes.is_valid_handle(message.destination()) {
2306                        self.make_topmost(message.destination());
2307                    }
2308                }
2309                WidgetMessage::Lowermost => {
2310                    if self.nodes.is_valid_handle(message.destination()) {
2311                        self.make_lowermost(message.destination());
2312                    }
2313                }
2314                WidgetMessage::Unlink => {
2315                    if self.nodes.is_valid_handle(message.destination()) {
2316                        self.unlink_node(message.destination());
2317
2318                        let node = &self.nodes[message.destination()];
2319                        let new_position = self.screen_to_root_canvas_space(node.screen_position());
2320                        self.send(
2321                            message.destination(),
2322                            WidgetMessage::DesiredPosition(new_position),
2323                        );
2324                    }
2325                }
2326                &WidgetMessage::LinkWith(parent) => {
2327                    if self.nodes.is_valid_handle(message.destination())
2328                        && self.nodes.is_valid_handle(parent)
2329                    {
2330                        self.link_nodes(message.destination(), parent, false);
2331                    }
2332                }
2333                &WidgetMessage::LinkWithReverse(parent) => {
2334                    if self.nodes.is_valid_handle(message.destination())
2335                        && self.nodes.is_valid_handle(parent)
2336                    {
2337                        self.link_nodes(message.destination(), parent, true);
2338                    }
2339                }
2340                WidgetMessage::ReplaceChildren(children) => {
2341                    if self.nodes.is_valid_handle(message.destination()) {
2342                        let old_children = self.node(message.destination()).children().to_vec();
2343                        for child in old_children.iter() {
2344                            if self.nodes.is_valid_handle(*child) {
2345                                if children.contains(child) {
2346                                    self.unlink_node(*child);
2347                                } else {
2348                                    self.remove_node(*child);
2349                                }
2350                            }
2351                        }
2352                        for &child in children.iter() {
2353                            if self.nodes.is_valid_handle(child) {
2354                                self.link_nodes(child, message.destination(), false);
2355                            }
2356                        }
2357                    }
2358                }
2359                WidgetMessage::Remove => {
2360                    if self.nodes.is_valid_handle(message.destination()) {
2361                        self.remove_node(message.destination());
2362                    }
2363                }
2364                WidgetMessage::ContextMenu(context_menu) => {
2365                    if self.nodes.is_valid_handle(message.destination()) {
2366                        let node = self.nodes.borrow_mut(message.destination());
2367                        node.set_context_menu(context_menu.clone());
2368                    }
2369                }
2370                WidgetMessage::Tooltip(tooltip) => {
2371                    if self.nodes.is_valid_handle(message.destination()) {
2372                        let node = self.nodes.borrow_mut(message.destination());
2373                        node.set_tooltip(tooltip.clone());
2374                    }
2375                }
2376                WidgetMessage::Center => {
2377                    if self.nodes.is_valid_handle(message.destination()) {
2378                        let node = self.node(message.destination());
2379                        let size = node.actual_initial_size();
2380                        let parent = node.parent();
2381                        let parent_size = if parent.is_some() {
2382                            self.node(parent).actual_initial_size()
2383                        } else {
2384                            self.screen_size
2385                        };
2386
2387                        self.send(
2388                            message.destination(),
2389                            WidgetMessage::DesiredPosition((parent_size - size).scale(0.5)),
2390                        );
2391                    }
2392                }
2393                WidgetMessage::RenderTransform(_) => {
2394                    if self.nodes.is_valid_handle(message.destination()) {
2395                        self.update_visual_transform(message.destination());
2396                    }
2397                }
2398                WidgetMessage::AdjustPositionToFit => {
2399                    if self.nodes.is_valid_handle(message.destination()) {
2400                        let node = self.node(message.destination());
2401                        let mut position = node.actual_local_position();
2402                        let size = node.actual_initial_size();
2403                        let parent = node.parent();
2404                        let parent_size = if parent.is_some() {
2405                            self.node(parent).actual_initial_size()
2406                        } else {
2407                            self.screen_size
2408                        };
2409
2410                        if position.x < 0.0 {
2411                            position.x = 0.0;
2412                        }
2413                        if position.x + size.x > parent_size.x {
2414                            position.x -= (position.x + size.x) - parent_size.x;
2415                        }
2416                        if position.y < 0.0 {
2417                            position.y = 0.0;
2418                        }
2419                        if position.y + size.y > parent_size.y {
2420                            position.y -= (position.y + size.y) - parent_size.y;
2421                        }
2422
2423                        self.send(
2424                            message.destination(),
2425                            WidgetMessage::DesiredPosition(position),
2426                        );
2427                    }
2428                }
2429                WidgetMessage::Align {
2430                    relative_to,
2431                    horizontal_alignment,
2432                    vertical_alignment,
2433                    margin,
2434                } => {
2435                    if let (Ok(node), Ok(relative_node)) = (
2436                        self.try_get_node(message.destination()),
2437                        self.try_get_node(*relative_to),
2438                    ) {
2439                        // Calculate new anchor point in screen coordinate system.
2440                        let relative_node_screen_size = relative_node.screen_bounds().size;
2441                        let relative_node_screen_position = relative_node.screen_position();
2442                        let node_screen_size = node.screen_bounds().size;
2443
2444                        let mut screen_anchor_point = Vector2::default();
2445                        match horizontal_alignment {
2446                            HorizontalAlignment::Stretch => {
2447                                // Do nothing.
2448                            }
2449                            HorizontalAlignment::Left => {
2450                                screen_anchor_point.x =
2451                                    relative_node_screen_position.x + margin.left;
2452                            }
2453                            HorizontalAlignment::Center => {
2454                                screen_anchor_point.x = relative_node_screen_position.x
2455                                    + (relative_node_screen_size.x
2456                                        + node_screen_size.x
2457                                        + margin.left
2458                                        + margin.right)
2459                                        * 0.5;
2460                            }
2461                            HorizontalAlignment::Right => {
2462                                screen_anchor_point.x = relative_node_screen_position.x
2463                                    + relative_node_screen_size.x
2464                                    - node_screen_size.x
2465                                    - margin.right;
2466                            }
2467                        }
2468
2469                        match vertical_alignment {
2470                            VerticalAlignment::Stretch => {
2471                                // Do nothing.
2472                            }
2473                            VerticalAlignment::Top => {
2474                                screen_anchor_point.y =
2475                                    relative_node_screen_position.y + margin.top;
2476                            }
2477                            VerticalAlignment::Center => {
2478                                screen_anchor_point.y = relative_node_screen_position.y
2479                                    + (relative_node_screen_size.y
2480                                        + node_screen_size.y
2481                                        + margin.top
2482                                        + margin.bottom)
2483                                        * 0.5;
2484                            }
2485                            VerticalAlignment::Bottom => {
2486                                screen_anchor_point.y = relative_node_screen_position.y
2487                                    + (relative_node_screen_size.y
2488                                        - node_screen_size.y
2489                                        - margin.bottom);
2490                            }
2491                        }
2492
2493                        if let Ok(parent) = self.try_get_node(node.parent()) {
2494                            // Transform screen anchor point into the local coordinate system
2495                            // of the parent node.
2496                            let local_anchor_point = parent.screen_to_local(screen_anchor_point);
2497                            self.send(
2498                                message.destination(),
2499                                WidgetMessage::DesiredPosition(local_anchor_point),
2500                            );
2501                        }
2502                    }
2503                }
2504                WidgetMessage::MouseUp { button, .. } => {
2505                    if *button == MouseButton::Right && !message.handled() {
2506                        if let Ok(picked) = self.nodes.try_borrow(self.picked_node) {
2507                            // Get the context menu from the current node or a parent node
2508                            let (context_menu, target) = if picked.context_menu().is_some() {
2509                                (picked.context_menu(), self.picked_node)
2510                            } else {
2511                                let parent_handle = picked
2512                                    .find_by_criteria_up(self, |n| n.context_menu().is_some());
2513
2514                                if let Ok(parent) = self.nodes.try_borrow(parent_handle) {
2515                                    (parent.context_menu(), parent_handle)
2516                                } else {
2517                                    (None, Handle::NONE)
2518                                }
2519                            };
2520
2521                            // Display context menu
2522                            if let Some(context_menu) = context_menu {
2523                                self.send(
2524                                    context_menu.handle(),
2525                                    PopupMessage::Placement(Placement::Cursor(target)),
2526                                );
2527                                self.send(context_menu.handle(), PopupMessage::Open);
2528                                // Send Event messages to the widget that was clicked on,
2529                                // not to the widget that has the context menu.
2530                                self.send(
2531                                    context_menu.handle(),
2532                                    PopupMessage::Owner(self.picked_node),
2533                                );
2534                            }
2535                        }
2536                    }
2537                }
2538                _ => {}
2539            }
2540        }
2541
2542        match message.delivery_mode {
2543            DeliveryMode::FullCycle => Some(message),
2544            DeliveryMode::SyncOnly => None,
2545        }
2546    }
2547
2548    pub fn screen_to_root_canvas_space(&self, position: Vector2<f32>) -> Vector2<f32> {
2549        self.node(self.root()).screen_to_local(position)
2550    }
2551
2552    fn show_tooltip(&self, tooltip: RcUiNodeHandle) {
2553        self.send(tooltip.handle(), WidgetMessage::Visibility(true));
2554        self.send(tooltip.handle(), WidgetMessage::Topmost);
2555        self.send(
2556            tooltip.handle(),
2557            WidgetMessage::DesiredPosition(
2558                self.screen_to_root_canvas_space(self.cursor_position() + Vector2::new(0.0, 16.0)),
2559            ),
2560        );
2561        self.send(tooltip.handle(), WidgetMessage::AdjustPositionToFit);
2562    }
2563
2564    fn replace_or_update_tooltip(&mut self, tooltip: RcUiNodeHandle, disappear_timeout: f32) {
2565        if let Some(entry) = self.active_tooltip.as_mut() {
2566            if entry.tooltip == tooltip {
2567                if entry.shown {
2568                    // Keep current visible.
2569                    entry.disappear_timer = disappear_timeout;
2570                }
2571            } else {
2572                let old_tooltip = entry.tooltip.clone();
2573
2574                entry.shown = false;
2575                entry.appear_timer = self.tooltip_appear_delay;
2576                entry.disappear_timer = disappear_timeout;
2577                entry.tooltip = tooltip.clone();
2578
2579                // Hide previous.
2580                self.send(old_tooltip.handle(), WidgetMessage::Visibility(false));
2581            }
2582        } else {
2583            self.active_tooltip = Some(TooltipEntry::new(
2584                tooltip,
2585                self.tooltip_appear_delay,
2586                disappear_timeout,
2587            ));
2588        }
2589    }
2590
2591    /// Find any tooltips that are being hovered and activate them.
2592    /// As well, update their time.
2593    fn update_tooltips(&mut self, dt: f32) {
2594        let sender = self.sender.clone();
2595        if let Some(entry) = self.active_tooltip.as_mut() {
2596            if entry.shown {
2597                entry.disappear_timer -= dt;
2598                if entry.disappear_timer <= 0.0 {
2599                    // This uses sender directly since we're currently mutably borrowing
2600                    // visible_tooltips
2601                    sender
2602                        .send(UiMessage::for_widget(
2603                            entry.tooltip.handle(),
2604                            WidgetMessage::Visibility(false),
2605                        ))
2606                        .unwrap();
2607
2608                    self.active_tooltip = None;
2609                }
2610            } else {
2611                let mut tooltip_owner_hovered = false;
2612                let mut handle = self.picked_node;
2613                while let Ok(node) = self.nodes.try_borrow(handle) {
2614                    if let Some(tooltip) = node.tooltip.as_ref() {
2615                        if &entry.tooltip == tooltip {
2616                            tooltip_owner_hovered = true;
2617                            break;
2618                        }
2619                    }
2620                    handle = node.parent();
2621                }
2622
2623                if tooltip_owner_hovered {
2624                    entry.appear_timer -= dt;
2625                    if entry.appear_timer <= 0.0 {
2626                        entry.shown = true;
2627                        let tooltip = entry.tooltip.clone();
2628                        self.show_tooltip(tooltip);
2629                    }
2630                } else {
2631                    self.active_tooltip = None;
2632                }
2633            }
2634        }
2635
2636        // Check for hovering over a widget with a tooltip, or hovering over a tooltip.
2637        let mut handle = self.picked_node;
2638        while let Ok(node) = self.nodes.try_borrow(handle) {
2639            let parent = node.parent();
2640
2641            if let Some(tooltip) = node.tooltip() {
2642                // They have a tooltip, we stop here and use that.
2643                let disappear_timeout = node.tooltip_time();
2644                self.replace_or_update_tooltip(tooltip, disappear_timeout);
2645                break;
2646            } else if let Some(entry) = self.active_tooltip.as_mut() {
2647                if entry.tooltip.handle() == handle {
2648                    // The current node was a tooltip.
2649                    // We refresh the timer back to the stored max time.
2650                    entry.disappear_timer = entry.max_time;
2651                    break;
2652                }
2653            }
2654
2655            handle = parent;
2656        }
2657    }
2658
2659    pub fn captured_node(&self) -> Handle<UiNode> {
2660        self.captured_node
2661    }
2662
2663    // Tries to set new picked node (a node under the cursor) and returns `true` if the node was
2664    // changed.
2665    fn try_set_picked_node(&mut self, node: Handle<UiNode>) -> bool {
2666        if self.picked_node != node {
2667            self.picked_node = node;
2668            self.reset_double_click_entries();
2669            true
2670        } else {
2671            false
2672        }
2673    }
2674
2675    fn reset_double_click_entries(&mut self) {
2676        for entry in self.double_click_entries.values_mut() {
2677            entry.timer = self.double_click_time_slice;
2678            entry.click_count = 0;
2679        }
2680    }
2681
2682    fn request_focus(&mut self, new_focused: Handle<UiNode>) {
2683        if self.keyboard_focus_node != new_focused {
2684            if self.keyboard_focus_node.is_some() {
2685                self.post(self.keyboard_focus_node, WidgetMessage::Unfocus);
2686            }
2687            self.keyboard_focus_node = new_focused;
2688            if self.keyboard_focus_node.is_some() {
2689                self.post(self.keyboard_focus_node, WidgetMessage::Focus);
2690            }
2691        }
2692    }
2693
2694    /// Translates raw window event into some specific UI message. This is one of the
2695    /// most important methods of UI. You must call it each time you receive a message
2696    /// from a window.
2697    pub fn process_os_event(&mut self, event: &OsEvent) -> bool {
2698        let mut event_processed = false;
2699
2700        match event {
2701            &OsEvent::MouseInput { button, state, .. } => {
2702                match button {
2703                    MouseButton::Left => self.mouse_state.left = state,
2704                    MouseButton::Right => self.mouse_state.right = state,
2705                    MouseButton::Middle => self.mouse_state.middle = state,
2706                    _ => {}
2707                }
2708
2709                match state {
2710                    ButtonState::Pressed => {
2711                        let picked_changed =
2712                            self.try_set_picked_node(self.hit_test(self.cursor_position));
2713
2714                        let mut emit_double_click = false;
2715                        if !picked_changed {
2716                            match self.double_click_entries.entry(button) {
2717                                Entry::Occupied(e) => {
2718                                    let entry = e.into_mut();
2719                                    if entry.timer > 0.0 {
2720                                        entry.click_count += 1;
2721                                        if entry.click_count >= 2 {
2722                                            entry.click_count = 0;
2723                                            entry.timer = self.double_click_time_slice;
2724                                            emit_double_click = true;
2725                                        }
2726                                    } else {
2727                                        entry.timer = self.double_click_time_slice;
2728                                        entry.click_count = 1;
2729                                    }
2730                                }
2731                                Entry::Vacant(entry) => {
2732                                    // A button was clicked for the first time, no double click
2733                                    // in this case.
2734                                    entry.insert(DoubleClickEntry {
2735                                        timer: self.double_click_time_slice,
2736                                        click_count: 1,
2737                                    });
2738                                }
2739                            }
2740                        }
2741
2742                        // Try to find draggable node in hierarchy starting from picked node.
2743                        if self.picked_node.is_some() {
2744                            self.stack.clear();
2745                            self.stack.push(self.picked_node);
2746                            while let Some(handle) = self.stack.pop() {
2747                                let node = &self.nodes[handle];
2748                                if node.is_drag_allowed() {
2749                                    self.drag_context.drag_node = handle;
2750                                    self.stack.clear();
2751                                    break;
2752                                } else if node.parent().is_some() {
2753                                    self.stack.push(node.parent());
2754                                }
2755                            }
2756                            self.drag_context.click_pos = self.cursor_position;
2757                        }
2758
2759                        self.request_focus(self.picked_node);
2760
2761                        if self.picked_node.is_some() {
2762                            self.post(
2763                                self.picked_node,
2764                                WidgetMessage::MouseDown {
2765                                    pos: self.cursor_position,
2766                                    button,
2767                                },
2768                            );
2769                            event_processed = true;
2770                        }
2771
2772                        // Make sure double click will be emitted after mouse down event.
2773                        if emit_double_click {
2774                            self.post(self.picked_node, WidgetMessage::DoubleClick { button });
2775                        }
2776                    }
2777                    ButtonState::Released => {
2778                        if self.picked_node.is_some() {
2779                            self.post(
2780                                self.picked_node,
2781                                WidgetMessage::MouseUp {
2782                                    pos: self.cursor_position,
2783                                    button,
2784                                },
2785                            );
2786
2787                            if self.drag_context.is_dragging {
2788                                self.drag_context.is_dragging = false;
2789                                self.cursor_icon = CursorIcon::Default;
2790
2791                                // Try to find node with drop allowed in hierarchy starting from picked node.
2792                                self.stack.clear();
2793                                self.stack.push(self.picked_node);
2794                                while let Some(handle) = self.stack.pop() {
2795                                    let node = &self.nodes[handle];
2796                                    if node.is_drop_allowed() {
2797                                        self.post(
2798                                            handle,
2799                                            WidgetMessage::Drop(self.drag_context.drag_node),
2800                                        );
2801                                        self.stack.clear();
2802                                        break;
2803                                    } else if node.parent().is_some() {
2804                                        self.stack.push(node.parent());
2805                                    }
2806                                }
2807                            }
2808                            self.drag_context.drag_node = Handle::NONE;
2809                            if self.nodes.is_valid_handle(self.drag_context.drag_preview) {
2810                                self.remove_node(self.drag_context.drag_preview);
2811                                self.drag_context.drag_preview = Default::default();
2812                            }
2813
2814                            event_processed = true;
2815                        }
2816                    }
2817                }
2818            }
2819            OsEvent::CursorMoved { position } => {
2820                self.cursor_position = *position;
2821                self.try_set_picked_node(self.hit_test(self.cursor_position));
2822
2823                if !self.drag_context.is_dragging
2824                    && self.mouse_state.left == ButtonState::Pressed
2825                    && self.picked_node.is_some()
2826                    && self.nodes.is_valid_handle(self.drag_context.drag_node)
2827                    && (self.drag_context.click_pos - *position).norm() > 5.0
2828                {
2829                    self.drag_context.drag_preview =
2830                        self.copy_node_with_limit(self.drag_context.drag_node, Some(30));
2831                    self.nodes[self.drag_context.drag_preview].set_opacity(Some(0.5));
2832
2833                    // Make preview nodes invisible for hit test.
2834                    let mut stack = vec![self.drag_context.drag_preview];
2835                    while let Some(handle) = stack.pop() {
2836                        let preview_node = &mut self.nodes[handle];
2837                        preview_node.hit_test_visibility.set_value_silent(false);
2838                        stack.extend_from_slice(preview_node.children());
2839                    }
2840
2841                    self.drag_context.is_dragging = true;
2842
2843                    self.post(
2844                        self.picked_node,
2845                        WidgetMessage::DragStarted(self.drag_context.drag_node),
2846                    );
2847
2848                    self.cursor_icon = CursorIcon::Crosshair;
2849                }
2850
2851                if self.drag_context.is_dragging
2852                    && self.nodes.is_valid_handle(self.drag_context.drag_preview)
2853                {
2854                    let local_position = self.screen_to_root_canvas_space(*position);
2855                    self.send(
2856                        self.drag_context.drag_preview,
2857                        WidgetMessage::DesiredPosition(local_position),
2858                    );
2859                }
2860
2861                // Fire mouse leave for previously picked node
2862                if self.picked_node != self.prev_picked_node && self.prev_picked_node.is_some() {
2863                    let prev_picked_node = self.nodes.borrow_mut(self.prev_picked_node);
2864                    if prev_picked_node.is_mouse_directly_over {
2865                        prev_picked_node.is_mouse_directly_over = false;
2866                        self.post(self.prev_picked_node, WidgetMessage::MouseLeave);
2867                    }
2868                }
2869
2870                if self.picked_node.is_some() {
2871                    let picked_node = self.nodes.borrow_mut(self.picked_node);
2872                    if !picked_node.is_mouse_directly_over {
2873                        picked_node.is_mouse_directly_over = true;
2874                        self.post(self.picked_node, WidgetMessage::MouseEnter);
2875                    }
2876
2877                    // Fire mouse move
2878                    self.post(
2879                        self.picked_node,
2880                        WidgetMessage::MouseMove {
2881                            pos: self.cursor_position,
2882                            state: self.mouse_state,
2883                        },
2884                    );
2885
2886                    if self.drag_context.is_dragging {
2887                        self.post(
2888                            self.picked_node,
2889                            WidgetMessage::DragOver(self.drag_context.drag_node),
2890                        );
2891                    }
2892
2893                    event_processed = true;
2894                }
2895            }
2896            OsEvent::MouseWheel(_, y) => {
2897                if self.picked_node.is_some() {
2898                    self.post(
2899                        self.picked_node,
2900                        WidgetMessage::MouseWheel {
2901                            pos: self.cursor_position,
2902                            amount: *y,
2903                        },
2904                    );
2905
2906                    event_processed = true;
2907                }
2908            }
2909            OsEvent::KeyboardInput {
2910                button,
2911                state,
2912                text,
2913            } => {
2914                if let Ok(keyboard_focus_node) = self.try_get_node(self.keyboard_focus_node) {
2915                    if keyboard_focus_node.is_globally_visible() {
2916                        match state {
2917                            ButtonState::Pressed => {
2918                                self.post(
2919                                    self.keyboard_focus_node,
2920                                    WidgetMessage::KeyDown(*button),
2921                                );
2922
2923                                if !text.is_empty() {
2924                                    self.post(
2925                                        self.keyboard_focus_node,
2926                                        WidgetMessage::Text(text.clone()),
2927                                    );
2928                                }
2929                            }
2930                            ButtonState::Released => {
2931                                self.post(self.keyboard_focus_node, WidgetMessage::KeyUp(*button))
2932                            }
2933                        }
2934
2935                        event_processed = true;
2936                    }
2937                }
2938            }
2939            &OsEvent::KeyboardModifiers(modifiers) => {
2940                // TODO: Is message needed for focused node?
2941                self.keyboard_modifiers = modifiers;
2942            }
2943            OsEvent::Touch {
2944                phase,
2945                location,
2946                force,
2947                id,
2948            } => match phase {
2949                TouchPhase::Started => {
2950                    self.cursor_position = *location;
2951                    let picked_changed =
2952                        self.try_set_picked_node(self.hit_test(self.cursor_position));
2953
2954                    let mut emit_double_tap = false;
2955                    if !picked_changed {
2956                        match self.double_click_entries.entry(MouseButton::Left) {
2957                            Entry::Occupied(e) => {
2958                                let entry = e.into_mut();
2959                                if entry.timer > 0.0 {
2960                                    entry.click_count += 1;
2961                                    if entry.click_count >= 2 {
2962                                        entry.click_count = 0;
2963                                        entry.timer = self.double_click_time_slice;
2964                                        emit_double_tap = true;
2965                                    }
2966                                } else {
2967                                    entry.timer = self.double_click_time_slice;
2968                                    entry.click_count = 1;
2969                                }
2970                            }
2971                            Entry::Vacant(entry) => {
2972                                // A button was clicked for the first time, no double click
2973                                // in this case.
2974                                entry.insert(DoubleClickEntry {
2975                                    timer: self.double_click_time_slice,
2976                                    click_count: 1,
2977                                });
2978                            }
2979                        }
2980                    }
2981
2982                    // Try to find draggable node in hierarchy starting from picked node.
2983                    if self.picked_node.is_some() {
2984                        self.stack.clear();
2985                        self.stack.push(self.picked_node);
2986                        while let Some(handle) = self.stack.pop() {
2987                            let node = &self.nodes[handle];
2988                            if node.is_drag_allowed() {
2989                                self.drag_context.drag_node = handle;
2990                                self.stack.clear();
2991                                break;
2992                            } else if node.parent().is_some() {
2993                                self.stack.push(node.parent());
2994                            }
2995                        }
2996                        self.drag_context.click_pos = self.cursor_position;
2997                    }
2998
2999                    self.request_focus(self.picked_node);
3000
3001                    if self.picked_node.is_some() {
3002                        self.post(
3003                            self.picked_node,
3004                            WidgetMessage::TouchStarted {
3005                                pos: self.cursor_position,
3006                                force: *force,
3007                                id: *id,
3008                            },
3009                        );
3010                        event_processed = true;
3011                    }
3012
3013                    // Make sure double click will be emitted after mouse down event.
3014                    if emit_double_tap {
3015                        self.post(
3016                            self.picked_node,
3017                            WidgetMessage::DoubleTap {
3018                                pos: *location,
3019                                force: *force,
3020                                id: *id,
3021                            },
3022                        );
3023                    }
3024                }
3025                TouchPhase::Moved => {
3026                    self.cursor_position = *location;
3027                    self.try_set_picked_node(self.hit_test(self.cursor_position));
3028
3029                    // Try to find draggable node in hierarchy starting from picked node.
3030                    if self.picked_node.is_some() {
3031                        self.stack.clear();
3032                        self.stack.push(self.picked_node);
3033                        while let Some(handle) = self.stack.pop() {
3034                            let node = &self.nodes[handle];
3035                            if node.is_drag_allowed() {
3036                                self.drag_context.drag_node = handle;
3037                                self.stack.clear();
3038                                break;
3039                            } else if node.parent().is_some() {
3040                                self.stack.push(node.parent());
3041                            }
3042                        }
3043                        self.drag_context.click_pos = self.cursor_position;
3044                    }
3045
3046                    self.request_focus(self.picked_node);
3047
3048                    if self.picked_node.is_some() {
3049                        self.post(
3050                            self.picked_node,
3051                            WidgetMessage::TouchMoved {
3052                                pos: self.cursor_position,
3053                                force: *force,
3054                                id: *id,
3055                            },
3056                        );
3057                        event_processed = true;
3058                    }
3059                }
3060                TouchPhase::Ended => {
3061                    if self.picked_node.is_some() {
3062                        self.post(
3063                            self.picked_node,
3064                            WidgetMessage::TouchEnded {
3065                                pos: self.cursor_position,
3066                                id: *id,
3067                            },
3068                        );
3069
3070                        if self.drag_context.is_dragging {
3071                            self.drag_context.is_dragging = false;
3072
3073                            // Try to find node with drop allowed in hierarchy starting from picked node.
3074                            self.stack.clear();
3075                            self.stack.push(self.picked_node);
3076                            while let Some(handle) = self.stack.pop() {
3077                                let node = &self.nodes[handle];
3078                                if node.is_drop_allowed() {
3079                                    self.post(
3080                                        handle,
3081                                        WidgetMessage::Drop(self.drag_context.drag_node),
3082                                    );
3083                                    self.stack.clear();
3084                                    break;
3085                                } else if node.parent().is_some() {
3086                                    self.stack.push(node.parent());
3087                                }
3088                            }
3089                        }
3090                        self.drag_context.drag_node = Handle::NONE;
3091                        if self.nodes.is_valid_handle(self.drag_context.drag_preview) {
3092                            self.remove_node(self.drag_context.drag_preview);
3093                            self.drag_context.drag_preview = Default::default();
3094                        }
3095
3096                        event_processed = true;
3097                    }
3098                }
3099                TouchPhase::Cancelled => {
3100                    if self.picked_node.is_some() {
3101                        self.post(
3102                            self.picked_node,
3103                            WidgetMessage::TouchCancelled {
3104                                pos: self.cursor_position,
3105                                id: *id,
3106                            },
3107                        );
3108
3109                        if self.drag_context.is_dragging {
3110                            self.drag_context.is_dragging = false;
3111                            self.cursor_icon = CursorIcon::Default;
3112                            self.stack.clear();
3113                        }
3114                        self.drag_context.drag_node = Handle::NONE;
3115                        if self.nodes.is_valid_handle(self.drag_context.drag_preview) {
3116                            self.remove_node(self.drag_context.drag_preview);
3117                            self.drag_context.drag_preview = Default::default();
3118                        }
3119
3120                        event_processed = true;
3121                    }
3122                }
3123            },
3124        }
3125
3126        self.prev_picked_node = self.picked_node;
3127
3128        let on_os_event_subs = std::mem::take(&mut self.methods_registry.handle_os_event);
3129
3130        for &handle in on_os_event_subs.iter() {
3131            let (ticket, mut node) = self.nodes.take_reserve(handle);
3132            node.handle_os_event(handle, self, event);
3133            self.nodes.put_back(ticket, node);
3134        }
3135
3136        self.methods_registry.handle_os_event = on_os_event_subs;
3137
3138        event_processed
3139    }
3140
3141    pub fn nodes(&self) -> &Pool<UiNode, WidgetContainer> {
3142        &self.nodes
3143    }
3144
3145    pub fn root(&self) -> Handle<UiNode> {
3146        self.root_canvas
3147    }
3148
3149    /// Extracts a widget from the user interface and reserves its handle. It is used to temporarily take
3150    /// ownership over the widget, and then put the widget back using the returned ticket. Extracted
3151    /// widget is detached from its parent!
3152    #[inline]
3153    pub fn take_reserve(&mut self, handle: Handle<UiNode>) -> (Ticket<UiNode>, UiNode) {
3154        self.isolate_node(handle);
3155        self.nodes.take_reserve(handle)
3156    }
3157
3158    /// Puts the widget back by the given ticket. Attaches it back to the root canvas of the user interface.
3159    #[inline]
3160    pub fn put_back(&mut self, ticket: Ticket<UiNode>, node: UiNode) -> Handle<UiNode> {
3161        let handle = self.nodes.put_back(ticket, node);
3162        self.link_nodes(handle, self.root_canvas, false);
3163        handle
3164    }
3165
3166    /// Makes a widget handle vacant again.
3167    #[inline]
3168    pub fn forget_ticket(&mut self, ticket: Ticket<UiNode>, node: UiNode) -> UiNode {
3169        self.nodes.forget_ticket(ticket);
3170        node
3171    }
3172
3173    /// Extracts sub-graph starting from the given widget. All handles to extracted widgets
3174    ///  become reserved and will be marked as "occupied", an attempt to borrow a widget
3175    /// at such handle will result in panic!. Please note that root widget will be
3176    /// detached from its parent!
3177    #[inline]
3178    pub fn take_reserve_sub_graph(&mut self, root: Handle<UiNode>) -> SubGraph {
3179        // Take out descendants first.
3180        let mut descendants = Vec::new();
3181        let root_ref = &mut self.nodes[root];
3182        let mut stack = root_ref.children().to_vec();
3183        let parent = root_ref.parent;
3184        while let Some(handle) = stack.pop() {
3185            stack.extend_from_slice(self.nodes[handle].children());
3186            descendants.push(self.nodes.take_reserve(handle));
3187        }
3188
3189        SubGraph {
3190            // Root must be extracted with detachment from its parent (if any).
3191            root: self.take_reserve(root),
3192            descendants,
3193            parent,
3194        }
3195    }
3196
3197    /// Puts previously extracted sub-graph into the user interface. Handles to widgets will become valid
3198    /// again. After that, you probably want to re-link the returned handle with its previous parent.
3199    #[inline]
3200    pub fn put_sub_graph_back(&mut self, sub_graph: SubGraph) -> Handle<UiNode> {
3201        for (ticket, node) in sub_graph.descendants {
3202            self.nodes.put_back(ticket, node);
3203        }
3204
3205        let (ticket, node) = sub_graph.root;
3206        let root_handle = self.put_back(ticket, node);
3207
3208        self.link_nodes(root_handle, sub_graph.parent, false);
3209
3210        root_handle
3211    }
3212
3213    /// Forgets the entire sub-graph making handles to widgets invalid.
3214    #[inline]
3215    pub fn forget_sub_graph(&mut self, sub_graph: SubGraph) {
3216        for (ticket, _) in sub_graph.descendants {
3217            self.nodes.forget_ticket(ticket);
3218        }
3219        let (ticket, _) = sub_graph.root;
3220        self.nodes.forget_ticket(ticket);
3221    }
3222
3223    pub fn restricts_picking(&self, node: Handle<UiNode>) -> bool {
3224        self.picking_stack.iter().any(|e| e.handle == node)
3225    }
3226
3227    pub fn push_picking_restriction(&mut self, restriction: RestrictionEntry) {
3228        if let Some(top) = self.top_picking_restriction() {
3229            assert_ne!(top.handle, restriction.handle);
3230        }
3231        self.picking_stack.push(restriction);
3232    }
3233
3234    pub fn remove_picking_restriction(&mut self, node: Handle<UiNode>) {
3235        if let Some(pos) = self.picking_stack.iter().position(|h| h.handle == node) {
3236            self.picking_stack.remove(pos);
3237        }
3238    }
3239
3240    pub fn picking_restriction_stack(&self) -> &[RestrictionEntry] {
3241        &self.picking_stack
3242    }
3243
3244    /// Removes all picking restrictions.
3245    pub fn drop_picking_restrictions(&mut self) {
3246        self.picking_stack.clear();
3247    }
3248
3249    pub fn top_picking_restriction(&self) -> Option<RestrictionEntry> {
3250        self.picking_stack.last().cloned()
3251    }
3252
3253    pub fn drag_context(&self) -> &DragContext {
3254        &self.drag_context
3255    }
3256
3257    /// Links the specified child widget with the specified parent widget.
3258    #[inline]
3259    pub fn link_nodes(
3260        &mut self,
3261        child_handle: Handle<impl ObjectOrVariant<UiNode>>,
3262        parent_handle: Handle<impl ObjectOrVariant<UiNode>>,
3263        in_front: bool,
3264    ) {
3265        let child_handle = child_handle.to_base();
3266        let parent_handle = parent_handle.to_base();
3267        assert_ne!(child_handle, parent_handle);
3268        self.isolate_node(child_handle);
3269        self.nodes[child_handle].set_parent(parent_handle);
3270        self.nodes[parent_handle].add_child(child_handle, in_front);
3271    }
3272
3273    #[inline]
3274    pub fn node_mut(&mut self, node_handle: Handle<UiNode>) -> &mut UiNode {
3275        self.nodes.borrow_mut(node_handle)
3276    }
3277
3278    #[inline]
3279    pub fn try_get_node_mut(
3280        &mut self,
3281        node_handle: Handle<UiNode>,
3282    ) -> Result<&mut UiNode, PoolError> {
3283        self.nodes.try_borrow_mut(node_handle)
3284    }
3285
3286    pub fn copy_node(&mut self, node: Handle<UiNode>) -> Handle<UiNode> {
3287        let mut old_new_mapping = NodeHandleMap::default();
3288
3289        let root = self.copy_node_recursive(node, &mut old_new_mapping);
3290
3291        remap_handles(&old_new_mapping, self);
3292
3293        root
3294    }
3295
3296    #[allow(clippy::unnecessary_to_owned)] // False positive
3297    fn copy_node_recursive(
3298        &mut self,
3299        node_handle: Handle<UiNode>,
3300        old_new_mapping: &mut NodeHandleMap<UiNode>,
3301    ) -> Handle<UiNode> {
3302        let node = self.nodes.borrow(node_handle);
3303        let mut cloned = UiNode(node.clone_boxed());
3304        cloned.id = Uuid::new_v4();
3305
3306        let mut cloned_children = Vec::new();
3307        for child in node.children().to_vec() {
3308            cloned_children.push(self.copy_node_recursive(child, old_new_mapping));
3309        }
3310
3311        cloned.set_children(cloned_children);
3312        let copy_handle = self.add_node(cloned);
3313        old_new_mapping.insert(node_handle, copy_handle);
3314        copy_handle
3315    }
3316
3317    pub fn copy_node_to<Post>(
3318        &self,
3319        node: Handle<UiNode>,
3320        dest: &mut UserInterface,
3321        post_process_callback: &mut Post,
3322    ) -> (Handle<UiNode>, NodeHandleMap<UiNode>)
3323    where
3324        Post: FnMut(Handle<UiNode>, Handle<UiNode>, &mut UiNode),
3325    {
3326        let mut old_new_mapping = NodeHandleMap::default();
3327
3328        let root =
3329            self.copy_node_to_recursive(node, dest, &mut old_new_mapping, post_process_callback);
3330
3331        remap_handles(&old_new_mapping, dest);
3332
3333        (root, old_new_mapping)
3334    }
3335
3336    fn copy_node_to_recursive<Post>(
3337        &self,
3338        node_handle: Handle<UiNode>,
3339        dest: &mut UserInterface,
3340        old_new_mapping: &mut NodeHandleMap<UiNode>,
3341        post_process_callback: &mut Post,
3342    ) -> Handle<UiNode>
3343    where
3344        Post: FnMut(Handle<UiNode>, Handle<UiNode>, &mut UiNode),
3345    {
3346        let node = self.nodes.borrow(node_handle);
3347        let children = node.children.clone();
3348
3349        let mut cloned = UiNode(node.clone_boxed());
3350        cloned.children.clear();
3351        cloned.parent = Handle::NONE;
3352        cloned.id = Uuid::new_v4();
3353        let cloned_node_handle = dest.add_node(cloned);
3354
3355        for child in children {
3356            let cloned_child_node_handle =
3357                self.copy_node_to_recursive(child, dest, old_new_mapping, post_process_callback);
3358            dest.link_nodes(cloned_child_node_handle, cloned_node_handle, false);
3359        }
3360
3361        old_new_mapping.insert(node_handle, cloned_node_handle);
3362
3363        post_process_callback(
3364            cloned_node_handle,
3365            node_handle,
3366            dest.try_get_node_mut(cloned_node_handle).unwrap(),
3367        );
3368
3369        cloned_node_handle
3370    }
3371
3372    pub fn copy_node_with_limit(
3373        &mut self,
3374        node: Handle<UiNode>,
3375        limit: Option<usize>,
3376    ) -> Handle<UiNode> {
3377        let mut old_new_mapping = NodeHandleMap::default();
3378        let mut counter = 0;
3379
3380        let root =
3381            self.copy_node_recursive_with_limit(node, &mut old_new_mapping, limit, &mut counter);
3382
3383        remap_handles(&old_new_mapping, self);
3384
3385        root
3386    }
3387
3388    #[allow(clippy::unnecessary_to_owned)] // False positive
3389    fn copy_node_recursive_with_limit(
3390        &mut self,
3391        node_handle: Handle<UiNode>,
3392        old_new_mapping: &mut NodeHandleMap<UiNode>,
3393        limit: Option<usize>,
3394        counter: &mut usize,
3395    ) -> Handle<UiNode> {
3396        if let Some(limit) = limit {
3397            if *counter >= limit {
3398                return Default::default();
3399            }
3400        }
3401
3402        let Ok(node) = self.nodes.try_borrow(node_handle) else {
3403            return Default::default();
3404        };
3405
3406        let mut cloned = UiNode(node.clone_boxed());
3407        cloned.id = Uuid::new_v4();
3408
3409        let mut cloned_children = Vec::new();
3410        for child in node.children().to_vec() {
3411            let cloned_child =
3412                self.copy_node_recursive_with_limit(child, old_new_mapping, limit, counter);
3413            if cloned_child.is_some() {
3414                cloned_children.push(cloned_child);
3415            } else {
3416                break;
3417            }
3418        }
3419
3420        cloned.set_children(cloned_children);
3421        let copy_handle = self.add_node(cloned);
3422        old_new_mapping.insert(node_handle, copy_handle);
3423
3424        *counter += 1;
3425
3426        copy_handle
3427    }
3428
3429    pub fn save(&mut self, path: &Path) -> Result<Visitor, VisitError> {
3430        let mut visitor = Visitor::new();
3431        self.visit("Ui", &mut visitor)?;
3432        visitor.save_ascii_to_file(path)?;
3433        Ok(visitor)
3434    }
3435
3436    #[allow(clippy::arc_with_non_send_sync)]
3437    pub async fn load_from_file<P: AsRef<Path>>(
3438        path: P,
3439        constructors: Arc<WidgetConstructorContainer>,
3440        dyn_type_constructors: Arc<DynTypeConstructorContainer>,
3441        resource_manager: ResourceManager,
3442    ) -> Result<(Self, Vec<u8>), VisitError> {
3443        Self::load_from_file_ex(
3444            path,
3445            constructors,
3446            dyn_type_constructors,
3447            resource_manager,
3448            &FsResourceIo,
3449        )
3450        .await
3451    }
3452
3453    fn restore_dynamic_node_data(&mut self) {
3454        for (handle, widget) in self.nodes.pair_iter_mut() {
3455            widget.handle = handle;
3456            widget.layout_events_sender = Some(self.layout_events_sender.clone());
3457            widget.invalidate_layout();
3458            widget.notify_z_index_changed();
3459        }
3460    }
3461
3462    pub fn resolve(&mut self) {
3463        self.restore_dynamic_node_data();
3464        self.restore_original_handles_and_inherit_properties(&[], |_, _| {});
3465        self.update_visual_transform(self.root_canvas);
3466        self.update_global_visibility(self.root_canvas);
3467        let instances = self.restore_integrity(|model, model_data, handle, dest_graph| {
3468            model_data.copy_node_to(handle, dest_graph, &mut |_, original_handle, node| {
3469                node.set_inheritance_data(original_handle, model.clone());
3470            })
3471        });
3472        self.remap_handles(&instances);
3473    }
3474
3475    /// Collects all resources used by the user interface. It uses reflection to "scan" the contents
3476    /// of the user interface, so if some fields marked with `#[reflect(hidden)]` attribute, then
3477    /// such field will be ignored!
3478    pub fn collect_used_resources(&self) -> FxHashSet<UntypedResource> {
3479        let mut collection = FxHashSet::default();
3480        fyrox_resource::collect_used_resources(self, &mut collection);
3481        collection
3482    }
3483
3484    #[allow(clippy::arc_with_non_send_sync)]
3485    pub async fn load_from_file_ex<P: AsRef<Path>>(
3486        path: P,
3487        constructors: Arc<WidgetConstructorContainer>,
3488        dyn_type_constructors: Arc<DynTypeConstructorContainer>,
3489        resource_manager: ResourceManager,
3490        io: &dyn ResourceIo,
3491    ) -> Result<(Self, Vec<u8>), VisitError> {
3492        if !resource_manager.registry_is_loaded() {
3493            return Err("The resource registry is unavailable!".to_string().into());
3494        }
3495        let (mut ui, data) = {
3496            let data = io.load_file(path.as_ref()).await?;
3497            let mut visitor = Visitor::load_from_memory(&data)?;
3498            let (sender, receiver) = mpsc::channel();
3499            visitor.blackboard.register(constructors);
3500            visitor.blackboard.register(Arc::new(sender.clone()));
3501            visitor.blackboard.register(Arc::new(resource_manager));
3502            visitor.blackboard.register(dyn_type_constructors);
3503            let mut ui =
3504                UserInterface::new_with_channel(sender, receiver, Vector2::new(100.0, 100.0));
3505            ui.visit("Ui", &mut visitor)?;
3506            (ui, data)
3507        };
3508
3509        Log::info("UserInterface - Collecting resources used by the scene...");
3510
3511        let used_resources = ui.collect_used_resources();
3512
3513        let used_resources_count = used_resources.len();
3514
3515        Log::info(format!(
3516            "UserInterface - {used_resources_count} resources collected. Waiting them to load..."
3517        ));
3518
3519        // Wait everything.
3520        join_all(used_resources.into_iter()).await;
3521
3522        ui.resolve();
3523
3524        Ok((ui, data))
3525    }
3526}
3527
3528impl PrefabData for UserInterface {
3529    type Graph = Self;
3530
3531    #[inline]
3532    fn graph(&self) -> &Self::Graph {
3533        self
3534    }
3535
3536    #[inline]
3537    fn mapping(&self) -> NodeMapping {
3538        NodeMapping::UseHandles
3539    }
3540}
3541
3542impl SceneGraph for UserInterface {
3543    type Prefab = Self;
3544    type NodeContainer = WidgetContainer;
3545    type Node = UiNode;
3546
3547    fn summary(&self) -> String {
3548        let mut result = String::new();
3549        self.recursive_summary(0, self.root_canvas, &mut result);
3550        result
3551    }
3552
3553    #[inline]
3554    fn actual_type_id(&self, handle: Handle<Self::Node>) -> Result<TypeId, PoolError> {
3555        self.nodes
3556            .try_borrow(handle)
3557            .map(|n| ControlAsAny::as_any(n.0.deref()).type_id())
3558    }
3559
3560    fn actual_type_name(&self, handle: Handle<Self::Node>) -> Result<&'static str, PoolError> {
3561        self.nodes
3562            .try_borrow(handle)
3563            .map(|n| Reflect::type_name(n.0.deref()))
3564    }
3565
3566    fn derived_type_ids(&self, handle: Handle<Self::Node>) -> Result<Vec<TypeId>, PoolError> {
3567        self.nodes
3568            .try_borrow(handle)
3569            .map(|n| n.0.query_derived_types().to_vec())
3570    }
3571
3572    #[inline]
3573    fn root(&self) -> Handle<Self::Node> {
3574        self.root_canvas
3575    }
3576
3577    #[inline]
3578    fn set_root(&mut self, root: Handle<Self::Node>) {
3579        self.root_canvas = root;
3580    }
3581
3582    #[inline]
3583    fn try_get_node(&self, handle: Handle<Self::Node>) -> Result<&Self::Node, PoolError> {
3584        self.nodes.try_borrow(handle)
3585    }
3586
3587    #[inline]
3588    fn try_get_node_mut(
3589        &mut self,
3590        handle: Handle<Self::Node>,
3591    ) -> Result<&mut Self::Node, PoolError> {
3592        self.nodes.try_borrow_mut(handle)
3593    }
3594
3595    #[inline]
3596    fn is_valid_handle(&self, handle: Handle<impl ObjectOrVariant<Self::Node>>) -> bool {
3597        self.nodes.is_valid_handle(handle)
3598    }
3599
3600    #[inline]
3601    fn add_node(&mut self, node: Self::Node) -> Handle<Self::Node> {
3602        let handle = self.nodes.next_free_handle();
3603        self.add_node_at_handle(node, handle);
3604        handle
3605    }
3606
3607    fn add_node_at_handle(&mut self, mut node: Self::Node, node_handle: Handle<Self::Node>) {
3608        let children = node.children().to_vec();
3609        node.clear_children();
3610        self.nodes
3611            .spawn_at_handle(node_handle, node)
3612            .expect("The handle must be valid!");
3613        if self.root_canvas.is_some() {
3614            self.link_nodes(node_handle, self.root_canvas, false);
3615        }
3616        for child in children {
3617            self.link_nodes(child, node_handle, false)
3618        }
3619        let node = self.nodes[node_handle].deref_mut();
3620        node.layout_events_sender = Some(self.layout_events_sender.clone());
3621        node.handle = node_handle;
3622        self.methods_registry.register(node);
3623        node.invalidate_layout();
3624        node.notify_z_index_changed();
3625        self.layout_events_sender
3626            .send(LayoutEvent::VisibilityChanged(node_handle))
3627            .unwrap();
3628    }
3629
3630    #[inline]
3631    fn remove_node(&mut self, node: Handle<impl ObjectOrVariant<Self::Node>>) {
3632        let node = node.to_base();
3633        self.isolate_node(node);
3634
3635        let sender = self.sender.clone();
3636        let mut stack = vec![node];
3637        while let Some(handle) = stack.pop() {
3638            if self.prev_picked_node == handle {
3639                self.prev_picked_node = Handle::NONE;
3640            }
3641            if self.picked_node == handle {
3642                self.try_set_picked_node(Handle::NONE);
3643            }
3644            if self.captured_node == handle {
3645                self.captured_node = Handle::NONE;
3646            }
3647            if self.keyboard_focus_node == handle {
3648                self.keyboard_focus_node = Handle::NONE;
3649            }
3650            self.remove_picking_restriction(handle);
3651
3652            let node_ref = self.nodes.borrow(handle);
3653            stack.extend_from_slice(node_ref.children());
3654
3655            // Notify node that it is about to be deleted so it will have a chance to remove
3656            // other widgets (like popups).
3657            node_ref.on_remove(&sender);
3658
3659            self.methods_registry.unregister(node_ref.deref());
3660            self.nodes.free(handle);
3661        }
3662    }
3663
3664    #[inline]
3665    fn link_nodes(
3666        &mut self,
3667        child: Handle<impl ObjectOrVariant<Self::Node>>,
3668        parent: Handle<impl ObjectOrVariant<Self::Node>>,
3669    ) {
3670        self.link_nodes(child.to_base(), parent.to_base(), false)
3671    }
3672
3673    #[inline]
3674    fn unlink_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::Node>>) {
3675        self.isolate_node(node_handle);
3676        self.link_nodes(node_handle, self.root_canvas, false);
3677    }
3678
3679    #[inline]
3680    fn isolate_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::Node>>) {
3681        let node_handle = node_handle.to_base();
3682        let node = self.nodes.borrow_mut(node_handle);
3683        let parent_handle = node.parent();
3684        if parent_handle.is_some() {
3685            node.set_parent(Handle::NONE);
3686
3687            // Remove child from parent's children list
3688            self.nodes[parent_handle].remove_child(node_handle);
3689        }
3690    }
3691
3692    #[inline]
3693    fn pair_iter(&self) -> impl Iterator<Item = (Handle<Self::Node>, &Self::Node)> {
3694        self.nodes.pair_iter()
3695    }
3696
3697    #[inline]
3698    fn linear_iter(&self) -> impl Iterator<Item = &Self::Node> {
3699        self.nodes.iter()
3700    }
3701
3702    #[inline]
3703    fn linear_iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Node> {
3704        self.nodes.iter_mut()
3705    }
3706
3707    fn try_get<U: ObjectOrVariant<UiNode>>(&self, handle: Handle<U>) -> Result<&U, PoolError> {
3708        self.nodes.try_get(handle)
3709    }
3710
3711    fn try_get_mut<U: ObjectOrVariant<UiNode>>(
3712        &mut self,
3713        handle: Handle<U>,
3714    ) -> Result<&mut U, PoolError> {
3715        self.nodes.try_get_mut(handle)
3716    }
3717}
3718
3719pub trait UserInterfaceResourceExtension {
3720    fn instantiate(&self, ui: &mut UserInterface) -> (Handle<UiNode>, NodeHandleMap<UiNode>);
3721}
3722
3723impl UserInterfaceResourceExtension for Resource<UserInterface> {
3724    fn instantiate(&self, ui: &mut UserInterface) -> (Handle<UiNode>, NodeHandleMap<UiNode>) {
3725        let resource = self.clone();
3726        let mut data = self.state();
3727        let data = data.data().expect("The resource must be loaded!");
3728
3729        let (root, mapping) =
3730            data.copy_node_to(data.root_canvas, ui, &mut |_, original_handle, node| {
3731                node.set_inheritance_data(original_handle, resource.clone());
3732            });
3733
3734        // Explicitly mark as root node.
3735        ui.node_mut(root).is_resource_instance_root = true;
3736
3737        (root, mapping)
3738    }
3739}
3740
3741fn is_approx_zero(v: f32) -> bool {
3742    v.abs() <= 10.0 * f32::EPSILON
3743}
3744
3745fn are_close(value1: f32, value2: f32) -> bool {
3746    //in case they are Infinities (then epsilon check does not work)
3747    if value1 == value2 {
3748        return true;
3749    }
3750    // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
3751    let eps = (value1.abs() + value2.abs() + 10.0) * f32::EPSILON;
3752    let delta = value1 - value2;
3753    (-eps < delta) && (eps > delta)
3754}
3755
3756fn greater_than_or_close(value1: f32, value2: f32) -> bool {
3757    (value1 > value2) || are_close(value1, value2)
3758}
3759
3760fn less_than_or_close(value1: f32, value2: f32) -> bool {
3761    (value1 < value2) || are_close(value1, value2)
3762}
3763
3764/// Calculates a new size for the rect after transforming it with the given matrix. Basically, it
3765/// finds a new rectangle that can contain the rotated rectangle.
3766///
3767/// # Origin
3768///
3769/// The Original code was taken from WPF source code (FindMaximalAreaLocalSpaceRect) and ported to Rust.
3770/// It handles a lot of edge cases that could occur due to the fact that the UI uses a lot of
3771/// special floating-point constants like Infinity or NaN. If there would be no such values, simple
3772/// `rect.transform(&matrix).size` could be used.
3773fn transform_size(transform_space_bounds: Vector2<f32>, matrix: &Matrix3<f32>) -> Vector2<f32> {
3774    // X (width) and Y (height) constraints for axis-aligned bounding box in dest. space
3775    let mut x_constr: f32 = transform_space_bounds.x;
3776    let mut y_constr: f32 = transform_space_bounds.y;
3777
3778    //if either of the sizes is 0, return 0,0 to avoid doing math on an empty rect (bug 963569)
3779    if is_approx_zero(x_constr) || is_approx_zero(y_constr) {
3780        return Vector2::new(0.0, 0.0);
3781    }
3782
3783    let x_constr_infinite = x_constr.is_infinite();
3784    let y_constr_infinite = y_constr.is_infinite();
3785
3786    if x_constr_infinite && y_constr_infinite {
3787        return Vector2::new(f32::INFINITY, f32::INFINITY);
3788    } else if x_constr_infinite
3789    //assume square for one-dimensional constraint
3790    {
3791        x_constr = y_constr;
3792    } else if y_constr_infinite {
3793        y_constr = x_constr;
3794    }
3795
3796    // We only deal with nonsingular matrices here. The nonsingular matrix is the one
3797    // that has inverse (determinant != 0).
3798    if !matrix.is_invertible() {
3799        return Vector2::new(0.0, 0.0);
3800    }
3801
3802    let a = matrix[(0, 0)];
3803    let b = matrix[(0, 1)];
3804    let c = matrix[(1, 0)];
3805    let d = matrix[(1, 1)];
3806
3807    // Result width and height (in child/local space)
3808    let mut w;
3809    let mut h;
3810
3811    // because we are dealing with nonsingular transform matrices,
3812    // we have (b==0 || c==0) XOR (a==0 || d==0)
3813
3814    if is_approx_zero(b) || is_approx_zero(c) {
3815        // (b==0 || c==0) ==> a!=0 && d!=0
3816
3817        let y_cover_d = if y_constr_infinite {
3818            f32::INFINITY
3819        } else {
3820            (y_constr / d).abs()
3821        };
3822        let x_cover_a = if x_constr_infinite {
3823            f32::INFINITY
3824        } else {
3825            (x_constr / a).abs()
3826        };
3827
3828        if is_approx_zero(b) {
3829            if is_approx_zero(c) {
3830                // Case: b=0, c=0, a!=0, d!=0
3831
3832                // No constraint relation; use maximal width and height
3833
3834                h = y_cover_d;
3835                w = x_cover_a;
3836            } else {
3837                // Case: b==0, a!=0, c!=0, d!=0
3838
3839                // Maximizing underline (hIntercept=xConstr/c, wIntercept=xConstr/a)
3840                // BUT we still have constraint: h <= yConstr/d
3841
3842                h = (0.5 * (x_constr / c).abs()).min(y_cover_d);
3843                w = x_cover_a - ((c * h) / a);
3844            }
3845        } else {
3846            // Case: c==0, a!=0, b!=0, d!=0
3847
3848            // Maximizing underline (hIntercept=yConstr/d, wIntercept=yConstr/b)
3849            // BUT we still have constraint: w <= xConstr/a
3850
3851            w = (0.5 * (y_constr / b).abs()).min(x_cover_a);
3852            h = y_cover_d - ((b * w) / d);
3853        }
3854    } else if is_approx_zero(a) || is_approx_zero(d) {
3855        // (a==0 || d==0) ==> b!=0 && c!=0
3856
3857        let y_cover_b = (y_constr / b).abs();
3858        let x_cover_c = (x_constr / c).abs();
3859
3860        if is_approx_zero(a) {
3861            if is_approx_zero(d) {
3862                // Case: a=0, d=0, b!=0, c!=0
3863
3864                // No constraint relation; use maximal width and height
3865
3866                h = x_cover_c;
3867                w = y_cover_b;
3868            } else {
3869                // Case: a==0, b!=0, c!=0, d!=0
3870
3871                // Maximizing underline (hIntercept=yConstr/d, wIntercept=yConstr/b)
3872                // BUT we still have constraint: h <= xConstr/c
3873
3874                h = (0.5 * (y_constr / d).abs()).min(x_cover_c);
3875                w = y_cover_b - ((d * h) / b);
3876            }
3877        } else {
3878            // Case: d==0, a!=0, b!=0, c!=0
3879
3880            // Maximizing underline (hIntercept=xConstr/c, wIntercept=xConstr/a)
3881            // BUT we still have constraint: w <= yConstr/b
3882
3883            w = (0.5 * (x_constr / a).abs()).min(y_cover_b);
3884            h = x_cover_c - ((a * w) / c);
3885        }
3886    } else {
3887        let x_cover_a = (x_constr / a).abs(); // w-intercept of x-constraint line.
3888        let x_cover_c = (x_constr / c).abs(); // h-intercept of x-constraint line.
3889
3890        let y_cover_b = (y_constr / b).abs(); // w-intercept of y-constraint line.
3891        let y_cover_d = (y_constr / d).abs(); // h-intercept of y-constraint line.
3892
3893        // The tightest constraint governs, so we pick the lowest constraint line.
3894        //
3895        //   The optimal point (w,h) for which Area = w*h is maximized occurs halfway
3896        //   to each intercept.
3897
3898        w = y_cover_b.min(x_cover_a) * 0.5;
3899        h = x_cover_c.min(y_cover_d) * 0.5;
3900
3901        if (greater_than_or_close(x_cover_a, y_cover_b) && less_than_or_close(x_cover_c, y_cover_d))
3902            || (less_than_or_close(x_cover_a, y_cover_b)
3903                && greater_than_or_close(x_cover_c, y_cover_d))
3904        {
3905            // Constraint lines cross; since the most restrictive constraint wins,
3906            // we have to maximize under two line segments, which together are discontinuous.
3907            // Instead, we maximize w*h under the line segment from the two smallest endpoints.
3908
3909            // Since we are not (except for in corner cases) on the original constraint lines,
3910            // we are not using up all the available area in transform space.  So scale our shape up
3911            // until it does in at least one dimension.
3912
3913            let child_bounds_tr = Rect::new(0.0, 0.0, w, h).transform(matrix);
3914            let expand_factor =
3915                (x_constr / child_bounds_tr.size.x).min(y_constr / child_bounds_tr.size.y);
3916
3917            if !expand_factor.is_nan() && !expand_factor.is_infinite() {
3918                w *= expand_factor;
3919                h *= expand_factor;
3920            }
3921        }
3922    }
3923
3924    Vector2::new(w, h)
3925}
3926
3927uuid_provider!(UserInterface = "0d065c93-ef9c-4dd2-9fe7-e2b33c1a21b6");
3928
3929impl ResourceData for UserInterface {
3930    fn type_uuid(&self) -> Uuid {
3931        <Self as TypeUuidProvider>::type_uuid()
3932    }
3933
3934    fn save(&mut self, path: &Path) -> Result<(), Box<dyn Error>> {
3935        self.save(path)?;
3936        Ok(())
3937    }
3938
3939    fn can_be_saved(&self) -> bool {
3940        true
3941    }
3942
3943    fn try_clone_box(&self) -> Option<Box<dyn ResourceData>> {
3944        Some(Box::new(self.clone()))
3945    }
3946}
3947
3948#[cfg(test)]
3949mod test_inner {
3950    use crate::message::UiMessage;
3951    use crate::{
3952        border::BorderBuilder,
3953        core::algebra::{Rotation2, UnitComplex, Vector2},
3954        message::{ButtonState, KeyCode},
3955        text_box::TextBoxBuilder,
3956        transform_size,
3957        widget::{WidgetBuilder, WidgetMessage},
3958        OsEvent, UserInterface,
3959    };
3960
3961    #[test]
3962    fn test_transform_size() {
3963        let input = Vector2::new(100.0, 100.0);
3964        let transform =
3965            Rotation2::from(UnitComplex::from_angle(45.0f32.to_radians())).to_homogeneous();
3966        let transformed = transform_size(input, &transform);
3967        dbg!(input, transformed);
3968    }
3969
3970    #[test]
3971    fn center() {
3972        let screen_size = Vector2::new(1000.0, 1000.0);
3973        let widget_size = Vector2::new(100.0, 100.0);
3974        let mut ui = UserInterface::new(screen_size);
3975        let widget = BorderBuilder::new(
3976            WidgetBuilder::new()
3977                .with_width(widget_size.x)
3978                .with_height(widget_size.y),
3979        )
3980        .build(&mut ui.build_ctx());
3981        ui.update(screen_size, 0.0, &Default::default()); // Make sure the layout was calculated.
3982        ui.send(widget, WidgetMessage::Center);
3983        while ui.poll_message().is_some() {}
3984        ui.update(screen_size, 0.0, &Default::default());
3985        let expected_position = (screen_size - widget_size).scale(0.5);
3986        let actual_position = ui[widget].actual_local_position();
3987        assert_eq!(actual_position, expected_position);
3988    }
3989
3990    #[test]
3991    fn test_keyboard_focus() {
3992        let screen_size = Vector2::new(1000.0, 1000.0);
3993        let mut ui = UserInterface::new(screen_size);
3994
3995        let text_box = TextBoxBuilder::new(WidgetBuilder::new()).build(&mut ui.build_ctx());
3996
3997        // Make sure the layout was calculated.
3998        ui.update(screen_size, 0.0, &Default::default());
3999
4000        assert!(ui.poll_message().is_none());
4001
4002        ui.send(text_box, WidgetMessage::Focus);
4003
4004        // Ensure that the message has gotten in the queue.
4005        assert_eq!(
4006            ui.poll_message(),
4007            Some(UiMessage::for_widget(text_box, WidgetMessage::Focus))
4008        );
4009        // Root must be unfocused right before the new widget is focused.
4010        assert_eq!(
4011            ui.poll_message(),
4012            Some(UiMessage::from_widget(ui.root(), WidgetMessage::Unfocus))
4013        );
4014        // Finally, there should be a response from newly focused node.
4015        assert_eq!(
4016            ui.poll_message(),
4017            Some(UiMessage::from_widget(text_box, WidgetMessage::Focus))
4018        );
4019
4020        // Do additional check - emulate key press of "A" and check if the focused text box has accepted it.
4021        ui.process_os_event(&OsEvent::KeyboardInput {
4022            button: KeyCode::KeyA,
4023            state: ButtonState::Pressed,
4024            text: "A".to_string(),
4025        });
4026
4027        let msg = UiMessage::from_widget(text_box, WidgetMessage::KeyDown(KeyCode::KeyA));
4028        msg.set_handled(true);
4029        assert_eq!(ui.poll_message(), Some(msg));
4030
4031        assert_eq!(
4032            ui.poll_message(),
4033            Some(UiMessage::from_widget(
4034                text_box,
4035                WidgetMessage::Text('A'.to_string())
4036            ))
4037        );
4038
4039        assert!(ui.poll_message().is_none());
4040    }
4041}