style: rustfmt the tree so the CI lint check passes

This commit is contained in:
Karim Jerbi committed 2026-10-15 04:10:06 +01:00
1 parent 1317a7b4fd
commit 6025d8be44
128 files changed
+4097 -1676

No files matched your search

+1 -2
View File
@@ -4,8 +4,7 @@
use crate::app::{Message, OpenCADStudio};
use crate::modules::insert::block_cmdline::{
AttsyncCommand, BlockTable, DashBeditCommand, DashBlockCommand, DashWblockCommand,
WblockSource,
AttsyncCommand, BlockTable, DashBeditCommand, DashBlockCommand, DashWblockCommand, WblockSource,
};
use iced::Task;
+27 -17
View File
@@ -112,12 +112,14 @@ impl OpenCADStudio {
) -> Box<dyn CadCommand> {
let document = &self.tabs[i].scene.document;
let defaults = crate::scene::creation_style::current_text_defaults(document);
Box::new(crate::modules::draw::clipboard::pastespec::PasteSpecCommand::new(
!self.clipboard.is_empty(),
text,
defaults.style_name,
defaults.height,
))
Box::new(
crate::modules::draw::clipboard::pastespec::PasteSpecCommand::new(
!self.clipboard.is_empty(),
text,
defaults.style_name,
defaults.height,
),
)
}
pub(super) fn dispatch_blocks(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
@@ -317,20 +319,22 @@ impl OpenCADStudio {
// ARRAYEDIT Source: edit the objects the array repeats in the
// Block Editor; every item follows when it is saved.
cmd if cmd.starts_with("ARRAYEDIT_SOURCE:") => {
let handle = codec::Handle::new(
cmd["ARRAYEDIT_SOURCE:".len()..].parse().unwrap_or(0),
);
let handle =
codec::Handle::new(cmd["ARRAYEDIT_SOURCE:".len()..].parse().unwrap_or(0));
let document = &self.tabs[i].scene.document;
let source = crate::scene::assoc_array::array_of_insert(document, handle)
.and_then(|array| {
let source = crate::scene::assoc_array::array_of_insert(document, handle).and_then(
|array| {
document
.block_records
.iter()
.find(|record| record.handle == array.source_block)
.map(|record| record.name.clone())
});
},
);
match source {
Some(name) => return Some(self.dispatch_command(&format!("BEDIT_OPEN:{name}"))),
Some(name) => {
return Some(self.dispatch_command(&format!("BEDIT_OPEN:{name}")))
}
None => self.command_line.push_error(
crate::t!("ARRAYEDIT: the selected object is not an associative array.")
.as_ref(),
@@ -437,8 +441,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
let wires = self.tabs[i].scene.wires_for_entities(&self.clipboard);
use crate::modules::insert::insert_block::InsertBlockCommand;
let cmd =
InsertBlockCommand::new_for_block(name, wires, base);
let cmd = InsertBlockCommand::new_for_block(name, wires, base);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
@@ -614,7 +617,11 @@ impl OpenCADStudio {
let arg = cmd.trim_start_matches("ATTSYNC").trim().to_string();
let document = &self.tabs[i].scene.document;
let table = crate::modules::insert::block_cmdline::BlockTable::of(document);
match table.attributed.iter().find(|b| b.eq_ignore_ascii_case(&arg)) {
match table
.attributed
.iter()
.find(|b| b.eq_ignore_ascii_case(&arg))
{
Some(block) => {
let block = block.clone();
self.attsync_block(i, &block);
@@ -1731,7 +1738,10 @@ mod tests {
fn attman_and_battman_report_a_drawing_without_attributed_blocks() {
for command in ["ATTMAN", "BATTMAN"] {
let output = run_capture(&mut fresh_app(), command);
assert_eq!(output, "This drawing contains no attributed blocks.", "{command}");
assert_eq!(
output, "This drawing contains no attributed blocks.",
"{command}"
);
}
}
+22 -12
View File
@@ -14,8 +14,11 @@ impl OpenCADStudio {
.map(|session| session.br_handle);
if block.is_none() {
self.command_line.push_error(
crate::tf!("{}: open the block in the Block Editor first (BEDIT).", command)
.as_ref(),
crate::tf!(
"{}: open the block in the Block Editor first (BEDIT).",
command
)
.as_ref(),
);
}
block
@@ -29,10 +32,12 @@ impl OpenCADStudio {
.block_records
.iter()
.find(|record| record.handle == block)
.and_then(|record| match document.get_entity(record.block_entity_handle) {
Some(EntityType::Block(begin)) => Some(begin.base_point),
_ => None,
})
.and_then(
|record| match document.get_entity(record.block_entity_handle) {
Some(EntityType::Block(begin)) => Some(begin.base_point),
_ => None,
},
)
.unwrap_or(codec::types::Vector3::ZERO);
visibility::create(document, block, base)
}
@@ -40,10 +45,15 @@ impl OpenCADStudio {
/// The state the block shows in the editor.
fn visibility_current(&self, i: usize, block: Handle) -> usize {
let scene = &self.tabs[i].scene;
scene.visibility_states.get(&block).copied().unwrap_or_else(|| {
visibility::parameter(&scene.document, block)
.map_or(0, |parameter| visibility::shown_state(&scene.document, parameter.handle))
})
scene
.visibility_states
.get(&block)
.copied()
.unwrap_or_else(|| {
visibility::parameter(&scene.document, block).map_or(0, |parameter| {
visibility::shown_state(&scene.document, parameter.handle)
})
})
}
fn show_visibility_state(&mut self, i: usize, block: Handle, parameter: Handle, state: usize) {
@@ -51,8 +61,8 @@ impl OpenCADStudio {
self.tabs[i].scene.visibility_states.insert(block, state);
self.tabs[i].scene.bump_geometry();
self.tabs[i].dirty = true;
if let Some(name) = visibility::state_names(&self.tabs[i].scene.document, parameter)
.get(state)
if let Some(name) =
visibility::state_names(&self.tabs[i].scene.document, parameter).get(state)
{
self.command_line
.push_output(crate::tf!("Current visibility state: {}", name).as_ref());
+5 -1
View File
@@ -188,7 +188,11 @@ impl OpenCADStudio {
}
}
pub(in crate::app) fn start_count_command(&mut self, i: usize, command: Box<dyn CadCommand>) -> Task<Message> {
pub(in crate::app) fn start_count_command(
&mut self,
i: usize,
command: Box<dyn CadCommand>,
) -> Task<Message> {
self.reset_command_start_state(i);
self.command_line.push_info(&command.prompt());
self.tabs[i].active_cmd = Some(command);
+5 -4
View File
@@ -2153,16 +2153,17 @@ impl OpenCADStudio {
}
let doc = &self.tabs[i].scene.document;
let current_style = doc.header.current_table_style_name.clone();
table.table_style_handle = doc.objects.iter().find_map(|(handle, object)| {
match object {
table.table_style_handle = doc
.objects
.iter()
.find_map(|(handle, object)| match object {
codec::objects::ObjectType::TableStyle(style)
if style.name.eq_ignore_ascii_case(&current_style) =>
{
Some(*handle)
}
_ => None,
}
});
});
let command =
crate::modules::annotate::data_link::DataLinkPlaceCommand::new(table, link_path);
self.command_line
+11 -9
View File
@@ -443,7 +443,8 @@ impl OpenCADStudio {
Ok(text) => return Some(self.run_script(clean_path, &text)),
Err(e) => {
self.command_line.push_error(
crate::tf!("SCRIPT: cannot read {clean_path}: {e}").as_ref(),
crate::tf!("SCRIPT: cannot read {clean_path}: {e}")
.as_ref(),
);
}
}
@@ -733,9 +734,8 @@ impl OpenCADStudio {
let drawing = match result {
Ok(bytes) => bytes,
Err(e) => {
self.command_line.push_error(
crate::tf!("{cmd}: cannot package the drawing ({e}).").as_ref(),
);
self.command_line
.push_error(crate::tf!("{cmd}: cannot package the drawing ({e}).").as_ref());
return Task::none();
}
};
@@ -752,16 +752,18 @@ impl OpenCADStudio {
crate::tf!("{cmd}: packaged {copied} file(s) into {}", zip_name).as_ref(),
);
}
Err(e) => self.command_line.push_error(
crate::tf!("{cmd}: cannot build the transmittal ZIP ({e}).").as_ref(),
),
Err(e) => self
.command_line
.push_error(crate::tf!("{cmd}: cannot build the transmittal ZIP ({e}).").as_ref()),
}
if !skipped.is_empty() {
let n = skipped.len();
let names = skipped.join(", ");
self.command_line.push_output(
crate::tf!("{cmd}: skipped {n} referenced file(s) not loaded in this session: {names}")
.as_ref(),
crate::tf!(
"{cmd}: skipped {n} referenced file(s) not loaded in this session: {names}"
)
.as_ref(),
);
}
Task::none()
+7 -4
View File
@@ -505,10 +505,13 @@ impl OpenCADStudio {
));
}
let pre_doc = self.tabs[i].scene.document.clone();
self.tabs[i]
.scene
.define_block_raw(&block_name, codec::types::Vector3::ZERO, vec![]);
let Some(record) = self.tabs[i].scene.document.block_records.get(&block_name) else {
self.tabs[i].scene.define_block_raw(
&block_name,
codec::types::Vector3::ZERO,
vec![],
);
let Some(record) = self.tabs[i].scene.document.block_records.get(&block_name)
else {
return Some(Task::none());
};
let br_handle = record.handle;
+4 -2
View File
@@ -785,7 +785,8 @@ impl OpenCADStudio {
// the command one by one, as typed.
"-VIEW" => {
use crate::command::CadCommand;
let c = crate::modules::view::view_cmd::DashViewCommand::new(self.dash_view_names(i));
let c =
crate::modules::view::view_cmd::DashViewCommand::new(self.dash_view_names(i));
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
@@ -926,7 +927,8 @@ impl OpenCADStudio {
// Standard orientation presets: the world views -VIEW sets,
// with the orthographic UCS while UCSORTHO is on. These
// names take precedence over a same-named saved view.
"TOP" | "FRONT" | "BACK" | "LEFT" | "RIGHT" | "BOTTOM" | "SWISO" | "SEISO" | "NEISO" | "NWISO" => {
"TOP" | "FRONT" | "BACK" | "LEFT" | "RIGHT" | "BOTTOM" | "SWISO" | "SEISO"
| "NEISO" | "NWISO" => {
return Some(self.apply_view_preset(&sub));
}
// ISO alone is the south-west one.
+16 -4
View File
@@ -759,7 +759,12 @@ impl OpenCADStudio {
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
} else {
let layer = self.tabs[i].scene.document.header.current_layer_name.clone();
let layer = self.tabs[i]
.scene
.document
.header
.current_layer_name
.clone();
let editable: Vec<_> = handles
.into_iter()
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
@@ -1193,7 +1198,10 @@ impl OpenCADStudio {
let scene = &mut self.tabs[i].scene;
let viewport = scene.active_viewport.filter(|handle| {
scene.current_layout != "Model"
&& matches!(scene.document.get_entity(*handle), Some(EntityType::Viewport(_)))
&& matches!(
scene.document.get_entity(*handle),
Some(EntityType::Viewport(_))
)
});
let document = &mut scene.document;
let Some(viewport) = viewport else {
@@ -1284,7 +1292,9 @@ impl OpenCADStudio {
.layer_viewport_overrides(layer.handle, kind)
.iter()
.any(|(handle, _)| *handle == viewport);
value.filter(|_| differs || existing).map(|value| (kind, value))
value
.filter(|_| differs || existing)
.map(|value| (kind, value))
})
.collect();
for (kind, value) in overrides {
@@ -1302,7 +1312,9 @@ impl OpenCADStudio {
scene.bump_geometry();
let doc_layers = self.tabs[i].scene.document.layers.clone();
let vp_info = self.tabs[i].scene.viewport_list();
self.tabs[i].layers.sync_with_viewports(&doc_layers, vp_info);
self.tabs[i]
.layers
.sync_with_viewports(&doc_layers, vp_info);
restored
}
}
+1 -1
View File
@@ -23,9 +23,9 @@ mod pc_extract;
mod pdf_dialogs;
pub(crate) mod pdf_import;
mod pdf_underlay;
mod refedit;
mod plotvars;
mod point_cloud;
mod refedit;
pub(crate) mod sheet_set;
mod styleprops;
mod ucsfollow;
+61 -24
View File
@@ -15,7 +15,11 @@ use std::collections::HashSet;
/// `** Command not allowed, NAME already checked out for editing **`
fn already_checked_out(name: &str) -> String {
crate::tf!("** Command not allowed, {} already checked out for editing **", name).into_owned()
crate::tf!(
"** Command not allowed, {} already checked out for editing **",
name
)
.into_owned()
}
impl OpenCADStudio {
@@ -24,12 +28,15 @@ impl OpenCADStudio {
"REFEDIT" | "-REFEDIT" => Some(self.start_refedit(i, cmd == "-REFEDIT")),
"REFSET" | "REFSET_ADD" | "REFSET_REMOVE" => {
if self.tabs[i].refedit_session.is_none() {
self.command_line.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
self.command_line
.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
return Some(Task::none());
}
self.command_line.push_info(
crate::t!("Transfer objects between the RefEdit working set and host drawing...")
.as_ref(),
crate::t!(
"Transfer objects between the RefEdit working set and host drawing..."
)
.as_ref(),
);
// The side toolbar's Add / Remove go straight to the selection.
let command = match cmd {
@@ -44,7 +51,8 @@ impl OpenCADStudio {
}
"REFCLOSE" => {
if self.tabs[i].refedit_session.is_none() {
self.command_line.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
self.command_line
.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
return Some(Task::none());
}
let command = RefCloseCommand::new();
@@ -106,10 +114,7 @@ impl OpenCADStudio {
if let [handle] = selected[..] {
if references.contains(&handle) {
self.tabs[i].scene.deselect_all();
self.refedit_picked(
i,
&format!("{}:{}", command_line as u8, handle.value()),
);
self.refedit_picked(i, &format!("{}:{}", command_line as u8, handle.value()));
return Task::none();
}
}
@@ -124,7 +129,11 @@ impl OpenCADStudio {
fn refedit_picked(&mut self, i: usize, args: &str) {
let parts: Vec<&str> = args.split(':').collect();
let command_line = parts.first() == Some(&"1");
let Some(top) = parts.get(1).and_then(|v| v.parse::<u64>().ok()).map(Handle::new) else {
let Some(top) = parts
.get(1)
.and_then(|v| v.parse::<u64>().ok())
.map(Handle::new)
else {
return;
};
let point = (parts.len() >= 5)
@@ -178,7 +187,10 @@ impl OpenCADStudio {
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(_)))
matches!(
document.get_entity(*h),
Some(EntityType::AttributeDefinition(_))
)
})
}),
xref_path: record
@@ -202,7 +214,10 @@ impl OpenCADStudio {
self.active_modal = Some(crate::app::ModalKind::RefEdit);
}
pub(in crate::app) fn update_refedit_dialog(&mut self, message: RefEditDialogMsg) -> Task<Message> {
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();
};
@@ -392,16 +407,21 @@ impl OpenCADStudio {
self.tabs[i].refedit_session = Some(session);
self.tabs[i].refedit_closed.clear();
// Fade everything outside the working set by XFADECTL. (#136)
self.tabs[i]
.scene
.set_refedit_keep(Some(temp_handles.iter().copied().collect::<rustc_hash::FxHashSet<_>>()));
self.tabs[i].scene.set_refedit_keep(Some(
temp_handles
.iter()
.copied()
.collect::<rustc_hash::FxHashSet<_>>(),
));
self.tabs[i].scene.refedit_lock = lock;
self.tabs[i].scene.deselect_all();
self.tabs[i].dirty = true;
if from_dialog {
match nested.len() {
0 => {}
1 => self.command_line.push_output(crate::t!("1 item selected").as_ref()),
1 => self
.command_line
.push_output(crate::t!("1 item selected").as_ref()),
n => self
.command_line
.push_output(crate::tf!("{} items selected", n).as_ref()),
@@ -419,7 +439,8 @@ impl OpenCADStudio {
/// REFSET Add / Remove on the current selection.
fn apply_refset(&mut self, i: usize, add: bool) {
let Some(mut session) = self.tabs[i].refedit_session.take() else {
self.command_line.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
self.command_line
.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
return;
};
let picked: Vec<Handle> = self.tabs[i]
@@ -465,7 +486,8 @@ impl OpenCADStudio {
/// REFCLOSE Save (`save`) or Discard.
fn close_refedit(&mut self, i: usize, save: bool) {
let Some(session) = self.tabs[i].refedit_session.take() else {
self.command_line.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
self.command_line
.push_error(crate::t!(NOT_CHECKED_OUT).as_ref());
return;
};
self.push_undo_snapshot(i, "REFCLOSE");
@@ -510,8 +532,8 @@ impl OpenCADStudio {
use crate::modules::draw::modify::explode::normalize_entity_for_block;
let originals: HashSet<Handle> = session.temp_handles.iter().copied().collect();
let added_count = working.iter().filter(|h| !originals.contains(h)).count();
let removed_count = session.extracted.len()
- working.iter().filter(|h| originals.contains(h)).count();
let removed_count =
session.extracted.len() - working.iter().filter(|h| originals.contains(h)).count();
let edited: Vec<EntityType> = working
.iter()
.filter_map(|h| self.tabs[i].scene.document.get_entity(*h).cloned())
@@ -705,7 +727,10 @@ impl OpenCADStudio {
}
crate::io::save(&source, &path)?;
let keys: rustc_hash::FxHashSet<Handle> = [session.br_handle].into_iter().collect();
self.tabs[i].xref_stat_cache.0.remove(&session.br_handle.value());
self.tabs[i]
.xref_stat_cache
.0
.remove(&session.br_handle.value());
let _ = crate::io::xref::resolve_xrefs_for_keys(
&mut self.tabs[i].scene.document,
&base_dir,
@@ -781,9 +806,21 @@ impl OpenCADStudio {
.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())))
.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 {
+38 -14
View File
@@ -1467,9 +1467,18 @@ impl OpenCADStudio {
}
if name == "LAYOUTCREATEVIEWPORT" {
// A profile switch shown and taken as ON / OFF or 1 / 0.
let current = if crate::scene::layout_create_viewport() { "ON" } else { "OFF" };
let current = if crate::scene::layout_create_viewport() {
"ON"
} else {
"OFF"
};
let parsed = value.as_deref().map(|v| {
match v.trim().trim_start_matches('_').to_ascii_uppercase().as_str() {
match v
.trim()
.trim_start_matches('_')
.to_ascii_uppercase()
.as_str()
{
"1" | "ON" => Some(true),
"0" | "OFF" => Some(false),
_ => None,
@@ -1486,13 +1495,15 @@ impl OpenCADStudio {
self.command_line.push_error(
crate::t!("Requires 0 or 1 only, or option keyword.").as_ref(),
);
self.command_line
.push_output(&format!("Enter new value for {name} <{current}>:"));
self.command_line.push_output(&format!(
"Enter new value for {name} <{current}>:"
));
self.pending_setvar = Some(name.clone());
}
None => {
self.command_line
.push_output(&format!("Enter new value for {name} <{current}>:"));
self.command_line.push_output(&format!(
"Enter new value for {name} <{current}>:"
));
self.pending_setvar = Some(name.clone());
}
}
@@ -1500,8 +1511,15 @@ impl OpenCADStudio {
}
if matches!(name.as_str(), "UCSORTHO" | "UCSVIEW") {
use crate::modules::view::view_cmd;
let current = i16::from(if name == "UCSORTHO" { view_cmd::ucs_ortho() } else { view_cmd::ucs_view() });
match value.as_deref().map(|v| v.trim().parse::<i16>().ok().filter(|v| (0..=1).contains(v))) {
let current = i16::from(if name == "UCSORTHO" {
view_cmd::ucs_ortho()
} else {
view_cmd::ucs_view()
});
match value
.as_deref()
.map(|v| v.trim().parse::<i16>().ok().filter(|v| (0..=1).contains(v)))
{
Some(Some(mode)) => {
if current != mode {
if name == "UCSORTHO" {
@@ -1513,12 +1531,17 @@ impl OpenCADStudio {
}
}
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 {name} <{current}>:"));
self.command_line
.push_error(crate::t!("Requires 0 or 1 only.").as_ref());
self.command_line.push_output(&format!(
"Enter new value for {name} <{current}>:"
));
self.pending_setvar = Some(name.clone());
}
None => {
self.command_line.push_output(&format!("Enter new value for {name} <{current}>:"));
self.command_line.push_output(&format!(
"Enter new value for {name} <{current}>:"
));
self.pending_setvar = Some(name.clone());
}
}
@@ -3454,10 +3477,11 @@ impl OpenCADStudio {
let path = std::path::PathBuf::from(cmd.trim_start_matches("COMPARE").trim());
match crate::io::load_file(&path) {
Ok(other) => {
let comparison =
crate::scene::compare::compare(&self.tabs[i].scene, other);
let comparison = crate::scene::compare::compare(&self.tabs[i].scene, other);
// The overlay shows at once, before the cursor moves.
self.tabs[i].scene.set_preview_wires(comparison.overlay.clone());
self.tabs[i]
.scene
.set_preview_wires(comparison.overlay.clone());
let command =
crate::modules::manage::compare::CompareCommand::new(comparison);
self.command_line.push_info(&command.prompt());
+13 -4
View File
@@ -2,7 +2,9 @@
use crate::app::{Message, OpenCADStudio};
use iced::Task;
inventory::submit!(crate::command::CommandRegistration { names: &["UCSFOLLOW"] });
inventory::submit!(crate::command::CommandRegistration {
names: &["UCSFOLLOW"]
});
impl OpenCADStudio {
pub(super) fn dispatch_ucsfollow(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
@@ -54,7 +56,8 @@ impl OpenCADStudio {
self.plan_snap(i, rotation);
self.tabs[i].dirty = true;
}
self.command_line.push_output(&format!("UCSFOLLOW = {}", u8::from(next)));
self.command_line
.push_output(&format!("UCSFOLLOW = {}", u8::from(next)));
}
}
Some(_) => {
@@ -111,7 +114,10 @@ mod tests {
assert_ne!(unchanged.rotation, followed.rotation);
let _ = app.run_command_line("UF 0");
let _ = app.run_command_line("SQ Z 30");
assert_eq!(followed.rotation, app.tabs[i].scene.camera.borrow().rotation);
assert_eq!(
followed.rotation,
app.tabs[i].scene.camera.borrow().rotation
);
}
#[test]
@@ -147,7 +153,10 @@ mod tests {
assert_eq!(before, app.tabs[i].scene.camera.borrow().rotation);
let _ = app.run_command_line("UCSFOLLOW 1");
let aligned = app.tabs[i].scene.camera.borrow().rotation;
assert_ne!(before, aligned, "enabling must align the existing UCS immediately");
assert_ne!(
before, aligned,
"enabling must align the existing UCS immediately"
);
// The same orientation must be obtained through the explicit PLAN path.
let _ = app.run_command_line("PLAN CURRENT");
assert_eq!(aligned, app.tabs[i].scene.camera.borrow().rotation);
+3 -3
View File
@@ -589,9 +589,9 @@ impl OpenCADStudio {
self.active_theme = resolved;
self.sync_model_space_theme(true);
self.persist_settings_if_changed();
self.command_line.push_output(crate::tf!(
"Color scheme set to 'System' (currently {name})."
).as_ref());
self.command_line.push_output(
crate::tf!("Color scheme set to 'System' (currently {name}).").as_ref(),
);
return Some(Task::none());
}
let theme = crate::app::config::parse_theme_name(sub);
+136 -51
View File
@@ -37,7 +37,11 @@ impl OpenCADStudio {
.collect();
let name_of = |list: &[(String, Handle)], handle: Handle| {
(!handle.is_null())
.then(|| list.iter().find(|(_, h)| *h == handle).map(|(name, _)| name.clone()))
.then(|| {
list.iter()
.find(|(_, h)| *h == handle)
.map(|(name, _)| name.clone())
})
.flatten()
};
let views = document
@@ -57,24 +61,25 @@ impl OpenCADStudio {
})
.collect();
let scene = &self.tabs[i].scene;
let sheet_viewports = (scene.current_layout != "Model" && scene.active_viewport.is_none()).then(|| {
scene
.layout_content_viewports()
.iter()
.filter_map(|handle| match document.get_entity(*handle) {
Some(codec::EntityType::Viewport(value)) => Some((
handle.value(),
[
value.center.x - value.width / 2.0,
value.center.y - value.height / 2.0,
value.center.x + value.width / 2.0,
value.center.y + value.height / 2.0,
],
)),
_ => None,
})
.collect()
});
let sheet_viewports = (scene.current_layout != "Model" && scene.active_viewport.is_none())
.then(|| {
scene
.layout_content_viewports()
.iter()
.filter_map(|handle| match document.get_entity(*handle) {
Some(codec::EntityType::Viewport(value)) => Some((
handle.value(),
[
value.center.x - value.width / 2.0,
value.center.y - value.height / 2.0,
value.center.x + value.width / 2.0,
value.center.y + value.height / 2.0,
],
)),
_ => None,
})
.collect()
});
ViewNames {
views,
visual_styles: visual_styles.into_iter().map(|(name, _)| name).collect(),
@@ -115,7 +120,11 @@ impl OpenCADStudio {
let want = glam::Vec3::new(x, y, 1.0).normalize();
(18..26)
.map(CubeRegion::Corner)
.max_by(|a, b| a.snap_direction().dot(want).total_cmp(&b.snap_direction().dot(want)))
.max_by(|a, b| {
a.snap_direction()
.dot(want)
.total_cmp(&b.snap_direction().dot(want))
})
.expect("the cube has corners")
}
};
@@ -133,7 +142,8 @@ impl OpenCADStudio {
self.commit_active_ucs_change(i, "-VIEW");
}
}
self.command_line.push_output(crate::t!("Regenerating model.").as_ref());
self.command_line
.push_output(crate::t!("Regenerating model.").as_ref());
self.snap_view_preset(region)
}
@@ -150,7 +160,12 @@ impl OpenCADStudio {
"PRESET" => return self.apply_view_preset(arg),
"DELETE" => {
let doomed: Vec<String> = view_cmd::matching(
self.tabs[i].scene.document.views.iter().map(|view| view.name.as_str()),
self.tabs[i]
.scene
.document
.views
.iter()
.map(|view| view.name.as_str()),
arg,
)
.into_iter()
@@ -166,7 +181,10 @@ impl OpenCADStudio {
view.background_handle,
);
}
self.tabs[i].scene.document.delete_layer_state(&snapshot_name(name));
self.tabs[i]
.scene
.document
.delete_layer_state(&snapshot_name(name));
}
self.tabs[i].dirty = true;
}
@@ -220,13 +238,15 @@ impl OpenCADStudio {
self.commit_active_ucs_change(i, "-VIEW");
}
if self.tabs[i].scene.active_gaze_dir().dot(before) < 0.9999 {
self.command_line.push_output(crate::t!("Regenerating model.").as_ref());
self.command_line
.push_output(crate::t!("Regenerating model.").as_ref());
}
}
"SAVE" => {
let mut view = self.tabs[i].scene.current_as_named_view(arg);
if view_cmd::ucs_view() {
self.command_line.push_output("UCSVIEW = 1 UCS will be saved with view");
self.command_line
.push_output("UCSVIEW = 1 UCS will be saved with view");
self.store_ucs_in_view(i, &mut view);
}
self.save_named_view(i, view);
@@ -237,18 +257,32 @@ impl OpenCADStudio {
let (x, y) = s.split_once(',')?;
Some((x.trim().parse::<f64>().ok()?, y.trim().parse::<f64>().ok()?))
};
match (parts.first(), parts.get(1).and_then(|s| corner(s)), parts.get(2).and_then(|s| corner(s))) {
match (
parts.first(),
parts.get(1).and_then(|s| corner(s)),
parts.get(2).and_then(|s| corner(s)),
) {
(Some(name), Some(a), Some(b)) if a.0 != b.0 && a.1 != b.1 => {
// A plan view of the window between the corners; the
// reference keeps no UCS with a window view.
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.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.save_named_view(i, view);
}
_ => self.command_line.push_output("Invalid window specification."),
_ => self
.command_line
.push_output("Invalid window specification."),
}
}
"SETTINGS" => settings_again = true,
@@ -307,12 +341,21 @@ impl OpenCADStudio {
/// A model-space view restored in the entered paper-space viewport, with
/// its background and visual style.
fn restore_view_in_active_viewport(&mut self, i: usize, view: &codec::tables::View) {
let Some(viewport) = self.tabs[i].scene.active_viewport else { return };
self.tabs[i].scene.restore_named_view_in_viewport(view, viewport);
if let Some(ObjectType::VisualStyle(style)) =
self.tabs[i].scene.document.objects.get(&view.visual_style_handle)
let Some(viewport) = self.tabs[i].scene.active_viewport else {
return;
};
self.tabs[i]
.scene
.restore_named_view_in_viewport(view, viewport);
if let Some(ObjectType::VisualStyle(style)) = self.tabs[i]
.scene
.document
.objects
.get(&view.visual_style_handle)
{
if let Some((mode, _)) = crate::modules::view::visual_style::mode_for_style_name(&style.description) {
if let Some((mode, _)) =
crate::modules::view::visual_style::mode_for_style_name(&style.description)
{
self.tabs[i].scene.set_active_viewport_render_mode(mode);
self.tabs[i].scene.bump_geometry_no_blocks();
}
@@ -368,11 +411,15 @@ impl OpenCADStudio {
view.handle = document.allocate_handle();
}
let find = |list: Vec<(String, Handle)>| {
list.into_iter().find(|(entry, _)| entry.eq_ignore_ascii_case(value)).map_or(Handle::NULL, |(_, h)| h)
list.into_iter()
.find(|(entry, _)| entry.eq_ignore_ascii_case(value))
.map_or(Handle::NULL, |(_, h)| h)
};
match setting {
"BACKGROUND" => replaced = std::mem::replace(&mut view.background_handle, Handle::NULL),
"VISUALSTYLE" => view.visual_style_handle = find(crate::io::visual_styles::offered(document)),
"VISUALSTYLE" => {
view.visual_style_handle = find(crate::io::visual_styles::offered(document))
}
"SECTION" => {
let sections: Vec<(String, Handle)> = document
.entities()
@@ -406,10 +453,18 @@ impl OpenCADStudio {
let text = |record: &codec::objects::XRecord, code: i32| {
record.get_string(code).unwrap_or_default().to_string()
};
let category = if setting == "CATEGORIZE" { value.to_string() } else { text(record, 300) };
let category = if setting == "CATEGORIZE" {
value.to_string()
} else {
text(record, 300)
};
let layers = layer_name.unwrap_or_else(|| text(record, 302));
let mut rest: Vec<_> =
record.entries.iter().filter(|entry| !matches!(entry.code, 300 | 302)).cloned().collect();
let mut rest: Vec<_> = record
.entries
.iter()
.filter(|entry| !matches!(entry.code, 300 | 302))
.cloned()
.collect();
if rest.is_empty() {
rest = vec![
codec::objects::XRecordEntry::bool(293, false),
@@ -467,7 +522,10 @@ impl OpenCADStudio {
canvas: [0, 1, 2].map(|k| (canvas[k].clamp(0.0, 1.0) * 255.0).round() as u8),
};
let document = &self.tabs[i].scene.document;
let current = document.views.get(view).map_or(Handle::NULL, |v| v.background_handle);
let current = document
.views
.get(view)
.map_or(Handle::NULL, |v| v.background_handle);
if let Some(ObjectType::ClassObject(object)) = document.objects.get(&current) {
match &object.data {
D::SolidBackground(value) => state.solid = unpack(value.color),
@@ -490,8 +548,10 @@ impl OpenCADStudio {
BgPosition::Center
};
state.aspect = value.maintain_aspect_ratio;
state.offset = [value.offset.x, value.offset.y].map(crate::ui::window::pdf_dialogs::short);
state.scale = [value.scale.x, value.scale.y].map(crate::ui::window::pdf_dialogs::short);
state.offset =
[value.offset.x, value.offset.y].map(crate::ui::window::pdf_dialogs::short);
state.scale =
[value.scale.x, value.scale.y].map(crate::ui::window::pdf_dialogs::short);
state.scale_base = [value.scale.x, value.scale.y];
state.preview = crate::ui::window::pdf_dialogs::bg_preview(&value.filename);
}
@@ -536,13 +596,23 @@ impl OpenCADStudio {
}
M::BgStep(field, dir) => {
use crate::ui::window::pdf_dialogs::{bg_step, short};
let current = |text: &String, default: f64| text.trim().parse::<f64>().ok().filter(|v| v.is_finite()).unwrap_or(default);
let current = |text: &String, default: f64| {
text.trim()
.parse::<f64>()
.ok()
.filter(|v| v.is_finite())
.unwrap_or(default)
};
if field < 2 {
let k = field as usize;
state.offset[k] = short(bg_step(field, current(&state.offset[k], 0.0), dir));
} else {
let k = field as usize - 2;
let next = short(bg_step(field, current(&state.scale[k], state.scale_base[k]), dir));
let next = short(bg_step(
field,
current(&state.scale[k], state.scale_base[k]),
dir,
));
if state.aspect {
state.scale = [next.clone(), next];
} else {
@@ -629,24 +699,32 @@ impl OpenCADStudio {
}
BgKind::Image => {
if !std::path::Path::new(state.image.trim()).is_file() {
self.command_line.push_error("Invalid Background Image File!");
self.command_line
.push_error("Invalid Background Image File!");
return Task::none();
}
use crate::ui::window::pdf_dialogs::{BG_OFFSET_LIMIT, BG_SCALE_LIMIT};
let number = |text: &String| text.trim().parse::<f64>().ok().filter(|v| v.is_finite());
let number = |text: &String| {
text.trim().parse::<f64>().ok().filter(|v| v.is_finite())
};
let (Some(ox), Some(oy), Some(sx), Some(sy)) = (
number(&state.offset[0]),
number(&state.offset[1]),
number(&state.scale[0]),
number(&state.scale[1]),
) else {
self.command_line.push_error(crate::t!("Requires a number.").as_ref());
self.command_line
.push_error(crate::t!("Requires a number.").as_ref());
return Task::none();
};
// Within the reference's slider ranges; a zero scale
// is ignored there, so the image keeps its scale.
let scale = |value: f64, base: f64| {
if value.abs() < 1e-9 { base } else { value.clamp(-BG_SCALE_LIMIT, BG_SCALE_LIMIT) }
if value.abs() < 1e-9 {
base
} else {
value.clamp(-BG_SCALE_LIMIT, BG_SCALE_LIMIT)
}
};
Some(D::ImageBackground(ImageBackground {
class_version: 1,
@@ -695,8 +773,11 @@ impl OpenCADStudio {
if self.tabs[i].scene.current_layout != "Model" {
return;
}
let Some(ObjectType::VisualStyle(style)) =
self.tabs[i].scene.document.objects.get(&view.visual_style_handle)
let Some(ObjectType::VisualStyle(style)) = self.tabs[i]
.scene
.document
.objects
.get(&view.visual_style_handle)
else {
return;
};
@@ -705,7 +786,11 @@ impl OpenCADStudio {
return;
};
// A style of its own keeps its name; the render modes keep theirs.
let label = if named { style.description.clone() } else { visual_style::label_for(mode).to_string() };
let label = if named {
style.description.clone()
} else {
visual_style::label_for(mode).to_string()
};
self.apply_render_mode(i, mode, &label);
}
}
+2 -4
View File
@@ -4,11 +4,11 @@
use super::*;
use crate::io::xref_model::Pathtype;
use crate::modules::insert::xattach::IMAGE_EXTENSIONS;
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};
@@ -90,9 +90,7 @@ impl OpenCADStudio {
}
// POINTCLOUDATTACH picks the file; with a file, or as
// -POINTCLOUDATTACH, it asks on the command line.
("POINTCLOUDATTACH", true) if dialog => {
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();