forked from 1b-agent/opencadstudio-upstream
Merge pull request #1613 from ramox81/codex/sheet-set-manager
Sheet Set Manager, NEWSHEETSET / OPENSHEETSET and sheet set fields
This commit is contained in:
commit
078306d8fc
50 files changed
+8974
-27
No files matched your search
@@ -784,6 +784,8 @@ impl OpenCADStudio {
|
||||
if tokens[0].eq_ignore_ascii_case("BACKGROUND")
|
||||
|| tokens[0].eq_ignore_ascii_case("COLORSCHEME")
|
||||
|| tokens[0].eq_ignore_ascii_case("XREF")
|
||||
// `VIEW WINDOW <name> <x1,y1> <x2,y2>` takes its arguments in one line.
|
||||
|| tokens[0].eq_ignore_ascii_case("VIEW")
|
||||
{
|
||||
return self.dispatch_command(cmd);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::app::{Message, OpenCADStudio};
|
||||
use crate::command::CadCommand;
|
||||
use crate::modules::annotate::field_cmd::{FieldObjectPickCommand, FieldPlaceCommand, FieldTablePickCommand};
|
||||
use crate::ui::window::field_dialog::{
|
||||
use crate::ui::window::field_dialog::{nav_props,
|
||||
fields_of, object_properties, FieldDialogMsg, FieldDialogState, FieldTarget, DATE_FORMATS,
|
||||
NAMED_TYPES,
|
||||
};
|
||||
@@ -103,6 +103,15 @@ 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();
|
||||
}
|
||||
state.ss_sets = self.sheet_set.sets.clone();
|
||||
state.ss_set = self.sheet_set.current.unwrap_or(0);
|
||||
self.field_dialog = Some(state);
|
||||
self.fill_named_objects();
|
||||
self.refresh_field_preview();
|
||||
@@ -180,8 +189,65 @@ 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();
|
||||
state.ss_node.clear();
|
||||
state.ss_prop.clear();
|
||||
// SheetSet starts on the set and its first property; SheetView on nothing.
|
||||
if n == "SheetSet" {
|
||||
if let Some(db) = state.ss_sets.get(state.ss_set) {
|
||||
state.ss_node = db.sheet_set().id().to_string();
|
||||
state.ss_prop = nav_props(db, &state.ss_node).first().map(|p| p.0.clone()).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
FieldDialogMsg::SsCustom(name) => state.ss_custom = name,
|
||||
FieldDialogMsg::SsSet(k) => {
|
||||
state.ss_set = k;
|
||||
state.ss_node.clear();
|
||||
state.ss_prop.clear();
|
||||
}
|
||||
FieldDialogMsg::SsNode(id) => {
|
||||
state.ss_prop = state.ss_sets.get(state.ss_set).and_then(|db| nav_props(db, &id).first().map(|p| p.0.clone())).unwrap_or_default();
|
||||
state.ss_node = id;
|
||||
}
|
||||
FieldDialogMsg::SsProp(p) => state.ss_prop = p,
|
||||
FieldDialogMsg::SsHref(v) => state.ss_href = v,
|
||||
FieldDialogMsg::SsBrowse => {
|
||||
return Task::perform(
|
||||
async {
|
||||
crate::sys::file_dialog()
|
||||
.set_title(crate::t!("Open Sheet Set").as_ref())
|
||||
.add_filter(crate::t!("Sheet Set (*.dst)").as_ref(), &["dst", "DST"])
|
||||
.pick_file()
|
||||
.await
|
||||
.map(|h| crate::sys::handle_path(&h))
|
||||
},
|
||||
|p| Message::FieldDialog(FieldDialogMsg::SsPicked(p)),
|
||||
);
|
||||
}
|
||||
FieldDialogMsg::SsPicked(None) => {}
|
||||
FieldDialogMsg::SsPicked(Some(path)) => match codec::sheet_set::SheetSetDatabase::read(&path.to_string_lossy()) {
|
||||
Ok(db) => {
|
||||
let key = codec::sheet_set::path_key(&path.to_string_lossy());
|
||||
state.ss_set = match state.ss_sets.iter().position(|d| d.path.as_deref().is_some_and(|p| codec::sheet_set::path_key(p) == key)) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
state.ss_sets.push(db);
|
||||
state.ss_sets.len() - 1
|
||||
}
|
||||
};
|
||||
state.ss_node.clear();
|
||||
state.ss_prop.clear();
|
||||
}
|
||||
Err(e) => self.command_line.push_error(&format!("{}: {e}", path.display())),
|
||||
},
|
||||
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) {
|
||||
|
||||
@@ -803,6 +803,29 @@ impl OpenCADStudio {
|
||||
.push_output(crate::tf!("View '{}' saved.", name).as_ref());
|
||||
}
|
||||
}
|
||||
"WINDOW" | "W" => {
|
||||
// A plan view of the window between two corners.
|
||||
let args: Vec<&str> = parts.get(2).map(|s| s.split_whitespace().collect()).unwrap_or_default();
|
||||
let corner = |s: &str| {
|
||||
let mut c = s.split(',');
|
||||
Some((c.next()?.trim().parse::<f64>().ok()?, c.next()?.trim().parse::<f64>().ok()?))
|
||||
};
|
||||
match (args.first(), args.get(1).and_then(|s| corner(s)), args.get(2).and_then(|s| corner(s))) {
|
||||
(Some(name), Some(a), Some(b)) if a.0 != b.0 && a.1 != b.1 => {
|
||||
use codec::types::Vector3;
|
||||
let mut view = self.tabs[i].scene.current_as_named_view(name);
|
||||
view.target = Vector3 { x: (a.0 + b.0) / 2.0, y: (a.1 + b.1) / 2.0, z: 0.0 };
|
||||
view.direction = Vector3 { x: 0.0, y: 0.0, z: 1.0 };
|
||||
view.width = (b.0 - a.0).abs();
|
||||
view.height = (b.1 - a.1).abs();
|
||||
self.tabs[i].scene.document.views.add_or_replace(view);
|
||||
self.command_line.push_output(crate::tf!("View '{}' saved.", name).as_ref());
|
||||
}
|
||||
_ => self
|
||||
.command_line
|
||||
.push_error(crate::t!("Usage: VIEW WINDOW <name> <x1,y1> <x2,y2>").as_ref()),
|
||||
}
|
||||
}
|
||||
"DELETE" | "DEL" | "D" => {
|
||||
let name = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
|
||||
if name.is_empty() {
|
||||
|
||||
@@ -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;
|
||||
@@ -321,6 +322,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);
|
||||
}
|
||||
@@ -882,6 +886,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
@@ -82,6 +82,7 @@ pub(super) const NAMES: &[&str] = &[
|
||||
"dialog_ok",
|
||||
"attdef_dialog",
|
||||
"field_dialog",
|
||||
"sheet_set",
|
||||
"close_document",
|
||||
"toggle_properties",
|
||||
"toggle_layers",
|
||||
@@ -1133,6 +1134,24 @@ 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_set" => F::SsSet(v.parse().map_err(|_| failure("invalid_value", "index"))?),
|
||||
"ss_dst" => F::SsPicked(Some(std::path::PathBuf::from(v))),
|
||||
"ss_node" => {
|
||||
let state = self.field_dialog.as_ref().ok_or_else(|| failure("invalid_state", "No Field dialog"))?;
|
||||
let db = state.ss_sets.get(state.ss_set).ok_or_else(|| failure("invalid_state", "No sheet set"))?;
|
||||
let views = state.name == "SheetView";
|
||||
let id = fd::nav_nodes(db, views)
|
||||
.into_iter()
|
||||
.find(|(_, id, label, _)| label == v || id == v)
|
||||
.map(|(_, id, _, _)| id)
|
||||
.ok_or_else(|| failure("invalid_value", "No such node"))?;
|
||||
F::SsNode(id)
|
||||
}
|
||||
"ss_prop" => F::SsProp(v.into()),
|
||||
"ss_href" => F::SsHref(v == "1"),
|
||||
"ss_placeholder" => F::SsPlaceholder(index(fd::PLACEHOLDER_TYPES.len())?),
|
||||
"ss_scale" => F::SsScaleFormat(index(codec::fields::PLOT_SCALE_FORMATS.len())?),
|
||||
"placeholder" => F::PlaceholderProperty(index(codec::fields::BLOCK_PLACEHOLDER_PROPERTIES.len())?),
|
||||
"table_function" => F::TableFunction(
|
||||
["Average", "Sum", "Count", "Cell"]
|
||||
@@ -1143,6 +1162,203 @@ impl OpenCADStudio {
|
||||
_ => 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"))?),
|
||||
"refresh" => M::Refresh,
|
||||
"open_after" => M::Toggle(F::OpenAfter, arg == "1"),
|
||||
"row_toggle" => {
|
||||
let (i, v) = index_value(arg)?;
|
||||
M::Toggle(F::Row(i), v == "1")
|
||||
}
|
||||
"publish" => M::Toggle(F::Publish, arg == "1"),
|
||||
"layout_name" => M::Input(F::LayoutName, arg.into()),
|
||||
"rename_opt" => {
|
||||
let (i, v) = index_value(arg)?;
|
||||
M::Toggle(F::RenameOption(i.min(3)), v == "1")
|
||||
}
|
||||
"import_add" => M::ImportAdd(arg.split('|').map(std::path::PathBuf::from).collect()),
|
||||
"import_row" => {
|
||||
let (i, v) = index_value(arg)?;
|
||||
M::Toggle(F::ImportRow(i), v == "1")
|
||||
}
|
||||
"prefix" => M::Toggle(F::ImportPrefix, arg == "1"),
|
||||
"previous" => M::Previous,
|
||||
"next" => M::Next,
|
||||
"views_by_category" => M::ViewsByCategory(arg == "1"),
|
||||
"new_category" => M::NewCategory,
|
||||
"category" => {
|
||||
let id = self
|
||||
.sheet_set
|
||||
.db()
|
||||
.and_then(|db| db.view_categories().iter().find(|c| c.prop("Name") == Some(arg)).map(|c| c.id().to_string()))
|
||||
.ok_or_else(|| failure("invalid_value", "No such view category"))?;
|
||||
M::CategoryProperties(id)
|
||||
}
|
||||
"remove_category" => {
|
||||
let id = self
|
||||
.sheet_set
|
||||
.db()
|
||||
.and_then(|db| db.view_categories().iter().find(|c| c.prop("Name") == Some(arg)).map(|c| c.id().to_string()))
|
||||
.ok_or_else(|| failure("invalid_value", "No such view category"))?;
|
||||
M::CategoryRemove(id)
|
||||
}
|
||||
"category_block" => {
|
||||
let (i, v) = index_value(arg)?;
|
||||
M::Toggle(F::CategoryBlock(i), v == "1")
|
||||
}
|
||||
"add_location" => M::LocationPicked(Some(std::path::PathBuf::from(arg))),
|
||||
"remove_location" => {
|
||||
let id = self
|
||||
.sheet_set
|
||||
.locations
|
||||
.iter()
|
||||
.find(|(_, folder, _)| codec::sheet_set::path_key(folder) == codec::sheet_set::path_key(arg))
|
||||
.map(|(id, _, _)| id.clone())
|
||||
.ok_or_else(|| failure("invalid_value", "No such location"))?;
|
||||
M::RemoveLocation(id)
|
||||
}
|
||||
"open_drawing" => M::OpenDrawing(arg.into()),
|
||||
"toggle_drawing" => M::ToggleDrawing(arg.into()),
|
||||
"see_views" => M::SeeViews(arg.into()),
|
||||
// place=<drawing>[|<view>]
|
||||
"place" => {
|
||||
let (drawing, view) = arg.split_once('|').map_or((arg, None), |(d, v)| (d, Some(v.to_string())));
|
||||
M::PlaceOnSheet(drawing.into(), view)
|
||||
}
|
||||
// view=<view title or number - title>:<display|rename|label|category=<name>|callout=<block>>
|
||||
"view" => {
|
||||
use crate::ui::window::sheet_set::ViewAction as VA;
|
||||
let (spec, action) = arg.rsplit_once(':').ok_or_else(|| failure("invalid_value", "view=<view>:<action>"))?;
|
||||
let db = self.sheet_set.db().ok_or_else(|| failure("invalid_state", "No sheet set"))?;
|
||||
let view = db
|
||||
.sheets()
|
||||
.into_iter()
|
||||
.flat_map(|s| db.sheet_views(s))
|
||||
.find(|v| codec::sheet_set::number_and_title(v) == spec || v.prop("Title") == Some(spec))
|
||||
.map(|v| v.id().to_string())
|
||||
.ok_or_else(|| failure("invalid_value", "No such sheet view"))?;
|
||||
let (verb, name) = action.split_once('=').unwrap_or((action, ""));
|
||||
let a = match verb {
|
||||
"display" => VA::Display,
|
||||
"rename" => VA::Rename,
|
||||
"label" => VA::Label,
|
||||
"category" => VA::Category(
|
||||
db.view_categories()
|
||||
.iter()
|
||||
.find(|c| c.prop("Name") == Some(name))
|
||||
.map(|c| c.id().to_string())
|
||||
.ok_or_else(|| failure("invalid_value", "No such view category"))?,
|
||||
),
|
||||
"callout" => VA::Callout(
|
||||
db.callout_blocks()
|
||||
.iter()
|
||||
.find(|b| b.prop("Name") == Some(name))
|
||||
.map(|b| b.id().to_string())
|
||||
.ok_or_else(|| failure("invalid_value", "No such callout block"))?,
|
||||
),
|
||||
_ => return Err(failure("invalid_value", "display|rename|label|category=|callout=")),
|
||||
};
|
||||
M::ViewMenu(view, a)
|
||||
}
|
||||
"add_blocks" => M::AddBlocks,
|
||||
"block_list_select" => M::BlockListSelect(arg.parse().map_err(|_| failure("invalid_value", "index"))?),
|
||||
"block_list_add" => M::BlockListAdd,
|
||||
"block_list_delete" => M::BlockListDelete,
|
||||
"select_block_file" => M::SelectBlockPicked(Some(std::path::PathBuf::from(arg))),
|
||||
"select_block_whole" => M::SelectBlockWhole(arg == "1"),
|
||||
"select_block_check" => {
|
||||
let (i, v) = index_value(arg)?;
|
||||
M::SelectBlockCheck(i, v == "1")
|
||||
}
|
||||
"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;
|
||||
@@ -1169,6 +1385,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,
|
||||
),
|
||||
|
||||
@@ -818,6 +818,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>,
|
||||
@@ -1990,6 +1997,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.
|
||||
@@ -3899,6 +3908,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>),
|
||||
@@ -4225,6 +4235,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(),
|
||||
|
||||
@@ -613,6 +613,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
|
||||
@@ -853,6 +856,7 @@ impl Default for UserSettings {
|
||||
block_mru_list: 50,
|
||||
block_redefine_mode: 1,
|
||||
block_navigate: ".".to_string(),
|
||||
sheet_set: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,6 +590,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);
|
||||
@@ -695,6 +699,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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-7
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,6 +876,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();
|
||||
@@ -2045,7 +2047,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(
|
||||
@@ -2150,6 +2153,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"))]
|
||||
@@ -3303,6 +3307,10 @@ impl OpenCADStudio {
|
||||
for i in 0..self.tabs.len() {
|
||||
let _ = std::fs::remove_file(self.autosave_target(i));
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
for path in &self.sheet_set.locks {
|
||||
crate::app::commands::sheet_set::release_lock(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the autosave recovery files, then quit the application.
|
||||
@@ -5511,12 +5519,9 @@ impl OpenCADStudio {
|
||||
let half_w = view.width.abs() * 0.5;
|
||||
let half_h = view.height.abs() * 0.5;
|
||||
(half_w > 1e-9 && half_h > 1e-9).then_some(())?;
|
||||
self.area_plot_job((
|
||||
view.center.x - half_w,
|
||||
view.center.y - half_h,
|
||||
view.center.x + half_w,
|
||||
view.center.y + half_h,
|
||||
))
|
||||
// The view centre is relative to its target (plan views).
|
||||
let (cx, cy) = (view.target.x + view.center.x, view.target.y + view.center.y);
|
||||
self.area_plot_job((cx - half_w, cy - half_h, cx + half_w, cy + half_h))
|
||||
}
|
||||
|
||||
pub(in crate::app) fn extents_plot_job(&self) -> Option<PdfPageInput> {
|
||||
|
||||
@@ -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()
|
||||
@@ -8548,6 +8549,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();
|
||||
|
||||
@@ -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>> {
|
||||
@@ -2642,6 +2643,14 @@ impl OpenCADStudio {
|
||||
};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let plugin_drain = Subscription::none();
|
||||
// Open sheet sets reload when their .dst changes on disk.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
// Open sheet sets reload when their .dst changes on disk; the
|
||||
// drawings' .dwl lock files follow the open tabs.
|
||||
let sheet_set_poll = iced::time::every(std::time::Duration::from_secs(1))
|
||||
.map(|_| Message::SheetSet(crate::ui::window::sheet_set::SheetSetMsg::Poll));
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let sheet_set_poll = Subscription::none();
|
||||
let hatch_pattern_keys = if self.tabs[self.active_tab]
|
||||
.properties
|
||||
.hatch_pattern_picker_open
|
||||
@@ -2843,6 +2852,7 @@ impl OpenCADStudio {
|
||||
web_fonts,
|
||||
autosave,
|
||||
plugin_drain,
|
||||
sheet_set_poll,
|
||||
single_instance,
|
||||
hatch_pattern_keys,
|
||||
keyboard_events,
|
||||
@@ -3029,6 +3039,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 {
|
||||
|
||||
@@ -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,24 @@ 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(f) => match f.kind {
|
||||
crate::ui::window::sheet_set::FormKind::Rename => (560, 470),
|
||||
crate::ui::window::sheet_set::FormKind::RenameView => (520, 200),
|
||||
crate::ui::window::sheet_set::FormKind::ImportLayout => (620, 470),
|
||||
_ => (560, 420),
|
||||
},
|
||||
crate::ui::window::sheet_set::SsDialog::Confirm(..) => (460, 190),
|
||||
crate::ui::window::sheet_set::SsDialog::Template(_) => (480, 400),
|
||||
crate::ui::window::sheet_set::SsDialog::Category(_) => (480, 440),
|
||||
crate::ui::window::sheet_set::SsDialog::BlockList(_) => (540, 330),
|
||||
crate::ui::window::sheet_set::SsDialog::SelectBlock(_) => (580, 390),
|
||||
};
|
||||
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))
|
||||
|
||||
Reference in new issue
Block a user