//! Status-bar customization — which toggle pills are shown on the bar. //! //! The customization menu (opened from the bar's far-right handle) lists every //! pill with a check mark next to the ones currently shown. Toggling a row //! adds or removes that pill from the bar. The choice is persisted so it //! survives across sessions. use rustc_hash::FxHashSet as HashSet; use std::path::PathBuf; /// Identifies a toggleable status-bar pill. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum StatusPill { Coords, Ortho, Lwt, Polar, Dyn, Otrack, Osnap, Space, Scale, Units, Transparency, Isolate, QuickProps, SelFilter, SelCycle, Vp, CleanScreen, } impl StatusPill { /// Every pill, in status-bar display order. Drives both the bar layout and /// the customization menu. pub const ALL: &'static [StatusPill] = &[ StatusPill::Coords, StatusPill::Ortho, StatusPill::Lwt, StatusPill::Polar, StatusPill::Dyn, StatusPill::Otrack, StatusPill::Osnap, StatusPill::Space, StatusPill::Scale, StatusPill::Units, StatusPill::Transparency, StatusPill::Isolate, StatusPill::QuickProps, StatusPill::SelFilter, StatusPill::SelCycle, StatusPill::Vp, StatusPill::CleanScreen, ]; /// Stable identifier used for persistence. pub fn id(self) -> &'static str { match self { StatusPill::Coords => "coords", StatusPill::Ortho => "ortho", StatusPill::Lwt => "lwt", StatusPill::Polar => "polar", StatusPill::Dyn => "dyn", StatusPill::Otrack => "otrack", StatusPill::Osnap => "osnap", StatusPill::Space => "space", StatusPill::Scale => "scale", StatusPill::Units => "units", StatusPill::Transparency => "transparency", StatusPill::Isolate => "isolate", StatusPill::QuickProps => "quickprops", StatusPill::SelFilter => "selfilter", StatusPill::SelCycle => "selcycle", StatusPill::Vp => "vp", StatusPill::CleanScreen => "cleanscreen", } } /// Label shown in the customization menu. pub fn label(self) -> &'static str { match self { StatusPill::Coords => "Coordinates", StatusPill::Ortho => "Ortho Mode", StatusPill::Lwt => "Show Lineweight", StatusPill::Polar => "Polar Tracking", StatusPill::Dyn => "Dynamic Input", StatusPill::Otrack => "Object Snap Tracking", StatusPill::Osnap => "Object Snap", StatusPill::Space => "Model/Paper Space", StatusPill::Scale => "Annotation Scale", StatusPill::Units => "Drawing Units", StatusPill::Transparency => "Show Transparency", StatusPill::Isolate => "Isolate Objects", StatusPill::QuickProps => "Quick Properties", StatusPill::SelFilter => "Selection Filtering", StatusPill::SelCycle => "Selection Cycling", StatusPill::Vp => "Viewport Count", StatusPill::CleanScreen => "Clean Screen", } } fn from_id(s: &str) -> Option { StatusPill::ALL.iter().copied().find(|p| p.id() == s) } } /// Tracks which pills the user has hidden. Empty = every pill visible. #[derive(Clone, Default)] pub struct StatusBarConfig { hidden: HashSet, } impl StatusBarConfig { /// Load the saved customization, or all-visible when none exists. pub fn load() -> Self { let mut hidden = HashSet::default(); if let Some(path) = config_path() { if let Ok(body) = std::fs::read_to_string(path) { for line in body.lines() { if let Some(p) = StatusPill::from_id(line.trim()) { hidden.insert(p); } } } } Self { hidden } } pub fn is_visible(&self, pill: StatusPill) -> bool { !self.hidden.contains(&pill) } /// Flip a pill's visibility and persist the change. pub fn toggle(&mut self, pill: StatusPill) { if !self.hidden.remove(&pill) { self.hidden.insert(pill); } self.save(); } fn save(&self) { let Some(path) = config_path() else { return }; if let Some(dir) = path.parent() { let _ = std::fs::create_dir_all(dir); } let body: String = StatusPill::ALL .iter() .filter(|p| self.hidden.contains(p)) .map(|p| p.id()) .collect::>() .join("\n"); let _ = std::fs::write(path, body); } } /// `/OpenCADStudio/statusbar.txt`, matching the recent-files store. fn config_path() -> Option { let base: PathBuf = if cfg!(target_os = "windows") { std::env::var_os("APPDATA").map(PathBuf::from)? } else if cfg!(target_os = "macos") { let home = std::env::var_os("HOME")?; let mut p = PathBuf::from(home); p.push("Library"); p.push("Application Support"); p } else if let Some(d) = std::env::var_os("XDG_CONFIG_HOME") { PathBuf::from(d) } else { let home = std::env::var_os("HOME")?; let mut p = PathBuf::from(home); p.push(".config"); p }; let mut p = base; p.push("OpenCADStudio"); Some(p.join("statusbar.txt")) }