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