Merge pull request #1627 from ramox81/codex/plotdate-refresh

Fields: evaluation events, UPDATEFIELD, FIELDEVAL, per-field shading and PlotDate redraw.

# Conflicts:
#	Cargo.lock
#	src/entities/field.rs
This commit is contained in:
Hakan Seven committed 2026-10-06 20:42:01 +03:00
commit 711799371a
14 files changed
+533 -36

No files matched your search

+1
View File
@@ -848,6 +848,7 @@ impl OpenCADStudio {
".{}.tmp.dwg",
path.file_name().unwrap().to_string_lossy()
));
self.tabs[i].scene.update_fields(2, None);
let document = self.tabs[i].scene.document_for_save();
if let Err(e) = crate::io::save(&document, &scratch) {
return err(format!("save: {e}"));
+2
View File
@@ -512,6 +512,8 @@ impl OpenCADStudio {
}
// Rebuild tessellation caches without modifying the document.
"REGEN" | "REGENALL" => {
// A regen is a field evaluation event (FIELDEVAL bit 16).
self.tabs[i].scene.update_fields(16, None);
self.tabs[i].scene.populate_meshes_from_document();
self.command_line.push_output(crate::t!("REGEN: regenerated model.").as_ref());
return Some(Task::none());
+74
View File
@@ -17,6 +17,80 @@ impl OpenCADStudio {
self.open_field_dialog(FieldTarget::NewText);
Some(Task::none())
}
// UPDATEFIELD — re-evaluate the fields of the selected objects
// (a block reference's attributes included), whatever FIELDEVAL.
"UPDATEFIELD" => {
let selected: Vec<codec::Handle> =
self.tabs[i].scene.selected_entities().into_iter().map(|(h, _)| h).collect();
if selected.is_empty() {
use crate::modules::draw::select::SelectObjectsCommand;
let cmd = SelectObjectsCommand::new("UPDATEFIELD");
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
return Some(Task::none());
}
// A block reference brings its attributes and the fields of its
// block definition; a table, the texts of its cells.
let document = &self.tabs[i].scene.document;
let mut hosts = selected.clone();
for handle in &selected {
let record = match document.get_entity(*handle) {
Some(codec::EntityType::Insert(insert)) => {
hosts.extend(insert.attributes.iter().map(|a| a.common.handle));
document.block_records.iter().find(|r| r.name.eq_ignore_ascii_case(&insert.block_name))
}
Some(codec::EntityType::Table(table)) => table
.block_record_handle
.and_then(|h| document.block_records.iter().find(|r| r.handle == h)),
_ => None,
};
if let Some(record) = record {
hosts.extend(record.entity_handles.iter().copied());
}
}
self.push_undo_snapshot(i, "UPDATEFIELD");
let found = self.tabs[i].scene.update_fields(32, Some(&hosts));
self.tabs[i].scene.deselect_all();
self.refresh_properties();
if found > 0 {
self.tabs[i].dirty = true;
}
self.command_line.push_output(crate::tf!("{} field(s) found.", found).as_ref());
self.command_line.push_output(crate::tf!("{} field(s) updated.", found).as_ref());
Some(Task::none())
}
// FIELDEVAL — the events that update fields, kept in the drawing.
cmd if cmd == "FIELDEVAL" || cmd.starts_with("FIELDEVAL ") || cmd.starts_with("SETVAR FIELDEVAL") => {
let value = cmd
.trim_start_matches("SETVAR ")
.trim_start_matches("FIELDEVAL")
.trim();
let current = crate::entities::field::fieldeval(&self.tabs[i].scene.document);
let ask = |app: &mut Self| {
app.command_line
.push_output(&format!("Enter new value for FIELDEVAL <{current}>:"));
app.pending_setvar = Some("FIELDEVAL".into());
};
match value.parse::<i32>() {
_ if value.is_empty() => ask(self),
Ok(n) if (0..=31).contains(&n) => {
if n != current {
self.push_undo_snapshot(i, "FIELDEVAL");
crate::io::set_drawing_variable(
&mut self.tabs[i].scene.document,
"FIELDEVAL",
&n.to_string(),
);
self.tabs[i].dirty = true;
}
}
_ => {
self.command_line.push_error("Requires an integer between 0 and 31.");
ask(self);
}
}
Some(Task::none())
}
cmd if cmd == "_FIELD_OBJECT" || cmd.starts_with("_FIELD_OBJECT ") => {
let handle = cmd
.split_whitespace()
+2
View File
@@ -708,6 +708,8 @@ inventory::submit!(crate::command::CommandRegistration {
"PDFOSNAP",
"UOSNAP",
"FIELDDISPLAY",
"FIELDEVAL",
"UPDATEFIELD",
"PDFIMPORTMODE",
"PDFIMPORTFILTER",
"PDFIMPORTLAYERS",
+10 -3
View File
@@ -2163,6 +2163,14 @@ impl OpenCADStudio {
#[cfg(not(target_arch = "wasm32"))]
pub(in crate::app) fn prepare_native_save(&mut self, i: usize) {
// A save is a field evaluation event (FIELDEVAL bit 2).
self.tabs[i].scene.update_fields(2, None);
self.prepare_snapshot_save(i);
}
/// Bring the drawing state the file stores up to date, without the save
/// event an autosave does not raise.
pub(in crate::app) fn prepare_snapshot_save(&mut self, i: usize) {
self.sync_view_state_for_save(i);
sync_annotation_scale_header(&mut self.tabs[i].scene);
self.stamp_header_sysvars(i);
@@ -3297,7 +3305,7 @@ impl OpenCADStudio {
if !self.tabs[i].dirty || self.active_save_jobs.contains_key(&self.tabs[i].id) {
continue;
}
self.prepare_native_save(i);
self.prepare_snapshot_save(i);
let version = self.tabs[i].scene.document.version;
let target = self.autosave_target(i);
tasks.push(self.queue_native_save(
@@ -3800,8 +3808,7 @@ impl OpenCADStudio {
let i = self.active_tab;
let hosts = crate::entities::field::stamp_plot_fields(&mut self.tabs[i].scene.document);
if !hosts.is_empty() {
let changes: Vec<_> = hosts.into_iter().map(|h| (h, crate::scene::ChangeKind::Modified)).collect();
self.tabs[i].scene.bump_entities(&changes);
self.tabs[i].scene.bump_text_hosts(&hosts);
self.tabs[i].dirty = true;
}
}