workflow-egui 0.19.0

Components for EGUI-based applications
Documentation
use crate::imports::*;

struct Inner<T> {
    deactivation: Option<Module<T>>,
    module: Module<T>,
    modules: AHashMap<TypeId, Module<T>>,
    stack: VecDeque<Module<T>>,
}

impl<T> Inner<T>
where
    T: App,
{
    pub fn new(module: Module<T>, modules: AHashMap<TypeId, Module<T>>) -> Self {
        Self {
            deactivation: None,
            module,
            modules,
            stack: VecDeque::new(),
        }
    }
}

/// Tracks the set of application modules and the currently active module,
/// providing navigation between them with a back-stack history.
pub struct ModuleManager<T> {
    inner: Rc<RefCell<Inner<T>>>,
}

impl<T> Clone for ModuleManager<T> {
    fn clone(&self) -> Self {
        Self {
            inner: Rc::clone(&self.inner),
        }
    }
}

impl<T> ModuleManager<T>
where
    T: App,
{
    /// Creates a new manager from the given registry of modules, with the
    /// module identified by `default_module` as the initially active module.
    pub fn new(default_module: TypeId, modules: AHashMap<TypeId, Module<T>>) -> Self {
        let default_module = modules
            .get(&default_module)
            .expect("Unknown module")
            .clone();
        Self {
            inner: Rc::new(RefCell::new(Inner::new(default_module, modules))),
        }
    }

    fn inner(&self) -> Ref<'_, Inner<T>> {
        self.inner.borrow()
    }

    fn inner_mut(&self) -> RefMut<'_, Inner<T>> {
        self.inner.borrow_mut()
    }

    /// Returns a clone of the currently active module.
    pub fn module(&self) -> Module<T> {
        self.inner().module.clone()
    }

    /// Activates the registered module of type `M`, making it the active module.
    pub fn select<M>(&mut self, core: &mut T)
    where
        M: 'static,
    {
        self.select_with_type_id(TypeId::of::<M>(), core);
    }

    /// Activates the module identified by `type_id`, pushing the current module
    /// onto the back-stack and scheduling it for deactivation.
    pub fn select_with_type_id(&self, type_id: TypeId, core: &mut T) {
        let (current, next) = {
            let inner = self.inner();
            (
                inner.module.clone(),
                inner.modules.get(&type_id).expect("Unknown module").clone(),
            )
        };

        if let Some(next) = (current.type_id() != next.type_id()).then(|| {
            let mut inner = self.inner_mut();
            inner.stack.push_back(current.clone());
            inner.deactivation = Some(current);
            inner.module = next.clone();
            next
        }) {
            next.activate(core);
        }
    }

    /// Returns `true` if there are modules on the navigation back-stack.
    pub fn has_stack(&self) -> bool {
        !self.inner().stack.is_empty()
    }

    /// Renders the currently active module and deactivates the previously
    /// active module if a switch occurred on the prior frame.
    pub fn render(
        &self,
        app: &mut T,
        ctx: &egui::Context,
        frame: &mut eframe::Frame,
        ui: &mut egui::Ui,
    ) {
        self.module().render(app, ctx, frame, ui);
        if let Some(previous) = self.inner_mut().deactivation.take() {
            previous.deactivate(app);
        }
    }

    /// Navigates back to the most recent non-secure module on the stack,
    /// making it the active module.
    pub fn back(&mut self) {
        let mut inner = self.inner_mut();
        while let Some(module) = inner.stack.pop_back() {
            if !module.secure() {
                inner.module = module;
                return;
            }
        }
    }

    /// Removes all secure modules from the navigation back-stack.
    pub fn purge_secure_stack(&mut self) {
        self.inner_mut().stack.retain(|module| !module.secure());
    }

    /// Returns a typed reference to the registered module of type `M`.
    pub fn get<M>(&self) -> ModuleReference<T, M>
    where
        M: ModuleT<Context = T> + 'static,
    {
        let inner = self.inner();
        let cell = inner.modules.get(&TypeId::of::<M>()).unwrap();
        ModuleReference::new(&cell.inner.module)
    }
}

/// A typed handle to a registered module of concrete type `M`, allowing it to
/// be borrowed (immutably or mutably) downcast back to its original type.
pub struct ModuleReference<T, M>
where
    T: App,
{
    module: Rc<RefCell<dyn ModuleT<Context = T>>>,
    _phantom: PhantomData<M>,
}

impl<T, M> ModuleReference<T, M>
where
    T: App,
{
    fn new(module: &Rc<RefCell<dyn ModuleT<Context = T>>>) -> Self {
        Self {
            module: module.clone(),
            _phantom: PhantomData,
        }
    }

    /// Immutably borrows the referenced module, downcast to its concrete type `M`.
    pub fn as_ref(&self) -> Ref<'_, M>
    where
        M: ModuleT<Context = T> + 'static,
    {
        Ref::map(self.module.borrow(), |r| {
            (r).as_any()
                .downcast_ref::<M>()
                .expect("unable to downcast section")
        })
    }

    /// Mutably borrows the referenced module, downcast to its concrete type `M`.
    pub fn as_mut(&self) -> RefMut<'_, M>
    where
        M: ModuleT<Context = T> + 'static,
    {
        RefMut::map(self.module.borrow_mut(), |r| {
            (r).as_any_mut()
                .downcast_mut::<M>()
                .expect("unable to downcast section")
        })
    }
}