forked from 1b-agent/opencadstudio-upstream
Merge main into codex/graphic-attributes-cleanup
Resolve conflicts from main's rustfmt pass by taking main's versions of command.rs, style.rs, view/mod.rs, scene/mod.rs, ui/window/mod.rs and ui/properties.rs and re-applying this branch's Graphic Attributes changes. Add the Graphic Attributes strings to the new lo-LA catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E1QnME6WJbD5iGFae1eeCb
This commit is contained in:
596 files changed
+69069
-34120
No files matched your search
+364
-205
@@ -8,8 +8,9 @@ impl OpenCADStudio {
|
||||
"PAN" => {
|
||||
self.tabs[i].pan_mode = true;
|
||||
self.clear_navigation_hover(i);
|
||||
self.command_line
|
||||
.push_output(crate::t!("PAN: drag with the left mouse button. Press Esc to exit.").as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::t!("PAN: drag with the left mouse button. Press Esc to exit.").as_ref(),
|
||||
);
|
||||
}
|
||||
|
||||
// ── TABLE structure and cell editing ───────────────────────────────
|
||||
@@ -33,12 +34,17 @@ impl OpenCADStudio {
|
||||
}
|
||||
let words: Vec<&str> = rest.split_whitespace().collect();
|
||||
let integer = |index: usize| {
|
||||
words.get(index).and_then(|value| value.parse::<usize>().ok())
|
||||
words
|
||||
.get(index)
|
||||
.and_then(|value| value.parse::<usize>().ok())
|
||||
};
|
||||
let real = |index: usize| {
|
||||
words.get(index).and_then(|value| value.parse::<f64>().ok())
|
||||
};
|
||||
let action = match words.first().map(|word| word.to_ascii_uppercase()).as_deref() {
|
||||
let real =
|
||||
|index: usize| words.get(index).and_then(|value| value.parse::<f64>().ok());
|
||||
let action = match words
|
||||
.first()
|
||||
.map(|word| word.to_ascii_uppercase())
|
||||
.as_deref()
|
||||
{
|
||||
Some("CELL") => {
|
||||
let parts: Vec<&str> = rest.splitn(4, char::is_whitespace).collect();
|
||||
match (integer(1), integer(2)) {
|
||||
@@ -117,11 +123,7 @@ impl OpenCADStudio {
|
||||
u64::from_str_radix(value.trim_start_matches("0x"), 16)
|
||||
.ok()
|
||||
.map(|handle| {
|
||||
TableAction::Field(
|
||||
row,
|
||||
column,
|
||||
codec::Handle::new(handle),
|
||||
)
|
||||
TableAction::Field(row, column, codec::Handle::new(handle))
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
@@ -158,16 +160,19 @@ impl OpenCADStudio {
|
||||
None
|
||||
};
|
||||
if matches!(action, TableAction::Block(_, _, _)) && block_handle.is_none() {
|
||||
self.command_line.push_error(
|
||||
crate::t!("TABLE: block definition not found.").as_ref(),
|
||||
);
|
||||
self.command_line
|
||||
.push_error(crate::t!("TABLE: block definition not found.").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
if let TableAction::Field(_, _, field_handle) = &action {
|
||||
if !self.tabs[i].scene.document.fields.contains_key(field_handle) {
|
||||
self.command_line.push_error(
|
||||
crate::t!("TABLE: field handle not found.").as_ref(),
|
||||
);
|
||||
if !self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.fields
|
||||
.contains_key(field_handle)
|
||||
{
|
||||
self.command_line
|
||||
.push_error(crate::t!("TABLE: field handle not found.").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
}
|
||||
@@ -337,10 +342,10 @@ impl OpenCADStudio {
|
||||
self.command_line
|
||||
.push_output(crate::t!("TABLE: edit applied.").as_ref());
|
||||
} else {
|
||||
self.command_line
|
||||
.push_error(crate::t!(
|
||||
"TABLE: row/column is out of range or the cell is locked."
|
||||
).as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("TABLE: row/column is out of range or the cell is locked.")
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,9 +393,10 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(crate::tf!(
|
||||
"UCSICON {sub}: updated {count} viewport(s) + model space."
|
||||
).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!("UCSICON {sub}: updated {count} viewport(s) + model space.")
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
"" => {
|
||||
// Bare UCSICON toggles visibility.
|
||||
@@ -405,11 +411,13 @@ impl OpenCADStudio {
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
let state = if visible { "ON" } else { "OFF" };
|
||||
self.command_line.push_output(crate::tf!("UCSICON {state}").as_ref());
|
||||
self.command_line
|
||||
.push_output(crate::tf!("UCSICON {state}").as_ref());
|
||||
}
|
||||
_ => {
|
||||
self.command_line
|
||||
.push_info(crate::t!("Usage: UCSICON ON | OFF | NOORIGIN | ORIGIN").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: UCSICON ON | OFF | NOORIGIN | ORIGIN").as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,40 +445,52 @@ impl OpenCADStudio {
|
||||
self.tabs[i].scene.set_drawing_limit_check(enabled);
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
self.command_line.push_output(crate::t!(if enabled {
|
||||
"Limits checking ON."
|
||||
} else {
|
||||
"Limits checking OFF."
|
||||
}).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::t!(if enabled {
|
||||
"Limits checking ON."
|
||||
} else {
|
||||
"Limits checking OFF."
|
||||
})
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
cmd if cmd.starts_with("LIMITS SET ") => {
|
||||
let tokens: Vec<&str> = cmd["LIMITS SET ".len()..].split_whitespace().collect();
|
||||
let values: Result<Vec<f64>, _> =
|
||||
tokens.iter().map(|value| value.parse()).collect();
|
||||
let Ok(values) = values else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("LIMITS: four numeric coordinates required.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("LIMITS: four numeric coordinates required.").as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
};
|
||||
if tokens.len() != 4 || !values.iter().all(|value| value.is_finite()) {
|
||||
self.command_line
|
||||
.push_error(crate::t!("LIMITS: four finite numeric coordinates required.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("LIMITS: four finite numeric coordinates required.").as_ref(),
|
||||
);
|
||||
} else {
|
||||
let first = glam::DVec2::new(values[0], values[1]);
|
||||
let opposite = glam::DVec2::new(values[2], values[3]);
|
||||
let min = first.min(opposite);
|
||||
let max = first.max(opposite);
|
||||
if min.x == max.x || min.y == max.y {
|
||||
self.command_line
|
||||
.push_error(crate::t!("LIMITS: corners must define a non-zero area.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("LIMITS: corners must define a non-zero area.").as_ref(),
|
||||
);
|
||||
} else {
|
||||
self.push_undo_snapshot(i, "LIMITS");
|
||||
self.tabs[i].scene.set_current_drawing_limits(min, max);
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(crate::tf!(
|
||||
"Drawing limits: {:.4},{:.4} to {:.4},{:.4}.",
|
||||
min.x, min.y, max.x, max.y
|
||||
).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
"Drawing limits: {:.4},{:.4} to {:.4},{:.4}.",
|
||||
min.x,
|
||||
min.y,
|
||||
max.x,
|
||||
max.y
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,15 +524,21 @@ impl OpenCADStudio {
|
||||
// it only queues a per-viewport cache invalidation.
|
||||
"REDRAW" => {
|
||||
use crate::scene::ViewportRefreshScope;
|
||||
self.tabs[i].scene.request_refresh(ViewportRefreshScope::Active);
|
||||
self.command_line.push_output(crate::t!("REDRAW: viewport refreshed.").as_ref());
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.request_refresh(ViewportRefreshScope::Active);
|
||||
self.command_line
|
||||
.push_output(crate::t!("REDRAW: viewport refreshed.").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
// REDRAWALL — force re-rasterize of every generated viewport.
|
||||
"REDRAWALL" => {
|
||||
use crate::scene::ViewportRefreshScope;
|
||||
self.tabs[i].scene.request_refresh(ViewportRefreshScope::All);
|
||||
self.command_line.push_output(crate::t!("REDRAWALL: viewports refreshed.").as_ref());
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.request_refresh(ViewportRefreshScope::All);
|
||||
self.command_line
|
||||
.push_output(crate::t!("REDRAWALL: viewports refreshed.").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
// Rebuild tessellation caches without modifying the document.
|
||||
@@ -520,7 +546,8 @@ impl OpenCADStudio {
|
||||
// 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());
|
||||
self.command_line
|
||||
.push_output(crate::t!("REGEN: regenerated model.").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
|
||||
@@ -598,8 +625,9 @@ impl OpenCADStudio {
|
||||
|
||||
// ── TOOLPALETTES — not yet implemented ───────────────────────────────
|
||||
"TOOLPALETTES" => {
|
||||
self.command_line
|
||||
.push_info(crate::t!("TOOLPALETTES: Tool Palettes not yet implemented.").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("TOOLPALETTES: Tool Palettes not yet implemented.").as_ref(),
|
||||
);
|
||||
}
|
||||
|
||||
// ── XDATA — read/write extended entity data ──────────────────────────
|
||||
@@ -640,19 +668,24 @@ impl OpenCADStudio {
|
||||
if let Some(entity) = self.tabs[i].scene.document.get_entity(*sh) {
|
||||
let xd = &entity.common().extended_data;
|
||||
if xd.is_empty() {
|
||||
self.command_line
|
||||
.push_output(crate::tf!(" {:x}: no xdata.", sh.value()).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!(" {:x}: no xdata.", sh.value()).as_ref(),
|
||||
);
|
||||
} else {
|
||||
for rec in xd.records() {
|
||||
self.command_line.push_output(crate::tf!(
|
||||
" {:x} [{}]: {} value(s)",
|
||||
sh.value(),
|
||||
rec.application_name,
|
||||
rec.values.len()
|
||||
).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
" {:x} [{}]: {} value(s)",
|
||||
sh.value(),
|
||||
rec.application_name,
|
||||
rec.values.len()
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
for v in &rec.values {
|
||||
self.command_line
|
||||
.push_output(crate::tf!(" {:?}", v).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!(" {:?}", v).as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -685,10 +718,13 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(crate::tf!(
|
||||
"XDATA: set [{app}] = \"{val}\" on {} entity/entities.",
|
||||
editable.len()
|
||||
).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
"XDATA: set [{app}] = \"{val}\" on {} entity/entities.",
|
||||
editable.len()
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
"CLEAR" => {
|
||||
let app_filter = parts.get(1).copied();
|
||||
@@ -728,11 +764,14 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(crate::t!("XDATA: cleared.").as_ref());
|
||||
self.command_line
|
||||
.push_output(crate::t!("XDATA: cleared.").as_ref());
|
||||
}
|
||||
_ => {
|
||||
self.command_line
|
||||
.push_info(crate::t!("Usage: XDATA LIST | SET <app> <value> | CLEAR [app]").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: XDATA LIST | SET <app> <value> | CLEAR [app]")
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -791,7 +830,9 @@ impl OpenCADStudio {
|
||||
use crate::modules::insert::solid3d_cmds::PresspullCommand;
|
||||
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
|
||||
let mut command = PresspullCommand::new(color);
|
||||
command.set_isolines(crate::entities::solid3d::clamp_header_isolines(self.tabs[i].scene.document.header.isolines));
|
||||
command.set_isolines(crate::entities::solid3d::clamp_header_isolines(
|
||||
self.tabs[i].scene.document.header.isolines,
|
||||
));
|
||||
command.set_preselection(self.presspull_preselection());
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
@@ -802,7 +843,9 @@ impl OpenCADStudio {
|
||||
use crate::modules::insert::solid3d_cmds::RevolveCommand;
|
||||
let selected: Vec<_> = self.tabs[i].scene.selected_entities().into_iter().collect();
|
||||
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
|
||||
let isolines = crate::entities::solid3d::clamp_header_isolines(self.tabs[i].scene.document.header.isolines);
|
||||
let isolines = crate::entities::solid3d::clamp_header_isolines(
|
||||
self.tabs[i].scene.document.header.isolines,
|
||||
);
|
||||
let mut cmd = RevolveCommand::new(color, isolines);
|
||||
if !selected.is_empty() {
|
||||
cmd.set_preselection(
|
||||
@@ -820,13 +863,23 @@ impl OpenCADStudio {
|
||||
"SWEEP" => {
|
||||
use crate::modules::insert::solid3d_cmds::SweepCommand;
|
||||
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
|
||||
let isolines = crate::entities::solid3d::clamp_header_isolines(self.tabs[i].scene.document.header.isolines);
|
||||
let isolines = crate::entities::solid3d::clamp_header_isolines(
|
||||
self.tabs[i].scene.document.header.isolines,
|
||||
);
|
||||
let mut cmd = SweepCommand::new(color, isolines);
|
||||
cmd.set_parameters(self.tabs[i].scene.named_parameters().clone());
|
||||
let selected = self.tabs[i].scene.selected_handles_in_order()
|
||||
let selected = self.tabs[i]
|
||||
.scene
|
||||
.selected_handles_in_order()
|
||||
.into_iter()
|
||||
.filter_map(|handle| self.tabs[i].scene.document.get_entity(handle)
|
||||
.cloned().map(|entity| (handle, entity)))
|
||||
.filter_map(|handle| {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity(handle)
|
||||
.cloned()
|
||||
.map(|entity| (handle, entity))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !selected.is_empty() {
|
||||
cmd.set_preselection(selected);
|
||||
@@ -839,13 +892,35 @@ impl OpenCADStudio {
|
||||
"LOFT" => {
|
||||
use crate::modules::insert::solid3d_cmds::LoftCommand;
|
||||
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
|
||||
let isolines = crate::entities::solid3d::clamp_header_isolines(self.tabs[i].scene.document.header.isolines);
|
||||
let selected = self.tabs[i].scene.selected_handles_in_order().into_iter()
|
||||
.filter_map(|handle| self.tabs[i].scene.document.get_entity(handle)
|
||||
.cloned().map(|entity| (handle, entity))).collect();
|
||||
let available = self.tabs[i].scene.document.entities()
|
||||
.map(|entity| (entity.common().handle, entity.clone())).collect();
|
||||
let cmd = LoftCommand::new(color, isolines, crate::command::ExtrudeMode::Solid, selected, available);
|
||||
let isolines = crate::entities::solid3d::clamp_header_isolines(
|
||||
self.tabs[i].scene.document.header.isolines,
|
||||
);
|
||||
let selected = self.tabs[i]
|
||||
.scene
|
||||
.selected_handles_in_order()
|
||||
.into_iter()
|
||||
.filter_map(|handle| {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity(handle)
|
||||
.cloned()
|
||||
.map(|entity| (handle, entity))
|
||||
})
|
||||
.collect();
|
||||
let available = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.entities()
|
||||
.map(|entity| (entity.common().handle, entity.clone()))
|
||||
.collect();
|
||||
let cmd = LoftCommand::new(
|
||||
color,
|
||||
isolines,
|
||||
crate::command::ExtrudeMode::Solid,
|
||||
selected,
|
||||
available,
|
||||
);
|
||||
self.command_line.push_info(&cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||
}
|
||||
@@ -928,14 +1003,18 @@ impl OpenCADStudio {
|
||||
"Plot style: {} ({} color overrides)",
|
||||
t.name,
|
||||
t.aci_entries.iter().filter(|e| e.color.is_some()).count()
|
||||
).into_owned()
|
||||
)
|
||||
.into_owned()
|
||||
})
|
||||
.unwrap_or_else(|| crate::t!("No plot style table loaded.").into_owned());
|
||||
.unwrap_or_else(|| {
|
||||
crate::t!("No plot style table loaded.").into_owned()
|
||||
});
|
||||
self.command_line.push_output(&msg);
|
||||
}
|
||||
_ => {
|
||||
self.command_line
|
||||
.push_error(crate::t!("Usage: PLOTSTYLE [LOAD | CLEAR | STATUS]").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("Usage: PLOTSTYLE [LOAD | CLEAR | STATUS]").as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -953,17 +1032,21 @@ impl OpenCADStudio {
|
||||
.selected_entities()
|
||||
.iter()
|
||||
.filter(|(handle, _)| !self.tabs[i].scene.is_layer_locked(*handle))
|
||||
.filter_map(|(handle, _)| match self.tabs[i].scene.document.get_entity(*handle) {
|
||||
Some(codec::EntityType::RasterImage(image)) => {
|
||||
Some((*handle, image.flags.contains(ImageDisplayFlags::TRANSPARENCY_ON)))
|
||||
.filter_map(|(handle, _)| {
|
||||
match self.tabs[i].scene.document.get_entity(*handle) {
|
||||
Some(codec::EntityType::RasterImage(image)) => Some((
|
||||
*handle,
|
||||
image.flags.contains(ImageDisplayFlags::TRANSPARENCY_ON),
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let Some(&(_, first_on)) = images.first() else {
|
||||
return Some(Task::none());
|
||||
};
|
||||
let handles: Vec<codec::Handle> = images.iter().map(|(handle, _)| *handle).collect();
|
||||
let handles: Vec<codec::Handle> =
|
||||
images.iter().map(|(handle, _)| *handle).collect();
|
||||
if cmd == "TRANSPARENCY MODE" {
|
||||
let c = crate::modules::insert::image_transparency::TransparencyCommand::mode(
|
||||
handles, first_on,
|
||||
@@ -1027,8 +1110,9 @@ impl OpenCADStudio {
|
||||
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
|
||||
.collect();
|
||||
if handles.is_empty() {
|
||||
self.command_line
|
||||
.push_error(crate::t!("UNDERLAY: select underlay entities first.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("UNDERLAY: select underlay entities first.").as_ref(),
|
||||
);
|
||||
} else {
|
||||
let parts: Vec<&str> = sub.splitn(2, char::is_whitespace).collect();
|
||||
let action = parts.first().copied().unwrap_or("");
|
||||
@@ -1065,8 +1149,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
"CLIP" => match arg {
|
||||
"ON" => {
|
||||
ul.flags |=
|
||||
codec::entities::UnderlayDisplayFlags::CLIPPING;
|
||||
ul.flags |= codec::entities::UnderlayDisplayFlags::CLIPPING;
|
||||
changed += 1;
|
||||
}
|
||||
"OFF" => {
|
||||
@@ -1145,8 +1228,10 @@ impl OpenCADStudio {
|
||||
return Some(Task::none());
|
||||
}
|
||||
let Some(scale) = self.tabs[i].scene.creation_annotation_scale_handle() else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("OBJECTSCALE: the active annotation scale is unavailable.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("OBJECTSCALE: the active annotation scale is unavailable.")
|
||||
.as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
};
|
||||
|
||||
@@ -1161,11 +1246,9 @@ impl OpenCADStudio {
|
||||
let member = memberships.iter().any(|(_, current)| *current == scale);
|
||||
if adding {
|
||||
!member
|
||||
&& self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity(*handle)
|
||||
.is_some_and(crate::scene::annotative::supports_annotation_context)
|
||||
&& self.tabs[i].scene.document.get_entity(*handle).is_some_and(
|
||||
crate::scene::annotative::supports_annotation_context,
|
||||
)
|
||||
} else {
|
||||
member
|
||||
}
|
||||
@@ -1218,11 +1301,14 @@ impl OpenCADStudio {
|
||||
.collect();
|
||||
self.tabs[i].scene.bump_entities(&changes);
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(crate::tf!(
|
||||
"OBJECTSCALE: {} the current scale on {} object(s).",
|
||||
if adding { "added" } else { "removed" },
|
||||
changed.len()
|
||||
).as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
"OBJECTSCALE: {} the current scale on {} object(s).",
|
||||
if adding { "added" } else { "removed" },
|
||||
changed.len()
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
|
||||
@@ -1231,19 +1317,22 @@ impl OpenCADStudio {
|
||||
"HYPERLINK" => {
|
||||
use crate::command::SelectThenValueCommand;
|
||||
let has_sel = !self.tabs[i].scene.selected_entities().is_empty();
|
||||
let c = SelectThenValueCommand::new(
|
||||
"HYPERLINK",
|
||||
"HYPERLINK URL to attach:",
|
||||
has_sel,
|
||||
);
|
||||
let c =
|
||||
SelectThenValueCommand::new("HYPERLINK", "HYPERLINK URL to attach:", has_sel);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
cmd if cmd.starts_with("HYPERLINK ") => {
|
||||
use codec::xdata::XDataValue;
|
||||
let url = cmd.strip_prefix("HYPERLINK").unwrap_or("").trim().to_string();
|
||||
let url = cmd
|
||||
.strip_prefix("HYPERLINK")
|
||||
.unwrap_or("")
|
||||
.trim()
|
||||
.to_string();
|
||||
if url.is_empty() {
|
||||
self.command_line.push_info(crate::t!("Usage: HYPERLINK <url> (select objects first)").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: HYPERLINK <url> (select objects first)").as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
let handles: Vec<codec::Handle> = self.tabs[i]
|
||||
@@ -1254,7 +1343,8 @@ impl OpenCADStudio {
|
||||
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
|
||||
.collect();
|
||||
if handles.is_empty() {
|
||||
self.command_line.push_error(crate::t!("HYPERLINK: select objects first.").as_ref());
|
||||
self.command_line
|
||||
.push_error(crate::t!("HYPERLINK: select objects first.").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
self.push_undo_snapshot(i, "HYPERLINK");
|
||||
@@ -1287,7 +1377,11 @@ impl OpenCADStudio {
|
||||
"ADJUST",
|
||||
"ADJUST [Brightness / Contrast / Fade]:",
|
||||
vec![
|
||||
("Brightness", "BRIGHTNESS", Some("ADJUST brightness 0-100:")),
|
||||
(
|
||||
"Brightness",
|
||||
"BRIGHTNESS",
|
||||
Some("ADJUST brightness 0-100:"),
|
||||
),
|
||||
("Contrast", "CONTRAST", Some("ADJUST contrast 0-100:")),
|
||||
("Fade", "FADE", Some("ADJUST fade 0-100:")),
|
||||
],
|
||||
@@ -1312,8 +1406,9 @@ impl OpenCADStudio {
|
||||
self.command_line
|
||||
.push_error(crate::t!("ADJUST: select raster image(s) first.").as_ref());
|
||||
} else if action.is_empty() {
|
||||
self.command_line
|
||||
.push_info(crate::t!("Usage: ADJUST BRIGHTNESS|CONTRAST|FADE <0-100>").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: ADJUST BRIGHTNESS|CONTRAST|FADE <0-100>").as_ref(),
|
||||
);
|
||||
} else if let Ok(v) = arg.parse::<u8>() {
|
||||
let v = v.min(100);
|
||||
self.push_undo_snapshot(i, "ADJUST");
|
||||
@@ -1356,15 +1451,17 @@ impl OpenCADStudio {
|
||||
.map(|handle| (handle, crate::scene::ChangeKind::Modified))
|
||||
.collect();
|
||||
self.tabs[i].scene.bump_entities(&changes);
|
||||
self.command_line
|
||||
.push_output(crate::tf!("ADJUST: {action} = {v} on {changed} image(s).").as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!("ADJUST: {action} = {v} on {changed} image(s).").as_ref(),
|
||||
);
|
||||
} else {
|
||||
self.command_line.push_error(
|
||||
crate::t!("ADJUST: no raster images selected, or unknown property (use BRIGHTNESS|CONTRAST|FADE).").as_ref(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.command_line.push_error(crate::t!("ADJUST: value must be 0-100.").as_ref());
|
||||
self.command_line
|
||||
.push_error(crate::t!("ADJUST: value must be 0-100.").as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,10 +1479,8 @@ impl OpenCADStudio {
|
||||
}
|
||||
"ANNOALLVISIBLE" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new(
|
||||
"ANNOALLVISIBLE",
|
||||
"ANNOALLVISIBLE new value [0/1]:",
|
||||
);
|
||||
let c =
|
||||
ValuePromptCommand::new("ANNOALLVISIBLE", "ANNOALLVISIBLE new value [0/1]:");
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
@@ -1407,10 +1502,8 @@ impl OpenCADStudio {
|
||||
}
|
||||
"ANNOAUTOSCALE" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new(
|
||||
"ANNOAUTOSCALE",
|
||||
"ANNOAUTOSCALE new value [-4..4]:",
|
||||
);
|
||||
let c =
|
||||
ValuePromptCommand::new("ANNOAUTOSCALE", "ANNOAUTOSCALE new value [-4..4]:");
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
@@ -1432,8 +1525,9 @@ impl OpenCADStudio {
|
||||
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
|
||||
.collect();
|
||||
if handles.is_empty() {
|
||||
self.command_line
|
||||
.push_error(crate::t!("ANNOUPDATE: select annotation objects first.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("ANNOUPDATE: select annotation objects first.").as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
self.push_undo_snapshot(i, "ANNOUPDATE");
|
||||
@@ -1492,9 +1586,9 @@ impl OpenCADStudio {
|
||||
self.command_line
|
||||
.push_output(crate::tf!("Annotation scale: {arg}").as_ref());
|
||||
}
|
||||
None => self
|
||||
.command_line
|
||||
.push_error(crate::t!("Usage: ANNOSCALE <ratio> e.g. 1:50, 2:1, or a factor").as_ref()),
|
||||
None => self.command_line.push_error(
|
||||
crate::t!("Usage: ANNOSCALE <ratio> e.g. 1:50, 2:1, or a factor").as_ref(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,8 +1602,16 @@ impl OpenCADStudio {
|
||||
"SCALELISTEDIT",
|
||||
"SCALELISTEDIT [Add / Delete]:",
|
||||
vec![
|
||||
("Add", "ADD", Some("SCALELISTEDIT ADD new scale ratio (e.g. 1:50):")),
|
||||
("Delete", "DELETE", Some("SCALELISTEDIT DELETE scale ratio to remove:")),
|
||||
(
|
||||
"Add",
|
||||
"ADD",
|
||||
Some("SCALELISTEDIT ADD new scale ratio (e.g. 1:50):"),
|
||||
),
|
||||
(
|
||||
"Delete",
|
||||
"DELETE",
|
||||
Some("SCALELISTEDIT DELETE scale ratio to remove:"),
|
||||
),
|
||||
],
|
||||
);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
@@ -1527,20 +1629,22 @@ impl OpenCADStudio {
|
||||
self.push_undo_snapshot(i, "SCALELISTEDIT");
|
||||
if self.tabs[i].scene.add_scale(arg, paper, drawing) {
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line
|
||||
.push_output(crate::tf!("Added annotation scale {arg}.").as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!("Added annotation scale {arg}.").as_ref(),
|
||||
);
|
||||
} else {
|
||||
self.command_line
|
||||
.push_info(crate::tf!("Scale {arg} already exists.").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::tf!("Scale {arg} already exists.").as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => self
|
||||
.command_line
|
||||
.push_error(crate::t!("SCALELISTEDIT ADD: use a ratio like 1:50.").as_ref()),
|
||||
_ => self.command_line.push_error(
|
||||
crate::t!("SCALELISTEDIT ADD: use a ratio like 1:50.").as_ref(),
|
||||
),
|
||||
},
|
||||
None => self
|
||||
.command_line
|
||||
.push_error(crate::t!("SCALELISTEDIT ADD: use a ratio like 1:50.").as_ref()),
|
||||
None => self.command_line.push_error(
|
||||
crate::t!("SCALELISTEDIT ADD: use a ratio like 1:50.").as_ref(),
|
||||
),
|
||||
},
|
||||
"DELETE" | "REMOVE" => {
|
||||
let current = self.tabs[i]
|
||||
@@ -1550,20 +1654,25 @@ impl OpenCADStudio {
|
||||
.current_annotation_scale
|
||||
.clone();
|
||||
if arg.is_empty() {
|
||||
self.command_line.push_info(crate::t!("Usage: SCALELISTEDIT DELETE <name>").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: SCALELISTEDIT DELETE <name>").as_ref(),
|
||||
);
|
||||
} else if arg.eq_ignore_ascii_case(¤t) {
|
||||
self.command_line.push_error(crate::tf!(
|
||||
"Cannot delete the current annotation scale ({arg})."
|
||||
).as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::tf!("Cannot delete the current annotation scale ({arg}).")
|
||||
.as_ref(),
|
||||
);
|
||||
} else {
|
||||
self.push_undo_snapshot(i, "SCALELISTEDIT");
|
||||
if self.tabs[i].scene.remove_scale(arg) {
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line
|
||||
.push_output(crate::tf!("Removed annotation scale {arg}.").as_ref());
|
||||
self.command_line.push_output(
|
||||
crate::tf!("Removed annotation scale {arg}.").as_ref(),
|
||||
);
|
||||
} else {
|
||||
self.command_line
|
||||
.push_info(crate::tf!("No annotation scale named {arg}.").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::tf!("No annotation scale named {arg}.").as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1575,15 +1684,17 @@ impl OpenCADStudio {
|
||||
.map(|(n, _, _)| n)
|
||||
.collect();
|
||||
if names.is_empty() {
|
||||
self.command_line.push_info(crate::t!("No annotation scales defined.").as_ref());
|
||||
} else {
|
||||
self.command_line
|
||||
.push_output(crate::tf!("Annotation scales: {}", names.join(", ")).as_ref());
|
||||
.push_info(crate::t!("No annotation scales defined.").as_ref());
|
||||
} else {
|
||||
self.command_line.push_output(
|
||||
crate::tf!("Annotation scales: {}", names.join(", ")).as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => self
|
||||
.command_line
|
||||
.push_info(crate::t!("Usage: SCALELISTEDIT [ADD 1:50 | DELETE 1:50]").as_ref()),
|
||||
_ => self.command_line.push_info(
|
||||
crate::t!("Usage: SCALELISTEDIT [ADD 1:50 | DELETE 1:50]").as_ref(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1629,8 +1740,10 @@ impl OpenCADStudio {
|
||||
.collect();
|
||||
if candidates.is_empty() {
|
||||
self.command_line.push_info(
|
||||
crate::t!("ANNORESET: no selected object has alternate scale representations.")
|
||||
.as_ref(),
|
||||
crate::t!(
|
||||
"ANNORESET: no selected object has alternate scale representations."
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
@@ -1671,9 +1784,8 @@ impl OpenCADStudio {
|
||||
cmd if cmd.starts_with("DATALINK ") => {
|
||||
let path = cmd.trim_start_matches("DATALINK").trim();
|
||||
if path.is_empty() {
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: DATALINK <path-to-.csv>").as_ref(),
|
||||
);
|
||||
self.command_line
|
||||
.push_info(crate::t!("Usage: DATALINK <path-to-.csv>").as_ref());
|
||||
return Some(Task::none());
|
||||
}
|
||||
match std::fs::read_to_string(path) {
|
||||
@@ -1700,29 +1812,32 @@ 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 {
|
||||
codec::objects::ObjectType::TableStyle(style)
|
||||
if style.name.eq_ignore_ascii_case(¤t_style) =>
|
||||
{
|
||||
Some(*handle)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
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(¤t_style) =>
|
||||
{
|
||||
Some(*handle)
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
let link_path = std::fs::canonicalize(path)
|
||||
.map(|value| value.to_string_lossy().into_owned())
|
||||
.unwrap_or_else(|_| path.to_string());
|
||||
let command = crate::modules::annotate::data_link::DataLinkPlaceCommand::new(
|
||||
table, &link_path,
|
||||
);
|
||||
let command =
|
||||
crate::modules::annotate::data_link::DataLinkPlaceCommand::new(
|
||||
table, &link_path,
|
||||
);
|
||||
self.command_line
|
||||
.push_info(&crate::command::CadCommand::prompt(&command));
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
}
|
||||
Err(e) => {
|
||||
self.command_line
|
||||
.push_error(crate::tf!("DATALINK: cannot read \"{path}\": {e}").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::tf!("DATALINK: cannot read \"{path}\": {e}").as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1789,15 +1904,17 @@ impl OpenCADStudio {
|
||||
&self.tabs[i].scene.document,
|
||||
*link_handle,
|
||||
)
|
||||
.and_then(|path| std::fs::write(path, csv).map_err(|error| error.to_string()))
|
||||
{
|
||||
.and_then(|path| {
|
||||
std::fs::write(path, csv).map_err(|error| error.to_string())
|
||||
}) {
|
||||
Ok(()) => written += 1,
|
||||
Err(error) => errors.push(error),
|
||||
}
|
||||
}
|
||||
if written > 0 {
|
||||
self.command_line.push_output(
|
||||
crate::tf!("DATALINKUPDATE: wrote {} linked source(s).", written).as_ref(),
|
||||
crate::tf!("DATALINKUPDATE: wrote {} linked source(s).", written)
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
for error in errors {
|
||||
@@ -1818,8 +1935,9 @@ impl OpenCADStudio {
|
||||
.filter(|(_, _, rows)| !rows.is_empty())
|
||||
.collect();
|
||||
if updates.is_empty() {
|
||||
self.command_line
|
||||
.push_error(crate::t!("DATALINKUPDATE: linked sources could not be read.").as_ref());
|
||||
self.command_line.push_error(
|
||||
crate::t!("DATALINKUPDATE: linked sources could not be read.").as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
self.push_undo_snapshot(i, "DATALINKUPDATE");
|
||||
@@ -1839,7 +1957,11 @@ impl OpenCADStudio {
|
||||
table.remove_row(table.row_count() - 1);
|
||||
}
|
||||
while table.column_count() < columns {
|
||||
let width = table.columns.last().map(|column| column.width).unwrap_or(2.0);
|
||||
let width = table
|
||||
.columns
|
||||
.last()
|
||||
.map(|column| column.width)
|
||||
.unwrap_or(2.0);
|
||||
table.add_column(width);
|
||||
}
|
||||
while table.column_count() > columns {
|
||||
@@ -1869,8 +1991,11 @@ impl OpenCADStudio {
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_properties();
|
||||
self.command_line.push_output(
|
||||
crate::tf!("DATALINKUPDATE: updated {} linked table(s).", changed_handles.len())
|
||||
.as_ref(),
|
||||
crate::tf!(
|
||||
"DATALINKUPDATE: updated {} linked table(s).",
|
||||
changed_handles.len()
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1879,8 +2004,10 @@ impl OpenCADStudio {
|
||||
// (northing easting elevation) → Point at (easting, northing, elev).
|
||||
"LANDXMLIMPORT" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c =
|
||||
ValuePromptCommand::new("LANDXMLIMPORT", "LANDXMLIMPORT path to the .xml file:");
|
||||
let c = ValuePromptCommand::new(
|
||||
"LANDXMLIMPORT",
|
||||
"LANDXMLIMPORT path to the .xml file:",
|
||||
);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
@@ -1888,7 +2015,10 @@ impl OpenCADStudio {
|
||||
let path = cmd.trim_start_matches("LANDXMLIMPORT").trim();
|
||||
if path.is_empty() {
|
||||
self.command_line.push_info(
|
||||
crate::t!("Usage: LANDXMLIMPORT <path-to-.xml> (imports CgPoint survey points)").as_ref(),
|
||||
crate::t!(
|
||||
"Usage: LANDXMLIMPORT <path-to-.xml> (imports CgPoint survey points)"
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
@@ -1896,8 +2026,10 @@ impl OpenCADStudio {
|
||||
Ok(xml) => {
|
||||
let pts = parse_landxml_cgpoints(&xml);
|
||||
if pts.is_empty() {
|
||||
self.command_line
|
||||
.push_info(crate::t!("LANDXMLIMPORT: no <CgPoint> survey points found.").as_ref());
|
||||
self.command_line.push_info(
|
||||
crate::t!("LANDXMLIMPORT: no <CgPoint> survey points found.")
|
||||
.as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
self.push_undo_snapshot(i, "LANDXMLIMPORT");
|
||||
@@ -1909,14 +2041,17 @@ impl OpenCADStudio {
|
||||
.add_entity_clone(codec::EntityType::Point(p));
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(crate::tf!(
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
"LANDXMLIMPORT: imported {} survey point(s). Use ZOOM EXTENTS to view.",
|
||||
pts.len()
|
||||
).as_ref());
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
Err(e) => self
|
||||
.command_line
|
||||
.push_error(crate::tf!("LANDXMLIMPORT: cannot read \"{path}\": {e}").as_ref()),
|
||||
Err(e) => self.command_line.push_error(
|
||||
crate::tf!("LANDXMLIMPORT: cannot read \"{path}\": {e}").as_ref(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2051,8 +2186,14 @@ mod tests {
|
||||
app.tabs[i].scene.refresh_pending_any(),
|
||||
"REDRAW must leave a pending force request"
|
||||
);
|
||||
assert_eq!(app.tabs[i].scene.geometry_epoch, geom_before, "REDRAW must not regen");
|
||||
assert_eq!(app.tabs[i].scene.block_epoch, block_before, "REDRAW must not regen blocks");
|
||||
assert_eq!(
|
||||
app.tabs[i].scene.geometry_epoch, geom_before,
|
||||
"REDRAW must not regen"
|
||||
);
|
||||
assert_eq!(
|
||||
app.tabs[i].scene.block_epoch, block_before,
|
||||
"REDRAW must not regen blocks"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2062,7 +2203,10 @@ mod tests {
|
||||
let _ = full.run_command_line("REDRAW");
|
||||
let _ = short.run_command_line("R");
|
||||
let i = full.active_tab;
|
||||
assert!(short.tabs[i].scene.refresh_pending_any(), "'R' must trigger REDRAW");
|
||||
assert!(
|
||||
short.tabs[i].scene.refresh_pending_any(),
|
||||
"'R' must trigger REDRAW"
|
||||
);
|
||||
assert_eq!(
|
||||
short.tabs[i].scene.refresh_pending_any(),
|
||||
full.tabs[i].scene.refresh_pending_any(),
|
||||
@@ -2075,7 +2219,10 @@ mod tests {
|
||||
let mut app = fresh_app();
|
||||
let i = app.active_tab;
|
||||
let _ = app.run_command_line("REDRAWALL");
|
||||
assert!(app.tabs[i].scene.refresh_pending_any(), "REDRAWALL must leave a force request");
|
||||
assert!(
|
||||
app.tabs[i].scene.refresh_pending_any(),
|
||||
"REDRAWALL must leave a force request"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2086,11 +2233,23 @@ mod tests {
|
||||
let block_before = app.tabs[i].scene.block_epoch;
|
||||
app.tabs[i].dirty = false;
|
||||
let _ = app.run_command_line("REGEN");
|
||||
assert_ne!(app.tabs[i].scene.geometry_epoch, geom_before, "REGEN must regenerate geometry");
|
||||
assert_ne!(app.tabs[i].scene.block_epoch, block_before, "REGEN must regenerate block epoch");
|
||||
assert!(!app.tabs[i].dirty, "REGEN must NOT mark the document as modified (no DB change)");
|
||||
assert_ne!(
|
||||
app.tabs[i].scene.geometry_epoch, geom_before,
|
||||
"REGEN must regenerate geometry"
|
||||
);
|
||||
assert_ne!(
|
||||
app.tabs[i].scene.block_epoch, block_before,
|
||||
"REGEN must regenerate block epoch"
|
||||
);
|
||||
assert!(
|
||||
!app.tabs[i].dirty,
|
||||
"REGEN must NOT mark the document as modified (no DB change)"
|
||||
);
|
||||
let _ = app.run_command_line("REGENALL");
|
||||
assert!(!app.tabs[i].dirty, "REGENALL must not dirty the document either");
|
||||
assert!(
|
||||
!app.tabs[i].dirty,
|
||||
"REGENALL must not dirty the document either"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user