use crate::command::CadCommand; use crate::linetypes; use crate::modules::home::modify::refedit::RefEditSession; use crate::scene::grip::GripEdit; use crate::scene::GripDef; use crate::scene::Scene; use crate::snap::SnapResult; use crate::ui::{LayerPanel, PropertiesPanel}; use acadrust::tables::Ucs; use acadrust::{CadDocument, Handle}; use iced; use std::path::PathBuf; // ── Per-document tab state ───────────────────────────────────────────────── pub(super) struct DocumentTab { pub(super) scene: Scene, pub(super) current_path: Option, pub(super) dirty: bool, pub(super) tab_title: String, pub(super) properties: PropertiesPanel, pub(super) layers: LayerPanel, pub(super) active_cmd: Option>, pub(super) last_cmd: Option, pub(super) snap_result: Option, pub(super) active_grip: Option, pub(super) selected_grips: Vec, pub(super) selected_handle: Option, pub(super) wireframe: bool, pub(super) visual_style: String, pub(super) last_cursor_world: glam::Vec3, pub(super) last_cursor_screen: iced::Point, pub(super) history: HistoryState, pub(super) active_layer: String, /// Currently active UCS. `None` means WCS (identity transform). pub(super) active_ucs: Option, /// Custom model-space background color. `None` = default dark grey. pub(super) bg_color: Option<[f32; 4]>, /// Custom paper-space background color. `None` = default off-white grey. pub(super) paper_bg_color: Option<[f32; 4]>, /// Active REFEDIT session, if any. pub(super) refedit_session: Option, /// Currently active MLeader style name. pub(super) active_mleader_style: String, /// Last camera_generation value written back to the document. pub(super) last_synced_camera_gen: u64, } impl DocumentTab { pub(super) fn new_drawing(n: usize) -> Self { let mut scene = Scene::new(); linetypes::populate_document(&mut scene.document); // Override acadrust's imperial default limits (12×9) with A4 landscape. for obj in scene.document.objects.values_mut() { if let acadrust::objects::ObjectType::Layout(l) = obj { if l.name != "Model" { l.min_limits = (0.0, 0.0); l.max_limits = (297.0, 210.0); l.min_extents = (0.0, 0.0, 0.0); l.max_extents = (297.0, 210.0, 0.0); } } } Self { scene, current_path: None, dirty: false, tab_title: format!("Drawing{}", n), properties: PropertiesPanel::empty(), layers: LayerPanel::default(), active_cmd: None, last_cmd: None, snap_result: None, active_grip: None, selected_grips: vec![], selected_handle: None, wireframe: false, visual_style: "Shaded".into(), last_cursor_world: glam::Vec3::ZERO, last_cursor_screen: iced::Point::ORIGIN, history: HistoryState::default(), active_layer: "0".to_string(), active_ucs: None, bg_color: None, paper_bg_color: None, refedit_session: None, active_mleader_style: "Standard".to_string(), last_synced_camera_gen: 0, } } pub(super) fn tab_display_name(&self) -> String { match &self.current_path { Some(p) => p .file_name() .unwrap_or_default() .to_string_lossy() .to_string(), None => self.tab_title.clone(), } } } #[derive(Clone)] pub(super) struct HistorySnapshot { pub(super) document: CadDocument, pub(super) current_layout: String, pub(super) selected: Vec, pub(super) dirty: bool, pub(super) label: String, } #[derive(Default)] pub(super) struct HistoryState { pub(super) undo_stack: Vec, pub(super) redo_stack: Vec, }