ferroui_controls/flyouts/
flyout_base.rs1use crate::Control;
2use ferroui_base::data::core::ValueTypes;
3use ferroui_base::reactive::{Disposable, IDisposable};
4use ferroui_base::utilities::HandlerList;
5use ferroui_base::{
6 ferro_class, ferro_property, AttachedProperty, DirectProperty, ElementRef, FerroObject, FerroObjectImpl,
7 FerroProperty, Nullable, Ref, StyledProperty,
8};
9use std::cell::RefCell;
10use std::rc::Rc;
11
12#[repr(C)]
16pub struct FlyoutBase {
17 base: FerroObject,
18 target: RefCell<Option<ElementRef<Control>>>,
20 opened: HandlerList<dyn Fn()>,
21 closed: HandlerList<dyn Fn()>,
22}
23
24ferro_class! {
25 FlyoutBase: FerroObject, virtuals FlyoutBaseImpl: FerroObjectImpl {
26 fn show_at(this, placement_target: &Control);
28 fn hide(this);
30 fn on_opened(this);
32 fn on_closed(this);
34 }
35}
36
37ferroui_base::ferro_impl_classes!(FlyoutBase: FerroObjectImpl);
38
39impl FlyoutBaseImpl for FlyoutBase {
40 fn show_at(_this: &Self, _placement_target: &Control) {
41 panic!("FlyoutBase is abstract.")
42 }
43
44 fn hide(_this: &Self) {
45 panic!("FlyoutBase is abstract.")
46 }
47
48 fn on_opened(this: &Self) {
49 for (_, handler) in this.opened.snapshot().iter() {
50 handler();
51 }
52 }
53
54 fn on_closed(this: &Self) {
55 for (_, handler) in this.closed.snapshot().iter() {
56 handler();
57 }
58 }
59}
60
61ferroui_base::ferro_properties! { impl FlyoutBase {
62 ferro_property!(
63 pub fn is_open_property() -> StyledProperty<bool> {
65 FerroProperty::register::<FlyoutBase, _>("IsOpen", false)
66 }
67 );
68
69 ferro_property!(
70 pub fn target_property() -> DirectProperty<FlyoutBase, Option<ElementRef<Control>>> {
72 ValueTypes::register_element_ref::<Control>();
73 FerroProperty::register_direct::<FlyoutBase, _>("Target", |x| x.target.borrow().clone(), None, None)
74 }
75 );
76
77 ferro_property!(
78 pub fn attached_flyout_property() -> AttachedProperty<Option<Ref<FlyoutBase>>> {
80 FerroProperty::register_attached::<FlyoutBase, Control, _>("AttachedFlyout", None)
81 }
82 );
83} }
84
85impl FlyoutBase {
86 pub fn construct() -> Self {
88 Self {
89 base: FerroObject::construct(),
90 target: RefCell::new(None),
91 opened: HandlerList::new(),
92 closed: HandlerList::new(),
93 }
94 }
95
96 fn subscribe(&self, select: fn(&FlyoutBase) -> &HandlerList<dyn Fn()>, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
97 let token = select(self).add(handler);
98 let weak = self.to_ref().downgrade();
99 Disposable::create(move || {
100 if let Some(this) = weak.upgrade() {
101 select(&this).remove(token);
102 }
103 })
104 }
105
106 pub fn opened(&self, handler: impl Fn() + 'static) -> Rc<dyn IDisposable> {
109 self.subscribe(|flyout| &flyout.opened, Rc::new(handler))
110 }
111
112 pub fn closed(&self, handler: impl Fn() + 'static) -> Rc<dyn IDisposable> {
115 self.subscribe(|flyout| &flyout.closed, Rc::new(handler))
116 }
117
118 pub fn is_open(&self) -> bool {
124 self.get_value(Self::is_open_property())
125 }
126
127 pub fn set_is_open(&self, value: bool) {
128 self.set_value(Self::is_open_property(), value)
129 }
130
131 pub fn target(&self) -> Option<Ref<Control>> {
133 ElementRef::resolve(&self.target.borrow())
134 }
135
136 pub fn set_target(&self, value: impl Into<Nullable<Control>>) {
138 self.set_and_raise(Self::target_property(), &self.target, ElementRef::from_nullable(value.into().0));
139 }
140
141 pub fn get_attached_flyout(element: &Control) -> Option<Ref<FlyoutBase>> {
143 element.get_value(Self::attached_flyout_property())
144 }
145
146 pub fn set_attached_flyout(element: &Control, value: impl Into<Nullable<FlyoutBase>>) {
148 element.set_value(Self::attached_flyout_property(), value.into().0)
149 }
150
151 pub fn show_attached_flyout(flyout_owner: &Control) {
153 let flyout = Self::get_attached_flyout(flyout_owner);
154 if let Some(flyout) = flyout {
155 flyout.show_at(flyout_owner);
156 }
157 }
158}