use std::collections::{BTreeMap, BTreeSet}; use iced::window; use common::{BarModule, Inbox, Modules, Service}; use toml::Table; /// Application state: module registry, routing, popup bookkeeping. pub(crate) struct Bar { /// Module whose popup is open; None = closed. pub(crate) active_popup: Option, /// Module registry keyed by stable module id. pub(crate) modules: BTreeMap<&'static str, Box>, /// Left, Middle, Right ; Module Order pub(crate) order: (Vec, Vec, Vec), /// Surface id of the open popup. pub(crate) popup_id: Option, /// Fan-out routing table: module id -> services it wants. pub(crate) routes: BTreeMap<&'static str, Vec>, /// One inbound mailbox per running service, keyed by route key. Modules /// send here (`Target::Service`) to talk to a running service. pub(crate) inputs: BTreeMap<&'static str, Inbox>, } impl Bar { pub(crate) fn new( modules_config_table: &Table, modules_order: (Vec, Vec, Vec), ) -> Self { // Registry owns construction: adding a module never edits this file. let modules: BTreeMap<&'static str, Box> = modules::all(modules_config_table.clone()) .into_iter() .map(|m| (m.id(), m)) .collect(); let routes: BTreeMap<&'static str, Vec> = modules .iter() .map(|(id, module)| (*id, module.services())) .collect(); // One inbox per distinct service any module wants. let wanted: BTreeSet<&'static str> = routes.values().flatten().map(|s| s.0).collect(); let inputs = wanted .into_iter() .map(|key| (key, Inbox::new(key))) .collect(); Self { active_popup: None, modules, order: modules_order, popup_id: None, routes, inputs, } } }