makepad_platform/
action.rs

1use crate::generate_any_trait_api;
2use crate::cx::Cx;
3use crate::thread::SignalToUI;
4use std::any::{TypeId};
5use std::fmt::Debug;
6use std::fmt;
7
8use std::sync::{
9    Mutex,
10    mpsc::{Sender}
11};
12
13
14pub (crate) static ACTION_SENDER_GLOBAL: Mutex<Option<Sender<ActionSend>>> = Mutex::new(None);
15
16pub trait ActionTrait: 'static {
17    fn debug_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
18    fn ref_cast_type_id(&self) -> TypeId where Self: 'static {TypeId::of::<Self>()}
19}
20
21impl<T: 'static + Debug + ?Sized > ActionTrait for T {
22    fn debug_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result{
23        self.fmt(f)
24    }
25}
26
27generate_any_trait_api!(ActionTrait);
28
29impl Debug for dyn ActionTrait {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result{
31        self.debug_fmt(f)
32    }
33}
34pub type ActionSend = Box<dyn ActionTrait + Send>;
35pub type Action = Box<dyn ActionTrait>;
36pub type ActionsBuf = Vec<Action>;
37pub type Actions = [Action];
38
39pub trait ActionDefaultRef{
40    fn default_ref()->&'static Self;
41}
42
43pub trait ActionCast<T> {
44    fn cast(&self) -> T;
45}
46
47pub trait ActionCastRef<T> {
48    fn cast_ref(&self) -> &T;
49}
50
51impl<T: ActionTrait + Default + Clone> ActionCast<T> for Box<dyn ActionTrait>{
52    fn cast(&self) -> T{
53        if let Some(item) = (*self).downcast_ref::<T>() {
54            item.clone()
55        }
56        else {
57            T::default()
58        }
59    }
60}
61
62
63impl<T: ActionTrait + ActionDefaultRef> ActionCastRef<T> for Box<dyn ActionTrait>{
64    fn cast_ref(&self) -> &T{
65        if let Some(item) = (*self).downcast_ref::<T>() {
66            item
67        }
68        else {
69            T::default_ref()
70        }
71    }
72}
73
74impl<T: ActionTrait + ActionDefaultRef> ActionCastRef<T> for Option<std::sync::Arc<dyn ActionTrait>>{
75    fn cast_ref(&self) -> &T{
76        if let Some(item) = self{
77            if let Some(item) = item.downcast_ref::<T>() {
78                return item
79            }
80        }
81        T::default_ref()
82    }
83}
84
85impl Cx{
86    pub fn handle_action_receiver(&mut self){
87        while let Ok(action) = self.action_receiver.try_recv(){
88            self.new_actions.push(action);
89        }
90        self.handle_actions();
91    }
92    
93    /// Enqueues an action from a background thread context.
94    ///
95    /// This will produce a bare action, *not* a widget action,
96    /// so you cannot use `as_widget_action()` when handling this action.
97    pub fn post_action(action:impl ActionTrait + Send){
98        ACTION_SENDER_GLOBAL.lock().unwrap().as_mut().unwrap().send(Box::new(action)).unwrap();
99        SignalToUI::set_action_signal();
100    }
101    
102    pub fn action(&mut self, action: impl ActionTrait){
103        self.new_actions.push(Box::new(action));
104    }
105
106    /// Adds the given `actions` back into the set of existing queued actions.
107    ///
108    /// This is useful when you want to allow other widgets elsewhere in the UI tree
109    /// to receive the given `actions`, e.g., after you have previously captured them
110    /// using `capture_actions()`.
111    pub fn extend_actions(&mut self, actions: ActionsBuf){
112        self.new_actions.extend(actions);
113    }
114    
115    pub fn map_actions<F, G, R>(&mut self, f: F, g:G) -> R
116    where
117        F: FnOnce(&mut Cx) -> R,
118        G: FnOnce(&mut Cx, ActionsBuf)->ActionsBuf,
119    {
120        let start = self.new_actions.len();
121        let r = f(self);
122        let end = self.new_actions.len();
123        if start != end{
124            let buf = self.new_actions.drain(start..end).collect();
125            let buf = g(self, buf);
126            self.new_actions.extend(buf);
127        }
128        r
129    }
130    
131    pub fn mutate_actions<F, G, R>(&mut self, f: F, g:G) -> R
132    where
133        F: FnOnce(&mut Cx) -> R,
134        G: FnOnce(&mut [Action]),
135    {
136        let start = self.new_actions.len();
137        let r = f(self);
138        let end = self.new_actions.len();
139        if start != end{
140            g(&mut self.new_actions[start..end]);
141        }
142        r
143    }
144
145    /// Captures the actions emitted by the given closure `f` and returns them.
146    ///
147    /// This allows you to handle the actions directly before they are delivered
148    /// to other widgets in the UI tree, enabling you to optionally prevent some or all
149    /// of the actions from being delivered to all other widgets.
150    ///
151    /// If you *do* want some or all of the returned `actions` to be delivered
152    /// to other widgets in the UI tree, you can call `extend_actions()` to enqueue them
153    /// back into the set of existing actions.
154    pub fn capture_actions<F>(&mut self, f: F) -> ActionsBuf
155    where
156        F: FnOnce(&mut Cx),
157    {
158        let mut actions = Vec::new();
159        std::mem::swap(&mut self.new_actions, &mut actions);
160        f(self);
161        std::mem::swap(&mut self.new_actions, &mut actions);
162        actions
163    }
164}