forked from 1b-agent/opencadstudio-upstream
Merge pull request #1754 from ramox81/codex/attach-command-line
ATTACH: FILEDIA, -ATTACH command line and reference file types # Conflicts: # src/app/settings.rs # src/app/update/file.rs
This commit is contained in:
commit
f8908e151f
33 files changed
+519
-47
No files matched your search
@@ -908,7 +908,7 @@ impl OpenCADStudio {
|
||||
.split_once(char::is_whitespace)
|
||||
.map(|(verb, rest)| (verb.to_ascii_uppercase(), rest.trim()))
|
||||
.unwrap_or_else(|| (cmd.to_ascii_uppercase(), ""));
|
||||
if verb == "PDFATTACH" && rest.is_empty() {
|
||||
if verb == "PDFATTACH" && rest.is_empty() && crate::sys::file_dia() {
|
||||
return Some(Task::done(Message::PdfAttachPick));
|
||||
}
|
||||
let insunits = self.tabs[i].scene.document.header.insertion_units;
|
||||
|
||||
@@ -713,6 +713,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"PDFOSNAP",
|
||||
"UOSNAP",
|
||||
"FIELDDISPLAY",
|
||||
"FILEDIA",
|
||||
"SURFACEASSOCIATIVITY",
|
||||
"LAYOUTCREATEVIEWPORT",
|
||||
"FIELDEVAL",
|
||||
@@ -952,6 +953,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"XR",
|
||||
"XREF",
|
||||
"-XREF",
|
||||
"-ATTACH",
|
||||
"XRELOAD",
|
||||
"ZOOM",
|
||||
"ZS",
|
||||
|
||||
@@ -1213,6 +1213,7 @@ impl OpenCADStudio {
|
||||
| "DGNOSNAP"
|
||||
| "UOSNAP"
|
||||
| "FIELDDISPLAY"
|
||||
| "FILEDIA"
|
||||
| "SURFACEASSOCIATIVITY"
|
||||
| "UCSORTHO"
|
||||
| "UCSVIEW"
|
||||
@@ -1602,6 +1603,35 @@ impl OpenCADStudio {
|
||||
}
|
||||
return Some(self.finish_dispatch(cmd));
|
||||
}
|
||||
if name == "FILEDIA" {
|
||||
let current = i16::from(crate::sys::file_dia());
|
||||
match value
|
||||
.as_deref()
|
||||
.map(|v| v.trim().parse::<i16>().ok().filter(|v| (0..=1).contains(v)))
|
||||
{
|
||||
Some(Some(mode)) => {
|
||||
if current != mode {
|
||||
crate::sys::set_file_dia(mode == 1);
|
||||
self.save_config();
|
||||
}
|
||||
}
|
||||
Some(None) => {
|
||||
self.command_line
|
||||
.push_error(crate::t!("Requires 0 or 1 only.").as_ref());
|
||||
self.command_line.push_output(&format!(
|
||||
"Enter new value for FILEDIA <{current}>:"
|
||||
));
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
None => {
|
||||
self.command_line.push_output(&format!(
|
||||
"Enter new value for FILEDIA <{current}>:"
|
||||
));
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
}
|
||||
return Some(self.finish_dispatch(cmd));
|
||||
}
|
||||
if matches!(
|
||||
name.as_str(),
|
||||
"PDFOSNAP" | "DWFOSNAP" | "DGNOSNAP" | "UOSNAP"
|
||||
|
||||
@@ -8,9 +8,23 @@ use crate::modules::insert::xattach::{
|
||||
existing_reference, path_to_block_name, prepare_xref_definition, stored_path, XAttachCommand,
|
||||
XrefAttachRequest, XrefPlacement,
|
||||
};
|
||||
use crate::modules::insert::xattach::IMAGE_EXTENSIONS;
|
||||
use crate::modules::insert::xref_cmd::display_path;
|
||||
use crate::ui::window::xref_attach::{XrefAttachMsg, XrefAttachState};
|
||||
|
||||
/// ATTACH's file types, in the reference order (the picker counts from 1).
|
||||
const ATTACH_FILTERS: [(&str, &[&str]); 8] = [
|
||||
("All image files", IMAGE_EXTENSIONS),
|
||||
("DWF files (*.dwfx; *.dwf)", &["dwfx", "dwf"]),
|
||||
("MicroStation DGN (*.dgn)", &["dgn"]),
|
||||
("All DGN Files (*.*)", &["*"]),
|
||||
("PDF files (*.pdf)", &["pdf"]),
|
||||
("Point Cloud (*.rcp; *.rcs)", &["rcp", "rcs"]),
|
||||
("Drawing (*.dwg)", &["dwg"]),
|
||||
("All files (*.*)", &["*"]),
|
||||
];
|
||||
const ALL_DGN_FILTER: u32 = 4;
|
||||
|
||||
impl OpenCADStudio {
|
||||
/// DWFATTACH / DGNATTACH on the command line: with a file, from its
|
||||
/// sheet / model prompt; without one, from the path prompt.
|
||||
@@ -42,12 +56,26 @@ impl OpenCADStudio {
|
||||
Some((verb, rest)) => (verb.to_ascii_uppercase(), rest.trim()),
|
||||
None => (upper.clone(), ""),
|
||||
};
|
||||
// FILEDIA 0 sends the picking commands to their command-line forms.
|
||||
let dialog = crate::sys::file_dia();
|
||||
match (verb.as_str(), rest.is_empty()) {
|
||||
("ATTACH", true) => Some(Task::done(Message::AttachPick)),
|
||||
("DWFATTACH", true) => Some(Task::done(Message::UnderlayAttachPick(
|
||||
("ATTACH", true) if dialog => Some(Task::done(Message::AttachPick)),
|
||||
("ATTACH", true) | ("-ATTACH", _) => {
|
||||
use crate::command::CadCommand;
|
||||
let command = crate::modules::insert::xref_cmd::AttachCommand::new();
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
if !rest.is_empty() {
|
||||
return Some(
|
||||
self.feed_command(crate::command::StepInput::Text(rest.to_string())),
|
||||
);
|
||||
}
|
||||
Some(Task::none())
|
||||
}
|
||||
("DWFATTACH", true) if dialog => Some(Task::done(Message::UnderlayAttachPick(
|
||||
codec::entities::UnderlayType::Dwf,
|
||||
))),
|
||||
("DGNATTACH", true) => Some(Task::done(Message::UnderlayAttachPick(
|
||||
("DGNATTACH", true) if dialog => Some(Task::done(Message::UnderlayAttachPick(
|
||||
codec::entities::UnderlayType::Dgn,
|
||||
))),
|
||||
// A file after DWFATTACH / DGNATTACH, or the - forms, go on the
|
||||
@@ -62,7 +90,9 @@ impl OpenCADStudio {
|
||||
}
|
||||
// POINTCLOUDATTACH picks the file; with a file, or as
|
||||
// -POINTCLOUDATTACH, it asks on the command line.
|
||||
("POINTCLOUDATTACH", true) => Some(Task::done(Message::PointCloudAttachPick)),
|
||||
("POINTCLOUDATTACH", true) if dialog => {
|
||||
Some(Task::done(Message::PointCloudAttachPick))
|
||||
}
|
||||
("POINTCLOUDATTACH" | "-POINTCLOUDATTACH", _) => {
|
||||
use crate::command::CadCommand;
|
||||
let command = crate::modules::insert::pc_attach::PointCloudAttachCommand::new();
|
||||
@@ -75,7 +105,14 @@ impl OpenCADStudio {
|
||||
}
|
||||
Some(Task::none())
|
||||
}
|
||||
("XATTACH", true) => Some(Task::done(Message::XAttachPick)),
|
||||
("XATTACH", true) if dialog => Some(Task::done(Message::XAttachPick)),
|
||||
("XATTACH", true) => {
|
||||
let command =
|
||||
crate::modules::insert::xref_cmd::XrefCommand::attach(self.saved_xref_paths(i));
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
Some(Task::none())
|
||||
}
|
||||
// A file named on the command line skips the picker.
|
||||
// Handled at once, so the placement it starts belongs to this
|
||||
// command line (automation included).
|
||||
@@ -96,15 +133,8 @@ impl OpenCADStudio {
|
||||
Some(self.finish_dispatch(cmd))
|
||||
}
|
||||
("-XREF", true) => {
|
||||
let saved: Vec<(String, String)> = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.block_records
|
||||
.iter()
|
||||
.filter(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.map(|br| (br.name.clone(), br.xref_path.clone()))
|
||||
.collect();
|
||||
let command = crate::modules::insert::xref_cmd::XrefCommand::new(saved);
|
||||
let command =
|
||||
crate::modules::insert::xref_cmd::XrefCommand::new(self.saved_xref_paths(i));
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
Some(Task::none())
|
||||
@@ -128,6 +158,18 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
|
||||
/// Saved paths by reference name, for -XREF.
|
||||
fn saved_xref_paths(&self, i: usize) -> Vec<(String, String)> {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.block_records
|
||||
.iter()
|
||||
.filter(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.map(|br| (br.name.clone(), br.xref_path.clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// `-XREF ?` — the reference table as the reference application prints it.
|
||||
fn list_xrefs(&mut self, i: usize, pattern: &str) {
|
||||
let rows: Vec<(String, &'static str, String)> = self.tabs[i]
|
||||
@@ -392,40 +434,41 @@ impl OpenCADStudio {
|
||||
},
|
||||
Message::AttachPickResult,
|
||||
),
|
||||
Message::AttachPick => Task::perform(
|
||||
async {
|
||||
let handle = crate::sys::file_dialog()
|
||||
.set_title(crate::t!("Select Reference File").as_ref())
|
||||
.add_filter(
|
||||
crate::t!("All Reference Files").as_ref(),
|
||||
&[
|
||||
"dwg", "dxf", "pdf", "dwf", "dwfx", "dgn", "png", "jpg", "jpeg",
|
||||
"bmp", "tif", "tiff", "rcp", "rcs",
|
||||
],
|
||||
)
|
||||
.add_filter(crate::t!("Drawing").as_ref(), &["dwg", "dxf"])
|
||||
.add_filter(crate::t!("PDF Files").as_ref(), &["pdf"])
|
||||
.add_filter(crate::t!("DWF Files").as_ref(), &["dwf", "dwfx"])
|
||||
.add_filter(crate::t!("DGN Files").as_ref(), &["dgn"])
|
||||
.add_filter(
|
||||
crate::t!("Images").as_ref(),
|
||||
&["png", "jpg", "jpeg", "bmp", "tif", "tiff"],
|
||||
)
|
||||
.add_filter(crate::t!("Point Clouds").as_ref(), &["rcp", "rcs"])
|
||||
.pick_file()
|
||||
.await;
|
||||
match handle {
|
||||
Some(h) => Ok(crate::sys::handle_path(&h)),
|
||||
None => Err("Cancelled".to_string()),
|
||||
}
|
||||
},
|
||||
Message::AttachPickResult,
|
||||
),
|
||||
Message::AttachPick => {
|
||||
let filters = ATTACH_FILTERS
|
||||
.iter()
|
||||
.map(|(label, extensions)| (crate::t!(label).to_string(), *extensions))
|
||||
.collect();
|
||||
let title = crate::t!("Select Reference File").to_string();
|
||||
let index = crate::sys::attach_filter();
|
||||
Task::perform(
|
||||
async move {
|
||||
match crate::sys::pick_file_with_filter(title, filters, index).await {
|
||||
Some((path, index)) => {
|
||||
crate::sys::set_attach_filter(index);
|
||||
Ok(path)
|
||||
}
|
||||
None => Err("Cancelled".to_string()),
|
||||
}
|
||||
},
|
||||
Message::AttachPickResult,
|
||||
)
|
||||
}
|
||||
Message::AttachPickResult(Ok(path)) => {
|
||||
let ext = path
|
||||
// The file type the picker was left on is a profile setting.
|
||||
self.save_config();
|
||||
let mut ext = path
|
||||
.extension()
|
||||
.map(|e| e.to_string_lossy().to_ascii_lowercase())
|
||||
.unwrap_or_default();
|
||||
// Any file picked under "All DGN Files" is a DGN.
|
||||
let known = ["dwg", "dxf", "pdf", "dwf", "dwfx", "dgn", "rcp", "rcs"];
|
||||
if crate::sys::attach_filter() == ALL_DGN_FILTER
|
||||
&& !known.contains(&ext.as_str())
|
||||
&& !IMAGE_EXTENSIONS.contains(&ext.as_str())
|
||||
{
|
||||
ext = "dgn".to_string();
|
||||
}
|
||||
match ext.as_str() {
|
||||
"pdf" => match std::fs::read(&path) {
|
||||
Ok(bytes) => self.update(Message::PdfAttachPickResult(Ok((
|
||||
@@ -477,7 +520,7 @@ impl OpenCADStudio {
|
||||
self.open_point_cloud_attach_dialog(&path);
|
||||
Task::none()
|
||||
}
|
||||
"png" | "jpg" | "jpeg" | "bmp" | "tif" | "tiff" => {
|
||||
e if IMAGE_EXTENSIONS.contains(&e) => {
|
||||
let result = image::image_dimensions(&path)
|
||||
.map(|(w, h)| (path.clone(), w, h))
|
||||
.map_err(|e| e.to_string());
|
||||
|
||||
@@ -425,6 +425,10 @@ pub struct UserSettings {
|
||||
pub field_display: bool,
|
||||
/// XDWGFADECTL: how much referenced drawings fade (-90..=90; negative is off).
|
||||
pub xref_fade: i32,
|
||||
/// FILEDIA: file dialogs of commands that have a command-line form.
|
||||
pub file_dia: bool,
|
||||
/// The file type ATTACH's picker was last left on (1-based).
|
||||
pub attach_filter: u32,
|
||||
/// SURFACEASSOCIATIVITY: new surfaces stay associative to their sources.
|
||||
pub surface_associativity: bool,
|
||||
/// UCSORTHO: an orthographic view preset also sets its orthographic UCS.
|
||||
@@ -856,6 +860,8 @@ impl Default for UserSettings {
|
||||
attdef_on_screen: true,
|
||||
field_display: true,
|
||||
xref_fade: 50,
|
||||
file_dia: true,
|
||||
attach_filter: 7,
|
||||
surface_associativity: true,
|
||||
ucs_ortho: true,
|
||||
ucs_view: true,
|
||||
|
||||
@@ -797,6 +797,8 @@ impl OpenCADStudio {
|
||||
attdef_on_screen: crate::modules::draw::draw::attdef::session().on_screen,
|
||||
field_display: crate::entities::field::display(),
|
||||
xref_fade: crate::scene::cache::block_cache::xref_fade_ctl(),
|
||||
file_dia: crate::sys::file_dia(),
|
||||
attach_filter: crate::sys::attach_filter(),
|
||||
surface_associativity: crate::scene::model::sweep_model::surface_associativity(),
|
||||
ucs_ortho: crate::modules::view::view_cmd::ucs_ortho(),
|
||||
ucs_view: crate::modules::view::view_cmd::ucs_view(),
|
||||
@@ -919,6 +921,8 @@ impl OpenCADStudio {
|
||||
crate::entities::field::set_display(s.field_display);
|
||||
crate::scene::cache::block_cache::set_xref_fade_ctl(s.xref_fade);
|
||||
self.ribbon.xref_fade = crate::scene::cache::block_cache::xref_fade_ctl();
|
||||
crate::sys::set_file_dia(s.file_dia);
|
||||
crate::sys::set_attach_filter(s.attach_filter);
|
||||
crate::scene::model::sweep_model::set_surface_associativity(s.surface_associativity);
|
||||
crate::modules::view::view_cmd::set_ucs_ortho(s.ucs_ortho);
|
||||
crate::modules::view::view_cmd::set_ucs_view(s.ucs_view);
|
||||
|
||||
Reference in new issue
Block a user