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