Skip to main content

ferroui_diagnostics/diagnostics/models/
event_chain_link.rs

1//! Port of `Diagnostics/Models/EventChainLink.cs`.
2
3use ferroui_base::data::core::{ValueType, ValueTypes};
4use ferroui_base::interactivity::RoutingStrategies;
5use ferroui_base::{ferro_markup_type, BoxedValue, StyledElement};
6use std::cell::Cell;
7use std::rc::Rc;
8
9/// One link of the chain of a routed event: an object whose handlers saw the event, whether the
10/// event was handled there and the route it took.
11pub struct EventChainLink {
12    handler: BoxedValue,
13    begins_new_route: Cell<bool>,
14    handled: Cell<bool>,
15    route: RoutingStrategies,
16}
17
18impl PartialEq for EventChainLink {
19    fn eq(&self, other: &Self) -> bool {
20        std::ptr::eq(self, other)
21    }
22}
23
24impl EventChainLink {
25    /// C# `new EventChainLink(object handler, bool handled, RoutingStrategies route)`.
26    pub fn new(handler: BoxedValue, handled: bool, route: RoutingStrategies) -> Rc<Self> {
27        Rc::new(Self { handler, begins_new_route: Cell::new(false), handled: Cell::new(handled), route })
28    }
29
30    pub fn handler(&self) -> BoxedValue {
31        self.handler.clone()
32    }
33
34    pub fn begins_new_route(&self) -> bool {
35        self.begins_new_route.get()
36    }
37
38    pub fn set_begins_new_route(&self, value: bool) {
39        self.begins_new_route.set(value);
40    }
41
42    /// The name of the handler: its name and the name of its type (`name (Button)`) when it is
43    /// a named element (`INamed`) with a name, else the name of its type.
44    pub fn handler_name(&self) -> String {
45        let object = ValueTypes::as_object(&*self.handler);
46        // `Handler.GetType().Name`.
47        let type_name = match &object {
48            Some(object) => object.get_type().name().to_string(),
49            None => {
50                let full_name = ValueTypes::type_full_name(ValueType::of_value(&*self.handler));
51                let start = full_name.rfind('.').map_or(0, |index| index + 1);
52                full_name[start..].to_string()
53            }
54        };
55
56        if let Some(name) = object
57            .and_then(|object| object.cast::<StyledElement>())
58            .and_then(|named| named.name())
59            .filter(|name| !name.is_empty())
60        {
61            return name + " (" + &type_name + ")";
62        }
63
64        type_name
65    }
66
67    pub fn handled(&self) -> bool {
68        self.handled.get()
69    }
70
71    pub fn set_handled(&self, value: bool) {
72        self.handled.set(value);
73    }
74
75    pub fn route(&self) -> RoutingStrategies {
76        self.route
77    }
78}
79
80ferro_markup_type!(class EventChainLink {
81    this: Rc<EventChainLink>,
82    handles: [Rc<EventChainLink>, Option<Rc<EventChainLink>>],
83    properties: [
84        Handler: Option<BoxedValue> { get: |l: &Rc<EventChainLink>| Some(l.handler()) },
85        BeginsNewRoute: bool {
86            get: |l: &Rc<EventChainLink>| l.begins_new_route(),
87            set: |l: &Rc<EventChainLink>, value: bool| l.set_begins_new_route(value)
88        },
89        HandlerName: String { get: |l: &Rc<EventChainLink>| l.handler_name() },
90        Handled: bool {
91            get: |l: &Rc<EventChainLink>| l.handled(),
92            set: |l: &Rc<EventChainLink>, value: bool| l.set_handled(value)
93        },
94        Route: RoutingStrategies { get: |l: &Rc<EventChainLink>| l.route() },
95    ],
96});