forked from 1b-agent/opencadstudio-upstream
Merge pull request #1845 from ramox81/codex/dgnimport-followups
DGNIMPORT: names, cells, text placement, curves, 3D, models and references # Conflicts: # Cargo.lock
This commit is contained in:
commit
2b807a7654
36 files changed
+2041
-461
No files matched your search
+308
-84
@@ -8,7 +8,9 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::*;
|
||||
use crate::modules::insert::dgn_import::{self, DgnImportCommand, DgnImportRequest};
|
||||
use crate::modules::insert::dgn_import::{
|
||||
self, DgnImportCommand, DgnImportRequest, ExistingReference, ReferenceMode,
|
||||
};
|
||||
use crate::ui::window::import_dialogs::{
|
||||
unsupported_reason, DgnImportState, ImportDialogMsg, ImportFileState, Support, FORMATS,
|
||||
};
|
||||
@@ -53,7 +55,7 @@ fn exists(path: &str) -> bool {
|
||||
|
||||
/// Whether the file is a DGN model DGNIMPORT reads.
|
||||
fn is_dgn(path: &str) -> bool {
|
||||
crate::scene::model::underlay_vector::item_names(codec::entities::UnderlayType::Dgn, path)
|
||||
crate::scene::model::underlay_vector::dgn_import_models(path)
|
||||
.and_then(|models| models.into_iter().next())
|
||||
.is_some_and(|model| crate::scene::model::underlay_vector::dgn_import(path, &model).is_some())
|
||||
}
|
||||
@@ -158,28 +160,38 @@ impl OpenCADStudio {
|
||||
|
||||
/// The DGN Import window for a file; an error when it is no DGN model.
|
||||
pub(in crate::app) fn open_dgn_import_dialog(&mut self, path: &str) -> Result<(), String> {
|
||||
use crate::scene::model::underlay_vector::{dgn_import, item_names};
|
||||
let models = item_names(codec::entities::UnderlayType::Dgn, path).unwrap_or_default();
|
||||
use crate::scene::model::underlay_vector::{dgn_import, dgn_import_models};
|
||||
let models = dgn_import_models(path).unwrap_or_default();
|
||||
let Some(import) = models.first().and_then(|m| dgn_import(path, m)) else {
|
||||
return Err(crate::t!("Invalid or unsupported DGN file.").into_owned());
|
||||
};
|
||||
// The options chosen last stay when the file is changed.
|
||||
// The options chosen last (DGNIMPORTMODE and the kept import
|
||||
// settings when the window opens) stay when the file is changed.
|
||||
let previous = self.import_dialogs.dgn.take();
|
||||
let saved = dgn_import::settings();
|
||||
let keep = |f: fn(&DgnImportState) -> bool, default: bool| {
|
||||
previous.as_ref().map_or(default, f)
|
||||
};
|
||||
self.import_dialogs.dgn = Some(DgnImportState {
|
||||
path: path.to_string(),
|
||||
version: if import.v7 { "V7" } else { "V8" },
|
||||
// Sheet models are not imported.
|
||||
models: crate::ui::window::pdf_dialogs::item_thumbs(
|
||||
codec::entities::UnderlayType::Dgn,
|
||||
path,
|
||||
),
|
||||
)
|
||||
.into_iter()
|
||||
.filter(|m| models.contains(&m.label))
|
||||
.collect(),
|
||||
model: 0,
|
||||
current_drawing: keep(|s| s.current_drawing, false),
|
||||
prefix_duplicates: keep(|s| s.prefix_duplicates, false),
|
||||
current_drawing: keep(|s| s.current_drawing, saved.mode != 0),
|
||||
prefix_duplicates: keep(|s| s.prefix_duplicates, saved.mode == 2),
|
||||
sub_units: keep(|s| s.sub_units, false),
|
||||
explode_text_nodes: keep(|s| s.explode_text_nodes, false),
|
||||
explode_text_nodes: keep(|s| s.explode_text_nodes, saved.explode_text_nodes),
|
||||
references: previous.as_ref().map_or(saved.references, |s| s.references),
|
||||
existing_reference: previous
|
||||
.as_ref()
|
||||
.map_or(saved.existing_reference, |s| s.existing_reference),
|
||||
units: import.unit_names.clone(),
|
||||
mapping_tab: previous.as_ref().map_or(0, |s| s.mapping_tab),
|
||||
mapping: [0, 1, 2, 3].map(|tab| dgn_import::mapping_rows(&import, tab)),
|
||||
@@ -366,6 +378,16 @@ impl OpenCADStudio {
|
||||
s.explode_text_nodes = on;
|
||||
}
|
||||
}
|
||||
ImportDialogMsg::DgnReferences(mode) => {
|
||||
if let Some(s) = self.import_dialogs.dgn.as_mut() {
|
||||
s.references = mode;
|
||||
}
|
||||
}
|
||||
ImportDialogMsg::DgnExisting(choice) => {
|
||||
if let Some(s) = self.import_dialogs.dgn.as_mut() {
|
||||
s.existing_reference = choice;
|
||||
}
|
||||
}
|
||||
ImportDialogMsg::DgnMappingTab(tab) => {
|
||||
if let Some(s) = self.import_dialogs.dgn.as_mut() {
|
||||
s.mapping_tab = tab.min(3);
|
||||
@@ -386,7 +408,22 @@ impl OpenCADStudio {
|
||||
explode_text_nodes: s.explode_text_nodes,
|
||||
current_drawing: s.current_drawing,
|
||||
prefix_duplicates: s.prefix_duplicates,
|
||||
references: s.references,
|
||||
existing_reference: s.existing_reference,
|
||||
};
|
||||
// The window's choices become DGNIMPORTMODE and the kept
|
||||
// settings the command line imports with.
|
||||
dgn_import::set_settings(dgn_import::DgnImportSettings {
|
||||
mode: match (s.current_drawing, s.prefix_duplicates) {
|
||||
(false, _) => 0,
|
||||
(true, false) => 1,
|
||||
(true, true) => 2,
|
||||
},
|
||||
explode_text_nodes: s.explode_text_nodes,
|
||||
references: s.references,
|
||||
existing_reference: s.existing_reference,
|
||||
});
|
||||
self.save_config();
|
||||
self.close_active_modal();
|
||||
return self.run_dgn_import(i, request);
|
||||
}
|
||||
@@ -394,7 +431,8 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// The import: into a new drawing (or the current one), one undo step.
|
||||
/// The import: into a new drawing (or the current one), one undo step;
|
||||
/// then the model's reference attachments as the request says.
|
||||
pub(in crate::app) fn run_dgn_import(&mut self, i: usize, request: DgnImportRequest) -> Task<Message> {
|
||||
let Some(import) =
|
||||
crate::scene::model::underlay_vector::dgn_import(&request.path, &request.model)
|
||||
@@ -413,84 +451,33 @@ impl OpenCADStudio {
|
||||
self.active_tab
|
||||
};
|
||||
self.push_undo_snapshot(i, "DGNIMPORT");
|
||||
let stem = std::path::Path::new(&request.path.replace('\\', "/"))
|
||||
.file_stem()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.unwrap_or_default();
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
// In the current drawing, names it already has keep the existing
|
||||
// definitions, or are imported under the file's name as prefix.
|
||||
let prefix = (request.current_drawing && request.prefix_duplicates)
|
||||
.then(|| format!("{stem}$0$"));
|
||||
let rename = |taken: bool, name: &str| match &prefix {
|
||||
Some(p) if taken && name != "0" => format!("{p}{name}"),
|
||||
_ => name.to_string(),
|
||||
let naming = if !request.current_drawing {
|
||||
Naming::Number
|
||||
} else if request.prefix_duplicates {
|
||||
let stem = std::path::Path::new(&request.path.replace('\\', "/"))
|
||||
.file_stem()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.unwrap_or_default();
|
||||
Naming::Prefix(format!("{stem} - {}$0$", request.model))
|
||||
} else {
|
||||
Naming::Keep
|
||||
};
|
||||
let mut layers: HashMap<String, String> = HashMap::new();
|
||||
for (name, color) in &converted.layers {
|
||||
let target = rename(scene.document.layers.contains(name), name);
|
||||
if !scene.document.layers.contains(&target) {
|
||||
let mut layer = codec::tables::Layer::new(target.as_str());
|
||||
layer.handle = scene.document.allocate_handle();
|
||||
layer.color = *color;
|
||||
let _ = scene.document.layers.add(layer);
|
||||
let layers = place_converted(&mut self.tabs[i].scene, converted, &naming);
|
||||
if request.references != ReferenceMode::Ignore {
|
||||
let k = if request.sub_units { import.sub_per_master } else { 1.0 };
|
||||
// A reference is placed on the model's default level.
|
||||
let layer = import
|
||||
.levels
|
||||
.get(&64)
|
||||
.map(|l| l.0.clone())
|
||||
.unwrap_or_else(|| "0".to_string());
|
||||
let layer = layers.get(&layer).cloned().unwrap_or(layer);
|
||||
for reference in &import.references {
|
||||
self.attach_dgn_reference(i, &request, reference, k, &layer);
|
||||
}
|
||||
layers.insert(name.clone(), target);
|
||||
}
|
||||
let mut styles: HashMap<String, String> = HashMap::new();
|
||||
for (name, font) in &converted.styles {
|
||||
let target = rename(scene.document.text_styles.contains(name), name);
|
||||
if !scene.document.text_styles.contains(&target) {
|
||||
let mut style = codec::tables::TextStyle::new(target.as_str());
|
||||
style.handle = scene.document.allocate_handle();
|
||||
style.font_file = font.clone();
|
||||
let _ = scene.document.text_styles.add(style);
|
||||
}
|
||||
styles.insert(name.clone(), target);
|
||||
}
|
||||
let mut blocks: HashMap<String, String> = HashMap::new();
|
||||
for (name, _) in &converted.blocks {
|
||||
let taken = scene.document.block_records.get(name).is_some();
|
||||
blocks.insert(name.clone(), rename(taken, name));
|
||||
}
|
||||
let fix = |mut entity: codec::EntityType| {
|
||||
let common = entity.common_mut();
|
||||
if let Some(layer) = layers.get(&common.layer) {
|
||||
common.layer = layer.clone();
|
||||
}
|
||||
match &mut entity {
|
||||
codec::EntityType::Text(t) => {
|
||||
if let Some(s) = styles.get(&t.style) {
|
||||
t.style = s.clone();
|
||||
}
|
||||
}
|
||||
codec::EntityType::MText(t) => {
|
||||
if let Some(s) = styles.get(&t.style) {
|
||||
t.style = s.clone();
|
||||
}
|
||||
}
|
||||
codec::EntityType::Insert(insert) => {
|
||||
if let Some(b) = blocks.get(&insert.block_name) {
|
||||
insert.block_name = b.clone();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
entity
|
||||
};
|
||||
for (name, entities) in converted.blocks {
|
||||
let target = &blocks[&name];
|
||||
if scene.document.block_records.get(target).is_some() {
|
||||
continue;
|
||||
}
|
||||
let entities = entities.into_iter().map(&fix).collect();
|
||||
let _ = scene.define_block_from_owned_entities(entities, target, glam::DVec3::ZERO);
|
||||
}
|
||||
for entity in converted.entities {
|
||||
scene.add_entity(fix(entity));
|
||||
}
|
||||
if !request.current_drawing {
|
||||
scene.fit_all();
|
||||
self.tabs[i].scene.fit_all();
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output("Regenerating model.");
|
||||
@@ -498,4 +485,241 @@ impl OpenCADStudio {
|
||||
self.refresh_properties();
|
||||
task
|
||||
}
|
||||
|
||||
/// One reference attachment: its file translated to "<file>-<model>.dwg"
|
||||
/// beside it and attached as the external reference "<file> - <model>",
|
||||
/// or the file attached as a DGN underlay, at the attachment's place.
|
||||
fn attach_dgn_reference(
|
||||
&mut self,
|
||||
i: usize,
|
||||
request: &DgnImportRequest,
|
||||
reference: &crate::scene::model::underlay_vector::DgnReference,
|
||||
units: f64,
|
||||
layer: &str,
|
||||
) {
|
||||
use crate::scene::model::underlay_vector::{dgn_import, dgn_import_models};
|
||||
let host_dir = std::path::Path::new(&request.path)
|
||||
.parent()
|
||||
.map(|p| p.to_path_buf())
|
||||
.unwrap_or_default();
|
||||
let named = std::path::Path::new(&reference.file.replace('\\', "/")).to_path_buf();
|
||||
let file = if named.is_file() {
|
||||
named
|
||||
} else {
|
||||
host_dir.join(named.file_name().unwrap_or_default())
|
||||
};
|
||||
let path = file.to_string_lossy().into_owned();
|
||||
if crate::scene::model::pdf_raster::source_bytes(&path).is_none() {
|
||||
return;
|
||||
}
|
||||
let Some(model) = (if reference.model.is_empty() {
|
||||
dgn_import_models(&path).and_then(|m| m.into_iter().next())
|
||||
} else {
|
||||
Some(reference.model.clone())
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
let origin = glam::DVec3::from_array(reference.origin) * units;
|
||||
if request.references == ReferenceMode::Underlay {
|
||||
let mut placed = crate::modules::insert::pdf_attach::underlays_for_pages(
|
||||
codec::entities::UnderlayType::Dgn,
|
||||
std::slice::from_ref(&model),
|
||||
origin,
|
||||
reference.scale,
|
||||
reference.rotation,
|
||||
);
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
for (page, mut entity) in placed.drain(..) {
|
||||
let definition = crate::modules::insert::pdf_attach::ensure_underlay_definition(
|
||||
&mut scene.document,
|
||||
codec::entities::UnderlayType::Dgn,
|
||||
&path,
|
||||
&page,
|
||||
);
|
||||
if let codec::EntityType::Underlay(underlay) = &mut entity {
|
||||
underlay.definition_handle = definition;
|
||||
}
|
||||
entity.common_mut().layer = layer.to_string();
|
||||
scene.add_entity(entity);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let stem = file
|
||||
.file_stem()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.unwrap_or_default();
|
||||
let target = file.with_file_name(format!("{stem}-{model}.dwg"));
|
||||
// ponytail: "Prompt to overwrite" keeps the existing drawing, as the
|
||||
// reference does when it cannot ask; ask here if a window is wanted.
|
||||
let write = !target.is_file() || request.existing_reference == ExistingReference::Overwrite;
|
||||
if write {
|
||||
let Some(source) = dgn_import(&path, &model) else {
|
||||
return;
|
||||
};
|
||||
let mut scene = crate::scene::Scene::new();
|
||||
let converted = dgn_import::convert(&source, false, request.explode_text_nodes);
|
||||
place_converted(&mut scene, converted, &Naming::Number);
|
||||
if let Err(error) = crate::io::save(&scene.document, &target) {
|
||||
self.command_line.push_error(&error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let xref = crate::modules::insert::xattach::XrefAttachRequest {
|
||||
path: target.to_string_lossy().into_owned(),
|
||||
overlay: false,
|
||||
path_type: crate::io::xref_model::Pathtype::Relative,
|
||||
};
|
||||
let name = format!("{stem} - {model}");
|
||||
let full = crate::modules::insert::xattach::resolve_xref_store_path(&xref.path, None);
|
||||
self.command_line
|
||||
.push_output(&format!("Attach Xref \"{name}\": {full}"));
|
||||
let host = self.tabs[i].current_path.clone();
|
||||
let block = crate::modules::insert::xattach::prepare_named_xref_definition(
|
||||
&mut self.tabs[i].scene,
|
||||
&xref,
|
||||
host.as_deref(),
|
||||
&name,
|
||||
);
|
||||
if host.is_none() {
|
||||
self.tabs[i].xref_relative_on_save.insert(block.clone());
|
||||
}
|
||||
self.command_line
|
||||
.push_output(&format!("\"{name}\" loaded: {full}"));
|
||||
let mut insert = codec::entities::Insert::new(
|
||||
block,
|
||||
codec::types::Vector3::new(origin.x, origin.y, origin.z),
|
||||
)
|
||||
.with_scale(reference.scale, reference.scale, reference.scale)
|
||||
.with_rotation(reference.rotation);
|
||||
insert.common.layer = layer.to_string();
|
||||
insert.common.linetype = "Continuous".to_string();
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.add_entity(codec::EntityType::Insert(insert));
|
||||
self.refresh_xref_manager();
|
||||
}
|
||||
}
|
||||
|
||||
/// How imported names meet the names a drawing already has: a new drawing
|
||||
/// numbers a clashing layer "<name>_1" and a clashing block or text style
|
||||
/// "<name>1" (layer 0 and the Standard style are shared); the current
|
||||
/// drawing either keeps its own definitions or prefixes every imported name
|
||||
/// (layers 0 and Defpoints excepted).
|
||||
enum Naming {
|
||||
Number,
|
||||
Keep,
|
||||
Prefix(String),
|
||||
}
|
||||
|
||||
impl Naming {
|
||||
fn name(&self, kind: char, name: &str, taken: &dyn Fn(&str) -> bool) -> String {
|
||||
match self {
|
||||
Naming::Keep => name.to_string(),
|
||||
Naming::Prefix(p) => {
|
||||
let shared = kind == 'l'
|
||||
&& (name == "0" || name.eq_ignore_ascii_case("Defpoints"));
|
||||
if shared {
|
||||
name.to_string()
|
||||
} else {
|
||||
format!("{p}{name}")
|
||||
}
|
||||
}
|
||||
Naming::Number => {
|
||||
let shared = (kind == 'l' && name == "0")
|
||||
|| (kind == 's' && name.eq_ignore_ascii_case("Standard"));
|
||||
if shared || !taken(name) {
|
||||
return name.to_string();
|
||||
}
|
||||
let sep = if kind == 'l' { "_" } else { "" };
|
||||
(1..)
|
||||
.map(|n| format!("{name}{sep}{n}"))
|
||||
.find(|n| !taken(n))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds converted objects to a drawing under the naming rule; returns the
|
||||
/// layer names as placed.
|
||||
fn place_converted(
|
||||
scene: &mut crate::scene::Scene,
|
||||
converted: dgn_import::Converted,
|
||||
naming: &Naming,
|
||||
) -> HashMap<String, String> {
|
||||
let mut layers: HashMap<String, String> = HashMap::new();
|
||||
for (name, color) in &converted.layers {
|
||||
let doc = &scene.document;
|
||||
let taken = |n: &str| doc.layers.iter().any(|l| l.name.eq_ignore_ascii_case(n));
|
||||
let target = naming.name('l', name, &taken);
|
||||
if !scene.document.layers.iter().any(|l| l.name.eq_ignore_ascii_case(&target)) {
|
||||
let mut layer = codec::tables::Layer::new(target.as_str());
|
||||
layer.handle = scene.document.allocate_handle();
|
||||
layer.color = *color;
|
||||
let _ = scene.document.layers.add(layer);
|
||||
}
|
||||
layers.insert(name.clone(), target);
|
||||
}
|
||||
let mut styles: HashMap<String, String> = HashMap::new();
|
||||
for (name, font) in &converted.styles {
|
||||
let doc = &scene.document;
|
||||
let taken = |n: &str| doc.text_styles.iter().any(|s| s.name.eq_ignore_ascii_case(n));
|
||||
let target = naming.name('s', name, &taken);
|
||||
if !scene.document.text_styles.iter().any(|s| s.name.eq_ignore_ascii_case(&target)) {
|
||||
let mut style = codec::tables::TextStyle::new(target.as_str());
|
||||
style.handle = scene.document.allocate_handle();
|
||||
style.font_file = font.clone();
|
||||
let _ = scene.document.text_styles.add(style);
|
||||
}
|
||||
styles.insert(name.clone(), target);
|
||||
}
|
||||
let mut blocks: HashMap<String, String> = HashMap::new();
|
||||
let mut claimed: Vec<String> = Vec::new();
|
||||
for (name, _) in &converted.blocks {
|
||||
let doc = &scene.document;
|
||||
let taken = |n: &str| {
|
||||
doc.block_records.iter().any(|b| b.name.eq_ignore_ascii_case(n))
|
||||
|| claimed.iter().any(|c| c.eq_ignore_ascii_case(n))
|
||||
};
|
||||
let target = naming.name('b', name, &taken);
|
||||
claimed.push(target.clone());
|
||||
blocks.insert(name.clone(), target);
|
||||
}
|
||||
let fix = |mut entity: codec::EntityType| {
|
||||
let common = entity.common_mut();
|
||||
if let Some(layer) = layers.get(&common.layer) {
|
||||
common.layer = layer.clone();
|
||||
}
|
||||
match &mut entity {
|
||||
codec::EntityType::Text(t) => {
|
||||
if let Some(s) = styles.get(&t.style) {
|
||||
t.style = s.clone();
|
||||
}
|
||||
}
|
||||
codec::EntityType::MText(t) => {
|
||||
if let Some(s) = styles.get(&t.style) {
|
||||
t.style = s.clone();
|
||||
}
|
||||
}
|
||||
codec::EntityType::Insert(insert) => {
|
||||
if let Some(b) = blocks.get(&insert.block_name) {
|
||||
insert.block_name = b.clone();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
entity
|
||||
};
|
||||
for (name, entities) in converted.blocks {
|
||||
let target = &blocks[&name];
|
||||
if scene.document.block_records.get(target).is_some() {
|
||||
continue;
|
||||
}
|
||||
let entities = entities.into_iter().map(&fix).collect();
|
||||
let _ = scene.define_block_from_owned_entities(entities, target, glam::DVec3::ZERO);
|
||||
}
|
||||
for entity in converted.entities {
|
||||
scene.add_entity(fix(entity));
|
||||
}
|
||||
layers
|
||||
}
|
||||
@@ -856,6 +856,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"SELECTIONCYCLING",
|
||||
"UCSDETECT",
|
||||
"SURFACEASSOCIATIVITY",
|
||||
"DGNIMPORTMODE",
|
||||
"LAYOUTCREATEVIEWPORT",
|
||||
"TXT2MTXTCOMBINEMTEXT",
|
||||
"TXT2MTXTTEXTORDER",
|
||||
|
||||
@@ -1223,6 +1223,7 @@ impl OpenCADStudio {
|
||||
| "SELECTIONCYCLING"
|
||||
| "UCSDETECT"
|
||||
| "SURFACEASSOCIATIVITY"
|
||||
| "DGNIMPORTMODE"
|
||||
| "UCSORTHO"
|
||||
| "UCSVIEW"
|
||||
| "LAYOUTCREATEVIEWPORT"
|
||||
@@ -1622,6 +1623,41 @@ impl OpenCADStudio {
|
||||
}
|
||||
return Some(self.finish_dispatch(cmd));
|
||||
}
|
||||
if name == "DGNIMPORTMODE" {
|
||||
// Where DGNIMPORT puts the model: 0 a new drawing, 1 the
|
||||
// current one keeping its definitions, 2 the current one
|
||||
// with prefixed names.
|
||||
use crate::modules::insert::dgn_import::{set_settings, settings};
|
||||
let mut s = settings();
|
||||
let current = s.mode;
|
||||
match value
|
||||
.as_deref()
|
||||
.map(|v| v.trim().parse::<u8>().ok().filter(|v| *v <= 2))
|
||||
{
|
||||
Some(Some(mode)) => {
|
||||
if current != mode {
|
||||
s.mode = mode;
|
||||
set_settings(s);
|
||||
self.save_config();
|
||||
}
|
||||
}
|
||||
Some(None) => {
|
||||
self.command_line
|
||||
.push_error("Requires an integer between 0 and 2.");
|
||||
self.command_line.push_output(&format!(
|
||||
"Enter new value for DGNIMPORTMODE <{current}>:"
|
||||
));
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
None => {
|
||||
self.command_line.push_output(&format!(
|
||||
"Enter new value for DGNIMPORTMODE <{current}>:"
|
||||
));
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
}
|
||||
return Some(self.finish_dispatch(cmd));
|
||||
}
|
||||
if name == "SURFACEASSOCIATIVITY" {
|
||||
use crate::scene::model::sweep_model;
|
||||
let current = i16::from(sweep_model::surface_associativity());
|
||||
|
||||
@@ -2237,6 +2237,7 @@ impl OpenCADStudio {
|
||||
// The DGN Import window, one field per call: "path=<file>" (as
|
||||
// Change… picks it), "model=<n>", "target=new|current",
|
||||
// "conflict=prefix|ignore", "units=master|sub", "explode=on|off",
|
||||
// "references=translate|ignore|underlay", "existing=prompt|overwrite|keep",
|
||||
// "mapping=layer|linetype|lineweight|color", "ok" or "cancel".
|
||||
"dgn_import_dialog" => {
|
||||
use crate::ui::window::import_dialogs::ImportDialogMsg as I;
|
||||
@@ -2274,6 +2275,18 @@ impl OpenCADStudio {
|
||||
_ => return Err(bad()),
|
||||
}),
|
||||
"explode" => I::DgnExplode(on(value)?),
|
||||
"references" => I::DgnReferences(match value {
|
||||
"translate" => crate::modules::insert::dgn_import::ReferenceMode::Translate,
|
||||
"ignore" => crate::modules::insert::dgn_import::ReferenceMode::Ignore,
|
||||
"underlay" => crate::modules::insert::dgn_import::ReferenceMode::Underlay,
|
||||
_ => return Err(bad()),
|
||||
}),
|
||||
"existing" => I::DgnExisting(match value {
|
||||
"prompt" => crate::modules::insert::dgn_import::ExistingReference::Prompt,
|
||||
"overwrite" => crate::modules::insert::dgn_import::ExistingReference::Overwrite,
|
||||
"keep" => crate::modules::insert::dgn_import::ExistingReference::Keep,
|
||||
_ => return Err(bad()),
|
||||
}),
|
||||
"mapping" => I::DgnMappingTab(match value {
|
||||
"layer" => 0,
|
||||
"linetype" => 1,
|
||||
|
||||
@@ -519,6 +519,8 @@ pub struct UserSettings {
|
||||
/// PDFSHXTEXT's recognition settings (fonts, threshold, PDFSHXLAYER,
|
||||
/// PDFSHXBESTFONT, PDFSHXTEXTSETTINGS).
|
||||
pub pdf_shx_text: crate::modules::insert::pdf_shx_text::ShxTextSettings,
|
||||
/// DGNIMPORTMODE and the DGN Import window's last choices.
|
||||
pub dgn_import: crate::modules::insert::dgn_import::DgnImportSettings,
|
||||
/// Nested-copy symbol handling: false inserts, true binds.
|
||||
pub ncopy_bind: bool,
|
||||
/// Last Options page; unknown saved names fall back without rejecting the config.
|
||||
@@ -999,6 +1001,7 @@ impl Default for UserSettings {
|
||||
ucs_view: true,
|
||||
layout_create_viewport: true,
|
||||
pdf_shx_text: Default::default(),
|
||||
dgn_import: Default::default(),
|
||||
ncopy_bind: false,
|
||||
cursor_type: CursorType::Crosshair,
|
||||
crosshair_color: None,
|
||||
|
||||
@@ -864,6 +864,7 @@ impl OpenCADStudio {
|
||||
ucs_view: crate::modules::view::view_cmd::ucs_view(),
|
||||
layout_create_viewport: crate::scene::layout_create_viewport(),
|
||||
pdf_shx_text: crate::modules::insert::pdf_shx_text::settings(),
|
||||
dgn_import: crate::modules::insert::dgn_import::settings(),
|
||||
ncopy_bind: self.ncopy_bind,
|
||||
cursor_type: self.cursor_type,
|
||||
crosshair_color: self.crosshair_color,
|
||||
@@ -1013,6 +1014,7 @@ impl OpenCADStudio {
|
||||
crate::modules::view::view_cmd::set_ucs_view(s.ucs_view);
|
||||
crate::scene::set_layout_create_viewport(s.layout_create_viewport);
|
||||
crate::modules::insert::pdf_shx_text::set_settings(s.pdf_shx_text.clone());
|
||||
crate::modules::insert::dgn_import::set_settings(s.dgn_import);
|
||||
self.ncopy_bind = s.ncopy_bind;
|
||||
self.cursor_type = s.cursor_type;
|
||||
self.crosshair_color = s.crosshair_color;
|
||||
|
||||
Reference in new issue
Block a user