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