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