ferroui_controls/
control_extensions.rs1use crate::{Control, RequestBringIntoViewEventArgs};
2use ferroui_base::controls::NameScopeExtensions;
3use ferroui_base::layout::{BringIntoViewRequest, Layoutable};
4use ferroui_base::reactive::{AnonymousObserver, IDisposable, IObservable};
5use ferroui_base::{ObjectType, Rect, Ref};
6use std::rc::Rc;
7
8impl Control {
9 pub fn bring_into_view(&self) {
11 self.bring_into_view_core(None);
12 }
13
14 pub fn bring_into_view_rect(&self, rect: Rect) {
18 self.bring_into_view_core(Some(rect));
19 }
20
21 fn bring_into_view_core(&self, rect: Option<Rect>) {
22 if self.try_execute_bring_into_view(rect) {
23 return;
24 }
25
26 if let Some(layout_root) = self.get_layout_root() {
27 let layout_manager = layout_root.layout_manager();
28 if let Some(layout_manager) = layout_manager.as_bring_into_view_layout_manager() {
29 layout_manager
30 .enqueue_bring_into_view(Rc::new(ControlBringIntoViewRequest { target: self.to_ref(), rect }));
31 }
32 }
33 }
34
35 fn try_execute_bring_into_view(&self, rect: Option<Rect>) -> bool {
36 if !self.is_effectively_visible() {
37 return true; }
39
40 if !self.is_measure_valid() || !self.is_arrange_valid() {
41 return false;
42 }
43
44 let mut ev = RequestBringIntoViewEventArgs::with_event(Control::request_bring_into_view_event());
45 ev.target_object = Some(self.to_ref().upcast());
46 ev.set_target_rect(rect.unwrap_or_else(|| Rect::from_size(self.bounds().size())));
47
48 self.raise_event(&ev);
49 true
50 }
51
52 pub fn find_control<T: ObjectType>(&self, name: &str) -> Option<Ref<T>> {
57 match NameScopeExtensions::find_name_scope(self) {
58 Some(name_scope) => name_scope.find_as::<T>(name),
59 None => panic!("Could not find parent name scope."),
60 }
61 }
62
63 pub fn get_control<T: ObjectType>(&self, name: &str) -> Ref<T> {
68 match self.find_control::<T>(name) {
69 Some(control) => control,
70 None => panic!("Could not find control named '{name}'."),
71 }
72 }
73
74 pub fn set_pseudo_class_from(&self, name: &str, trigger: &dyn IObservable<bool>) -> Rc<dyn IDisposable> {
78 let name = name.to_string();
79 let weak = self.to_ref().downgrade();
80 trigger.subscribe(Rc::new(AnonymousObserver::new(move |x: bool| {
81 if let Some(this) = weak.upgrade() {
82 this.pseudo_classes().set(&name, x);
83 }
84 })))
85 }
86}
87
88struct ControlBringIntoViewRequest {
89 target: Ref<Control>,
90 rect: Option<Rect>,
91}
92
93impl BringIntoViewRequest for ControlBringIntoViewRequest {
94 fn target(&self) -> Ref<Layoutable> {
95 self.target.clone().upcast()
96 }
97
98 fn try_execute(&self) -> bool {
99 self.target.try_execute_bring_into_view(self.rect)
100 }
101}