ferroui_base/interactivity/
routed_event_args.rs1use super::{RoutedEvent, RoutingStrategies};
2use crate::{FerroObject, Nullable, Ref};
3use std::any::{Any, TypeId};
4use std::cell::{Cell, RefCell};
5use std::ops::Deref;
6use std::rc::Rc;
7
8pub trait IRoutedEventArgs: Any {
18 fn as_routed_event_args(&self) -> &RoutedEventArgs;
20
21 fn query_args(&self, type_id: TypeId) -> Option<&dyn Any>;
24
25 fn is_args_type(type_id: TypeId) -> bool
28 where
29 Self: Sized;
30
31 fn share(&self) -> Rc<dyn IRoutedEventArgs>;
36}
37
38impl PartialEq for dyn IRoutedEventArgs {
42 #[inline]
43 fn eq(&self, other: &Self) -> bool {
44 self.as_routed_event_args() == other.as_routed_event_args()
45 }
46}
47
48impl dyn IRoutedEventArgs {
49 #[inline]
52 pub fn downcast_ref<T: IRoutedEventArgs>(&self) -> Option<&T> {
53 self.query_args(TypeId::of::<T>()).and_then(<dyn Any>::downcast_ref::<T>)
54 }
55
56 #[inline]
58 pub fn is<T: IRoutedEventArgs>(&self) -> bool {
59 self.query_args(TypeId::of::<T>()).is_some()
60 }
61}
62
63impl Deref for dyn IRoutedEventArgs {
64 type Target = RoutedEventArgs;
65
66 #[inline]
67 fn deref(&self) -> &RoutedEventArgs {
68 self.as_routed_event_args()
69 }
70}
71
72#[derive(Clone, Default)]
83pub struct RoutedEventArgs {
84 state: Rc<RoutedEventArgsState>,
85}
86
87#[derive(Default)]
88struct RoutedEventArgsState {
89 handled: Cell<bool>,
90 routed_event: Cell<Option<RoutedEvent>>,
91 route: Cell<RoutingStrategies>,
92 source: RefCell<Option<Ref<FerroObject>>>,
93}
94
95impl PartialEq for RoutedEventArgs {
96 #[inline]
97 fn eq(&self, other: &Self) -> bool {
98 Rc::ptr_eq(&self.state, &other.state)
99 }
100}
101
102impl RoutedEventArgs {
103 pub fn new() -> Self {
105 Self::default()
106 }
107
108 pub fn with_event<T: ?Sized>(routed_event: &RoutedEvent<T>) -> Self {
110 let result = Self::default();
111 result.state.routed_event.set(Some(routed_event.as_routed_event()));
112 result
113 }
114
115 pub fn with_event_and_source<T: ?Sized>(
117 routed_event: &RoutedEvent<T>,
118 source: impl Into<Nullable<FerroObject>>,
119 ) -> Self {
120 let result = Self::with_event(routed_event);
121 result.state.source.replace(source.into().0);
122 result
123 }
124
125 #[inline]
130 pub fn handled(&self) -> bool {
131 self.state.handled.get()
132 }
133
134 #[inline]
136 pub fn set_handled(&self, value: bool) {
137 self.state.handled.set(value)
138 }
139
140 #[inline]
142 pub fn routed_event(&self) -> Option<RoutedEvent> {
143 self.state.routed_event.get()
144 }
145
146 #[inline]
148 pub fn set_routed_event<T: ?Sized>(&self, value: Option<&RoutedEvent<T>>) {
149 self.state.routed_event.set(value.map(RoutedEvent::as_routed_event))
150 }
151
152 #[inline]
154 pub fn route(&self) -> RoutingStrategies {
155 self.state.route.get()
156 }
157
158 #[inline]
160 pub fn set_route(&self, value: RoutingStrategies) {
161 self.state.route.set(value)
162 }
163
164 #[inline]
166 pub fn source(&self) -> Option<Ref<FerroObject>> {
167 self.state.source.borrow().clone()
168 }
169
170 pub fn set_source(&self, value: impl Into<Nullable<FerroObject>>) {
172 let old = self.state.source.replace(value.into().0);
174 drop(old);
175 }
176
177 #[inline]
179 pub fn is_source(&self, object: &FerroObject) -> bool {
180 match &*self.state.source.borrow() {
181 Some(source) => std::ptr::eq::<FerroObject>(&**source, object),
182 None => false,
183 }
184 }
185}
186
187impl IRoutedEventArgs for RoutedEventArgs {
188 #[inline]
189 fn as_routed_event_args(&self) -> &RoutedEventArgs {
190 self
191 }
192
193 #[inline]
194 fn query_args(&self, type_id: TypeId) -> Option<&dyn Any> {
195 if type_id == TypeId::of::<RoutedEventArgs>() {
196 Some(self)
197 } else {
198 None
199 }
200 }
201
202 #[inline]
203 fn is_args_type(type_id: TypeId) -> bool {
204 type_id == TypeId::of::<RoutedEventArgs>()
205 }
206
207 fn share(&self) -> Rc<dyn IRoutedEventArgs> {
208 Rc::new(self.clone())
209 }
210}
211
212#[macro_export]
228macro_rules! ferro_routed_event_args {
229 ($name:ident : $base:ty) => {
230 impl ::std::ops::Deref for $name {
231 type Target = $base;
232
233 #[inline]
234 fn deref(&self) -> &$base {
235 &self.base
236 }
237 }
238
239 impl $crate::interactivity::IRoutedEventArgs for $name {
240 #[inline]
241 fn as_routed_event_args(&self) -> &$crate::interactivity::RoutedEventArgs {
242 $crate::interactivity::IRoutedEventArgs::as_routed_event_args(&self.base)
243 }
244
245 #[inline]
246 fn query_args(&self, type_id: ::std::any::TypeId) -> ::std::option::Option<&dyn ::std::any::Any> {
247 if type_id == ::std::any::TypeId::of::<$name>() {
248 ::std::option::Option::Some(self)
249 } else {
250 $crate::interactivity::IRoutedEventArgs::query_args(&self.base, type_id)
251 }
252 }
253
254 #[inline]
255 fn is_args_type(type_id: ::std::any::TypeId) -> bool {
256 type_id == ::std::any::TypeId::of::<$name>()
257 || <$base as $crate::interactivity::IRoutedEventArgs>::is_args_type(type_id)
258 }
259
260 fn share(&self) -> ::std::rc::Rc<dyn $crate::interactivity::IRoutedEventArgs> {
261 ::std::rc::Rc::new(::std::clone::Clone::clone(self))
262 }
263 }
264 };
265}