workflow_egui/module/
module.rs

1use crate::imports::*;
2
3pub enum ModuleStyle {
4    Mobile,
5    Default,
6}
7
8/// Capabilities of a module. Defines whether the module
9/// should be available on the Desktop, Mobile, WebApp or
10/// in a browser Extension.
11pub enum ModuleCaps {
12    Desktop,
13    Mobile,
14    WebApp,
15    Extension,
16}
17
18pub trait ModuleT: Downcast {
19    type Context;
20
21    fn name(&self) -> Option<&'static str> {
22        None
23    }
24
25    fn modal(&self) -> bool {
26        false
27    }
28
29    fn secure(&self) -> bool {
30        false
31    }
32
33    fn style(&self) -> ModuleStyle {
34        ModuleStyle::Default
35    }
36
37    fn activate(&mut self, _core: &mut Self::Context) {}
38
39    fn deactivate(&mut self, _core: &mut Self::Context) {}
40
41    fn main(&mut self, _core: &mut Self::Context) {}
42
43    fn render(
44        &mut self,
45        core: &mut Self::Context,
46        ctx: &egui::Context,
47        frame: &mut eframe::Frame,
48        ui: &mut egui::Ui,
49    );
50
51    fn shutdown(&mut self) {}
52}
53
54impl_downcast!(ModuleT assoc Context);
55
56pub struct Inner<T> {
57    pub name: String,
58    pub type_name: String,
59    pub type_id: TypeId,
60    pub module: Rc<RefCell<dyn ModuleT<Context = T>>>,
61}
62
63pub struct Module<T> {
64    pub inner: Rc<Inner<T>>,
65}
66
67impl<T> Clone for Module<T> {
68    fn clone(&self) -> Self {
69        Self {
70            inner: Rc::clone(&self.inner),
71        }
72    }
73}
74
75impl<T> Module<T>
76where
77    T: App + 'static,
78{
79    pub fn any(&self) -> Rc<RefCell<dyn ModuleT<Context = T>>> {
80        Rc::clone(&self.inner.module)
81    }
82
83    pub fn main(&self, core: &mut T) {
84        self.inner.module.borrow_mut().main(core)
85    }
86
87    pub fn activate(&self, core: &mut T) {
88        self.inner.module.borrow_mut().activate(core)
89    }
90
91    pub fn deactivate(&self, core: &mut T) {
92        self.inner.module.borrow_mut().deactivate(core)
93    }
94
95    pub fn render(
96        &self,
97        core: &mut T,
98        ctx: &egui::Context,
99        frame: &mut eframe::Frame,
100        ui: &mut egui::Ui,
101    ) {
102        let mut module = self.inner.module.borrow_mut();
103
104        match module.style() {
105            ModuleStyle::Mobile => {
106                if let Some(text_styles) = core.mobile_text_styles() {
107                    ui.style_mut().text_styles = text_styles;
108                }
109            }
110            ModuleStyle::Default => {
111                if let Some(text_styles) = core.default_text_styles() {
112                    ui.style_mut().text_styles = text_styles;
113                }
114            }
115        }
116
117        module.render(core, ctx, frame, ui)
118    }
119
120    pub fn name(&self) -> &str {
121        self.inner
122            .module
123            .borrow_mut()
124            .name()
125            .unwrap_or_else(|| self.inner.name.as_str())
126    }
127
128    pub fn modal(&self) -> bool {
129        self.inner.module.borrow_mut().modal()
130    }
131
132    pub fn secure(&self) -> bool {
133        self.inner.module.borrow_mut().secure()
134    }
135
136    pub fn type_id(&self) -> TypeId {
137        self.inner.type_id
138    }
139
140    pub fn as_ref<M>(&self) -> Ref<'_, M>
141    where
142        M: ModuleT + 'static,
143    {
144        Ref::map(self.inner.module.borrow(), |r| {
145            (r).as_any()
146                .downcast_ref::<M>()
147                .expect("unable to downcast section")
148        })
149    }
150
151    pub fn as_mut<M>(&mut self) -> RefMut<'_, M>
152    where
153        M: ModuleT + 'static,
154    {
155        RefMut::map(self.inner.module.borrow_mut(), |r| {
156            (r).as_any_mut()
157                .downcast_mut::<M>()
158                .expect("unable to downcast_mut module")
159        })
160    }
161}
162
163impl<T> std::fmt::Debug for Module<T> {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        write!(f, "{}", self.inner.name)
166    }
167}
168
169impl<T> Eq for Module<T> {}
170
171impl<T> PartialEq for Module<T> {
172    fn eq(&self, other: &Self) -> bool {
173        self.inner.type_id == other.inner.type_id
174    }
175}
176
177impl<T, M> From<M> for Module<T>
178where
179    M: ModuleT<Context = T> + 'static,
180    T: App,
181{
182    fn from(section: M) -> Self {
183        let type_name = type_name::<M>().to_string();
184        let name = type_name.split("::").last().unwrap().to_string();
185        let type_id = TypeId::of::<M>();
186        Self {
187            inner: Rc::new(Inner {
188                name,
189                type_name,
190                type_id,
191                module: Rc::new(RefCell::new(section)),
192            }),
193        }
194    }
195}
196
197pub trait HashMapModuleExtension<T, M> {
198    fn insert_typeid(&mut self, value: M)
199    where
200        M: ModuleT<Context = T> + 'static,
201        T: App;
202}
203
204impl<T, M> HashMapModuleExtension<T, M> for AHashMap<TypeId, Module<T>>
205where
206    M: ModuleT<Context = T> + 'static,
207    T: App,
208{
209    fn insert_typeid(&mut self, section: M) {
210        self.insert(TypeId::of::<M>(), Module::<T>::from(section));
211    }
212}