WIP: Sheet Set Manager palette, wizard, properties and sheet set fields

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-05 09:10:17 +03:00
1 parent b8def31145
commit 0e1e13e524
44 files changed
+4752 -10

No files matched your search

-6
View File
@@ -587,12 +587,6 @@ impl OpenCADStudio {
.push_info(crate::t!("TOOLPALETTES: Tool Palettes not yet implemented.").as_ref());
}
// ── SHEETSET — not yet implemented ───────────────────────────────────
"SHEETSET" => {
self.command_line
.push_info(crate::t!("SHEETSET: Sheet Set Manager not yet implemented.").as_ref());
}
// ── XDATA — read/write extended entity data ──────────────────────────
// XDATA LIST — show all xdata records on selected entities
// XDATA SET <app> <str> — append a string xdata value for <app>
+16 -1
View File
@@ -46,6 +46,13 @@ impl OpenCADStudio {
.iter()
.map(|f| self.field_value(&format!("\\AcVar Date \\f \"{f}\""), &[]))
.collect();
if let Some(db) = self.sheet_set.db() {
let custom = codec::sheet_set::custom_properties(db.sheet_set());
let names = |flag: i32| custom.iter().filter(|(_, _, f)| f & flag != 0).map(|(n, _, _)| n.clone()).collect();
state.ss_sheet_custom = names(codec::sheet_set::CUSTOM_SHEET_PROP);
state.ss_set_custom = names(codec::sheet_set::CUSTOM_SHEET_SET_PROP);
state.ss_set_name = db.name().to_string();
}
self.field_dialog = Some(state);
self.fill_named_objects();
self.refresh_field_preview();
@@ -113,8 +120,16 @@ impl OpenCADStudio {
}
FieldDialogMsg::Name(n) => {
state.name = n;
state.text_case = 0;
// Sheet set fields start in Title case.
state.text_case = if crate::ui::window::field_dialog::SHEET_SET_FIELDS.contains(&n) { 4 } else { 0 };
state.ss_custom.clear();
}
FieldDialogMsg::SsCustom(name) => state.ss_custom = name,
FieldDialogMsg::SsPlaceholder(k) => {
state.ss_placeholder = k;
state.ss_custom.clear();
}
FieldDialogMsg::SsScaleFormat(k) => state.ss_scale_format = k,
FieldDialogMsg::DateFormat(f) => state.date_format = f,
FieldDialogMsg::DateExample(k) => {
if let Some(f) = DATE_FORMATS.get(k) {
+13
View File
@@ -21,6 +21,7 @@ mod pc_colormap;
mod pc_extract;
mod pdf_underlay;
mod pdf_dialogs;
pub(crate) mod sheet_set;
mod xclip;
mod blockvars;
mod plotvars;
@@ -293,6 +294,9 @@ impl OpenCADStudio {
if let Some(t) = self.dispatch_attdef(cmd, i) {
return Some(t);
}
if let Some(t) = self.dispatch_sheet_set(cmd, i) {
return Some(t);
}
if let Some(t) = self.dispatch_field(cmd, i) {
return Some(t);
}
@@ -854,6 +858,15 @@ inventory::submit!(crate::command::CommandRegistration {
"CREATESKETCH",
"FINISHSKETCH",
"SHEETSET",
"SHEETSETHIDE",
"NEWSHEETSET",
"OPENSHEETSET",
"SSMAUTOOPEN",
"SSLOCATE",
"SSMPOLLTIME",
"SSMSHEETSTATUS",
"SSMSTATE",
"SSFOUND",
"SHORTCUTS",
"SSM",
"STEPOUT",
File diff suppressed because it is too large. Load diff
+98
View File
@@ -82,6 +82,7 @@ pub(super) const NAMES: &[&str] = &[
"dialog_ok",
"attdef_dialog",
"field_dialog",
"sheet_set",
"close_document",
"toggle_properties",
"toggle_layers",
@@ -1019,9 +1020,103 @@ impl OpenCADStudio {
"link_text" => F::HyperlinkText(v.into()),
"link_url" => F::HyperlinkUrl(v.into()),
"plot_scale" => F::PlotScale(index(codec::fields::PLOT_SCALE_FORMATS.len())?),
"ss_custom" => F::SsCustom(v.into()),
"ss_placeholder" => F::SsPlaceholder(index(fd::PLACEHOLDER_TYPES.len())?),
"ss_scale" => F::SsScaleFormat(index(codec::fields::PLOT_SCALE_FORMATS.len())?),
_ => return Err(failure("invalid_value", "Unknown field dialog key")),
})
}
// Sheet Set Manager and its dialogs: "open=<dst>", "tab=list|views|model",
// "select=<target>", "activate=<target>", "menu=<action>:<target>"
// (open, new_sheet, new_subset, import, rename, remove, properties,
// close; a target is a sheet number or title, a subset name or
// "set"), "import_file=<dwg>", "new" (wizard), "existing=0|1",
// "step=<n>", "name=", "description=", "folder=", "hierarchy=0|1",
// "add_folder=<dir>", "layout=<i>:0|1", "wizard_props",
// "row=<i>:<value>", "prompt=0|1:<row>", "template=<file>",
// "custom=<i>:<value>", "add_custom", "custom_name=", "custom_default=",
// "custom_owner=0|1", "add_custom_ok", "number=", "title=",
// "file_name=", "pick_layout=<i>", "ok", "cancel".
"sheet_set" => {
use crate::ui::window::sheet_set::{FieldId as F, MenuAction as A, SheetSetMsg as M, SsmTab, WizardMsg as W};
let value = string(req, "value")?;
let (key, arg) = value.split_once('=').unwrap_or((value, ""));
let target = |app: &Self, spec: &str| {
app.sheet_set_target(spec).ok_or_else(|| failure("invalid_value", "No such sheet set component"))
};
let index_value = |spec: &str| -> Result<(usize, String), Value> {
let (i, v) = spec.split_once(':').unwrap_or((spec, ""));
Ok((i.parse().map_err(|_| failure("invalid_value", "Expected <index>:<value>"))?, v.to_string()))
};
Message::SheetSet(match key {
"open" => M::OpenPicked(Some(std::path::PathBuf::from(arg))),
"import_file" => M::ImportPicked(Some(std::path::PathBuf::from(arg))),
"tab" => M::Tab(match arg {
"views" => SsmTab::SheetViews,
"model" => SsmTab::ModelViews,
_ => SsmTab::SheetList,
}),
"select" => M::Select(target(self, arg)?),
"activate" => M::Activate(target(self, arg)?),
"menu" => {
let (action, spec) = arg.split_once(':').unwrap_or((arg, "set"));
let action = match action {
"open" => A::Open,
"new_sheet" => A::NewSheet,
"new_subset" => A::NewSubset,
"import" => A::ImportLayout,
"rename" => A::Rename,
"remove" => A::Remove,
"properties" => A::Properties,
"close" => A::Close,
_ => return Err(failure("invalid_value", "Unknown sheet set menu action")),
};
if action == A::ImportLayout {
self.sheet_set_import_parent = Some(target(self, spec)?);
return Ok(Task::none());
}
M::Menu(target(self, spec)?, action)
}
"new" => return Ok(self.dispatch_command("NEWSHEETSET")),
"existing" => M::Wizard(W::Existing(arg == "1")),
"step" => M::Wizard(W::Step(arg.parse().map_err(|_| failure("invalid_value", "step"))?)),
"layout" => {
let (i, v) = index_value(arg)?;
M::Wizard(W::LayoutOn(i, v == "1"))
}
"name" => M::Input(F::Name, arg.into()),
"description" => M::Input(F::Description, arg.into()),
"folder" => M::Input(F::Folder, arg.into()),
"hierarchy" => M::Toggle(F::Hierarchy, arg == "1"),
"add_folder" => M::FolderPicked(F::AddFolder, Some(std::path::PathBuf::from(arg))),
"wizard_props" => M::WizardProperties,
"row" => {
let (i, v) = index_value(arg)?;
M::Input(F::Row(i), v)
}
"prompt" => {
let (i, v) = index_value(arg)?;
M::Choose(F::Row(i), usize::from(v != "1"))
}
"template" => M::TemplatePicked(Some(std::path::PathBuf::from(arg))),
"custom" => {
let (i, v) = index_value(arg)?;
M::CustomValue(i, v)
}
"add_custom" => M::AddCustom,
"custom_name" => M::Input(F::CustomName, arg.into()),
"custom_default" => M::Input(F::CustomDefault, arg.into()),
"custom_owner" => M::Choose(F::CustomOwner, usize::from(arg == "1")),
"add_custom_ok" => M::AddCustomOk,
"number" => M::Input(F::Number, arg.into()),
"title" => M::Input(F::Title, arg.into()),
"file_name" => M::Input(F::FileName, arg.into()),
"pick_layout" => M::Choose(F::Layout, arg.parse().map_err(|_| failure("invalid_value", "index"))?),
"ok" => M::Ok,
"cancel" => M::Cancel,
_ => return Err(failure("invalid_value", "Unknown sheet set action")),
})
}
"ribbon_dropdown" => Message::ToggleRibbonDropdown(string(req, "value")?.into()),
"pdf_dialog_ok" => {
use crate::ui::window::pdf_dialogs::PdfDialogMsg;
@@ -1048,6 +1143,9 @@ impl OpenCADStudio {
Some(crate::app::ModalKind::AttDefEdit) => Message::AttdefDialog(
crate::ui::window::attdef_dialog::AttdefDialogMsg::EditOk,
),
Some(crate::app::ModalKind::SheetSet) => Message::SheetSet(
crate::ui::window::sheet_set::SheetSetMsg::Ok,
),
Some(crate::app::ModalKind::Field) => Message::FieldDialog(
crate::ui::window::field_dialog::FieldDialogMsg::Ok,
),
+13
View File
@@ -816,6 +816,13 @@ pub(super) struct OpenCADStudio {
pub(crate) show_browser: bool,
/// Point Cloud Manager palette (POINTCLOUDMANAGER).
pub(crate) pc_manager: crate::ui::window::pc_manager::PcManager,
/// Sheet Set Manager palette, the open sheet sets and their dialogs.
pub(crate) sheet_set: crate::ui::window::sheet_set::SheetSetManager,
/// A sheet opened from the manager: its drawing (path key) and layout,
/// switched to once the drawing has loaded.
pub(crate) sheet_set_pending_layout: Option<(String, String)>,
/// The subset / set Import Layout as Sheet adds to, while its file picker is open.
pub(crate) sheet_set_import_parent: Option<String>,
/// Which viewport background the colour wheel is editing, or `None` when
/// it is closed. One slot, because only one wheel can be open at a time.
pub(crate) bg_picker: Option<BgTarget>,
@@ -1988,6 +1995,8 @@ pub enum ModalKind {
GpuWarning,
/// Reference Manager help window (toolbar Help button).
XrefHelp,
/// Sheet set wizard, properties and sheet / subset forms.
SheetSet,
}
/// A property group controlled by a layer state's restore mask.
@@ -3897,6 +3906,7 @@ pub enum Message {
FieldDialog(crate::ui::window::field_dialog::FieldDialogMsg),
/// A click or search in the Point Cloud Manager.
PcManager(crate::ui::window::pc_manager::PcManagerMsg),
SheetSet(crate::ui::window::sheet_set::SheetSetMsg),
PdfImportPickResult(Result<(std::path::PathBuf, std::sync::Arc<Vec<u8>>), String>),
/// Result of the PDFATTACH file picker.
PdfAttachPickResult(Result<(std::path::PathBuf, std::sync::Arc<Vec<u8>>), String>),
@@ -4222,6 +4232,9 @@ impl OpenCADStudio {
show_external_references: false,
show_browser: false,
pc_manager: Default::default(),
sheet_set: Default::default(),
sheet_set_pending_layout: None,
sheet_set_import_parent: None,
bg_picker: None,
block_palette: Default::default(),
xref_manager: Default::default(),
+4
View File
@@ -612,6 +612,9 @@ pub struct UserSettings {
/// BLOCKNAVIGATE (default ".").
#[serde(default = "default_block_navigate")]
pub block_navigate: String,
/// SSMAUTOOPEN, SSLOCATE, SSMPOLLTIME, SSMSHEETSTATUS.
#[serde(default)]
pub sheet_set: crate::ui::window::sheet_set::SheetSetSettings,
}
/// A block the Blocks palette lists from outside the current drawing (a
@@ -851,6 +854,7 @@ impl Default for UserSettings {
block_mru_list: 50,
block_redefine_mode: 1,
block_navigate: ".".to_string(),
sheet_set: Default::default(),
}
}
}
+5
View File
@@ -606,6 +606,10 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
PanelId::PointCloudManager => {
self.pc_manager.show = false;
}
PanelId::SheetSetManager => {
self.sheet_set.show = false;
self.ribbon.set_sheet_set(false);
}
PanelId::Properties => {
self.show_properties = false;
self.ribbon.set_properties(false);
@@ -711,6 +715,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
PanelId::Browser => self.show_browser,
PanelId::NodeGraph => self.show_node_graph,
PanelId::PointCloudManager => self.pc_manager.show,
PanelId::SheetSetManager => self.sheet_set.show,
}
}
+5 -1
View File
@@ -744,6 +744,7 @@ impl OpenCADStudio {
block_mru_list: self.block_mru_list,
block_redefine_mode: self.block_redefine_mode,
block_navigate: self.block_navigate.clone(),
sheet_set: self.sheet_set.settings,
}
}
@@ -874,6 +875,7 @@ impl OpenCADStudio {
self.block_mru_list = s.block_mru_list.min(100);
self.block_redefine_mode = s.block_redefine_mode.min(2);
self.block_navigate = s.block_navigate.clone();
self.sheet_set.settings = s.sheet_set;
self.block_palette.recent = s.block_recent.clone();
self.block_palette.favorites = s.block_favorites.clone();
self.block_palette.libraries = s.block_libraries.clone();
@@ -2044,7 +2046,8 @@ impl OpenCADStudio {
} else {
Task::none()
};
Task::batch([thumbs_task, pending_open_task, interaction_task, startup_script_task])
let sheet_set_task = self.sheet_set_after_open(i);
Task::batch([thumbs_task, pending_open_task, interaction_task, startup_script_task, sheet_set_task])
}
pub(super) fn on_wblock_save_result_some(
@@ -2149,6 +2152,7 @@ impl OpenCADStudio {
self.tabs[i].scene.document.header.user_real1 = self.tabs[i].scene.annotation_scale as f64;
self.sync_solid_models_for_save(i);
self.tabs[i].scene.sync_native_parametric_graph();
self.stamp_sheet_set_data(i);
}
#[cfg(not(target_arch = "wasm32"))]
+5
View File
@@ -1819,6 +1819,7 @@ impl OpenCADStudio {
Message::AttdefDialog(message) => self.on_attdef_dialog(message),
Message::FieldDialog(message) => self.on_field_dialog(message),
Message::PcManager(message) => self.update_pc_manager(message),
Message::SheetSet(message) => self.on_sheet_set(message),
Message::RibbonSelectTab(idx) => {
self.ribbon.select(idx);
Task::none()
@@ -8521,6 +8522,10 @@ impl OpenCADStudio {
}
Message::CloseModal => {
if self.active_modal == Some(super::ModalKind::SheetSet) {
self.close_sheet_set_dialog();
return Task::none();
}
if self.active_modal == Some(super::ModalKind::Field) {
self.close_field_dialog();
return Task::none();
+4
View File
@@ -1888,6 +1888,7 @@ bg={bg_ms:.1}ms n={view_count}"
crate::ui::dock::PanelId::Browser => self.show_browser,
crate::ui::dock::PanelId::NodeGraph => self.show_node_graph,
crate::ui::dock::PanelId::PointCloudManager => self.pc_manager.show,
crate::ui::dock::PanelId::SheetSetManager => self.sheet_set.show,
}
};
let edge_stack = |side: crate::app::config::DockSide| -> Option<Element<'_, Message>> {
@@ -3030,6 +3031,9 @@ impl OpenCADStudio {
width,
auto_collapse,
),
crate::ui::dock::PanelId::SheetSetManager => {
crate::ui::window::sheet_set::view(&self.sheet_set, width, auto_collapse)
}
};
let divider = dock_divider(id);
match side {
+9
View File
@@ -75,6 +75,7 @@ impl OpenCADStudio {
Some(K::RecoveryPrompt) => crate::tr!("modal", "recovery-prompt"),
Some(K::GpuWarning) => crate::tr!("gpu", "title"),
Some(K::XrefHelp) => crate::t!("Reference Manager Help").into_owned(),
Some(K::SheetSet) => self.sheet_set.dialog.as_ref().map(|d| d.title()).unwrap_or_default(),
None => String::new(),
}
}
@@ -580,6 +581,14 @@ impl OpenCADStudio {
let state = self.attdef_dialog.as_ref()?;
sized_flow(ex, 720, 520, |flow| crate::ui::window::attdef_dialog::view(state, flow))
}
super::super::ModalKind::SheetSet => {
let (w, h) = match self.sheet_set.dialog.as_ref()? {
crate::ui::window::sheet_set::SsDialog::Wizard(_) => (720, 560),
crate::ui::window::sheet_set::SsDialog::Properties(_) => (640, 700),
crate::ui::window::sheet_set::SsDialog::Form(_) => (560, 420),
};
sized_flow(ex, w, h, |flow| crate::ui::window::sheet_set::dialog_view(&self.sheet_set, flow))
}
super::super::ModalKind::Field => {
let state = self.field_dialog.as_ref()?;
sized_flow(ex, 760, 660, |flow| crate::ui::window::field_dialog::view(state, flow))