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