Skip to main content

workflow_egui/module/
manager.rs

1use crate::imports::*;
2
3struct Inner<T> {
4    deactivation: Option<Module<T>>,
5    module: Module<T>,
6    modules: AHashMap<TypeId, Module<T>>,
7    stack: VecDeque<Module<T>>,
8}
9
10impl<T> Inner<T>
11where
12    T: App,
13{
14    pub fn new(module: Module<T>, modules: AHashMap<TypeId, Module<T>>) -> Self {
15        Self {
16            deactivation: None,
17            module,
18            modules,
19            stack: VecDeque::new(),
20        }
21    }
22}
23
24/// Tracks the set of application modules and the currently active module,
25/// providing navigation between them with a back-stack history.
26pub struct ModuleManager<T> {
27    inner: Rc<RefCell<Inner<T>>>,
28}
29
30impl<T> Clone for ModuleManager<T> {
31    fn clone(&self) -> Self {
32        Self {
33            inner: Rc::clone(&self.inner),
34        }
35    }
36}
37
38impl<T> ModuleManager<T>
39where
40    T: App,
41{
42    /// Creates a new manager from the given registry of modules, with the
43    /// module identified by `default_module` as the initially active module.
44    pub fn new(default_module: TypeId, modules: AHashMap<TypeId, Module<T>>) -> Self {
45        let default_module = modules
46            .get(&default_module)
47            .expect("Unknown module")
48            .clone();
49        Self {
50            inner: Rc::new(RefCell::new(Inner::new(default_module, modules))),
51        }
52    }
53
54    fn inner(&self) -> Ref<'_, Inner<T>> {
55        self.inner.borrow()
56    }
57
58    fn inner_mut(&self) -> RefMut<'_, Inner<T>> {
59        self.inner.borrow_mut()
60    }
61
62    /// Returns a clone of the currently active module.
63    pub fn module(&self) -> Module<T> {
64        self.inner().module.clone()
65    }
66
67    /// Activates the registered module of type `M`, making it the active module.
68    pub fn select<M>(&mut self, core: &mut T)
69    where
70        M: 'static,
71    {
72        self.select_with_type_id(TypeId::of::<M>(), core);
73    }
74
75    /// Activates the module identified by `type_id`, pushing the current module
76    /// onto the back-stack and scheduling it for deactivation.
77    pub fn select_with_type_id(&self, type_id: TypeId, core: &mut T) {
78        let (current, next) = {
79            let inner = self.inner();
80            (
81                inner.module.clone(),
82                inner.modules.get(&type_id).expect("Unknown module").clone(),
83            )
84        };
85
86        if let Some(next) = (current.type_id() != next.type_id()).then(|| {
87            let mut inner = self.inner_mut();
88            inner.stack.push_back(current.clone());
89            inner.deactivation = Some(current);
90            inner.module = next.clone();
91            next
92        }) {
93            next.activate(core);
94        }
95    }
96
97    /// Returns `true` if there are modules on the navigation back-stack.
98    pub fn has_stack(&self) -> bool {
99        !self.inner().stack.is_empty()
100    }
101
102    /// Renders the currently active module and deactivates the previously
103    /// active module if a switch occurred on the prior frame.
104    pub fn render(
105        &self,
106        app: &mut T,
107        ctx: &egui::Context,
108        frame: &mut eframe::Frame,
109        ui: &mut egui::Ui,
110    ) {
111        self.module().render(app, ctx, frame, ui);
112        if let Some(previous) = self.inner_mut().deactivation.take() {
113            previous.deactivate(app);
114        }
115    }
116
117    /// Navigates back to the most recent non-secure module on the stack,
118    /// making it the active module.
119    pub fn back(&mut self) {
120        let mut inner = self.inner_mut();
121        while let Some(module) = inner.stack.pop_back() {
122            if !module.secure() {
123                inner.module = module;
124                return;
125            }
126        }
127    }
128
129    /// Removes all secure modules from the navigation back-stack.
130    pub fn purge_secure_stack(&mut self) {
131        self.inner_mut().stack.retain(|module| !module.secure());
132    }
133
134    /// Returns a typed reference to the registered module of type `M`.
135    pub fn get<M>(&self) -> ModuleReference<T, M>
136    where
137        M: ModuleT<Context = T> + 'static,
138    {
139        let inner = self.inner();
140        let cell = inner.modules.get(&TypeId::of::<M>()).unwrap();
141        ModuleReference::new(&cell.inner.module)
142    }
143}
144
145/// A typed handle to a registered module of concrete type `M`, allowing it to
146/// be borrowed (immutably or mutably) downcast back to its original type.
147pub struct ModuleReference<T, M>
148where
149    T: App,
150{
151    module: Rc<RefCell<dyn ModuleT<Context = T>>>,
152    _phantom: PhantomData<M>,
153}
154
155impl<T, M> ModuleReference<T, M>
156where
157    T: App,
158{
159    fn new(module: &Rc<RefCell<dyn ModuleT<Context = T>>>) -> Self {
160        Self {
161            module: module.clone(),
162            _phantom: PhantomData,
163        }
164    }
165
166    /// Immutably borrows the referenced module, downcast to its concrete type `M`.
167    pub fn as_ref(&self) -> Ref<'_, M>
168    where
169        M: ModuleT<Context = T> + 'static,
170    {
171        Ref::map(self.module.borrow(), |r| {
172            (r).as_any()
173                .downcast_ref::<M>()
174                .expect("unable to downcast section")
175        })
176    }
177
178    /// Mutably borrows the referenced module, downcast to its concrete type `M`.
179    pub fn as_mut(&self) -> RefMut<'_, M>
180    where
181        M: ModuleT<Context = T> + 'static,
182    {
183        RefMut::map(self.module.borrow_mut(), |r| {
184            (r).as_any_mut()
185                .downcast_mut::<M>()
186                .expect("unable to downcast section")
187        })
188    }
189}