forked from 1b-agent/opencadstudio-upstream
REFEDIT: Edit Reference dialog and unique names for xref objects
REFEDIT opens a dialog after the pick: the nesting chain as chips with a preview of the chosen definition, all objects or picking them in the drawing, attribute definitions (offered only when the definition has them), locking objects outside the working set and unique names for an external reference's named objects. The settings are remembered. With unique names an xref's dependent layers, linetypes, text styles and blocks are checked out as $N$NAME records of their own; without, under the plain name, sharing a host record of that name. Save writes them back under the reference's names, and the records made for the session are removed when it closes. -REFEDIT uses the remembered settings. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
592289f4fd
commit
92a3a8ee4d
33 files changed
+1061
-22
No files matched your search
+330
-18
@@ -4,10 +4,11 @@
|
||||
|
||||
use crate::app::{Message, OpenCADStudio};
|
||||
use crate::modules::draw::modify::refedit::{
|
||||
apply_insert_inverse_transform, apply_insert_transform, level_hits,
|
||||
nesting_chain, RefCloseCommand, RefEditOptionsCommand, RefEditPickCommand, RefEditSession,
|
||||
RefSetCommand, NOT_CHECKED_OUT,
|
||||
apply_insert_inverse_transform, apply_insert_transform, level_hits, nesting_chain,
|
||||
rename_symbols, ChainLevel, RefCloseCommand, RefEditNames, RefEditOptionsCommand,
|
||||
RefEditPickCommand, RefEditSession, RefSetCommand, SymbolKind, NOT_CHECKED_OUT,
|
||||
};
|
||||
use crate::ui::window::refedit_dialog::{RefEditDialogMsg, RefEditDialogState, RefEditLevel};
|
||||
use codec::{EntityType, Handle};
|
||||
use iced::Task;
|
||||
use std::collections::HashSet;
|
||||
@@ -142,25 +143,127 @@ impl OpenCADStudio {
|
||||
.iter()
|
||||
.map(|level| level_hits(&self.tabs[i].scene.document, level))
|
||||
.collect();
|
||||
let command = RefEditOptionsCommand::new(top, chain, hits);
|
||||
let command = RefEditOptionsCommand::new(
|
||||
top,
|
||||
chain,
|
||||
hits,
|
||||
self.refedit_options.lock,
|
||||
self.refedit_options.unique_names,
|
||||
);
|
||||
use crate::command::CadCommand;
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
} else {
|
||||
// The dialog's defaults: the innermost reference, all objects,
|
||||
// attribute definitions not displayed.
|
||||
let path: Vec<String> = chain[1..]
|
||||
.iter()
|
||||
.map(|l| l.insert.value().to_string())
|
||||
.collect();
|
||||
let _ = self.dispatch_command(&format!(
|
||||
"REFEDIT_BEGIN:{}:{}:0:",
|
||||
top.value(),
|
||||
path.join(",")
|
||||
));
|
||||
self.open_refedit_dialog(i, top, chain);
|
||||
}
|
||||
}
|
||||
|
||||
/// The Edit Reference dialog over the picked chain: the innermost level
|
||||
/// chosen, the remembered settings.
|
||||
fn open_refedit_dialog(&mut self, i: usize, top: Handle, chain: Vec<ChainLevel>) {
|
||||
let scene = &self.tabs[i].scene;
|
||||
let document = &scene.document;
|
||||
let levels = chain
|
||||
.iter()
|
||||
.map(|level| {
|
||||
let record = document.block_records.get(&level.block_name);
|
||||
RefEditLevel {
|
||||
insert: level.insert,
|
||||
name: level.block_name.clone(),
|
||||
wires: scene.block_preview_wires(&level.block_name),
|
||||
has_attdefs: record.is_some_and(|br| {
|
||||
br.entity_handles.iter().any(|h| {
|
||||
matches!(document.get_entity(*h), Some(EntityType::AttributeDefinition(_)))
|
||||
})
|
||||
}),
|
||||
xref_path: record
|
||||
.filter(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.map(|br| br.xref_path.clone())
|
||||
.filter(|p| !p.is_empty()),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let options = &self.refedit_options;
|
||||
self.refedit_dialog = Some(RefEditDialogState {
|
||||
top,
|
||||
level: levels.len().saturating_sub(1),
|
||||
levels,
|
||||
chain,
|
||||
nested: options.nested,
|
||||
attributes: options.attributes,
|
||||
lock: options.lock,
|
||||
unique: options.unique_names,
|
||||
});
|
||||
self.active_modal = Some(crate::app::ModalKind::RefEdit);
|
||||
}
|
||||
|
||||
pub(in crate::app) fn update_refedit_dialog(&mut self, message: RefEditDialogMsg) -> Task<Message> {
|
||||
let Some(state) = self.refedit_dialog.as_mut() else {
|
||||
return Task::none();
|
||||
};
|
||||
match message {
|
||||
RefEditDialogMsg::Level(level) => {
|
||||
state.level = level.min(state.levels.len().saturating_sub(1))
|
||||
}
|
||||
RefEditDialogMsg::Nested(on) => state.nested = on,
|
||||
RefEditDialogMsg::Attributes(on) => state.attributes = on,
|
||||
RefEditDialogMsg::Lock(on) => state.lock = on,
|
||||
RefEditDialogMsg::Unique(on) => state.unique = on,
|
||||
RefEditDialogMsg::Help => {
|
||||
self.command_line
|
||||
.push_info(&crate::tr!("ref-edit", "dialog-help"));
|
||||
}
|
||||
RefEditDialogMsg::Ok => {
|
||||
let Some(state) = self.refedit_dialog.take() else {
|
||||
return Task::none();
|
||||
};
|
||||
self.close_active_modal();
|
||||
let attributes = state.attributes && state.attributes_enabled();
|
||||
self.refedit_options = crate::app::settings::RefEditOptions {
|
||||
unique_names: state.unique,
|
||||
attributes: state.attributes,
|
||||
lock: state.lock,
|
||||
nested: state.nested,
|
||||
};
|
||||
let i = self.active_tab;
|
||||
if state.nested {
|
||||
let hits = state
|
||||
.chain
|
||||
.iter()
|
||||
.map(|level| level_hits(&self.tabs[i].scene.document, level))
|
||||
.collect();
|
||||
let command = RefEditOptionsCommand::nested_pick(
|
||||
state.top,
|
||||
state.chain,
|
||||
hits,
|
||||
state.level,
|
||||
attributes,
|
||||
state.lock,
|
||||
state.unique,
|
||||
);
|
||||
use crate::command::CadCommand;
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
} else {
|
||||
let last = state.level.min(state.chain.len().saturating_sub(1));
|
||||
let path: Vec<String> = state.chain[1..=last]
|
||||
.iter()
|
||||
.map(|l| l.insert.value().to_string())
|
||||
.collect();
|
||||
return self.dispatch_command(&format!(
|
||||
"REFEDIT_BEGIN:{}:{}:{}::{}:{}",
|
||||
state.top.value(),
|
||||
path.join(","),
|
||||
attributes as u8,
|
||||
state.lock as u8,
|
||||
state.unique as u8
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// `top[:path[:attributes[:nested]]]` — open the session.
|
||||
fn begin_refedit(&mut self, i: usize, args: &str) {
|
||||
let mut parts = args.split(':');
|
||||
@@ -181,6 +284,10 @@ impl OpenCADStudio {
|
||||
let path = handles(parts.next());
|
||||
let attributes = parts.next() == Some("1");
|
||||
let nested = handles(parts.next());
|
||||
let lock = parts.next().map_or(self.refedit_options.lock, |v| v == "1");
|
||||
let unique = parts
|
||||
.next()
|
||||
.map_or(self.refedit_options.unique_names, |v| v == "1");
|
||||
if self.tabs[i].refedit_session.is_some() || self.reject_locked_edit(i, top) {
|
||||
return;
|
||||
}
|
||||
@@ -206,6 +313,15 @@ impl OpenCADStudio {
|
||||
});
|
||||
}
|
||||
let level = chain.last().expect("non-empty chain").clone();
|
||||
// An external reference's dependent names (`XREF|NAME`) of the
|
||||
// outermost xref in the chain.
|
||||
let xref_prefix = chain.iter().find_map(|l| {
|
||||
document
|
||||
.block_records
|
||||
.get(&l.block_name)
|
||||
.filter(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.map(|br| format!("{}|", br.name))
|
||||
});
|
||||
let Some(br) = document.block_records.get(&level.block_name) else {
|
||||
return;
|
||||
};
|
||||
@@ -240,6 +356,8 @@ impl OpenCADStudio {
|
||||
// Everything allocated from here on is part of the session.
|
||||
handle_watermark: document.next_handle().max(document.header.handle_seed),
|
||||
xref_path,
|
||||
lock,
|
||||
names: RefEditNames::default(),
|
||||
};
|
||||
let copies: Vec<EntityType> = extracted
|
||||
.iter()
|
||||
@@ -247,6 +365,15 @@ impl OpenCADStudio {
|
||||
.collect();
|
||||
|
||||
self.push_undo_snapshot(i, "REFEDIT");
|
||||
let mut session = session;
|
||||
let copies = match xref_prefix {
|
||||
Some(prefix) => {
|
||||
let (copies, names) = self.refedit_host_names(i, copies, &prefix, unique);
|
||||
session.names = names;
|
||||
copies
|
||||
}
|
||||
None => copies,
|
||||
};
|
||||
let mut temp_handles = Vec::new();
|
||||
for mut entity in copies {
|
||||
apply_insert_transform(&mut entity, &session);
|
||||
@@ -254,7 +381,6 @@ impl OpenCADStudio {
|
||||
entity.common_mut().owner_handle = Handle::NULL;
|
||||
temp_handles.push(self.tabs[i].scene.add_entity(entity));
|
||||
}
|
||||
let mut session = session;
|
||||
session.temp_handles = temp_handles.clone();
|
||||
self.tabs[i].refedit_session = Some(session);
|
||||
self.tabs[i].refedit_closed.clear();
|
||||
@@ -262,7 +388,7 @@ impl OpenCADStudio {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.set_refedit_keep(Some(temp_handles.iter().copied().collect::<rustc_hash::FxHashSet<_>>()));
|
||||
self.tabs[i].scene.refedit_lock = true;
|
||||
self.tabs[i].scene.refedit_lock = lock;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].dirty = true;
|
||||
// No active command — the definition's objects are edited freely
|
||||
@@ -370,6 +496,10 @@ impl OpenCADStudio {
|
||||
.iter()
|
||||
.filter_map(|h| self.tabs[i].scene.document.get_entity(*h).cloned())
|
||||
.map(|mut entity| {
|
||||
// Back to the reference's own dependent names.
|
||||
rename_symbols(&mut entity, &|kind, name| {
|
||||
session.names.original(kind, name).map(str::to_string)
|
||||
});
|
||||
apply_insert_inverse_transform(&mut entity, &session);
|
||||
let mut entity = normalize_entity_for_block(entity);
|
||||
entity.common_mut().handle = Handle::NULL;
|
||||
@@ -452,6 +582,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
fn finish_refedit_close(&mut self, i: usize, session: RefEditSession) {
|
||||
self.drop_refedit_names(i, &session.names);
|
||||
self.tabs[i].refedit_closed.push(session);
|
||||
self.tabs[i].scene.refedit_lock = false;
|
||||
self.tabs[i].scene.set_refedit_keep(None);
|
||||
@@ -581,8 +712,8 @@ impl OpenCADStudio {
|
||||
.map(|e| e.common().handle)
|
||||
.filter(|h| session.in_working_set(*h))
|
||||
.collect();
|
||||
self.tabs[i].scene.refedit_lock = session.lock;
|
||||
self.tabs[i].refedit_session = Some(session);
|
||||
self.tabs[i].scene.refedit_lock = true;
|
||||
self.tabs[i].scene.set_refedit_keep(Some(keep));
|
||||
}
|
||||
}
|
||||
@@ -600,4 +731,185 @@ impl OpenCADStudio {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// The working set's objects of an external reference under host names:
|
||||
/// `XREF|NAME` becomes `$N$NAME` (the first free N) with records of its
|
||||
/// own when `unique`, else `NAME`, sharing a host record of that name when
|
||||
/// one exists. Missing records are copied from the reference's.
|
||||
fn refedit_host_names(
|
||||
&mut self,
|
||||
i: usize,
|
||||
mut copies: Vec<EntityType>,
|
||||
prefix: &str,
|
||||
unique: bool,
|
||||
) -> (Vec<EntityType>, RefEditNames) {
|
||||
let document = &mut self.tabs[i].scene.document;
|
||||
let deps = crate::app::ClipboardDeps::capture(document, &copies);
|
||||
let strip = |name: &str| -> Option<String> {
|
||||
(name.len() > prefix.len()
|
||||
&& name.is_char_boundary(prefix.len())
|
||||
&& name[..prefix.len()].eq_ignore_ascii_case(prefix))
|
||||
.then(|| name[prefix.len()..].to_string())
|
||||
};
|
||||
let exists = |document: &codec::CadDocument, kind: SymbolKind, name: &str| match kind {
|
||||
SymbolKind::Layer => document.layers.contains(name),
|
||||
SymbolKind::Linetype => document.line_types.contains(name),
|
||||
SymbolKind::TextStyle => document.text_styles.contains(name),
|
||||
SymbolKind::Block => document.block_records.get(name).is_some(),
|
||||
};
|
||||
let wanted: Vec<(SymbolKind, String)> = deps
|
||||
.layers
|
||||
.iter()
|
||||
.map(|r| (SymbolKind::Layer, r.name.clone()))
|
||||
.chain(deps.linetypes.iter().map(|r| (SymbolKind::Linetype, r.name.clone())))
|
||||
.chain(deps.text_styles.iter().map(|r| (SymbolKind::TextStyle, r.name.clone())))
|
||||
.chain(deps.blocks.iter().map(|b| (SymbolKind::Block, b.name.clone())))
|
||||
.collect();
|
||||
let mut names = RefEditNames::default();
|
||||
for (kind, original) in wanted {
|
||||
let Some(base) = strip(&original) else {
|
||||
continue;
|
||||
};
|
||||
let taken = |names: &RefEditNames, candidate: &str| {
|
||||
exists(document, kind, candidate)
|
||||
|| names
|
||||
.renamed
|
||||
.iter()
|
||||
.any(|(k, used, _)| *k == kind && used.eq_ignore_ascii_case(candidate))
|
||||
};
|
||||
// Layer 0 is the host's own in every drawing.
|
||||
let used = if kind == SymbolKind::Layer && base == "0" {
|
||||
base
|
||||
} else if unique {
|
||||
(0u32..)
|
||||
.map(|n| format!("${n}${base}"))
|
||||
.find(|candidate| !taken(&names, candidate))
|
||||
.expect("a free name")
|
||||
} else {
|
||||
base
|
||||
};
|
||||
if !exists(document, kind, &used)
|
||||
&& !names
|
||||
.created
|
||||
.iter()
|
||||
.any(|(k, n)| *k == kind && n.eq_ignore_ascii_case(&used))
|
||||
{
|
||||
names.created.push((kind, used.clone()));
|
||||
}
|
||||
names.renamed.push((kind, used, original));
|
||||
}
|
||||
let used_for = |kind: SymbolKind, name: &str| {
|
||||
names
|
||||
.renamed
|
||||
.iter()
|
||||
.find(|(k, _, original)| *k == kind && original.eq_ignore_ascii_case(name))
|
||||
.map(|(_, used, _)| used.clone())
|
||||
};
|
||||
let created = |kind: SymbolKind, name: &str| -> Option<String> {
|
||||
used_for(kind, name).filter(|used| {
|
||||
names
|
||||
.created
|
||||
.iter()
|
||||
.any(|(k, n)| *k == kind && n.eq_ignore_ascii_case(used))
|
||||
})
|
||||
};
|
||||
for record in &deps.layers {
|
||||
if let Some(used) = created(SymbolKind::Layer, &record.name) {
|
||||
let mut copy = record.clone();
|
||||
copy.name = used;
|
||||
copy.flags.xref_dependent = false;
|
||||
copy.xref_block_record_handle = Handle::NULL;
|
||||
if let Some(linetype) = used_for(SymbolKind::Linetype, ©.line_type) {
|
||||
copy.line_type = linetype;
|
||||
}
|
||||
copy.handle = document.allocate_handle();
|
||||
let _ = document.layers.add(copy);
|
||||
}
|
||||
}
|
||||
for record in &deps.linetypes {
|
||||
if let Some(used) = created(SymbolKind::Linetype, &record.name) {
|
||||
let mut copy = record.clone();
|
||||
copy.name = used;
|
||||
copy.xref_dependent = false;
|
||||
copy.xref_block_record_handle = Handle::NULL;
|
||||
copy.handle = document.allocate_handle();
|
||||
let _ = document.line_types.add(copy);
|
||||
}
|
||||
}
|
||||
for record in &deps.text_styles {
|
||||
if let Some(used) = created(SymbolKind::TextStyle, &record.name) {
|
||||
let mut copy = record.clone();
|
||||
copy.name = used;
|
||||
copy.xref_dependent = false;
|
||||
copy.xref_block_record_handle = Handle::NULL;
|
||||
copy.handle = document.allocate_handle();
|
||||
let _ = document.text_styles.add(copy);
|
||||
}
|
||||
}
|
||||
let rename = |kind: SymbolKind, name: &str| used_for(kind, name);
|
||||
let blocks: Vec<crate::app::BlockDef> = deps
|
||||
.blocks
|
||||
.iter()
|
||||
.filter_map(|def| {
|
||||
let used = created(SymbolKind::Block, &def.name)?;
|
||||
let mut entities = def.entities.clone();
|
||||
for entity in &mut entities {
|
||||
rename_symbols(entity, &rename);
|
||||
}
|
||||
Some(crate::app::BlockDef {
|
||||
name: used,
|
||||
base_point: def.base_point,
|
||||
entities,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
crate::app::command_driver::clipboard::merge_block_defs(document, &blocks);
|
||||
for entity in &mut copies {
|
||||
rename_symbols(entity, &rename);
|
||||
}
|
||||
(copies, names)
|
||||
}
|
||||
|
||||
/// Removes the host records made for a session that nothing uses any more.
|
||||
fn drop_refedit_names(&mut self, i: usize, names: &RefEditNames) {
|
||||
for (kind, name) in names.created.iter().rev() {
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
let in_use = scene.document.entities().any(|entity| {
|
||||
let common = entity.common();
|
||||
match kind {
|
||||
SymbolKind::Layer => common.layer.eq_ignore_ascii_case(name),
|
||||
SymbolKind::Linetype => common.linetype.eq_ignore_ascii_case(name),
|
||||
SymbolKind::TextStyle => match entity {
|
||||
EntityType::Text(t) => t.style.eq_ignore_ascii_case(name),
|
||||
EntityType::MText(t) => t.style.eq_ignore_ascii_case(name),
|
||||
EntityType::AttributeDefinition(a) => {
|
||||
a.text_style.eq_ignore_ascii_case(name)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
SymbolKind::Block => matches!(
|
||||
entity,
|
||||
EntityType::Insert(insert) if insert.block_name.eq_ignore_ascii_case(name)
|
||||
),
|
||||
}
|
||||
});
|
||||
if in_use {
|
||||
continue;
|
||||
}
|
||||
match kind {
|
||||
SymbolKind::Layer => {
|
||||
scene.document.layers.remove(name);
|
||||
}
|
||||
SymbolKind::Linetype => {
|
||||
scene.document.line_types.remove(name);
|
||||
}
|
||||
SymbolKind::TextStyle => {
|
||||
scene.document.text_styles.remove(name);
|
||||
}
|
||||
SymbolKind::Block => {
|
||||
let _ = crate::scene::block_service::erase(scene, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,7 @@ pub(super) const NAMES: &[&str] = &[
|
||||
"external_change_cancel",
|
||||
"pdf_dialog_ok",
|
||||
"view_background",
|
||||
"refedit_dialog",
|
||||
"pdf_layer_toggle",
|
||||
"pc_manager_toggle",
|
||||
"pc_manager",
|
||||
@@ -1884,6 +1885,36 @@ impl OpenCADStudio {
|
||||
})
|
||||
}
|
||||
"ribbon_dropdown" => Message::ToggleRibbonDropdown(string(req, "value")?.into()),
|
||||
// The Edit Reference dialog, one field per call: "level=<n>" (0 =
|
||||
// the picked reference), "nested=0|1" (pick the working set in the
|
||||
// drawing), "attributes=0|1", "lock=0|1", "unique=0|1", "ok" or
|
||||
// "cancel".
|
||||
"refedit_dialog" => {
|
||||
use crate::ui::window::refedit_dialog::RefEditDialogMsg as R;
|
||||
if self.active_modal != Some(crate::app::ModalKind::RefEdit) {
|
||||
return Err(failure("no_dialog", "The Reference Edit dialog is not open"));
|
||||
}
|
||||
let spec = string(req, "value")?;
|
||||
let (key, value) = spec.split_once('=').unwrap_or((spec, ""));
|
||||
let flag = || match value {
|
||||
"1" => Ok(true),
|
||||
"0" => Ok(false),
|
||||
_ => Err(failure("invalid_value", spec)),
|
||||
};
|
||||
if key == "cancel" {
|
||||
Message::CloseModal
|
||||
} else {
|
||||
Message::RefEditDialog(match key {
|
||||
"ok" => R::Ok,
|
||||
"level" => R::Level(value.parse().map_err(|_| failure("invalid_value", spec))?),
|
||||
"nested" => R::Nested(flag()?),
|
||||
"attributes" => R::Attributes(flag()?),
|
||||
"lock" => R::Lock(flag()?),
|
||||
"unique" => R::Unique(flag()?),
|
||||
_ => return Err(failure("invalid_value", "Unknown Reference Edit field")),
|
||||
})
|
||||
}
|
||||
}
|
||||
// The -VIEW Background dialog, one field per call: "type=gradient",
|
||||
// "color|top|middle|bottom=r,g,b", "three=1", "rotation=30",
|
||||
// "image=<path>", "position=center|stretch|tile", "aspect=1", "offset=x,y" (pixels), "scale=x,y",
|
||||
|
||||
@@ -582,6 +582,8 @@ pub(super) struct OpenCADStudio {
|
||||
pc_section: Option<crate::ui::window::pdf_dialogs::PcSectionState>,
|
||||
/// -VIEW sEttings Background dialog.
|
||||
view_background: Option<crate::ui::window::pdf_dialogs::ViewBackgroundState>,
|
||||
/// The Edit Reference dialog (REFEDIT).
|
||||
refedit_dialog: Option<crate::ui::window::refedit_dialog::RefEditDialogState>,
|
||||
underlay_layers: Option<crate::ui::window::pdf_dialogs::UnderlayLayersState>,
|
||||
pdf_import_settings: Option<crate::modules::insert::pdf_import::PdfImportSettings>,
|
||||
pdf_import_file: Option<crate::ui::window::pdf_dialogs::PdfImportFileState>,
|
||||
@@ -790,6 +792,8 @@ pub(super) struct OpenCADStudio {
|
||||
block_freq: std::collections::HashMap<String, u32>,
|
||||
/// BLOCKMRULIST: how many recent blocks the palette keeps (0–100).
|
||||
pub(crate) block_mru_list: u8,
|
||||
/// The Edit Reference dialog's remembered settings.
|
||||
pub(crate) refedit_options: crate::app::settings::RefEditOptions,
|
||||
/// BLOCKREDEFINEMODE (0–2).
|
||||
pub(crate) block_redefine_mode: u8,
|
||||
/// BLOCKNAVIGATE: the Libraries tab's start folder ("." for none).
|
||||
@@ -2153,6 +2157,7 @@ pub enum ModalKind {
|
||||
PointCloudColorMap,
|
||||
PcSection,
|
||||
ViewBackground,
|
||||
RefEdit,
|
||||
UnderlayLayers,
|
||||
PdfImportSettings,
|
||||
PdfImportFile,
|
||||
@@ -4348,6 +4353,8 @@ pub enum Message {
|
||||
PdfDialog(crate::ui::window::pdf_dialogs::PdfDialogMsg),
|
||||
AttdefDialog(crate::ui::window::attdef_dialog::AttdefDialogMsg),
|
||||
FieldDialog(crate::ui::window::field_dialog::FieldDialogMsg),
|
||||
/// An edit in the Edit Reference dialog.
|
||||
RefEditDialog(crate::ui::window::refedit_dialog::RefEditDialogMsg),
|
||||
/// A click or search in the Point Cloud Manager.
|
||||
PcManager(crate::ui::window::pc_manager::PcManagerMsg),
|
||||
Count(crate::ui::window::count_palette::CountMsg),
|
||||
@@ -4559,6 +4566,7 @@ impl OpenCADStudio {
|
||||
point_cloud_color_map: None,
|
||||
pc_section: None,
|
||||
view_background: None,
|
||||
refedit_dialog: None,
|
||||
underlay_layers: None,
|
||||
pdf_import_settings: None,
|
||||
pdf_import_file: None,
|
||||
@@ -4658,6 +4666,7 @@ impl OpenCADStudio {
|
||||
block_mru: Vec::new(),
|
||||
block_freq: std::collections::HashMap::new(),
|
||||
block_mru_list: 50,
|
||||
refedit_options: Default::default(),
|
||||
block_redefine_mode: 1,
|
||||
block_navigate: ".".to_string(),
|
||||
insname: String::new(),
|
||||
|
||||
@@ -652,6 +652,9 @@ pub struct UserSettings {
|
||||
/// BLOCKNAVIGATE (default ".").
|
||||
#[serde(default = "default_block_navigate")]
|
||||
pub block_navigate: String,
|
||||
/// The Edit Reference dialog's settings.
|
||||
#[serde(default)]
|
||||
pub refedit: RefEditOptions,
|
||||
/// XFADECTL: how far objects outside the REFEDIT working set fade (0–90, default 70).
|
||||
#[serde(default = "default_xfadectl")]
|
||||
pub xfadectl: u8,
|
||||
@@ -687,6 +690,30 @@ pub struct PaletteBlockRef {
|
||||
pub drawing: bool,
|
||||
}
|
||||
|
||||
/// The Edit Reference dialog's settings, remembered between sessions: give
|
||||
/// an external reference's clashing named objects unique names, check out
|
||||
/// attribute definitions, lock what is outside the working set, pick the
|
||||
/// working set's objects in the drawing.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct RefEditOptions {
|
||||
pub unique_names: bool,
|
||||
pub attributes: bool,
|
||||
pub lock: bool,
|
||||
pub nested: bool,
|
||||
}
|
||||
|
||||
impl Default for RefEditOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
unique_names: true,
|
||||
attributes: false,
|
||||
lock: true,
|
||||
nested: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Blocks palette's insertion options.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockInsertOptions {
|
||||
@@ -938,6 +965,7 @@ impl Default for UserSettings {
|
||||
block_mru_list: 50,
|
||||
block_redefine_mode: 1,
|
||||
block_navigate: ".".to_string(),
|
||||
refedit: RefEditOptions::default(),
|
||||
xfadectl: 70,
|
||||
count_color: 3,
|
||||
count_error_color: 1,
|
||||
|
||||
@@ -873,6 +873,7 @@ impl OpenCADStudio {
|
||||
block_mru_list: self.block_mru_list,
|
||||
block_redefine_mode: self.block_redefine_mode,
|
||||
block_navigate: self.block_navigate.clone(),
|
||||
refedit: self.refedit_options.clone(),
|
||||
xfadectl: crate::scene::cache::block_cache::refedit_fade_ctl() as u8,
|
||||
count_color: self.count_palette.color,
|
||||
count_error_color: self.count_palette.error_color,
|
||||
@@ -1036,6 +1037,7 @@ impl OpenCADStudio {
|
||||
self.block_redefine_mode = s.block_redefine_mode.min(2);
|
||||
self.block_navigate = s.block_navigate.clone();
|
||||
crate::scene::cache::block_cache::set_refedit_fade_ctl(i32::from(s.xfadectl.min(90)));
|
||||
self.refedit_options = s.refedit.clone();
|
||||
self.count_palette.color = s.count_color;
|
||||
self.count_palette.error_color = s.count_error_color;
|
||||
self.count_palette.service = s.count_service;
|
||||
|
||||
@@ -2274,6 +2274,7 @@ impl OpenCADStudio {
|
||||
Message::PdfDialog(message) => self.update_pdf_dialog(message),
|
||||
Message::AttdefDialog(message) => self.on_attdef_dialog(message),
|
||||
Message::FieldDialog(message) => self.on_field_dialog(message),
|
||||
Message::RefEditDialog(message) => self.update_refedit_dialog(message),
|
||||
Message::PcManager(message) => self.update_pc_manager(message),
|
||||
Message::Count(message) => self.on_count(message),
|
||||
Message::SheetSet(message) => self.on_sheet_set(message),
|
||||
@@ -9487,6 +9488,9 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
};
|
||||
}
|
||||
if self.active_modal == Some(super::ModalKind::RefEdit) {
|
||||
self.refedit_dialog = None;
|
||||
}
|
||||
// Cancelling the section settings drops the waiting extraction.
|
||||
if self.active_modal == Some(super::ModalKind::PcSection) {
|
||||
crate::modules::insert::pc_extract::drop_job();
|
||||
|
||||
@@ -40,6 +40,7 @@ impl OpenCADStudio {
|
||||
crate::tr!("view-background", "title"),
|
||||
self.view_background.as_ref().map_or("", |s| s.view.as_str())
|
||||
),
|
||||
Some(K::RefEdit) => crate::tr!("ref-edit", "dialog-title"),
|
||||
Some(K::UnderlayLayers) => crate::t!("Underlay Layers").into_owned(),
|
||||
Some(K::PdfImportSettings) => crate::t!("PDF Import Settings").into_owned(),
|
||||
Some(K::PdfImportFile) => crate::t!("Import PDF").into_owned(),
|
||||
@@ -528,6 +529,12 @@ impl OpenCADStudio {
|
||||
crate::ui::window::pdf_dialogs::view_background(state, flow)
|
||||
})
|
||||
}
|
||||
super::super::ModalKind::RefEdit => {
|
||||
let state = self.refedit_dialog.as_ref()?;
|
||||
sized_flow(ex, 560, 470, |flow| {
|
||||
crate::ui::window::refedit_dialog::view(state, flow)
|
||||
})
|
||||
}
|
||||
super::super::ModalKind::UnderlayLayers => {
|
||||
let state = self.underlay_layers.as_ref()?;
|
||||
sized_flow(ex, 460, 520, |flow| {
|
||||
|
||||
Reference in new issue
Block a user