Files
OneCAD-Draft/src/ui/statusbar/statusbar_config.rs
T
Hakan SevenandClaude Opus 4.8 dc7117f203 refactor(config): consolidate settings into one grouped settings.json
App preferences were spread across six flat plain-text files (settings.txt,
recent.txt, recent_limit.txt, statusbar.txt, ribbon.txt, plot.txt), each with a
bespoke line parser and no grouping. Replace them with a single grouped JSON,
serialized via serde (enabling the derive feature; serde_json was already a
dependency).

- New app/config.rs: AppConfig { settings, recent, statusbar, ribbon, plot } →
  <config>/settings.json (pretty JSON), load()/save().
- Make UserSettings, StatusBarConfig/StatusPill, CollapseMode and
  PlotDialogState serde-derived; #[serde(skip)] marks the plot dialog's runtime
  fields so only print preferences persist. Their bespoke .txt load/save is
  removed.
- App gains current_config/apply_config/save_config: one AppConfig::load at
  startup distributes into live state; every settings-change site
  (persist_settings_if_changed, recent add/remove/limit, status-bar pill
  toggle, ribbon density, plot commit) routes through save_config, which diffs
  against the last write to avoid thrashing.
- Clean start: the old flat files are ignored (no migration). ocad.pgp stays a
  separate hand-editable file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 16:41:34 +03:00

147 lines
4.6 KiB
Rust

//! 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 serde::{Deserialize, Serialize};
/// Identifies a toggleable status-bar pill.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
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",
}
}
}
/// Tracks which pills the user has hidden. Serialized as the "statusbar" section
/// of the app config ([`crate::app::config`]).
#[derive(Clone, PartialEq, Serialize, Deserialize)]
#[serde(default)]
pub struct StatusBarConfig {
hidden: HashSet<StatusPill>,
}
impl Default for StatusBarConfig {
/// The out-of-the-box bar: a few informational / niche pills are hidden by
/// default to keep it uncluttered, and the user turns them on from the
/// customization (⚙) menu if wanted. The mode toggles that matter most
/// (Ortho, Polar, Otrack, Osnap, …) stay visible.
fn default() -> Self {
let hidden = [
StatusPill::Coords,
StatusPill::Lwt,
StatusPill::Dyn,
StatusPill::Space,
StatusPill::Units,
StatusPill::Transparency,
StatusPill::SelCycle,
StatusPill::Vp,
]
.into_iter()
.collect();
Self { hidden }
}
}
impl StatusBarConfig {
pub fn is_visible(&self, pill: StatusPill) -> bool {
!self.hidden.contains(&pill)
}
/// Flip a pill's visibility. Persistence is handled by the caller via the
/// consolidated app config (`save_config`).
pub fn toggle(&mut self, pill: StatusPill) {
if !self.hidden.remove(&pill) {
self.hidden.insert(pill);
}
}
}