feat(locale): localize full interface

This commit is contained in:
Hakan Seven 2026-08-02 22:09:25 +03:00
commit 3e6693b93f
205 changed files with 32367 additions and 3808 deletions

View file

@ -172,7 +172,7 @@ impl OpenCADStudio {
tasks.push(self.apply_cmd_result(CmdResult::CancelForSpaceChange));
} else if message_pending {
self.command_line
.push_info("Command cancelled because the active drawing space changed.");
.push_info(crate::t!("Command cancelled because the active drawing space changed.").as_ref());
}
cancellation_reported = true;
}
@ -186,7 +186,7 @@ impl OpenCADStudio {
}
if !cancellation_reported && (grip_cancelled || suspended_cancelled || editor_cancelled) {
self.command_line
.push_info("Command cancelled because the active drawing space changed.");
.push_info(crate::t!("Command cancelled because the active drawing space changed.").as_ref());
}
self.command_line.input.clear();
@ -210,7 +210,7 @@ impl OpenCADStudio {
.is_some_and(|command| command.name() != "LIMITS")
&& self.tabs[i].scene.drawing_limit_check_enabled();
if checks_limits && !self.tabs[i].scene.point_inside_drawing_limits(point) {
self.command_line.push_error("Outside limits.");
self.command_line.push_error(crate::t!("Outside limits.").as_ref());
return false;
}
true
@ -389,7 +389,7 @@ impl OpenCADStudio {
self.tabs[i].scene.select_entity(h, false);
}
self.command_line
.push_info(&format!("{count} object(s) added to selection."));
.push_info(crate::tf!("{count} object(s) added to selection.").as_ref());
self.refresh_properties();
let handles: Vec<Handle> = self.tabs[i]
.scene
@ -754,7 +754,7 @@ impl OpenCADStudio {
});
let Some((min_x, min_y, max_x, max_y)) = bounds else {
self.command_line
.push_error("MVIEW: the clipping boundary has no usable area.");
.push_error(crate::t!("MVIEW: the clipping boundary has no usable area.").as_ref());
self.tabs[i].active_cmd = None;
if let Some(pending) = pending {
self.commit_undo_delta(i, pending);
@ -763,7 +763,7 @@ impl OpenCADStudio {
};
if max_x - min_x < 1e-6 || max_y - min_y < 1e-6 {
self.command_line
.push_error("MVIEW: the clipping boundary has no usable area.");
.push_error(crate::t!("MVIEW: the clipping boundary has no usable area.").as_ref());
self.tabs[i].active_cmd = None;
if let Some(pending) = pending {
self.commit_undo_delta(i, pending);
@ -1051,7 +1051,7 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.command_line
.push_output(&format!("Block \"{name}\" created."));
.push_output(crate::tf!("Block \"{name}\" created.").as_ref());
self.refresh_properties();
}
Err(err) => {
@ -1098,7 +1098,7 @@ impl OpenCADStudio {
self.restore_pre_cmd_tangent();
let noun = if count == 1 { "copy" } else { "copies" };
self.command_line
.push_output(&format!("{label}: {count} {noun} created."));
.push_output(crate::tf!("{label}: {count} {noun} created.").as_ref());
self.refresh_properties();
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
@ -1133,7 +1133,7 @@ impl OpenCADStudio {
self.tabs[i].snap_result = None;
if was_catchment {
self.command_line
.push_info("Catchment tagged successfully.");
.push_info(crate::t!("Catchment tagged successfully.").as_ref());
}
self.refresh_properties();
}
@ -1171,7 +1171,7 @@ impl OpenCADStudio {
// Report honestly rather than claiming success while
// changing nothing. (#181 / DIM-020)
self.command_line
.push_info("DIMBREAK: not yet implemented — nothing changed.");
.push_info(crate::t!("DIMBREAK: not yet implemented — nothing changed.").as_ref());
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
return Task::none();
@ -1181,7 +1181,7 @@ impl OpenCADStudio {
apply_dimspace(&mut self.tabs[i].scene, encoded);
}
self.push_undo_snapshot(i, "DIMSPACE");
self.command_line.push_output("DIMSPACE Spacing adjusted.");
self.command_line.push_output(crate::t!("DIMSPACE Spacing adjusted.").as_ref());
self.tabs[i].dirty = true;
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -1192,7 +1192,7 @@ impl OpenCADStudio {
// model (not yet present) to store and render the jog.
// Report honestly rather than faking success. (DIM-019)
self.command_line
.push_info("DIMJOGLINE: not yet implemented — nothing changed.");
.push_info(crate::t!("DIMJOGLINE: not yet implemented — nothing changed.").as_ref());
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
return Task::none();
@ -1203,7 +1203,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "MLEADERALIGN");
self.command_line
.push_output("MLEADERALIGN Leaders aligned.");
.push_output(crate::t!("MLEADERALIGN Leaders aligned.").as_ref());
self.tabs[i].dirty = true;
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -1215,7 +1215,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "MLEADERCOLLECT");
self.command_line
.push_output("MLEADERCOLLECT Leaders collected.");
.push_output(crate::t!("MLEADERCOLLECT Leaders collected.").as_ref());
self.tabs[i].dirty = true;
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -1461,10 +1461,10 @@ impl OpenCADStudio {
self.invalidate_property_targets(i, &dest);
self.tabs[i].dirty = true;
self.command_line
.push_info(&format!("Layer matched to \"{layer}\"."));
.push_info(crate::tf!("Layer matched to \"{layer}\".").as_ref());
self.sync_ribbon_layers();
} else {
self.command_line.push_error("Source object not found.");
self.command_line.push_error(crate::t!("Source object not found.").as_ref());
}
}
CmdResult::MatchProperties { dest, src } => {
@ -1605,14 +1605,14 @@ impl OpenCADStudio {
self.tabs[i].scene.bump_entities(&changes);
self.refresh_properties();
self.command_line
.push_info(&format!("Properties matched to {} object(s).", dest.len()));
.push_info(crate::tf!("Properties matched to {} object(s).", dest.len()).as_ref());
// Clear the consumed target selection and keep prompting.
self.tabs[i].scene.deselect_all();
if let Some(cmd) = &self.tabs[i].active_cmd {
self.command_line.push_info(&cmd.prompt());
}
} else {
self.command_line.push_error("Source object not found.");
self.command_line.push_error(crate::t!("Source object not found.").as_ref());
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.tabs[i].scene.clear_preview_wire();
@ -1623,7 +1623,7 @@ impl OpenCADStudio {
self.tabs[i].snap_result = None;
self.tabs[i].scene.clear_preview_wire();
if self.clipboard.is_empty() {
self.command_line.push_error("Clipboard is empty.");
self.command_line.push_error(crate::t!("Clipboard is empty.").as_ref());
} else {
let delta = base_pt - self.clipboard_base;
let translate = crate::command::EntityTransform::Translate(delta);
@ -1640,7 +1640,7 @@ impl OpenCADStudio {
self.refresh_layer_panel();
self.refresh_properties();
self.command_line
.push_info(&format!("{count} object(s) pasted."));
.push_info(crate::tf!("{count} object(s) pasted.").as_ref());
}
}
CmdResult::CreateGroup { handles, name } => {
@ -1652,7 +1652,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_group_undo(i, undo);
self.command_line
.push_info(&format!("Group \"{}\" created.", name));
.push_info(crate::tf!("Group \"{}\" created.", name).as_ref());
}
CmdResult::DeleteGroups { handles } => {
self.tabs[i].active_cmd = None;
@ -1664,10 +1664,10 @@ impl OpenCADStudio {
self.commit_group_undo(i, undo);
if count > 0 {
self.command_line
.push_info(&format!("{} group(s) dissolved.", count));
.push_info(crate::tf!("{} group(s) dissolved.", count).as_ref());
} else {
self.command_line
.push_info("No groups found for selected objects.");
.push_info(crate::t!("No groups found for selected objects.").as_ref());
}
}
CmdResult::VpLayerUpdate {
@ -1747,14 +1747,14 @@ impl OpenCADStudio {
self.push_undo_snapshot(i, "VPLAYER");
self.tabs[i].dirty = true;
if frozen_count > 0 {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"VPLAYER: {frozen_count} layer(s) frozen in viewport."
));
).as_ref());
}
if thawed_count > 0 {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"VPLAYER: {thawed_count} layer(s) thawed in viewport."
));
).as_ref());
}
// Sync layer panel so VP freeze columns update immediately.
let doc_layers = self.tabs[i].scene.document.layers.clone();
@ -1778,7 +1778,7 @@ impl OpenCADStudio {
self.tabs[i]
.scene
.zoom_to_window(p1.as_vec3(), p2.as_vec3());
self.command_line.push_output("Zoom Window");
self.command_line.push_output(crate::t!("Zoom Window").as_ref());
}
CmdResult::Measurement(msg) => {
self.tabs[i].active_cmd = None;
@ -1844,7 +1844,7 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.restore_pre_cmd_tangent();
self.command_line.push_output("ALIGN: applied.");
self.command_line.push_output(crate::t!("ALIGN: applied.").as_ref());
self.refresh_properties();
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
@ -1869,12 +1869,12 @@ impl OpenCADStudio {
self.tabs[i].scene.erase_entities(&[handle]);
self.tabs[i].scene.add_entity(new_entity);
self.tabs[i].dirty = true;
self.command_line.push_output("LENGTHEN: applied.");
self.command_line.push_output(crate::t!("LENGTHEN: applied.").as_ref());
self.refresh_properties();
}
None => {
self.command_line
.push_error("LENGTHEN: entity type not supported.");
.push_error(crate::t!("LENGTHEN: entity type not supported.").as_ref());
}
}
self.tabs[i].active_cmd = None;
@ -1898,10 +1898,10 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("DIVIDE: {count} point(s) placed."));
.push_output(crate::tf!("DIVIDE: {count} point(s) placed.").as_ref());
} else {
self.command_line
.push_error("DIVIDE: entity type not supported or N < 2.");
.push_error(crate::t!("DIVIDE: entity type not supported or N < 2.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -1927,10 +1927,10 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("MEASURE: {count} point(s) placed."));
.push_output(crate::tf!("MEASURE: {count} point(s) placed.").as_ref());
} else {
self.command_line
.push_error("MEASURE: entity type not supported or distance too large.");
.push_error(crate::t!("MEASURE: entity type not supported or distance too large.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -1956,7 +1956,7 @@ impl OpenCADStudio {
}
None => self
.command_line
.push_error("PEDIT: cannot convert this entity."),
.push_error(crate::t!("PEDIT: cannot convert this entity.").as_ref()),
}
}
_ => {
@ -1976,12 +1976,12 @@ impl OpenCADStudio {
self.tabs[i]
.scene
.bump_entities(&[(handle, crate::scene::ChangeKind::Modified)]);
self.command_line.push_output("PEDIT: applied.");
self.command_line.push_output(crate::t!("PEDIT: applied.").as_ref());
self.refresh_properties();
} else {
self.discard_last_undo_entry(i);
self.command_line
.push_error("PEDIT: operation not applicable to this entity.");
.push_error(crate::t!("PEDIT: operation not applicable to this entity.").as_ref());
}
}
}
@ -2011,9 +2011,9 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.restore_pre_cmd_tangent();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"JOIN: {count_in} object(s) joined into {count_out}."
));
).as_ref());
self.refresh_properties();
}
None => {
@ -2049,7 +2049,7 @@ impl OpenCADStudio {
self.tabs[i].snap_result = None;
self.restore_pre_cmd_tangent();
self.command_line
.push_output(&format!("BREAK: {} fragment(s).", count));
.push_output(crate::tf!("BREAK: {} fragment(s).", count).as_ref());
self.refresh_properties();
}
None => {
@ -2058,7 +2058,7 @@ impl OpenCADStudio {
self.tabs[i].scene.clear_preview_wire();
self.restore_pre_cmd_tangent();
self.command_line
.push_error("BREAK: entity type not supported.");
.push_error(crate::t!("BREAK: entity type not supported.").as_ref());
}
}
}
@ -2072,7 +2072,7 @@ impl OpenCADStudio {
let y1 = p1.y.max(p2.y);
self.plot_window = Some((x0, y0, x1, y1));
self.command_line
.push_output(&format!("Plot window: {x0:.2},{y0:.2} to {x1:.2},{y1:.2}"));
.push_output(crate::tf!("Plot window: {x0:.2},{y0:.2} to {x1:.2},{y1:.2}").as_ref());
// Pick window closed the plot dialog so the viewport could
// receive the two clicks — bring the dialog back with the
// window now active.
@ -2089,9 +2089,9 @@ impl OpenCADStudio {
let x2 = p1.x.max(p2.x);
let y2 = p1.y.max(p2.y);
self.plot_window = Some((x1, y1, x2, y2));
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Plot window: {x1:.2},{y1:.2} to {x2:.2},{y2:.2}"
));
).as_ref());
self.plot_dialog.area = "Window".to_string();
self.active_modal = Some(super::ModalKind::Plot);
}
@ -2127,7 +2127,7 @@ impl OpenCADStudio {
}
if handles.is_empty() {
self.command_line
.push_output("STRETCH: nothing crosses the window.");
.push_output(crate::t!("STRETCH: nothing crosses the window.").as_ref());
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.tabs[i].scene.clear_preview_wire();
@ -2395,7 +2395,7 @@ impl OpenCADStudio {
self.tabs[i].scene.clear_preview_wire();
self.restore_pre_cmd_tangent();
self.command_line
.push_output(&format!("STRETCH: {count} entity(ies) stretched."));
.push_output(crate::tf!("STRETCH: {count} entity(ies) stretched.").as_ref());
self.refresh_properties();
if let Some(pending) = pending {
self.commit_undo_delta(i, pending);
@ -2418,7 +2418,7 @@ impl OpenCADStudio {
.insert(handle, crate::scene::MeshLodSet::from_single(mesh));
}
self.tabs[i].dirty = true;
self.command_line.push_output("Solid created.");
self.command_line.push_output(crate::t!("Solid created.").as_ref());
}
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
@ -2492,15 +2492,15 @@ impl OpenCADStudio {
// ACIS geometry (else the solid is dropped by other CAD apps).
self.tabs[i].scene.solid_models.insert(new_handle, solid);
self.tabs[i].dirty = true;
self.command_line.push_output("EXTRUDE: solid created.");
self.command_line.push_output(crate::t!("EXTRUDE: solid created.").as_ref());
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
}
} else {
self.command_line.push_error("EXTRUDE: could not build profile. Select a closed 2D entity (Circle, LwPolyline, etc.).");
self.command_line.push_error(crate::t!("EXTRUDE: could not build profile. Select a closed 2D entity (Circle, LwPolyline, etc.).").as_ref());
}
} else {
self.command_line.push_error("EXTRUDE: entity not found.");
self.command_line.push_error(crate::t!("EXTRUDE: entity not found.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -2577,16 +2577,16 @@ impl OpenCADStudio {
.insert(new_handle, crate::scene::MeshLodSet::from_single(mesh));
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("REVOLVE: solid created ({:.0}°).", angle_deg));
.push_output(crate::tf!("REVOLVE: solid created ({:.0}°).", angle_deg).as_ref());
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
}
} else {
self.command_line
.push_error("REVOLVE: could not revolve profile.");
.push_error(crate::t!("REVOLVE: could not revolve profile.").as_ref());
}
} else {
self.command_line.push_error("REVOLVE: entity not found.");
self.command_line.push_error(crate::t!("REVOLVE: entity not found.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -2755,12 +2755,12 @@ impl OpenCADStudio {
.meshes
.insert(new_handle, crate::scene::MeshLodSet::from_single(mesh));
self.tabs[i].dirty = true;
self.command_line.push_output("SWEEP: solid created.");
self.command_line.push_output(crate::t!("SWEEP: solid created.").as_ref());
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
}
} else {
self.command_line.push_error("SWEEP: could not sweep profile along path. Use a closed 2D profile and a Line or Polyline path.");
self.command_line.push_error(crate::t!("SWEEP: could not sweep profile along path. Use a closed 2D profile and a Line or Polyline path.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -2849,15 +2849,15 @@ impl OpenCADStudio {
.meshes
.insert(new_handle, crate::scene::MeshLodSet::from_single(mesh));
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LOFT: solid created from {} profiles.",
handles.len()
));
).as_ref());
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
}
} else {
self.command_line.push_error("LOFT: could not loft profiles. Ensure sections have the same edge count and are compatible.");
self.command_line.push_error(crate::t!("LOFT: could not loft profiles. Ensure sections have the same edge count and are compatible.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -2893,10 +2893,10 @@ impl OpenCADStudio {
// Re-add with updated model
self.tabs[i].scene.add_hatch(model);
self.tabs[i].dirty = true;
self.command_line.push_output("HATCHEDIT: hatch updated.");
self.command_line.push_output(crate::t!("HATCHEDIT: hatch updated.").as_ref());
} else {
self.command_line
.push_error("HATCHEDIT: hatch entity not found.");
.push_error(crate::t!("HATCHEDIT: hatch entity not found.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
@ -2942,7 +2942,7 @@ impl OpenCADStudio {
crate::app::text_inline::can_edit_text(handle, &self.tabs[i].scene.document);
if !is_editable {
self.command_line
.push_error("TEXTEDIT: selected entity is not text.");
.push_error(crate::t!("TEXTEDIT: selected entity is not text.").as_ref());
let prompt = self.tabs[i].active_cmd.as_ref().map(|c| c.prompt());
if let Some(p) = prompt {
self.command_line.push_info(&p);
@ -2970,7 +2970,7 @@ impl OpenCADStudio {
self.texteditmode = val;
let display_val = if val { 1 } else { 0 };
self.command_line
.push_output(&format!("TEXTEDITMODE set to {display_val}"));
.push_output(crate::tf!("TEXTEDITMODE set to {display_val}").as_ref());
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.tabs[i].scene.clear_preview_wire();
@ -3014,11 +3014,11 @@ impl OpenCADStudio {
}
if updated {
self.tabs[i].dirty = true;
self.command_line.push_output("DDEDIT: text updated.");
self.command_line.push_output(crate::t!("DDEDIT: text updated.").as_ref());
} else {
self.discard_last_undo_entry(i);
self.command_line
.push_error("DDEDIT: entity type not supported.");
.push_error(crate::t!("DDEDIT: entity type not supported.").as_ref());
}
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;

View file

@ -43,12 +43,12 @@ impl OpenCADStudio {
} else {
"model space"
};
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Base point ({}, {}, {}) set for {space}.",
nums[0], nums[1], z
));
).as_ref());
} else {
self.command_line.push_error("Usage: BASE <x> <y> [z]");
self.command_line.push_error(crate::t!("Usage: BASE <x> <y> [z]").as_ref());
}
}
}
@ -60,7 +60,7 @@ impl OpenCADStudio {
return match self.mtext_selected_text() {
Some(text) => {
self.command_line
.push_info("Copied selected text to clipboard.");
.push_info(crate::t!("Copied selected text to clipboard.").as_ref());
Some(iced::clipboard::write(text).discard())
}
None => Some(Task::none()),
@ -91,10 +91,10 @@ impl OpenCADStudio {
&self.tabs[i].scene.document,
&self.clipboard,
);
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{} object(s) copied to clipboard.",
self.clipboard.len()
));
).as_ref());
}
}
@ -145,12 +145,12 @@ impl OpenCADStudio {
&self.tabs[i].scene.document,
&self.clipboard,
);
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{} object(s) copied to clipboard (base {:.3},{:.3}).",
self.clipboard.len(),
base.x,
base.y
));
).as_ref());
}
}
@ -187,13 +187,13 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_info(&format!("{} object(s) cut to clipboard.", count));
.push_info(crate::tf!("{} object(s) cut to clipboard.", count).as_ref());
}
}
"PASTECLIP" => {
if self.clipboard.is_empty() {
self.command_line.push_error("Clipboard is empty.");
self.command_line.push_error(crate::t!("Clipboard is empty.").as_ref());
} else {
let wires = self.tabs[i].scene.wires_for_entities(&self.clipboard);
let base = self.clipboard_base;
@ -210,7 +210,7 @@ impl OpenCADStudio {
"PASTEORIG" => {
if self.clipboard.is_empty() {
self.command_line
.push_error("PASTEORIG: clipboard is empty.");
.push_error(crate::t!("PASTEORIG: clipboard is empty.").as_ref());
} else {
let count = self.clipboard.len();
self.push_undo_snapshot(i, "PASTEORIG");
@ -219,10 +219,10 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_layer_panel();
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"PASTEORIG: {} object(s) pasted at original coordinates.",
count
));
).as_ref());
}
}
@ -231,7 +231,7 @@ impl OpenCADStudio {
"PASTEBLOCK" => {
if self.clipboard.is_empty() {
self.command_line
.push_error("PASTEBLOCK: clipboard is empty.");
.push_error(crate::t!("PASTEBLOCK: clipboard is empty.").as_ref());
} else {
self.push_undo_snapshot(i, "PASTEBLOCK");
self.merge_clipboard_deps(i);
@ -294,7 +294,7 @@ impl OpenCADStudio {
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
Err(e) => self.command_line.push_error(&format!("PASTEBLOCK: {e}")),
Err(e) => self.command_line.push_error(crate::tf!("PASTEBLOCK: {e}").as_ref()),
}
}
}
@ -323,7 +323,7 @@ impl OpenCADStudio {
let blocks = self.tabs[i].scene.custom_block_names();
if blocks.is_empty() {
self.command_line
.push_error("No user-defined blocks found in this drawing.");
.push_error(crate::t!("No user-defined blocks found in this drawing.").as_ref());
} else {
use crate::modules::insert::insert_block::InsertBlockCommand;
let cmd = InsertBlockCommand::new(blocks);
@ -336,7 +336,7 @@ impl OpenCADStudio {
let blocks = self.tabs[i].scene.custom_block_names();
if blocks.is_empty() {
self.command_line
.push_error("No user-defined blocks found in this drawing.");
.push_error(crate::t!("No user-defined blocks found in this drawing.").as_ref());
} else {
use crate::modules::insert::minsert::MinsertCommand;
let cmd = MinsertCommand::new(blocks);
@ -359,20 +359,20 @@ impl OpenCADStudio {
let arg = cmd.trim_start_matches("ATTSYNC").trim();
let blocks = self.tabs[i].scene.custom_block_names();
if arg.is_empty() {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Usage: ATTSYNC <block name>. Blocks: {}",
if blocks.is_empty() {
"(none)".to_string()
} else {
blocks.join(", ")
}
));
).as_ref());
return Some(Task::none());
}
let Some(block) = blocks.iter().find(|b| b.eq_ignore_ascii_case(arg)).cloned()
else {
self.command_line
.push_error(&format!("ATTSYNC: no block named \"{arg}\"."));
.push_error(crate::tf!("ATTSYNC: no block named \"{arg}\".").as_ref());
return Some(Task::none());
};
// Gather the block's attribute definitions (tag, default value).
@ -422,10 +422,10 @@ impl OpenCADStudio {
}
self.tabs[i].scene.bump_entities(&changes);
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"ATTSYNC: synchronised {synced} insert(s) of \"{block}\" against {} attribute definition(s).",
attdefs.len()
));
).as_ref());
}
// ADCENTER / CONTENTBROWSER — report the drawing's named content
@ -440,7 +440,7 @@ impl OpenCADStudio {
.names()
.map(|s| s.to_string())
.collect();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Blocks ({}): {}",
blocks.len(),
if blocks.is_empty() {
@ -448,12 +448,12 @@ impl OpenCADStudio {
} else {
blocks.join(", ")
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
"Layers ({}): {}",
layers.len(),
layers.join(", ")
));
).as_ref());
}
// BLOCKPALETTE — list the blocks available to insert.
@ -464,11 +464,11 @@ impl OpenCADStudio {
"No user-defined blocks. Define one with BLOCK, then INSERT it.",
);
} else {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Blocks ({}) — insert with INSERT <name>: {}",
blocks.len(),
blocks.join(", ")
));
).as_ref());
}
}
@ -527,9 +527,9 @@ impl OpenCADStudio {
.collect();
if xrefs.is_empty() {
self.command_line
.push_output("XREF No external references in this drawing.");
.push_output(crate::t!("XREF No external references in this drawing.").as_ref());
} else {
self.command_line.push_output("XREF External references:");
self.command_line.push_output(crate::t!("XREF External references:").as_ref());
for line in xrefs {
self.command_line.push_output(&line);
}
@ -548,19 +548,19 @@ impl OpenCADStudio {
match info.status {
crate::io::xref::XrefStatus::Loaded => {
self.command_line
.push_output(&format!("XREF Reloaded \"{}\"", info.name));
.push_output(crate::tf!("XREF Reloaded \"{}\"", info.name).as_ref());
}
crate::io::xref::XrefStatus::NotFound => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"XREF Not found: \"{}\" ({})",
info.name, info.path
));
).as_ref());
}
crate::io::xref::XrefStatus::Unloaded => {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"XREF Unloaded (skipped): \"{}\"",
info.name
));
).as_ref());
}
}
}
@ -574,7 +574,7 @@ impl OpenCADStudio {
}
} else {
self.command_line
.push_error("XREF Save the drawing first to resolve relative XREF paths.");
.push_error(crate::t!("XREF Save the drawing first to resolve relative XREF paths.").as_ref());
}
}
@ -604,7 +604,7 @@ impl OpenCADStudio {
}
None => self
.command_line
.push_error("XOPEN: select an external reference (xref) to open."),
.push_error(crate::t!("XOPEN: select an external reference (xref) to open.").as_ref()),
}
}
@ -622,7 +622,7 @@ impl OpenCADStudio {
.collect();
if inserts.is_empty() {
self.command_line
.push_error("NCOPY: select a block reference first.");
.push_error(crate::t!("NCOPY: select a block reference first.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "NCOPY");
@ -638,9 +638,9 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"NCOPY: copied {n} nested object(s) into model space (blocks kept)."
));
).as_ref());
}
_ => return None,

View file

@ -85,7 +85,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("JUSTIFYTEXT: select text objects first.");
.push_error(crate::t!("JUSTIFYTEXT: select text objects first.").as_ref());
return Some(Task::none());
}
if opt.is_empty() {
@ -130,7 +130,7 @@ impl OpenCADStudio {
};
if text_align.is_none() && mtext_ap.is_none() {
self.command_line
.push_error("JUSTIFYTEXT: unknown justification option.");
.push_error(crate::t!("JUSTIFYTEXT: unknown justification option.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "JUSTIFYTEXT");
@ -175,7 +175,7 @@ impl OpenCADStudio {
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.command_line
.push_output(&format!("JUSTIFYTEXT: updated {n} text object(s)."));
.push_output(crate::tf!("JUSTIFYTEXT: updated {n} text object(s).").as_ref());
}
// TCASE <Upper|Lower|Sentence|Title> — change the case of the text in
@ -207,7 +207,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("TCASE: select text objects first.");
.push_error(crate::t!("TCASE: select text objects first.").as_ref());
return Some(Task::none());
}
if !matches!(
@ -223,7 +223,7 @@ impl OpenCADStudio {
| "TITLE"
) {
self.command_line
.push_info("Usage: TCASE <Upper|Lower|Sentence|Title>");
.push_info(crate::t!("Usage: TCASE <Upper|Lower|Sentence|Title>").as_ref());
return Some(Task::none());
}
let conv = move |s: &str| -> String {
@ -263,7 +263,7 @@ impl OpenCADStudio {
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.command_line
.push_output(&format!("TCASE: updated {n} text object(s)."));
.push_output(crate::tf!("TCASE: updated {n} text object(s).").as_ref());
}
// TEXTMASK — place a wipeout mask sized to each selected text object's
@ -296,7 +296,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("TEXTMASK: select text objects first.");
.push_error(crate::t!("TEXTMASK: select text objects first.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "TEXTMASK");
@ -339,7 +339,7 @@ impl OpenCADStudio {
.replace_selection(handles.iter().cloned().collect());
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("TEXTMASK: masked {n} text object(s)."));
.push_output(crate::tf!("TEXTMASK: masked {n} text object(s).").as_ref());
return self.dispatch_view("DRAWORDER FRONT", i);
}
@ -373,7 +373,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("TEXTFIT: select single-line text first.");
.push_error(crate::t!("TEXTFIT: select single-line text first.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "TEXTFIT");
@ -412,9 +412,9 @@ impl OpenCADStudio {
.map(|handle| (handle, crate::scene::ChangeKind::Modified))
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"TEXTFIT: fitted {n} text object(s) to width {target}."
));
).as_ref());
}
// (text sequential numbering)
@ -450,7 +450,7 @@ impl OpenCADStudio {
.collect();
if texts.is_empty() {
self.command_line
.push_error("TCOUNT: select single-line text first.");
.push_error(crate::t!("TCOUNT: select single-line text first.").as_ref());
return Some(Task::none());
}
// Reading order: higher Y first, then smaller X.
@ -478,10 +478,10 @@ impl OpenCADStudio {
.map(|(handle, _, _)| (*handle, crate::scene::ChangeKind::Modified))
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"TCOUNT: numbered {} text object(s) from {start}.",
texts.len()
));
).as_ref());
}
"MLEADER" => {
@ -575,7 +575,7 @@ impl OpenCADStudio {
}
if pts.len() < 2 {
self.command_line
.push_error("QDIM: no dimensionable endpoints in the selection.");
.push_error(crate::t!("QDIM: no dimensionable endpoints in the selection.").as_ref());
return Some(Task::none());
}
// Choose the dimension axis from the points' spread: a wider X
@ -596,7 +596,7 @@ impl OpenCADStudio {
}
if pts.len() < 2 {
self.command_line
.push_error("QDIM: endpoints collapse to a single position.");
.push_error(crate::t!("QDIM: endpoints collapse to a single position.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "QDIM");
@ -628,7 +628,7 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("QDIM {made} dimensions created."));
.push_output(crate::tf!("QDIM {made} dimensions created.").as_ref());
return Some(Task::none());
}
@ -697,28 +697,28 @@ impl OpenCADStudio {
"ZOOM EXTENTS ALL" | "ZOOM EXTENTS ALL VIEWPORTS" | "ZEA" => {
self.tabs[i].scene.fit_all_model_viewports();
self.command_line.push_output("Zoom Extents — All Viewports");
self.command_line.push_output(crate::t!("Zoom Extents — All Viewports").as_ref());
}
"ZOOM EXTENTS" | "ZOOMEXTENTS" | "ZE" => {
self.tabs[i].scene.fit_all();
self.command_line.push_output("Zoom Extents");
self.command_line.push_output(crate::t!("Zoom Extents").as_ref());
}
"ZOOM IN" | "ZI" => {
self.tabs[i].scene.zoom_camera(1.0 / 1.5);
self.command_line.push_output("Zoom In");
self.command_line.push_output(crate::t!("Zoom In").as_ref());
}
"ZOOM OUT" | "ZO" => {
self.tabs[i].scene.zoom_camera(1.5);
self.command_line.push_output("Zoom Out");
self.command_line.push_output(crate::t!("Zoom Out").as_ref());
}
// ZOOM ALL — fit the configured drawing limits.
"ZOOM ALL" | "ZOOM A" | "ZA" => {
self.tabs[i].scene.fit_all_with_limits();
self.command_line.push_output("Zoom All");
self.command_line.push_output(crate::t!("Zoom All").as_ref());
}
// ZOOM SCALE — set zoom factor (e.g. "ZOOM SCALE 2" or "ZS 0.5")
@ -731,7 +731,7 @@ impl OpenCADStudio {
if factor > 0.0 {
self.tabs[i].scene.zoom_camera(1.0 / factor);
self.command_line
.push_output(&format!("Zoom Scale ×{factor:.3}"));
.push_output(crate::tf!("Zoom Scale ×{factor:.3}").as_ref());
}
}
}
@ -992,10 +992,10 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("{exploded} object(s) exploded."));
.push_output(crate::tf!("{exploded} object(s) exploded.").as_ref());
} else {
self.command_line
.push_info("EXPLODE: no explodable objects selected.");
.push_info(crate::t!("EXPLODE: no explodable objects selected.").as_ref());
}
}
}
@ -1108,11 +1108,11 @@ impl OpenCADStudio {
});
let Some((center, radius)) = found else {
self.command_line
.push_error("DIMJOGGED: select an arc or circle first.");
.push_error(crate::t!("DIMJOGGED: select an arc or circle first.").as_ref());
return None;
};
if radius <= 0.0 {
self.command_line.push_error("DIMJOGGED: invalid radius.");
self.command_line.push_error(crate::t!("DIMJOGGED: invalid radius.").as_ref());
return None;
}
let k = std::f64::consts::FRAC_1_SQRT_2;
@ -1129,7 +1129,7 @@ impl OpenCADStudio {
.add_entity(acadrust::EntityType::Dimension(Dimension::Radius(dim)));
self.tabs[i].dirty = true;
self.command_line
.push_output("DIMJOGGED: created a jogged radius dimension.");
.push_output(crate::t!("DIMJOGGED: created a jogged radius dimension.").as_ref());
}
// ARCTEXT <text> — lay the text out as one Text entity per character
@ -1166,12 +1166,12 @@ impl OpenCADStudio {
});
let Some(arc) = arc else {
self.command_line
.push_error("ARCTEXT: select an arc first.");
.push_error(crate::t!("ARCTEXT: select an arc first.").as_ref());
return None;
};
let chars: Vec<char> = text.chars().filter(|c| !c.is_control()).collect();
if chars.is_empty() {
self.command_line.push_error("ARCTEXT: no printable text.");
self.command_line.push_error(crate::t!("ARCTEXT: no printable text.").as_ref());
return None;
}
let n = chars.len();
@ -1195,7 +1195,7 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("ARCTEXT: placed {n} character(s) along the arc."));
.push_output(crate::tf!("ARCTEXT: placed {n} character(s) along the arc.").as_ref());
}
_ => return None,

View file

@ -8,7 +8,7 @@ impl OpenCADStudio {
"PAN" => {
self.tabs[i].pan_mode = true;
self.command_line
.push_output("PAN: drag with the left mouse button. Press Esc to exit.");
.push_output(crate::t!("PAN: drag with the left mouse button. Press Esc to exit.").as_ref());
}
// ── TABLE cell editing ─────────────────────────────────────────────
@ -46,18 +46,18 @@ impl OpenCADStudio {
if found {
self.push_undo_snapshot(i, "TABLE CELL");
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"TABLE CELL: set [{row},{col}] = \"{text}\"."
));
).as_ref());
} else {
self.command_line.push_error(
"TABLE CELL: select a Table entity first, or row/col out of range."
crate::t!("TABLE CELL: select a Table entity first, or row/col out of range.").as_ref()
);
}
}
_ => {
self.command_line
.push_info("Usage: TABLE CELL <row> <col> <text>");
.push_info(crate::t!("Usage: TABLE CELL <row> <col> <text>").as_ref());
}
}
} else {
@ -111,9 +111,9 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"UCSICON {sub}: updated {count} viewport(s) + model space."
));
).as_ref());
}
"" => {
// Bare UCSICON toggles visibility.
@ -128,11 +128,11 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
let state = if visible { "ON" } else { "OFF" };
self.command_line.push_output(&format!("UCSICON {state}"));
self.command_line.push_output(crate::tf!("UCSICON {state}").as_ref());
}
_ => {
self.command_line
.push_info("Usage: UCSICON ON | OFF | NOORIGIN | ORIGIN");
.push_info(crate::t!("Usage: UCSICON ON | OFF | NOORIGIN | ORIGIN").as_ref());
}
}
}
@ -172,12 +172,12 @@ impl OpenCADStudio {
tokens.iter().map(|value| value.parse()).collect();
let Ok(values) = values else {
self.command_line
.push_error("LIMITS: four numeric coordinates required.");
.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("LIMITS: four finite numeric coordinates required.");
.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]);
@ -185,15 +185,15 @@ impl OpenCADStudio {
let max = first.max(opposite);
if min.x == max.x || min.y == max.y {
self.command_line
.push_error("LIMITS: corners must define a non-zero area.");
.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(&format!(
self.command_line.push_output(crate::tf!(
"Drawing limits: {:.4},{:.4} to {:.4},{:.4}.",
min.x, min.y, max.x, max.y
));
).as_ref());
}
}
}
@ -249,13 +249,13 @@ impl OpenCADStudio {
// ── TOOLPALETTES — not yet implemented ───────────────────────────────
"TOOLPALETTES" => {
self.command_line
.push_info("TOOLPALETTES: Tool Palettes not yet implemented.");
.push_info(crate::t!("TOOLPALETTES: Tool Palettes not yet implemented.").as_ref());
}
// ── SHEETSET — not yet implemented ───────────────────────────────────
"SHEETSET" => {
self.command_line
.push_info("SHEETSET: Sheet Set Manager not yet implemented.");
.push_info(crate::t!("SHEETSET: Sheet Set Manager not yet implemented.").as_ref());
}
// ── XDATA — read/write extended entity data ──────────────────────────
@ -288,7 +288,7 @@ impl OpenCADStudio {
.collect();
if selected_handles.is_empty() {
self.command_line
.push_error("XDATA: select entities first.");
.push_error(crate::t!("XDATA: select entities first.").as_ref());
} else {
match sub.as_str() {
"LIST" | "" => {
@ -297,18 +297,18 @@ impl OpenCADStudio {
let xd = &entity.common().extended_data;
if xd.is_empty() {
self.command_line
.push_output(&format!(" {:x}: no xdata.", sh.value()));
.push_output(crate::tf!(" {:x}: no xdata.", sh.value()).as_ref());
} else {
for rec in xd.records() {
self.command_line.push_output(&format!(
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(&format!(" {:?}", v));
.push_output(crate::tf!(" {:?}", v).as_ref());
}
}
}
@ -329,10 +329,10 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"XDATA: set [{app}] = \"{val}\" on {} entity/entities.",
selected_handles.len()
));
).as_ref());
}
"CLEAR" => {
let app_filter = parts.get(1).copied();
@ -360,11 +360,11 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output("XDATA: cleared.");
self.command_line.push_output(crate::t!("XDATA: cleared.").as_ref());
}
_ => {
self.command_line
.push_info("Usage: XDATA LIST | SET <app> <value> | CLEAR [app]");
.push_info(crate::t!("Usage: XDATA LIST | SET <app> <value> | CLEAR [app]").as_ref());
}
}
}
@ -486,7 +486,7 @@ impl OpenCADStudio {
}
_ => {
self.command_line
.push_error("Usage: PLOTSTYLE [LOAD | CLEAR | STATUS]");
.push_error(crate::t!("Usage: PLOTSTYLE [LOAD | CLEAR | STATUS]").as_ref());
}
}
}
@ -529,7 +529,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("UNDERLAY: select underlay entities first.");
.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("");
@ -589,7 +589,7 @@ impl OpenCADStudio {
},
_ => {
// No sub-command: print status.
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Underlay {:x}: fade={}, contrast={}, on={}, clip={}, mono={}",
h.value(),
ul.fade,
@ -597,7 +597,7 @@ impl OpenCADStudio {
ul.is_on(),
ul.is_clipping(),
ul.is_monochrome(),
));
).as_ref());
}
}
}
@ -605,10 +605,10 @@ impl OpenCADStudio {
if changed > 0 {
self.tabs[i].dirty = true;
self.command_line
.push_info(&format!("Updated {changed} underlay(s)."));
.push_info(crate::tf!("Updated {changed} underlay(s).").as_ref());
} else if !action.is_empty() {
self.command_line.push_error(
"Usage: UNDERLAY [FADE <n>|CONTRAST <n>|ON|OFF|CLIP ON|OFF|MONO ON|OFF]"
crate::t!("Usage: UNDERLAY [FADE <n>|CONTRAST <n>|ON|OFF|CLIP ON|OFF|MONO ON|OFF]").as_ref()
);
}
}
@ -635,13 +635,13 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("OBJECTSCALE: select objects first.");
.push_error(crate::t!("OBJECTSCALE: select objects first.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "OBJECTSCALE");
let Some(scale) = self.tabs[i].scene.creation_annotation_scale_handle() else {
self.command_line
.push_error("OBJECTSCALE: the active annotation scale is unavailable.");
.push_error(crate::t!("OBJECTSCALE: the active annotation scale is unavailable.").as_ref());
return Some(Task::none());
};
let mut n = 0usize;
@ -665,9 +665,9 @@ impl OpenCADStudio {
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"OBJECTSCALE: added the active scale to {n} object(s)."
));
).as_ref());
return Some(Task::none());
}
@ -688,13 +688,13 @@ impl OpenCADStudio {
use acadrust::xdata::{ExtendedDataRecord, XDataValue};
let url = cmd.strip_prefix("HYPERLINK").unwrap_or("").trim().to_string();
if url.is_empty() {
self.command_line.push_info("Usage: HYPERLINK <url> (select objects first)");
self.command_line.push_info(crate::t!("Usage: HYPERLINK <url> (select objects first)").as_ref());
return Some(Task::none());
}
let handles: Vec<acadrust::Handle> =
self.tabs[i].scene.selected_entities().iter().map(|(h, _)| *h).collect();
if handles.is_empty() {
self.command_line.push_error("HYPERLINK: select objects first.");
self.command_line.push_error(crate::t!("HYPERLINK: select objects first.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "HYPERLINK");
@ -710,7 +710,7 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("HYPERLINK: attached to {n} object(s)."));
.push_output(crate::tf!("HYPERLINK: attached to {n} object(s).").as_ref());
return Some(Task::none());
}
@ -745,10 +745,10 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("ADJUST: select raster image(s) first.");
.push_error(crate::t!("ADJUST: select raster image(s) first.").as_ref());
} else if action.is_empty() {
self.command_line
.push_info("Usage: ADJUST BRIGHTNESS|CONTRAST|FADE <0-100>");
.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");
@ -792,14 +792,14 @@ impl OpenCADStudio {
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.command_line
.push_output(&format!("ADJUST: {action} = {v} on {changed} image(s)."));
.push_output(crate::tf!("ADJUST: {action} = {v} on {changed} image(s).").as_ref());
} else {
self.command_line.push_error(
"ADJUST: no raster images selected, or unknown property (use BRIGHTNESS|CONTRAST|FADE).",
);
}
} else {
self.command_line.push_error("ADJUST: value must be 0-100.");
self.command_line.push_error(crate::t!("ADJUST: value must be 0-100.").as_ref());
}
}
@ -837,7 +837,7 @@ impl OpenCADStudio {
}
_ => self
.command_line
.push_error("ANNOALLVISIBLE: enter 0 or 1."),
.push_error(crate::t!("ANNOALLVISIBLE: enter 0 or 1.").as_ref()),
}
}
"ANNOAUTOSCALE" => {
@ -867,7 +867,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("ANNOUPDATE: select annotation objects first.");
.push_error(crate::t!("ANNOUPDATE: select annotation objects first.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "ANNOUPDATE");
@ -891,7 +891,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
}
self.command_line
.push_output(&format!("ANNOUPDATE: updated {updated} object(s)."));
.push_output(crate::tf!("ANNOUPDATE: updated {updated} object(s).").as_ref());
return Some(Task::none());
}
cmd if cmd.starts_with("ANNOSCALE ") || cmd.starts_with("CANNOSCALE ") => {
@ -909,7 +909,7 @@ impl OpenCADStudio {
.current_annotation_scale
.clone();
self.command_line
.push_output(&format!("Current annotation scale: {name}"));
.push_output(crate::tf!("Current annotation scale: {name}").as_ref());
return Some(Task::none());
}
let previous = self.tabs[i].scene.displayed_annotation_scale_handle();
@ -924,11 +924,11 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Annotation scale: {arg}"));
.push_output(crate::tf!("Annotation scale: {arg}").as_ref());
}
None => self
.command_line
.push_error("Usage: ANNOSCALE <ratio> e.g. 1:50, 2:1, or a factor"),
.push_error(crate::t!("Usage: ANNOSCALE <ratio> e.g. 1:50, 2:1, or a factor").as_ref()),
}
}
@ -962,19 +962,19 @@ impl OpenCADStudio {
if self.tabs[i].scene.add_scale(arg, paper, drawing) {
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Added annotation scale {arg}."));
.push_output(crate::tf!("Added annotation scale {arg}.").as_ref());
} else {
self.command_line
.push_info(&format!("Scale {arg} already exists."));
.push_info(crate::tf!("Scale {arg} already exists.").as_ref());
}
}
_ => self
.command_line
.push_error("SCALELISTEDIT ADD: use a ratio like 1:50."),
.push_error(crate::t!("SCALELISTEDIT ADD: use a ratio like 1:50.").as_ref()),
},
None => self
.command_line
.push_error("SCALELISTEDIT ADD: use a ratio like 1:50."),
.push_error(crate::t!("SCALELISTEDIT ADD: use a ratio like 1:50.").as_ref()),
},
"DELETE" | "REMOVE" => {
let current = self.tabs[i]
@ -984,20 +984,20 @@ impl OpenCADStudio {
.current_annotation_scale
.clone();
if arg.is_empty() {
self.command_line.push_info("Usage: SCALELISTEDIT DELETE <name>");
self.command_line.push_info(crate::t!("Usage: SCALELISTEDIT DELETE <name>").as_ref());
} else if arg.eq_ignore_ascii_case(&current) {
self.command_line.push_error(&format!(
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(&format!("Removed annotation scale {arg}."));
.push_output(crate::tf!("Removed annotation scale {arg}.").as_ref());
} else {
self.command_line
.push_info(&format!("No annotation scale named {arg}."));
.push_info(crate::tf!("No annotation scale named {arg}.").as_ref());
}
}
}
@ -1009,15 +1009,15 @@ impl OpenCADStudio {
.map(|(n, _, _)| n)
.collect();
if names.is_empty() {
self.command_line.push_info("No annotation scales defined.");
self.command_line.push_info(crate::t!("No annotation scales defined.").as_ref());
} else {
self.command_line
.push_output(&format!("Annotation scales: {}", names.join(", ")));
.push_output(crate::tf!("Annotation scales: {}", names.join(", ")).as_ref());
}
}
_ => self
.command_line
.push_info("Usage: SCALELISTEDIT [ADD 1:50 | DELETE 1:50]"),
.push_info(crate::t!("Usage: SCALELISTEDIT [ADD 1:50 | DELETE 1:50]").as_ref()),
}
}
@ -1056,7 +1056,7 @@ impl OpenCADStudio {
let ncols = rows_data.iter().map(|r| r.len()).max().unwrap_or(0);
if nrows == 0 || ncols == 0 {
self.command_line
.push_error("DATALINK: the CSV file is empty.");
.push_error(crate::t!("DATALINK: the CSV file is empty.").as_ref());
return Some(Task::none());
}
use acadrust::entities::TableBuilder;
@ -1076,13 +1076,13 @@ impl OpenCADStudio {
.scene
.add_entity_clone(acadrust::EntityType::Table(table));
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"DATALINK: imported {nrows}×{ncols} cells into a table at the origin."
));
).as_ref());
}
Err(e) => {
self.command_line
.push_error(&format!("DATALINK: cannot read \"{path}\": {e}"));
.push_error(crate::tf!("DATALINK: cannot read \"{path}\": {e}").as_ref());
}
}
}
@ -1110,7 +1110,7 @@ impl OpenCADStudio {
let pts = parse_landxml_cgpoints(&xml);
if pts.is_empty() {
self.command_line
.push_info("LANDXMLIMPORT: no <CgPoint> survey points found.");
.push_info(crate::t!("LANDXMLIMPORT: no <CgPoint> survey points found.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "LANDXMLIMPORT");
@ -1122,21 +1122,21 @@ impl OpenCADStudio {
.add_entity_clone(acadrust::EntityType::Point(p));
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LANDXMLIMPORT: imported {} survey point(s). Use ZOOM EXTENTS to view.",
pts.len()
));
).as_ref());
}
Err(e) => self
.command_line
.push_error(&format!("LANDXMLIMPORT: cannot read \"{path}\": {e}")),
.push_error(crate::tf!("LANDXMLIMPORT: cannot read \"{path}\": {e}").as_ref()),
}
}
"POINTCLOUDATTACH" | "RECAP" | "SYNCPVIEWPORTS" | "UNDERLAYLAYERS"
| "UOSNAP" => {
self.command_line
.push_info(&format!("{cmd}: not yet implemented."));
.push_info(crate::tf!("{cmd}: not yet implemented.").as_ref());
}
_ => return None,

View file

@ -76,7 +76,7 @@ impl OpenCADStudio {
.collect();
if selected_handles.is_empty() {
self.command_line
.push_error("ATTEDIT: select an Insert entity first.");
.push_error(crate::t!("ATTEDIT: select an Insert entity first.").as_ref());
} else {
let mut found_any = false;
for sh in &selected_handles {
@ -90,17 +90,17 @@ impl OpenCADStudio {
if rest.is_empty() {
// List attributes.
if ins.attributes.is_empty() {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
" Insert {:x}: no attributes.",
sh.value()
));
).as_ref());
} else {
for attr in &ins.attributes {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
" [{tag}] = {val}",
tag = attr.tag,
val = attr.get_value()
));
).as_ref());
}
}
}
@ -108,7 +108,7 @@ impl OpenCADStudio {
}
if !found_any {
self.command_line
.push_error("ATTEDIT: no Insert entities in selection.");
.push_error(crate::t!("ATTEDIT: no Insert entities in selection.").as_ref());
}
// If tag + value supplied, mutate attributes.
if parts.len() == 2 && !parts[0].is_empty() {
@ -133,13 +133,13 @@ impl OpenCADStudio {
}
if changed > 0 {
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"ATTEDIT: updated {changed} attribute(s) [{tag_up}] = {new_val}."
));
).as_ref());
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"ATTEDIT: tag '{tag_up}' not found in selection."
));
).as_ref());
}
}
}
@ -187,13 +187,13 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"ATTDISP {sub}: {count} attribute definition(s) updated."
));
).as_ref());
}
_ => {
self.command_line
.push_info("Usage: ATTDISP ON | OFF | NORMAL");
.push_info(crate::t!("Usage: ATTDISP ON | OFF | NORMAL").as_ref());
}
}
}
@ -327,7 +327,7 @@ impl OpenCADStudio {
}
None => {
self.command_line
.push_info("ARC Continue No previous line or arc to continue.");
.push_info(crate::t!("ARC Continue No previous line or arc to continue.").as_ref());
}
}
}
@ -599,7 +599,7 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = Some(Box::new(cmd));
} else {
self.command_line
.push_error("HATCHEDIT: selected entity is not a hatch.");
.push_error(crate::t!("HATCHEDIT: selected entity is not a hatch.").as_ref());
}
} else {
let cmd = HatcheditCommand::new();
@ -721,7 +721,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("{n} object(s) erased."));
.push_output(crate::tf!("{n} object(s) erased.").as_ref());
if let Some(pd) = pending {
self.commit_undo_delta(i, pd);
}
@ -783,7 +783,7 @@ impl OpenCADStudio {
return Some(self.solid_polysolid(nums[0], nums[1]));
}
self.command_line
.push_info("Usage: POLYSOLID <width> <height> (select a polyline first)");
.push_info(crate::t!("Usage: POLYSOLID <width> <height> (select a polyline first)").as_ref());
}
// SPLINEFIT — fit a smooth spline through the selected polyline's points.
@ -829,7 +829,7 @@ impl OpenCADStudio {
}
if loops.is_empty() {
self.command_line
.push_error("REGION: select closed polylines or circles.");
.push_error(crate::t!("REGION: select closed polylines or circles.").as_ref());
} else {
self.push_undo_snapshot(i, "REGION");
let count = loops.len();
@ -845,7 +845,7 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("REGION: created {count} region(s)."));
.push_output(crate::tf!("REGION: created {count} region(s).").as_ref());
}
}
@ -871,7 +871,7 @@ impl OpenCADStudio {
return Some(self.solid_pyramid(nums[0], nums[1], sides));
}
self.command_line
.push_info("Usage: PYRAMID <radius> <height> [sides] (default 4 sides)");
.push_info(crate::t!("Usage: PYRAMID <radius> <height> [sides] (default 4 sides)").as_ref());
}
// SECTION [X|Y|Z] <value> — draw the cross-section outline of the solid.
@ -1070,7 +1070,7 @@ impl OpenCADStudio {
}
if sel.len() == 1 {
self.command_line
.push_error("DDEDIT: selected entity is not text.");
.push_error(crate::t!("DDEDIT: selected entity is not text.").as_ref());
} else {
let cmd = DdeditCommand::new();
self.command_line.push_info(&cmd.prompt());
@ -1093,7 +1093,7 @@ impl OpenCADStudio {
"Multiple"
};
self.command_line
.push_output(&format!("Current settings: Edit mode = {}", mode_str));
.push_output(crate::tf!("Current settings: Edit mode = {}", mode_str).as_ref());
let new_cmd = TexteditCommand::new(self.texteditmode);
self.command_line.push_info(&new_cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(new_cmd));

View file

@ -11,7 +11,7 @@ impl OpenCADStudio {
"SAVEALL" => {
if self.read_only {
self.command_line
.push_error("Read-only session (--read-only): saving is disabled.");
.push_error(crate::t!("Read-only session (--read-only): saving is disabled.").as_ref());
return Some(Task::none());
}
#[cfg(not(target_arch = "wasm32"))]
@ -27,10 +27,10 @@ impl OpenCADStudio {
.active_save_jobs
.contains_key(&self.tabs[t].id)
{
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"SAVEALL: {} already has a save running",
path.display()
));
).as_ref());
skipped += 1;
continue;
}
@ -42,28 +42,28 @@ impl OpenCADStudio {
Ok(()) => {
saved += 1;
}
Err(e) => self.command_line.push_error(&format!(
Err(e) => self.command_line.push_error(crate::tf!(
"SAVEALL: {} failed: {e}",
path.display()
)),
).as_ref()),
}
} else {
skipped += 1;
}
}
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SAVEALL: saved {saved} drawing(s){}.",
if skipped > 0 {
format!("; {skipped} need SAVEAS (no file path yet)")
} else {
String::new()
}
));
).as_ref());
}
#[cfg(target_arch = "wasm32")]
{
self.command_line
.push_info("SAVEALL: save each tab individually in the web build.");
.push_info(crate::t!("SAVEALL: save each tab individually in the web build.").as_ref());
}
return Some(Task::none());
}
@ -76,7 +76,7 @@ impl OpenCADStudio {
Ok(n) => return Some(Task::done(Message::UndoMany(n))),
Err(_) => {
self.command_line
.push_error("Usage: UNDO [number of steps]");
.push_error(crate::t!("Usage: UNDO [number of steps]").as_ref());
return Some(Task::none());
}
}
@ -87,7 +87,7 @@ impl OpenCADStudio {
// without undoing any work done since.
"OOPS" => {
if self.oops_cache.is_empty() {
self.command_line.push_info("OOPS: nothing to restore.");
self.command_line.push_info(crate::t!("OOPS: nothing to restore.").as_ref());
} else {
let restored = std::mem::take(&mut self.oops_cache);
let pending = self.begin_undo(i, "OOPS", restored.len(), true);
@ -99,7 +99,7 @@ impl OpenCADStudio {
self.commit_undo_delta(i, pending);
}
self.command_line
.push_output(&format!("OOPS: restored {n} object(s)."));
.push_output(crate::tf!("OOPS: restored {n} object(s).").as_ref());
}
}
"CLEAR" | "CLR" => return Some(Task::done(Message::ClearScene)),
@ -161,7 +161,7 @@ impl OpenCADStudio {
}
};
self.command_line
.push_output(&format!("Visual style: {label}."));
.push_output(crate::tf!("Visual style: {label}.").as_ref());
return Some(Task::done(Message::SetWireframe(wireframe)));
}
// CLOSE — close the active drawing tab (with the unsaved-changes
@ -216,18 +216,18 @@ impl OpenCADStudio {
}
}
}
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{cmd}: packaged {copied} file(s) into {}",
folder.display()
));
).as_ref());
}
Err(e) => self
.command_line
.push_error(&format!("{cmd}: cannot create folder ({e}).")),
.push_error(crate::tf!("{cmd}: cannot create folder ({e}).").as_ref()),
}
} else {
self.command_line
.push_error("ARCHIVE: save the drawing first (it has no file path yet).");
.push_error(crate::t!("ARCHIVE: save the drawing first (it has no file path yet).").as_ref());
}
}
@ -302,7 +302,7 @@ impl OpenCADStudio {
self.tabs[i].scene.recolor_meshes();
self.tabs[i].scene.bump_geometry();
self.command_line
.push_output("Background reset to default.");
.push_output(crate::t!("Background reset to default.").as_ref());
} else if let Some(rgba) = parse_background_color(&args) {
if is_paper {
self.tabs[i].paper_bg_color = Some(rgba);
@ -316,12 +316,12 @@ impl OpenCADStudio {
self.tabs[i].scene.recolor_meshes();
self.tabs[i].scene.bump_geometry();
let [r, g, b, _] = rgba;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Background: rgb({}, {}, {})",
(r * 255.0).round() as u8,
(g * 255.0).round() as u8,
(b * 255.0).round() as u8
));
).as_ref());
// Persisted centrally after this message via
// `persist_settings_if_changed()`.
} else {
@ -361,20 +361,20 @@ impl OpenCADStudio {
})
.map(|l| Task::done(Message::Command(l.to_string())))
.collect();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SCRIPT: running {} command(s) from {p}.",
cmds.len()
));
).as_ref());
return Some(Task::batch(cmds));
}
Err(e) => {
self.command_line
.push_error(&format!("SCRIPT: cannot read {p}: {e}"));
.push_error(crate::tf!("SCRIPT: cannot read {p}: {e}").as_ref());
}
},
_ => {
self.command_line
.push_info("Usage: SCRIPT <path to .scr file>");
.push_info(crate::t!("Usage: SCRIPT <path to .scr file>").as_ref());
}
}
}

View file

@ -5,7 +5,7 @@ impl OpenCADStudio {
match cmd {
"3DORBIT" => {
self.command_line
.push_info("3D Orbit: drag with right mouse button.");
.push_info(crate::t!("3D Orbit: drag with right mouse button.").as_ref());
}
// ── Selection utilities ───────────────────────────────────────
@ -24,20 +24,20 @@ impl OpenCADStudio {
self.tabs[i].scene.select_entity(h, false);
}
self.command_line
.push_output(&format!("SELECTALL: {} object(s) selected.", count));
.push_output(crate::tf!("SELECTALL: {} object(s) selected.", count).as_ref());
self.refresh_properties();
}
"DESELECT" | "DESELALL" => {
self.tabs[i].scene.deselect_all();
self.command_line.push_output("Deselected.");
self.command_line.push_output(crate::t!("Deselected.").as_ref());
self.refresh_properties();
}
"SELECTSIMILAR" | "SELSIM" => {
let added = self.tabs[i].scene.select_similar();
self.command_line
.push_output(&format!("Select Similar: {} added.", added));
.push_output(crate::tf!("Select Similar: {} added.", added).as_ref());
self.refresh_properties();
}
@ -68,11 +68,11 @@ impl OpenCADStudio {
let expr = cmd.splitn(2, char::is_whitespace).nth(1).unwrap_or("").trim();
if expr.is_empty() {
self.command_line
.push_info("Usage: CAL <expression> e.g. CAL (2+3)*4");
.push_info(crate::t!("Usage: CAL <expression> e.g. CAL (2+3)*4").as_ref());
} else {
match arith_eval(expr) {
Ok(v) => self.command_line.push_output(&format!("= {v}")),
Err(e) => self.command_line.push_error(&format!("CAL: {e}")),
Ok(v) => self.command_line.push_output(crate::tf!("= {v}").as_ref()),
Err(e) => self.command_line.push_error(crate::tf!("CAL: {e}").as_ref()),
}
}
}
@ -82,7 +82,7 @@ impl OpenCADStudio {
let selected: Vec<_> = self.tabs[i].scene.selected_entities();
if selected.is_empty() {
self.command_line
.push_error("LIST: no entities selected. Select entities first.");
.push_error(crate::t!("LIST: no entities selected. Select entities first.").as_ref());
} else {
for (handle, _) in &selected {
if let Some(entity) = self.tabs[i].scene.document.get_entity(*handle) {
@ -101,7 +101,7 @@ impl OpenCADStudio {
};
// Entity-specific details
let details = entity_list_details(entity);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{type_name} Handle:{:X} Layer:{} Color:{} LT:{}{}",
handle.value(),
common.layer,
@ -112,7 +112,7 @@ impl OpenCADStudio {
} else {
format!("\n {details}")
}
));
).as_ref());
}
}
}
@ -127,7 +127,7 @@ impl OpenCADStudio {
let selected = scene.selected_entities();
if selected.is_empty() {
self.command_line
.push_error("SELHANDLES: no entities selected. Select entities first.");
.push_error(crate::t!("SELHANDLES: no entities selected. Select entities first.").as_ref());
} else {
use std::collections::BTreeMap;
let space = if scene.current_layout == "Model" {
@ -207,16 +207,14 @@ impl OpenCADStudio {
.collect();
if lines.is_empty() {
self.command_line
.push_info("DBLIST: drawing has no entities.");
.push_info(crate::t!("DBLIST: drawing has no entities.").as_ref());
} else {
let count = lines.len();
for l in lines {
self.command_line.push_output(&l);
}
self.command_line.push_output(&format!(
"DBLIST: {count} entit{}.",
if count == 1 { "y" } else { "ies" }
));
self.command_line
.push_output(crate::tf!("DBLIST: {count} objects.").as_ref());
}
}
@ -311,7 +309,7 @@ impl OpenCADStudio {
// If a session is already active, tell the user.
if self.tabs[i].refedit_session.is_some() {
self.command_line
.push_error("REFEDIT: a session is already active. Use REFCLOSE first.");
.push_error(crate::t!("REFEDIT: a session is already active. Use REFCLOSE first.").as_ref());
} else {
// Check if a single INSERT is already selected.
let selected: Vec<_> =
@ -337,7 +335,7 @@ impl OpenCADStudio {
use crate::modules::draw::modify::block_edit::BlockEditPickCommand;
if self.tabs[i].refedit_session.is_some() {
self.command_line
.push_error("BEDIT: finish the active REFEDIT (REFCLOSE) first.");
.push_error(crate::t!("BEDIT: finish the active REFEDIT (REFCLOSE) first.").as_ref());
} else {
// Jump straight to begin when a single INSERT is preselected.
let selected: Vec<_> =
@ -369,7 +367,7 @@ impl OpenCADStudio {
Some(acadrust::EntityType::Insert(ins)) => ins.clone(),
_ => {
self.command_line
.push_error("BEDIT: selected object is not a block reference.");
.push_error(crate::t!("BEDIT: selected object is not a block reference.").as_ref());
return Some(Task::none());
}
};
@ -383,16 +381,16 @@ impl OpenCADStudio {
{
Some(br) => (br.handle, br.flags.is_xref),
None => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"BEDIT: block \"{}\" not found.",
insert.block_name
));
).as_ref());
return Some(Task::none());
}
};
if is_xref {
self.command_line
.push_error("BEDIT: cannot edit an external reference (xref).");
.push_error(crate::t!("BEDIT: cannot edit an external reference (xref).").as_ref());
return Some(Task::none());
}
if self.tabs[i]
@ -519,10 +517,10 @@ impl OpenCADStudio {
self.refresh_properties();
self.tabs[i].active_cmd = None;
self.tabs[i].dirty = true;
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"BEDIT: Editing block \"{}\". Use Save Block or Discard to finish.",
insert.block_name
));
).as_ref());
}
"BEDIT_SAVE" => {
@ -532,12 +530,12 @@ impl OpenCADStudio {
}
None => {
self.command_line
.push_error("BEDIT_SAVE: no block editor is open.");
.push_error(crate::t!("BEDIT_SAVE: no block editor is open.").as_ref());
return Some(Task::none());
}
Some(_) => {
self.command_line
.push_error("BEDIT_SAVE: invalid block editor state.");
.push_error(crate::t!("BEDIT_SAVE: invalid block editor state.").as_ref());
return Some(Task::none());
}
};
@ -549,10 +547,10 @@ impl OpenCADStudio {
&session.return_camera,
);
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"BEDIT: Block \"{}\" saved. All references updated.",
session.block_name
));
).as_ref());
}
"BEDIT_DISCARD" => {
@ -562,12 +560,12 @@ impl OpenCADStudio {
}
None => {
self.command_line
.push_error("BEDIT_DISCARD: no block editor is open.");
.push_error(crate::t!("BEDIT_DISCARD: no block editor is open.").as_ref());
return Some(Task::none());
}
Some(_) => {
self.command_line
.push_error("BEDIT_DISCARD: invalid block editor state.");
.push_error(crate::t!("BEDIT_DISCARD: invalid block editor state.").as_ref());
return Some(Task::none());
}
};
@ -625,10 +623,10 @@ impl OpenCADStudio {
&return_camera,
);
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"BEDIT: Block \"{}\" edit discarded.",
block_name
));
).as_ref());
}
cmd if cmd.starts_with("REFEDIT_BEGIN:") => {
@ -645,7 +643,7 @@ impl OpenCADStudio {
Some(acadrust::EntityType::Insert(ins)) => ins.clone(),
_ => {
self.command_line
.push_error("REFEDIT: selected object is not an INSERT.");
.push_error(crate::t!("REFEDIT: selected object is not an INSERT.").as_ref());
return Some(Task::none());
}
};
@ -681,10 +679,10 @@ impl OpenCADStudio {
{
Some(br) => br.handle,
None => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"REFEDIT: block \"{}\" not found.",
insert.block_name
));
).as_ref());
return Some(Task::none());
}
};
@ -712,7 +710,7 @@ impl OpenCADStudio {
};
if block_entities.is_empty() {
self.command_line.push_error("REFEDIT: block is empty.");
self.command_line.push_error(crate::t!("REFEDIT: block is empty.").as_ref());
return Some(Task::none());
}
@ -762,10 +760,10 @@ impl OpenCADStudio {
// No active command — the user edits the block's geometry freely
// (move, grips, draw, erase…) and runs REFCLOSE when done. (#136)
self.tabs[i].active_cmd = None;
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"REFEDIT: Editing block \"{}\". Run REFCLOSE to save, REFCLOSE_DISCARD to cancel.",
insert.block_name
));
).as_ref());
}
"REFCLOSE" => {
@ -776,7 +774,7 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = Some(Box::new(cmd_obj));
} else {
self.command_line
.push_error("REFCLOSE: no REFEDIT session active.");
.push_error(crate::t!("REFCLOSE: no REFEDIT session active.").as_ref());
}
}
@ -788,7 +786,7 @@ impl OpenCADStudio {
Some(s) => s,
None => {
self.command_line
.push_error("REFCLOSE: no REFEDIT session active.");
.push_error(crate::t!("REFCLOSE: no REFEDIT session active.").as_ref());
return Some(Task::none());
}
};
@ -866,10 +864,10 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"REFCLOSE: Block \"{}\" saved. All references updated.",
session.block_name
));
).as_ref());
// End the edit fade before rebuilding, so the restored geometry
// recolours bright. (#136)
self.tabs[i].scene.set_refedit_keep(None);
@ -882,7 +880,7 @@ impl OpenCADStudio {
Some(s) => s,
None => {
self.command_line
.push_error("REFCLOSE: no REFEDIT session active.");
.push_error(crate::t!("REFCLOSE: no REFEDIT session active.").as_ref());
return Some(Task::none());
}
};
@ -908,7 +906,7 @@ impl OpenCADStudio {
// End the edit fade — restore the drawing to full brightness.
self.tabs[i].scene.set_refedit_keep(None);
self.command_line
.push_output("REFCLOSE: Changes discarded.");
.push_output(crate::t!("REFCLOSE: Changes discarded.").as_ref());
}
"ALIGN" => {
@ -966,20 +964,20 @@ impl OpenCADStudio {
let selected = self.tabs[i].scene.selected_entities();
if selected.is_empty() {
self.command_line
.push_error("MASSPROP: no entities selected. Select entities first.");
.push_error(crate::t!("MASSPROP: no entities selected. Select entities first.").as_ref());
} else {
for (handle, _) in &selected {
if let Some(entity) = self.tabs[i].scene.document.get_entity(*handle) {
use crate::entities::traits::EntityTypeOps;
if let Some(props) = entity.mass_props() {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{} Area={:.4} Perimeter={:.4} Centroid=({:.4},{:.4})",
crate::entities::names::dxf_name(entity),
props.area,
props.perimeter,
props.cx,
props.cy,
));
).as_ref());
}
}
}
@ -1003,7 +1001,7 @@ impl OpenCADStudio {
}
};
if handles.is_empty() {
self.command_line.push_error("FLATTEN: no entities.");
self.command_line.push_error(crate::t!("FLATTEN: no entities.").as_ref());
} else {
self.push_undo_snapshot(i, "FLATTEN");
for h in &handles {
@ -1012,10 +1010,10 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"FLATTEN: {} entity(ies) moved to Z=0.",
handles.len()
));
).as_ref());
self.refresh_properties();
}
}
@ -1054,17 +1052,17 @@ impl OpenCADStudio {
if prop.is_empty() {
self.command_line
.push_info("Usage: QSELECT TYPE|LAYER|COLOR|LINETYPE <value>");
.push_info(crate::t!("Usage: QSELECT TYPE|LAYER|COLOR|LINETYPE <value>").as_ref());
} else if matched.is_empty() {
self.command_line
.push_output("QSELECT: no matching entities.");
.push_output(crate::t!("QSELECT: no matching entities.").as_ref());
} else {
self.tabs[i].scene.deselect_all();
for h in &matched {
self.tabs[i].scene.select_entity(*h, false);
}
self.command_line
.push_output(&format!("QSELECT: {} entity(ies) selected.", matched.len()));
.push_output(crate::tf!("QSELECT: {} entity(ies) selected.", matched.len()).as_ref());
self.refresh_properties();
}
}
@ -1102,10 +1100,10 @@ impl OpenCADStudio {
}
let total: usize = counts.values().sum();
for (k, n) in &counts {
self.command_line.push_output(&format!(" {k}: {n}"));
self.command_line.push_output(crate::tf!(" {k}: {n}").as_ref());
}
self.command_line
.push_output(&format!("COUNT: {total} entity(ies) total."));
.push_output(crate::tf!("COUNT: {total} entity(ies) total.").as_ref());
}
"DATAEXTRACTION" | "EATTEXT" | "ATTEXT" => {
@ -1142,7 +1140,7 @@ impl OpenCADStudio {
};
if search.is_empty() {
self.command_line.push_error("FIND: specify search text.");
self.command_line.push_error(crate::t!("FIND: specify search text.").as_ref());
} else {
let search_lc = search.to_lowercase();
let mut count = 0usize;
@ -1170,7 +1168,7 @@ impl OpenCADStudio {
};
if targets.is_empty() {
self.command_line
.push_output(&format!("FIND: \"{}\" not found.", search));
.push_output(crate::tf!("FIND: \"{}\" not found.", search).as_ref());
} else {
self.push_undo_snapshot(i, "FIND/REPLACE");
for h in &targets {
@ -1182,34 +1180,34 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"FIND/REPLACE: replaced {} occurrence(s) of \"{}\" → \"{}\".",
count, search, rep
));
).as_ref());
self.refresh_properties();
}
} else {
// List mode
if handles.is_empty() {
self.command_line
.push_output(&format!("FIND: \"{}\" not found.", search));
.push_output(crate::tf!("FIND: \"{}\" not found.", search).as_ref());
} else {
for h in &handles {
if let Some(e) = self.tabs[i].scene.document.get_entity(*h) {
use crate::entities::traits::EntityTypeOps;
let txt = e.text_content().unwrap_or_default();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
" Handle {:X}: \"{}\"",
h.value(),
txt
));
).as_ref());
}
}
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"FIND: {} match(es) for \"{}\".",
handles.len(),
search
));
).as_ref());
}
}
}
@ -1309,12 +1307,12 @@ impl OpenCADStudio {
let Some((verb, kind, layer, color, linetype, lt_scale, lw, template_dimstyle)) = info
else {
self.command_line
.push_error("ADDSELECTED: selected object not found.");
.push_error(crate::t!("ADDSELECTED: selected object not found.").as_ref());
return Task::none();
};
let Some(verb) = verb else {
self.command_line
.push_error(&format!("ADDSELECTED: creating a new {kind} is not supported."));
.push_error(crate::tf!("ADDSELECTED: creating a new {kind} is not supported.").as_ref());
return Task::none();
};
@ -1399,9 +1397,9 @@ impl OpenCADStudio {
self.ribbon.active_lineweight = lw;
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Add Selected: drawing a new {kind} on layer \"{layer}\"."
));
).as_ref());
// Launch the matching draw command (installs its interactive step).
self.dispatch_command(verb)
}

View file

@ -36,15 +36,15 @@ impl OpenCADStudio {
})
.collect();
self.command_line
.push_output(&format!("Layers: {}", info.join(", ")));
.push_output(crate::tf!("Layers: {}", info.join(", ")).as_ref());
}
"NEW" | "N" => {
let name = parts.get(1).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: LAYER NEW <name>");
self.command_line.push_error(crate::t!("Usage: LAYER NEW <name>").as_ref());
} else if self.tabs[i].scene.document.layers.contains(&name) {
self.command_line
.push_error(&format!("LAYER: '{}' already exists.", name));
.push_error(crate::tf!("LAYER: '{}' already exists.", name).as_ref());
} else {
let mut layer = Layer::new(&name);
// Allocate a unique handle so the layer survives a
@ -54,7 +54,7 @@ impl OpenCADStudio {
self.push_undo_snapshot(i, "LAYER NEW");
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("LAYER: '{}' created.", name));
.push_output(crate::tf!("LAYER: '{}' created.", name).as_ref());
}
}
"ON" => {
@ -66,7 +66,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "LAYER ON");
self.tabs[i].dirty = true;
self.command_line.push_output("LAYER: layers turned on.");
self.command_line.push_output(crate::t!("LAYER: layers turned on.").as_ref());
}
"OFF" => {
for name in &parts[1..] {
@ -76,7 +76,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "LAYER OFF");
self.tabs[i].dirty = true;
self.command_line.push_output("LAYER: layers turned off.");
self.command_line.push_output(crate::t!("LAYER: layers turned off.").as_ref());
}
"FREEZE" | "FR" => {
for name in &parts[1..] {
@ -86,7 +86,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "LAYER FREEZE");
self.tabs[i].dirty = true;
self.command_line.push_output("LAYER: layers frozen.");
self.command_line.push_output(crate::t!("LAYER: layers frozen.").as_ref());
}
"THAW" | "TH" => {
for name in &parts[1..] {
@ -96,7 +96,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "LAYER THAW");
self.tabs[i].dirty = true;
self.command_line.push_output("LAYER: layers thawed.");
self.command_line.push_output(crate::t!("LAYER: layers thawed.").as_ref());
}
"LOCK" | "LO" => {
for name in &parts[1..] {
@ -106,7 +106,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "LAYER LOCK");
self.tabs[i].dirty = true;
self.command_line.push_output("LAYER: layers locked.");
self.command_line.push_output(crate::t!("LAYER: layers locked.").as_ref());
}
"UNLOCK" | "UL" => {
for name in &parts[1..] {
@ -116,7 +116,7 @@ impl OpenCADStudio {
}
self.push_undo_snapshot(i, "LAYER UNLOCK");
self.tabs[i].dirty = true;
self.command_line.push_output("LAYER: layers unlocked.");
self.command_line.push_output(crate::t!("LAYER: layers unlocked.").as_ref());
}
"COLOR" | "C" => {
// LAYER COLOR <name> <aci_index>
@ -137,17 +137,17 @@ impl OpenCADStudio {
.invalidate_layer_dependencies(std::slice::from_ref(
&layer_name,
));
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LAYER: '{}' color set to ACI {}.",
layer_name, idx
));
).as_ref());
} else {
self.command_line
.push_error(&format!("LAYER: '{}' not found.", layer_name));
.push_error(crate::tf!("LAYER: '{}' not found.", layer_name).as_ref());
}
} else {
self.command_line
.push_error("Usage: LAYER COLOR <name> <aci_index>");
.push_error(crate::t!("Usage: LAYER COLOR <name> <aci_index>").as_ref());
}
}
"SET" | "S" | "CURRENT" => {
@ -155,15 +155,15 @@ impl OpenCADStudio {
if self.tabs[i].scene.document.layers.contains(&name) {
self.tabs[i].layers.current_layer = name.clone();
self.command_line
.push_output(&format!("LAYER: current layer set to '{}'.", name));
.push_output(crate::tf!("LAYER: current layer set to '{}'.", name).as_ref());
} else {
self.command_line
.push_error(&format!("LAYER: '{}' not found.", name));
.push_error(crate::tf!("LAYER: '{}' not found.", name).as_ref());
}
}
_ => {
self.command_line.push_info(
"Usage: LAYER LIST | NEW <name> | ON/OFF/FREEZE/THAW/LOCK/UNLOCK <name> | COLOR <name> <aci> | SET <name>"
crate::t!("Usage: LAYER LIST | NEW <name> | ON/OFF/FREEZE/THAW/LOCK/UNLOCK <name> | COLOR <name> <aci> | SET <name>").as_ref()
);
}
}
@ -202,22 +202,22 @@ impl OpenCADStudio {
.map(|u| u.name.clone())
.collect();
if names.is_empty() {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Active UCS: {} | No named UCSs defined.",
active_name
));
).as_ref());
} else {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Active UCS: {} | Named: {}",
active_name,
names.join(", ")
));
).as_ref());
}
}
"SAVE" | "S" => {
let name = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: UCS SAVE <name>");
self.command_line.push_error(crate::t!("Usage: UCS SAVE <name>").as_ref());
} else {
// Save the current active UCS under this name.
let ucs = match &self.tabs[i].active_ucs {
@ -231,27 +231,27 @@ impl OpenCADStudio {
self.tabs[i].scene.document.ucss.add_or_replace(ucs);
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("UCS '{}' saved.", name));
.push_output(crate::tf!("UCS '{}' saved.", name).as_ref());
}
}
"DELETE" | "DEL" | "D" => {
let name = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: UCS DELETE <name>");
self.command_line.push_error(crate::t!("Usage: UCS DELETE <name>").as_ref());
} else if self.tabs[i].scene.document.ucss.remove(&name).is_some() {
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("UCS '{}' deleted.", name));
.push_output(crate::tf!("UCS '{}' deleted.", name).as_ref());
} else {
self.command_line
.push_error(&format!("UCS '{}' not found.", name));
.push_error(crate::tf!("UCS '{}' not found.", name).as_ref());
}
}
"W" | "WORLD" => {
self.tabs[i].active_ucs = None;
active_changed = true;
self.command_line
.push_output("UCS reset to World Coordinate System.");
.push_output(crate::t!("UCS reset to World Coordinate System.").as_ref());
}
// UCS ORIGIN x,y,z — shift the active UCS origin, keep axes
"ORIGIN" | "O" => {
@ -274,12 +274,12 @@ impl OpenCADStudio {
wcs_origin.z as f64,
);
active_changed = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"UCS origin set to ({:.4}, {:.4}, {:.4}).",
wcs_origin.x, wcs_origin.y, wcs_origin.z
));
).as_ref());
} else {
self.command_line.push_error("Usage: UCS ORIGIN x,y,z");
self.command_line.push_error(crate::t!("Usage: UCS ORIGIN x,y,z").as_ref());
}
}
// UCS Z angle — rotate active UCS around its Z axis by degrees
@ -318,9 +318,9 @@ impl OpenCADStudio {
self.tabs[i].active_ucs = Some(new_ucs);
active_changed = true;
self.command_line
.push_output(&format!("UCS rotated {:.2}° around Z.", angle_deg));
.push_output(crate::tf!("UCS rotated {:.2}° around Z.", angle_deg).as_ref());
} else {
self.command_line.push_error("Usage: UCS Z <angle_degrees>");
self.command_line.push_error(crate::t!("Usage: UCS Z <angle_degrees>").as_ref());
}
}
// UCS X angle — rotate around current UCS X axis
@ -346,9 +346,9 @@ impl OpenCADStudio {
ucs.y_axis = Vector3::new(ny.x as f64, ny.y as f64, ny.z as f64);
active_changed = true;
self.command_line
.push_output(&format!("UCS rotated {:.2}° around X.", angle_deg));
.push_output(crate::tf!("UCS rotated {:.2}° around X.", angle_deg).as_ref());
} else {
self.command_line.push_error("Usage: UCS X <angle_degrees>");
self.command_line.push_error(crate::t!("Usage: UCS X <angle_degrees>").as_ref());
}
}
// UCS Y angle — rotate around current UCS Y axis
@ -374,9 +374,9 @@ impl OpenCADStudio {
ucs.x_axis = Vector3::new(nx.x as f64, nx.y as f64, nx.z as f64);
active_changed = true;
self.command_line
.push_output(&format!("UCS rotated {:.2}° around Y.", angle_deg));
.push_output(crate::tf!("UCS rotated {:.2}° around Y.", angle_deg).as_ref());
} else {
self.command_line.push_error("Usage: UCS Y <angle_degrees>");
self.command_line.push_error(crate::t!("Usage: UCS Y <angle_degrees>").as_ref());
}
}
_ => {
@ -386,12 +386,12 @@ impl OpenCADStudio {
self.tabs[i].active_ucs = Some(named);
active_changed = true;
self.command_line
.push_output(&format!("UCS '{}' activated.", name));
.push_output(crate::tf!("UCS '{}' activated.", name).as_ref());
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"UCS '{}' not found. Usage: UCS LIST | SAVE <name> | DELETE <name> | W | ORIGIN x,y,z | X/Y/Z <angle>",
name
));
).as_ref());
}
}
}
@ -429,16 +429,16 @@ impl OpenCADStudio {
"" | "CURRENT" | "C" => {
let r = self.tabs[i].scene.viewcube_ucs_mat();
self.plan_snap(i, r);
self.command_line.push_output("PLAN: current UCS plan view.");
self.command_line.push_output(crate::t!("PLAN: current UCS plan view.").as_ref());
}
"WORLD" | "W" => {
self.plan_snap(i, glam::Mat4::IDENTITY);
self.command_line.push_output("PLAN: world plan view.");
self.command_line.push_output(crate::t!("PLAN: world plan view.").as_ref());
}
"UCS" | "U" => {
let name = parts.get(2).map(|s| s.trim()).unwrap_or("");
if name.is_empty() {
self.command_line.push_info("Usage: PLAN UCS <name>");
self.command_line.push_info(crate::t!("Usage: PLAN UCS <name>").as_ref());
} else {
let ucs = self.tabs[i]
.scene
@ -452,20 +452,20 @@ impl OpenCADStudio {
let r = crate::app::helpers::UcsXform::from_ucs(&u)
.rotation_mat();
self.plan_snap(i, r);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"PLAN: plan view of UCS '{}'.",
u.name
));
).as_ref());
}
None => self
.command_line
.push_error(&format!("UCS '{name}' not found.")),
.push_error(crate::tf!("UCS '{name}' not found.").as_ref()),
}
}
}
_ => self
.command_line
.push_info("Usage: PLAN [CURRENT / UCS <name> / WORLD]"),
.push_info(crate::t!("Usage: PLAN [CURRENT / UCS <name> / WORLD]").as_ref()),
}
}
@ -497,50 +497,50 @@ impl OpenCADStudio {
.map(|v| v.name.clone())
.collect();
if views.is_empty() {
self.command_line.push_output("No named views saved.");
self.command_line.push_output(crate::t!("No named views saved.").as_ref());
} else {
self.command_line
.push_output(&format!("Named views: {}", views.join(", ")));
.push_output(crate::tf!("Named views: {}", views.join(", ")).as_ref());
}
}
"SAVE" | "S" => {
let name = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: VIEW SAVE <name>");
self.command_line.push_error(crate::t!("Usage: VIEW SAVE <name>").as_ref());
} else {
let new_view = self.tabs[i].scene.current_as_named_view(&name);
self.tabs[i].scene.document.views.add_or_replace(new_view);
self.command_line
.push_output(&format!("View '{}' saved.", name));
.push_output(crate::tf!("View '{}' saved.", name).as_ref());
}
}
"DELETE" | "DEL" | "D" => {
let name = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: VIEW DELETE <name>");
self.command_line.push_error(crate::t!("Usage: VIEW DELETE <name>").as_ref());
} else {
if self.tabs[i].scene.document.views.remove(&name).is_some() {
self.command_line
.push_output(&format!("View '{}' deleted.", name));
.push_output(crate::tf!("View '{}' deleted.", name).as_ref());
} else {
self.command_line
.push_error(&format!("View '{}' not found.", name));
.push_error(crate::tf!("View '{}' not found.", name).as_ref());
}
}
}
"RESTORE" | "R" => {
let name = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: VIEW RESTORE <name>");
self.command_line.push_error(crate::t!("Usage: VIEW RESTORE <name>").as_ref());
} else {
let found = self.tabs[i].scene.document.views.get(&name).cloned();
if let Some(v) = found {
self.tabs[i].scene.restore_named_view(&v);
self.command_line
.push_output(&format!("View '{}' restored.", v.name));
.push_output(crate::tf!("View '{}' restored.", v.name).as_ref());
} else {
self.command_line
.push_error(&format!("View '{}' not found.", name));
.push_error(crate::tf!("View '{}' not found.", name).as_ref());
}
}
}
@ -573,10 +573,10 @@ impl OpenCADStudio {
if let Some(v) = found {
self.tabs[i].scene.restore_named_view(&v);
self.command_line
.push_output(&format!("View '{}' restored.", v.name));
.push_output(crate::tf!("View '{}' restored.", v.name).as_ref());
} else {
self.command_line.push_error(
"Usage: VIEW LIST | VIEW SAVE <name> | VIEW RESTORE <name> | VIEW DELETE <name>"
crate::t!("Usage: VIEW LIST | VIEW SAVE <name> | VIEW RESTORE <name> | VIEW DELETE <name>").as_ref()
);
}
}
@ -614,16 +614,16 @@ impl OpenCADStudio {
})
.collect();
if styles.is_empty() {
self.command_line.push_output("No table styles.");
self.command_line.push_output(crate::t!("No table styles.").as_ref());
} else {
self.command_line
.push_output(&format!("TableStyles:\n {}", styles.join("\n ")));
.push_output(crate::tf!("TableStyles:\n {}", styles.join("\n ")).as_ref());
}
}
"NEW" | "N" => {
let name = parts.get(1).copied().unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: TABLESTYLE NEW <name>");
self.command_line.push_error(crate::t!("Usage: TABLESTYLE NEW <name>").as_ref());
} else {
let doc = &self.tabs[i].scene.document;
let exists = doc.objects.values().any(|o| {
@ -631,7 +631,7 @@ impl OpenCADStudio {
});
if exists {
self.command_line
.push_error(&format!("TABLESTYLE: '{}' already exists.", name));
.push_error(crate::tf!("TABLESTYLE: '{}' already exists.", name).as_ref());
} else {
self.push_undo_snapshot(i, "TABLESTYLE NEW");
let mut style = TableStyle::standard();
@ -647,13 +647,13 @@ impl OpenCADStudio {
.insert(nh, ObjectType::TableStyle(style));
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("TABLESTYLE: '{}' created.", name));
.push_output(crate::tf!("TABLESTYLE: '{}' created.", name).as_ref());
}
}
}
_ => {
self.command_line
.push_error("Usage: TABLESTYLE [LIST|NEW <name>]");
.push_error(crate::t!("Usage: TABLESTYLE [LIST|NEW <name>]").as_ref());
}
}
}
@ -693,16 +693,16 @@ impl OpenCADStudio {
})
.collect();
if styles.is_empty() {
self.command_line.push_output("No multiline styles.");
self.command_line.push_output(crate::t!("No multiline styles.").as_ref());
} else {
self.command_line
.push_output(&format!("MLineStyles:\n {}", styles.join("\n ")));
.push_output(crate::tf!("MLineStyles:\n {}", styles.join("\n ")).as_ref());
}
}
"NEW" | "N" => {
let name = parts.get(1).copied().unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: MLSTYLE NEW <name>");
self.command_line.push_error(crate::t!("Usage: MLSTYLE NEW <name>").as_ref());
} else {
let doc = &self.tabs[i].scene.document;
let exists = doc.objects.values().any(|o| {
@ -710,7 +710,7 @@ impl OpenCADStudio {
});
if exists {
self.command_line
.push_error(&format!("MLSTYLE: '{}' already exists.", name));
.push_error(crate::tf!("MLSTYLE: '{}' already exists.", name).as_ref());
} else {
self.push_undo_snapshot(i, "MLSTYLE NEW");
let mut style = MLineStyle::standard();
@ -726,14 +726,14 @@ impl OpenCADStudio {
.insert(nh, ObjectType::MLineStyle(style));
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("MLSTYLE: '{}' created.", name));
.push_output(crate::tf!("MLSTYLE: '{}' created.", name).as_ref());
}
}
}
"SET" | "S" => {
let name = parts.get(1).copied().unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: MLSTYLE SET <name>");
self.command_line.push_error(crate::t!("Usage: MLSTYLE SET <name>").as_ref());
} else {
let doc = &self.tabs[i].scene.document;
let exists = doc.objects.values().any(|o| {
@ -743,13 +743,13 @@ impl OpenCADStudio {
self.push_undo_snapshot(i, "MLSTYLE SET");
self.tabs[i].scene.document.header.multiline_style = name.clone();
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"MLSTYLE: current style set to '{}'.",
name
));
).as_ref());
} else {
self.command_line
.push_error(&format!("MLSTYLE: '{}' not found.", name));
.push_error(crate::tf!("MLSTYLE: '{}' not found.", name).as_ref());
}
}
}
@ -757,7 +757,7 @@ impl OpenCADStudio {
let name = parts.get(1).copied().unwrap_or("").to_string();
if name.is_empty() || name.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error("Cannot delete the Standard style.");
.push_error(crate::t!("Cannot delete the Standard style.").as_ref());
} else {
let doc = &self.tabs[i].scene.document;
let handle = doc.objects.iter().find_map(|(&h, o)| {
@ -776,16 +776,16 @@ impl OpenCADStudio {
self.tabs[i].scene.document.objects.remove(&h);
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("MLSTYLE: '{}' deleted.", name));
.push_output(crate::tf!("MLSTYLE: '{}' deleted.", name).as_ref());
} else {
self.command_line
.push_error(&format!("MLSTYLE: '{}' not found.", name));
.push_error(crate::tf!("MLSTYLE: '{}' not found.", name).as_ref());
}
}
}
_ => {
self.command_line
.push_error("Usage: MLSTYLE [LIST|NEW <name>|SET <name>|DEL <name>]");
.push_error(crate::t!("Usage: MLSTYLE [LIST|NEW <name>|SET <name>|DEL <name>]").as_ref());
}
}
}
@ -813,19 +813,19 @@ impl OpenCADStudio {
.map(|s| format!("{}(txt:{:.2} asz:{:.2})", s.name, s.dimtxt, s.dimasz))
.collect();
if styles.is_empty() {
self.command_line.push_output("No dim styles defined.");
self.command_line.push_output(crate::t!("No dim styles defined.").as_ref());
} else {
self.command_line
.push_output(&format!("DimStyles: {}", styles.join(", ")));
.push_output(crate::tf!("DimStyles: {}", styles.join(", ")).as_ref());
}
}
"NEW" | "N" => {
let name = parts.get(1).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_error("Usage: DIMSTYLE NEW <name>");
self.command_line.push_error(crate::t!("Usage: DIMSTYLE NEW <name>").as_ref());
} else if self.tabs[i].scene.document.dim_styles.contains(&name) {
self.command_line
.push_error(&format!("DIMSTYLE: '{}' already exists.", name));
.push_error(crate::tf!("DIMSTYLE: '{}' already exists.", name).as_ref());
} else {
let undo = self.begin_dim_style_undo(
i,
@ -837,7 +837,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_dim_style_undo(i, undo);
self.command_line
.push_output(&format!("DIMSTYLE: '{}' created.", name));
.push_output(crate::tf!("DIMSTYLE: '{}' created.", name).as_ref());
}
}
"SET" | "S" => {
@ -896,9 +896,9 @@ impl OpenCADStudio {
ds.dimfxl = val;
}
_ => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"DIMSTYLE: unknown property '{}'. Try: dimtxt dimasz dimdli dimexo dimexe dimgap dimscale dimlfac dimdle dimcen dimtsz", prop
));
).as_ref());
return Some(Task::none());
}
}
@ -906,16 +906,16 @@ impl OpenCADStudio {
self.tabs[i].scene
.invalidate_dim_style_dependencies(&style_name);
self.commit_dim_style_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"DIMSTYLE: '{style_name}'.{prop} = {val:.3}"
));
).as_ref());
} else {
self.command_line
.push_error(&format!("DIMSTYLE: '{}' not found.", style_name));
.push_error(crate::tf!("DIMSTYLE: '{}' not found.", style_name).as_ref());
}
} else {
self.command_line
.push_error("Usage: DIMSTYLE SET <name> <property> <value>");
.push_error(crate::t!("Usage: DIMSTYLE SET <name> <property> <value>").as_ref());
}
}
_ => {
@ -956,28 +956,28 @@ impl OpenCADStudio {
let current = &self.tabs[i].active_mleader_style;
if styles.is_empty() {
self.command_line
.push_output(&format!("MLeader styles: (none) active: {current}"));
.push_output(crate::tf!("MLeader styles: (none) active: {current}").as_ref());
} else {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"MLeader styles: {} active: {current}",
styles.join(", ")
));
).as_ref());
}
}
"NEW" | "N" => {
let name = parts.get(1).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line
.push_error("Usage: MLEADERSTYLE NEW <name>");
.push_error(crate::t!("Usage: MLEADERSTYLE NEW <name>").as_ref());
} else {
let already_exists = self.tabs[i].scene.document.objects.values().any(
|o| matches!(o, ObjectType::MultiLeaderStyle(s) if s.name == name),
);
if already_exists {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"MLEADERSTYLE: '{}' already exists.",
name
));
).as_ref());
} else {
let handle = self.tabs[i].scene.document.allocate_handle();
let mut style = MultiLeaderStyle::new(&name);
@ -990,7 +990,7 @@ impl OpenCADStudio {
self.push_undo_snapshot(i, "MLEADERSTYLE NEW");
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("MLEADERSTYLE: '{}' created.", name));
.push_output(crate::tf!("MLEADERSTYLE: '{}' created.", name).as_ref());
}
}
}
@ -1032,52 +1032,52 @@ impl OpenCADStudio {
s.landing_gap = val;
}
_ => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"MLEADERSTYLE: unknown property '{}'. Try: text_height arrowhead_size landing_distance landing_gap", prop
));
).as_ref());
return Some(Task::none());
}
}
self.push_undo_snapshot(i, "MLEADERSTYLE SET");
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"MLEADERSTYLE: '{style_name}'.{prop} = {val:.3}"
));
).as_ref());
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"MLEADERSTYLE: '{}' not found.",
style_name
));
).as_ref());
}
} else {
self.command_line
.push_error("Usage: MLEADERSTYLE SET <name> <property> <value>");
.push_error(crate::t!("Usage: MLEADERSTYLE SET <name> <property> <value>").as_ref());
}
}
"CURRENT" | "C" | "ACTIVE" => {
let name = parts.get(1).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Current MLeader style: {}",
self.tabs[i].active_mleader_style
));
).as_ref());
} else {
let exists = name == "Standard" || self.tabs[i].scene.document.objects.values()
.any(|o| matches!(o, ObjectType::MultiLeaderStyle(s) if s.name == name));
if exists {
self.tabs[i].active_mleader_style = name.clone();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"MLEADERSTYLE: current style set to '{name}'."
));
).as_ref());
} else {
self.command_line
.push_error(&format!("MLEADERSTYLE: '{}' not found.", name));
.push_error(crate::tf!("MLEADERSTYLE: '{}' not found.", name).as_ref());
}
}
}
_ => {
self.command_line.push_info(
"Usage: MLEADERSTYLE LIST | NEW <name> | SET <name> <prop> <val> | CURRENT [<name>]"
crate::t!("Usage: MLEADERSTYLE LIST | NEW <name> | SET <name> <prop> <val> | CURRENT [<name>]").as_ref()
);
}
}
@ -1117,10 +1117,10 @@ impl OpenCADStudio {
})
.collect();
if styles.is_empty() {
self.command_line.push_output("No text styles defined.");
self.command_line.push_output(crate::t!("No text styles defined.").as_ref());
} else {
self.command_line
.push_output(&format!("Text styles: {}", styles.join(" | ")));
.push_output(crate::tf!("Text styles: {}", styles.join(" | ")).as_ref());
}
}
"SET" | "S" => {
@ -1128,20 +1128,20 @@ impl OpenCADStudio {
let name = parts.get(1).map(|s| s.trim()).unwrap_or("");
if self.tabs[i].scene.document.text_styles.get(name).is_some() {
self.command_line
.push_output(&format!("{prefix}: active style set to '{name}'."));
.push_output(crate::tf!("{prefix}: active style set to '{name}'.").as_ref());
} else {
self.command_line
.push_error(&format!("{prefix}: style '{name}' not found."));
.push_error(crate::tf!("{prefix}: style '{name}' not found.").as_ref());
}
}
"NEW" | "N" => {
let name = parts.get(1).map(|s| s.trim()).unwrap_or("").to_string();
if name.is_empty() {
self.command_line
.push_error(&format!("Usage: {prefix} NEW <name>"));
.push_error(crate::tf!("Usage: {prefix} NEW <name>").as_ref());
} else if self.tabs[i].scene.document.text_styles.contains(&name) {
self.command_line
.push_error(&format!("{prefix}: style '{name}' already exists."));
.push_error(crate::tf!("{prefix}: style '{name}' already exists.").as_ref());
} else {
let undo = self.begin_text_style_undo(
i,
@ -1153,7 +1153,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_text_style_undo(i, undo);
self.command_line
.push_output(&format!("{prefix}: style '{name}' created."));
.push_output(crate::tf!("{prefix}: style '{name}' created.").as_ref());
}
}
"FONT" | "F" => {
@ -1162,7 +1162,7 @@ impl OpenCADStudio {
let font = parts.get(2).map(|s| s.trim()).unwrap_or("").to_string();
if style_name.is_empty() || font.is_empty() {
self.command_line
.push_error(&format!("Usage: {prefix} FONT <style> <font_file>"));
.push_error(crate::tf!("Usage: {prefix} FONT <style> <font_file>").as_ref());
} else {
let undo = self.begin_text_style_undo(
i,
@ -1178,12 +1178,12 @@ impl OpenCADStudio {
.scene
.invalidate_text_style_dependencies(&style_name);
self.commit_text_style_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{prefix}: '{style_name}' font set to '{font}'."
));
).as_ref());
} else {
self.command_line
.push_error(&format!("{prefix}: style '{style_name}' not found."));
.push_error(crate::tf!("{prefix}: style '{style_name}' not found.").as_ref());
}
}
}
@ -1206,17 +1206,17 @@ impl OpenCADStudio {
.scene
.invalidate_text_style_dependencies(&style_name);
self.commit_text_style_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{prefix}: '{style_name}' width factor set to {factor:.3}."
));
).as_ref());
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"{prefix}: style '{style_name}' not found."
));
).as_ref());
}
} else {
self.command_line
.push_error(&format!("Usage: {prefix} WIDTH <style> <factor>"));
.push_error(crate::tf!("Usage: {prefix} WIDTH <style> <factor>").as_ref());
}
}
"OBLIQUE" => {
@ -1238,24 +1238,24 @@ impl OpenCADStudio {
.scene
.invalidate_text_style_dependencies(&style_name);
self.commit_text_style_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{prefix}: '{style_name}' oblique angle set to {deg:.1}°."
));
).as_ref());
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"{prefix}: style '{style_name}' not found."
));
).as_ref());
}
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Usage: {prefix} OBLIQUE <style> <angle_degrees>"
));
).as_ref());
}
}
_ => {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Usage: {prefix} LIST | NEW <name> | FONT <style> <file> | WIDTH <style> <factor> | OBLIQUE <style> <angle>"
));
).as_ref());
}
}
}

View file

@ -37,7 +37,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_info("Layer(s) turned off.");
self.command_line.push_info(crate::t!("Layer(s) turned off.").as_ref());
}
}
@ -74,7 +74,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_info("Layer(s) frozen.");
self.command_line.push_info(crate::t!("Layer(s) frozen.").as_ref());
}
}
@ -88,7 +88,7 @@ impl OpenCADStudio {
cmd if cmd.starts_with("LAYDEL ") => {
let name = cmd.trim_start_matches("LAYDEL").trim();
if name.is_empty() {
self.command_line.push_info("Usage: LAYDEL <layer name>");
self.command_line.push_info(crate::t!("Usage: LAYDEL <layer name>").as_ref());
return Some(Task::none());
}
let resolved = self.tabs[i]
@ -100,12 +100,12 @@ impl OpenCADStudio {
.map(|s| s.to_string());
let Some(layer) = resolved else {
self.command_line
.push_error(&format!("LAYDEL: no layer named \"{name}\"."));
.push_error(crate::tf!("LAYDEL: no layer named \"{name}\".").as_ref());
return Some(Task::none());
};
if layer == "0" {
self.command_line
.push_error("LAYDEL: layer \"0\" cannot be deleted.");
.push_error(crate::t!("LAYDEL: layer \"0\" cannot be deleted.").as_ref());
return Some(Task::none());
}
if layer.eq_ignore_ascii_case(&self.tabs[i].active_layer) {
@ -130,9 +130,9 @@ impl OpenCADStudio {
self.tabs[i].scene.bump_geometry();
self.tabs[i].dirty = true;
self.refresh_layer_panel();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LAYDEL: deleted layer \"{layer}\" and {n} object(s)."
));
).as_ref());
}
// LAYMRG <source> <target> — move every object from <source> onto
@ -152,7 +152,7 @@ impl OpenCADStudio {
let parts: Vec<&str> = rest.split_whitespace().collect();
if parts.len() != 2 {
self.command_line
.push_info("Usage: LAYMRG <source layer> <target layer>");
.push_info(crate::t!("Usage: LAYMRG <source layer> <target layer>").as_ref());
return Some(Task::none());
}
let keys: Vec<String> = self.tabs[i]
@ -172,17 +172,17 @@ impl OpenCADStudio {
.cloned();
let (Some(src), Some(dst)) = (src, dst) else {
self.command_line
.push_error("LAYMRG: source and target layers must both exist.");
.push_error(crate::t!("LAYMRG: source and target layers must both exist.").as_ref());
return Some(Task::none());
};
if src == dst {
self.command_line
.push_error("LAYMRG: source and target are the same layer.");
.push_error(crate::t!("LAYMRG: source and target are the same layer.").as_ref());
return Some(Task::none());
}
if src == "0" {
self.command_line
.push_error("LAYMRG: layer \"0\" cannot be merged away.");
.push_error(crate::t!("LAYMRG: layer \"0\" cannot be merged away.").as_ref());
return Some(Task::none());
}
if src.eq_ignore_ascii_case(&self.tabs[i].active_layer) {
@ -206,9 +206,9 @@ impl OpenCADStudio {
.invalidate_layer_dependencies(std::slice::from_ref(&dst));
self.tabs[i].dirty = true;
self.refresh_layer_panel();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LAYMRG: merged \"{src}\" into \"{dst}\" ({moved} object(s))."
));
).as_ref());
}
// LAYERSTATE — save / restore named snapshots of all layer states
@ -241,12 +241,12 @@ impl OpenCADStudio {
states.iter().map(|state| state.name.as_str()).collect();
names.sort_unstable();
self.command_line
.push_output(&format!("Saved layer states: {}", names.join(", ")));
.push_output(crate::tf!("Saved layer states: {}", names.join(", ")).as_ref());
}
}
"SAVE" | "S" => {
if arg.is_empty() {
self.command_line.push_info("Usage: LAYERSTATE SAVE <name>");
self.command_line.push_info(crate::t!("Usage: LAYERSTATE SAVE <name>").as_ref());
} else {
let description = self.tabs[i]
.scene
@ -261,17 +261,17 @@ impl OpenCADStudio {
.capture_layer_state(arg, description);
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("LAYERSTATE: saved \"{arg}\"."));
.push_output(crate::tf!("LAYERSTATE: saved \"{arg}\".").as_ref());
}
}
"RESTORE" | "R" => {
if arg.is_empty() {
self.command_line
.push_info("Usage: LAYERSTATE RESTORE <name>");
.push_info(crate::t!("Usage: LAYERSTATE RESTORE <name>").as_ref());
} else if self.tabs[i].scene.document.layer_state(arg).is_none() {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"LAYERSTATE: no saved state named \"{arg}\"."
));
).as_ref());
} else {
let names: Vec<String> = self.tabs[i]
.scene
@ -295,30 +295,30 @@ impl OpenCADStudio {
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].dirty = true;
self.refresh_layer_panel();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LAYERSTATE: restored \"{arg}\" ({n} layer(s))."
));
).as_ref());
}
}
"DELETE" | "D" => {
if arg.is_empty() {
self.command_line
.push_info("Usage: LAYERSTATE DELETE <name>");
.push_info(crate::t!("Usage: LAYERSTATE DELETE <name>").as_ref());
} else if self.tabs[i].scene.document.layer_state(arg).is_none() {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"LAYERSTATE: no saved state named \"{arg}\"."
));
).as_ref());
} else {
self.push_undo_snapshot(i, "LAYERSTATE DELETE");
self.tabs[i].scene.document.delete_layer_state(arg);
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("LAYERSTATE: deleted \"{arg}\"."));
.push_output(crate::tf!("LAYERSTATE: deleted \"{arg}\".").as_ref());
}
}
_ => {
self.command_line
.push_info("Usage: LAYERSTATE SAVE|RESTORE|DELETE <name> | ? (list)");
.push_info(crate::t!("Usage: LAYERSTATE SAVE|RESTORE|DELETE <name> | ? (list)").as_ref());
}
}
}
@ -353,7 +353,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_info("Layer(s) locked.");
self.command_line.push_info(crate::t!("Layer(s) locked.").as_ref());
}
}
@ -385,7 +385,7 @@ impl OpenCADStudio {
self.tabs[i].layers.current_layer = layer.clone();
self.tabs[i].dirty = true;
self.command_line
.push_info(&format!("Current layer set to \"{layer}\"."));
.push_info(crate::tf!("Current layer set to \"{layer}\".").as_ref());
self.refresh_layer_panel();
}
}
@ -408,7 +408,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_info("All layers turned on.");
self.command_line.push_info(crate::t!("All layers turned on.").as_ref());
}
"LAYTHW" => {
@ -429,7 +429,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_info("All layers thawed.");
self.command_line.push_info(crate::t!("All layers thawed.").as_ref());
}
"LAYULK" => {
@ -462,7 +462,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_info("Layer(s) unlocked.");
self.command_line.push_info(crate::t!("Layer(s) unlocked.").as_ref());
}
}
@ -476,7 +476,7 @@ impl OpenCADStudio {
.collect();
if sel_layers.is_empty() {
self.command_line
.push_error("LAYISO: select entities on the layers to isolate first.");
.push_error(crate::t!("LAYISO: select entities on the layers to isolate first.").as_ref());
} else {
let names: Vec<String> = self.tabs[i]
.scene
@ -498,7 +498,7 @@ impl OpenCADStudio {
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line
.push_info(&format!("LAYISO: isolated {} layer(s).", sel_layers.len()));
.push_info(crate::tf!("LAYISO: isolated {} layer(s).", sel_layers.len()).as_ref());
}
}
@ -506,7 +506,7 @@ impl OpenCADStudio {
"ISOLATEOBJECTS" => {
if self.tabs[i].scene.selected.is_empty() {
self.command_line
.push_error("ISOLATEOBJECTS: select the objects to isolate first.");
.push_error(crate::t!("ISOLATEOBJECTS: select the objects to isolate first.").as_ref());
} else {
let n = self.tabs[i].scene.selected.len();
let before = self.tabs[i].scene.object_isolation.clone();
@ -519,9 +519,9 @@ impl OpenCADStudio {
before,
selected_before,
);
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Isolated {n} object(s). UNISOLATEOBJECTS to restore."
));
).as_ref());
}
}
@ -529,7 +529,7 @@ impl OpenCADStudio {
"HIDEOBJECTS" => {
if self.tabs[i].scene.selected.is_empty() {
self.command_line
.push_error("HIDEOBJECTS: select the objects to hide first.");
.push_error(crate::t!("HIDEOBJECTS: select the objects to hide first.").as_ref());
} else {
let n = self.tabs[i].scene.selected.len();
let before = self.tabs[i].scene.object_isolation.clone();
@ -544,7 +544,7 @@ impl OpenCADStudio {
);
self.refresh_properties();
self.command_line
.push_info(&format!("Hid {n} object(s). UNISOLATEOBJECTS to restore."));
.push_info(crate::tf!("Hid {n} object(s). UNISOLATEOBJECTS to restore.").as_ref());
}
}
@ -562,9 +562,9 @@ impl OpenCADStudio {
selected_before,
);
self.command_line
.push_info("Isolation ended — all objects shown.");
.push_info(crate::t!("Isolation ended — all objects shown.").as_ref());
} else {
self.command_line.push_info("No hidden objects.");
self.command_line.push_info(crate::t!("No hidden objects.").as_ref());
}
}
@ -588,7 +588,7 @@ impl OpenCADStudio {
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line
.push_info("LAYUNISO: all layers restored.");
.push_info(crate::t!("LAYUNISO: all layers restored.").as_ref());
}
"LAYMATCH" | "LAYMCH" => {
@ -653,10 +653,10 @@ impl OpenCADStudio {
self.commit_group_undo(i, undo);
if count > 0 {
self.command_line
.push_info(&format!("{} group(s) dissolved.", count));
.push_info(crate::tf!("{} group(s) dissolved.", count).as_ref());
} else {
self.command_line
.push_info("No groups found for selected objects.");
.push_info(crate::t!("No groups found for selected objects.").as_ref());
}
}
}

View file

@ -116,7 +116,7 @@ impl OpenCADStudio {
// rather than keeping a second, blunter copy (#388, #389).
if self.tabs[i].is_start && !start_allowed(cmd) {
self.command_line
.push_info("No drawing open. Use NEW or OPEN to start a drawing.");
.push_info(crate::t!("No drawing open. Use NEW or OPEN to start a drawing.").as_ref());
return Task::none();
}
@ -164,7 +164,7 @@ impl OpenCADStudio {
}
}
self.command_line
.push_error(&format!("Unknown command: {cmd}"));
.push_error(crate::tf!("Unknown command: {cmd}").as_ref());
self.finish_dispatch(cmd)
}

View file

@ -38,7 +38,7 @@ impl OpenCADStudio {
"" => {
let c = self.tabs[i].scene.document.header.current_entity_color;
self.command_line
.push_output(&format!("Current object colour: {}", describe(&c)));
.push_output(crate::tf!("Current object colour: {}", describe(&c)).as_ref());
return Some(Task::none());
}
"BYLAYER" => Some(Color::ByLayer),
@ -58,7 +58,7 @@ impl OpenCADStudio {
self.ribbon.active_color = c;
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Object colour set to {}.", describe(&c)));
.push_output(crate::tf!("Object colour set to {}.", describe(&c)).as_ref());
}
None => {
self.command_line.push_error(
@ -96,10 +96,10 @@ impl OpenCADStudio {
.map(|lt| format!("{} ({})", lt.name, lt.description))
.collect();
if ltypes.is_empty() {
self.command_line.push_output("No linetypes defined.");
self.command_line.push_output(crate::t!("No linetypes defined.").as_ref());
} else {
self.command_line
.push_output(&format!("Linetypes: {}", ltypes.join(", ")));
.push_output(crate::tf!("Linetypes: {}", ltypes.join(", ")).as_ref());
}
}
// Set the current linetype applied to newly drawn entities.
@ -107,7 +107,7 @@ impl OpenCADStudio {
let name = parts.get(1).copied().unwrap_or("");
if name.is_empty() {
self.command_line
.push_info("Usage: LINETYPE SET <name | ByLayer | ByBlock>");
.push_info(crate::t!("Usage: LINETYPE SET <name | ByLayer | ByBlock>").as_ref());
} else {
let canon = if name.eq_ignore_ascii_case("BYLAYER") {
Some(("ByLayer".to_string(), acadrust::types::Handle::NULL))
@ -129,19 +129,19 @@ impl OpenCADStudio {
h.current_linetype_handle = handle;
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Current linetype set to {nm}."));
.push_output(crate::tf!("Current linetype set to {nm}.").as_ref());
}
None => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"LINETYPE: \"{name}\" is not loaded. Use LINETYPE LIST to see available linetypes."
));
).as_ref());
}
}
}
}
_ => {
self.command_line
.push_info("Usage: LINETYPE LIST | SET <name>");
.push_info(crate::t!("Usage: LINETYPE LIST | SET <name>").as_ref());
}
}
}
@ -177,9 +177,9 @@ impl OpenCADStudio {
let do_lts = all || matches!(sub.as_str(), "LINETYPES" | "LT");
let do_blocks = all || matches!(sub.as_str(), "BLOCKS" | "BLOCK" | "B");
if !(do_layers || do_styles || do_lts || do_blocks) {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"PURGE: unknown option \"{sub}\" — use ALL, Blocks, LAyers, LineTypes or STyles."
));
).as_ref());
return Some(Task::none());
}
@ -560,13 +560,13 @@ impl OpenCADStudio {
if n_sortents > 0 {
parts.push(format!("{n_sortents} stale draw-order table(s)"));
}
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"PURGE: {} item(s) removed — {}.",
purged + n_sortents,
parts.join(", ")
));
).as_ref());
} else {
self.command_line.push_output("PURGE: nothing to purge.");
self.command_line.push_output(crate::t!("PURGE: nothing to purge.").as_ref());
}
}
@ -610,7 +610,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("CHPROP: no entities selected.");
.push_error(crate::t!("CHPROP: no entities selected.").as_ref());
} else {
// Validate value early to give clear errors
let color_val: Option<acadrust::types::Color> = if prop == "COLOR" {
@ -640,10 +640,10 @@ impl OpenCADStudio {
|| (prop == "LTSCALE" && ltscale_val.is_none())
|| (prop == "TRANSPARENCY" && transparency_val.is_none())
{
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"CHPROP: invalid value '{}' for {}.",
value, prop
));
).as_ref());
} else {
let mut changed = 0usize;
for handle in &handles {
@ -673,9 +673,9 @@ impl OpenCADStudio {
changed += 1;
}
_ => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"CHPROP: unknown property '{}'. Use: LAYER COLOR LINETYPE LTSCALE TRANSPARENCY", prop
));
).as_ref());
break;
}
}
@ -689,10 +689,10 @@ impl OpenCADStudio {
// re-tessellate the changed entities so they
// repaint immediately (issue #231 class).
self.invalidate_property_targets(i, &handles);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"CHPROP: {} entity/entities updated.",
changed
));
).as_ref());
}
}
}
@ -711,7 +711,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("SETBYLAYER: select entities first.");
.push_error(crate::t!("SETBYLAYER: select entities first.").as_ref());
} else {
self.push_undo_snapshot(i, "SETBYLAYER");
let mut changed = 0usize;
@ -730,9 +730,9 @@ impl OpenCADStudio {
.map(|handle| (handle, crate::scene::ChangeKind::Modified))
.collect();
self.tabs[i].scene.bump_entities(&changes);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SETBYLAYER: reset {changed} entity/entities to ByLayer."
));
).as_ref());
}
}
@ -778,7 +778,7 @@ impl OpenCADStudio {
}
if dups.is_empty() {
self.command_line
.push_output("OVERKILL: no duplicate objects found.");
.push_output(crate::t!("OVERKILL: no duplicate objects found.").as_ref());
} else {
let n = dups.len();
self.push_undo_snapshot(i, "OVERKILL");
@ -786,7 +786,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("OVERKILL: deleted {n} duplicate object(s)."));
.push_output(crate::tf!("OVERKILL: deleted {n} duplicate object(s).").as_ref());
}
}
@ -813,17 +813,17 @@ impl OpenCADStudio {
} else {
u8::from(self.pick_drag_rect)
};
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{} = {v}",
if is_add { "PICKADD" } else { "PICKDRAG" }
));
).as_ref());
} else {
match arg {
"0" | "1" => {
let on = arg == "1";
if is_add {
self.pick_add = on;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"PICKADD = {} ({})",
arg,
if on {
@ -831,10 +831,10 @@ impl OpenCADStudio {
} else {
"click replaces selection, Shift toggles"
}
));
).as_ref());
} else {
self.pick_drag_rect = on;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"PICKDRAG = {} ({})",
arg,
if on {
@ -842,14 +842,14 @@ impl OpenCADStudio {
} else {
"press-drag lassoes"
}
));
).as_ref());
}
self.persist_settings_if_changed();
}
_ => self.command_line.push_error(&format!(
_ => self.command_line.push_error(crate::tf!(
"{}: expected 0 or 1.",
if is_add { "PICKADD" } else { "PICKDRAG" }
)),
).as_ref()),
}
}
}
@ -1586,9 +1586,9 @@ impl OpenCADStudio {
// prompt for a new value on the next line instead
// of only echoing the current one. Enter keeps it.
let current = msg.split('=').nth(1).map(str::trim).unwrap_or("");
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Enter new value for {name} <{current}>:"
));
).as_ref());
self.pending_setvar = Some(name.clone());
}
}
@ -1667,15 +1667,15 @@ impl OpenCADStudio {
}
};
self.command_line
.push_output("FINDNONPURGEABLE: named objects in use (not purgeable):");
.push_output(crate::t!("FINDNONPURGEABLE: named objects in use (not purgeable):").as_ref());
self.command_line
.push_output(&format!(" Layers: {}", fmt(layers)));
.push_output(crate::tf!(" Layers: {}", fmt(layers)).as_ref());
self.command_line
.push_output(&format!(" Linetypes: {}", fmt(linetypes)));
.push_output(crate::tf!(" Linetypes: {}", fmt(linetypes)).as_ref());
self.command_line
.push_output(&format!(" Text styles: {}", fmt(styles)));
.push_output(crate::tf!(" Text styles: {}", fmt(styles)).as_ref());
self.command_line
.push_output(&format!(" Blocks: {}", fmt(blocks)));
.push_output(crate::tf!(" Blocks: {}", fmt(blocks)).as_ref());
}
// ── AUDIT — report drawing-database integrity issues ─────────
@ -1703,24 +1703,24 @@ impl OpenCADStudio {
}
}
self.command_line
.push_output(&format!("AUDIT: scanned {total} object(s)."));
.push_output(crate::tf!("AUDIT: scanned {total} object(s).").as_ref());
if undefined_layers.is_empty() && undefined_blocks.is_empty() {
self.command_line.push_output("AUDIT: no issues found.");
self.command_line.push_output(crate::t!("AUDIT: no issues found.").as_ref());
} else {
if !undefined_layers.is_empty() {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"AUDIT: reference(s) to undefined layer(s): {}",
undefined_layers.into_iter().collect::<Vec<_>>().join(", ")
));
).as_ref());
}
if !undefined_blocks.is_empty() {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"AUDIT: reference(s) to undefined block(s): {}",
undefined_blocks.into_iter().collect::<Vec<_>>().join(", ")
));
).as_ref());
}
self.command_line
.push_info("AUDIT: report only — no automatic repair performed.");
.push_info(crate::t!("AUDIT: report only — no automatic repair performed.").as_ref());
}
}
@ -1744,7 +1744,7 @@ impl OpenCADStudio {
if type_str.is_empty() || old_name.is_empty() || new_name.is_empty() {
self.command_line.push_info(
"Usage: RENAME <type> <old> <new> (types: LAYER BLOCK STYLE DIMSTYLE LINETYPE UCS VIEW)"
crate::t!("Usage: RENAME <type> <old> <new> (types: LAYER BLOCK STYLE DIMSTYLE LINETYPE UCS VIEW)").as_ref()
);
} else {
// Snapshot BEFORE mutating (undo must restore the old
@ -1789,21 +1789,21 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("RENAME: '{}' → '{}'.", old_name, new_name));
.push_output(crate::tf!("RENAME: '{}' → '{}'.", old_name, new_name).as_ref());
} else {
self.discard_last_undo_entry(i);
if !known {
self.command_line.push_error(&format!("RENAME: unknown type '{}'. Use LAYER BLOCK STYLE DIMSTYLE LINETYPE UCS VIEW", type_str));
self.command_line.push_error(crate::tf!("RENAME: unknown type '{}'. Use LAYER BLOCK STYLE DIMSTYLE LINETYPE UCS VIEW", type_str).as_ref());
} else if type_str == "BLOCK" {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"RENAME: could not rename block '{}' — missing/anonymous/xref, or '{}' is invalid or taken.",
old_name, new_name
));
).as_ref());
} else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"RENAME: could not rename '{}' in {} — not found or protected, or '{}' is invalid or taken.",
old_name, type_str, new_name
));
).as_ref());
}
}
}
@ -1825,17 +1825,17 @@ impl OpenCADStudio {
if name_arg.is_empty() {
let cur = &self.tabs[i].scene.document.header.current_layer_name;
self.command_line
.push_output(&format!("CLAYER = \"{cur}\""));
.push_output(crate::tf!("CLAYER = \"{cur}\"").as_ref());
} else {
if self.tabs[i].scene.document.layers.contains(name_arg) {
self.tabs[i].scene.document.header.current_layer_name =
name_arg.to_string();
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("CLAYER set to \"{name_arg}\""));
.push_output(crate::tf!("CLAYER set to \"{name_arg}\"").as_ref());
} else {
self.command_line
.push_error(&format!("CLAYER: layer '{}' not found.", name_arg));
.push_error(crate::tf!("CLAYER: layer '{}' not found.", name_arg).as_ref());
}
}
}
@ -1851,16 +1851,16 @@ impl OpenCADStudio {
if name_arg.is_empty() {
let cur = &self.tabs[i].scene.document.header.current_dimstyle_name;
self.command_line
.push_output(&format!("CDIMSTY = \"{cur}\""));
.push_output(crate::tf!("CDIMSTY = \"{cur}\"").as_ref());
} else {
if self.tabs[i].scene.document.dim_styles.contains(&name_arg) {
self.tabs[i].scene.document.header.current_dimstyle_name = name_arg.clone();
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Active dim style set to \"{name_arg}\""));
.push_output(crate::tf!("Active dim style set to \"{name_arg}\"").as_ref());
} else {
self.command_line
.push_error(&format!("CDIMSTY: dim style '{}' not found.", name_arg));
.push_error(crate::tf!("CDIMSTY: dim style '{}' not found.", name_arg).as_ref());
}
}
}
@ -1874,20 +1874,20 @@ impl OpenCADStudio {
let val_str = cmd.trim_start_matches("LTSCALE").trim();
if val_str.is_empty() {
let v = self.tabs[i].scene.document.header.linetype_scale;
self.command_line.push_output(&format!("LTSCALE = {v:.4}"));
self.command_line.push_output(crate::tf!("LTSCALE = {v:.4}").as_ref());
} else if let Ok(v) = val_str.parse::<f64>() {
if v > 0.0 {
self.push_undo_snapshot(i, "LTSCALE");
self.tabs[i].scene.document.header.linetype_scale = v;
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("LTSCALE set to {v:.4}"));
.push_output(crate::tf!("LTSCALE set to {v:.4}").as_ref());
} else {
self.command_line
.push_error("LTSCALE: value must be positive.");
.push_error(crate::t!("LTSCALE: value must be positive.").as_ref());
}
} else {
self.command_line.push_error("Usage: LTSCALE [value]");
self.command_line.push_error(crate::t!("Usage: LTSCALE [value]").as_ref());
}
}
"PDMODE" => {
@ -1903,14 +1903,14 @@ impl OpenCADStudio {
let val_str = cmd.trim_start_matches("PDMODE").trim();
if val_str.is_empty() {
let v = self.tabs[i].scene.document.header.point_display_mode;
self.command_line.push_output(&format!("PDMODE = {v}"));
self.command_line.push_output(crate::tf!("PDMODE = {v}").as_ref());
} else if let Ok(v) = val_str.parse::<i16>() {
self.push_undo_snapshot(i, "PDMODE");
self.tabs[i].scene.document.header.point_display_mode = v;
// Point glyphs are built at tessellation time — rebuild them.
self.tabs[i].scene.invalidate_point_dependencies();
self.tabs[i].dirty = true;
self.command_line.push_output(&format!("PDMODE set to {v}"));
self.command_line.push_output(crate::tf!("PDMODE set to {v}").as_ref());
} else {
self.command_line.push_error(
"Usage: PDMODE [value] (0=dot 1=none 2=+ 3=x 4=tick; +32 circle, +64 square)",
@ -1922,17 +1922,17 @@ impl OpenCADStudio {
if val_str.is_empty() {
let v = if self.texteditmode { 1 } else { 0 };
self.command_line
.push_output(&format!("TEXTEDITMODE = {v}"));
.push_output(crate::tf!("TEXTEDITMODE = {v}").as_ref());
} else if let Some(v) =
crate::modules::annotate::textedit::parse_texteditmode(&val_str)
{
self.texteditmode = v;
let n = if v { 1 } else { 0 };
self.command_line
.push_output(&format!("TEXTEDITMODE set to {n}"));
.push_output(crate::tf!("TEXTEDITMODE set to {n}").as_ref());
} else {
self.command_line
.push_error("Requires 0 OR 1 OR MULTIPLE OR SINGLE");
.push_error(crate::t!("Requires 0 OR 1 OR MULTIPLE OR SINGLE").as_ref());
}
}
"ISAVEBAK" => {
@ -1946,19 +1946,19 @@ impl OpenCADStudio {
match cmd.trim_start_matches("ISAVEBAK").trim() {
"" => {
let v = if self.backup_on_save { 1 } else { 0 };
self.command_line.push_output(&format!("ISAVEBAK = {v}"));
self.command_line.push_output(crate::tf!("ISAVEBAK = {v}").as_ref());
}
"0" => {
self.backup_on_save = false;
self.persist_settings_if_changed();
self.command_line.push_output("ISAVEBAK set to 0");
self.command_line.push_output(crate::t!("ISAVEBAK set to 0").as_ref());
}
"1" => {
self.backup_on_save = true;
self.persist_settings_if_changed();
self.command_line.push_output("ISAVEBAK set to 1");
self.command_line.push_output(crate::t!("ISAVEBAK set to 1").as_ref());
}
_ => self.command_line.push_error("Requires 0 or 1"),
_ => self.command_line.push_error(crate::t!("Requires 0 or 1").as_ref()),
}
}
"FILEASSOC" => {
@ -1974,7 +1974,7 @@ impl OpenCADStudio {
match cmd.trim_start_matches("FILEASSOC").trim() {
"" => {
let v = if self.file_assoc_enabled { 1 } else { 0 };
self.command_line.push_output(&format!("FILEASSOC = {v}"));
self.command_line.push_output(crate::tf!("FILEASSOC = {v}").as_ref());
}
"1" => {
self.file_assoc_enabled = true;
@ -1985,7 +1985,7 @@ impl OpenCADStudio {
),
Err(e) => self
.command_line
.push_error(&format!("FILEASSOC: registration failed: {e}")),
.push_error(crate::tf!("FILEASSOC: registration failed: {e}").as_ref()),
}
}
"0" => {
@ -1994,13 +1994,13 @@ impl OpenCADStudio {
match crate::io::file_association::unregister_handler() {
Ok(()) => self
.command_line
.push_output("FILEASSOC set to 0 — unregistered as a file handler"),
.push_output(crate::t!("FILEASSOC set to 0 — unregistered as a file handler").as_ref()),
Err(e) => self
.command_line
.push_error(&format!("FILEASSOC: unregister failed: {e}")),
.push_error(crate::tf!("FILEASSOC: unregister failed: {e}").as_ref()),
}
}
_ => self.command_line.push_error("Requires 0 or 1"),
_ => self.command_line.push_error(crate::t!("Requires 0 or 1").as_ref()),
}
}
"SAVETIME" => {
@ -2016,7 +2016,7 @@ impl OpenCADStudio {
let arg = cmd.trim_start_matches("SAVETIME").trim();
if arg.is_empty() {
self.command_line
.push_output(&format!("SAVETIME = {}", self.savetime_min));
.push_output(crate::tf!("SAVETIME = {}", self.savetime_min).as_ref());
return Some(Task::none());
}
match arg.parse::<i32>() {
@ -2032,7 +2032,7 @@ impl OpenCADStudio {
}
_ => self
.command_line
.push_error("Requires a non-negative number of minutes (0 = off)"),
.push_error(crate::t!("Requires a non-negative number of minutes (0 = off)").as_ref()),
}
}
"PDSIZE" => {
@ -2048,14 +2048,14 @@ impl OpenCADStudio {
let val_str = cmd.trim_start_matches("PDSIZE").trim();
if val_str.is_empty() {
let v = self.tabs[i].scene.document.header.point_display_size;
self.command_line.push_output(&format!("PDSIZE = {v:.4}"));
self.command_line.push_output(crate::tf!("PDSIZE = {v:.4}").as_ref());
} else if let Ok(v) = val_str.parse::<f64>() {
self.push_undo_snapshot(i, "PDSIZE");
self.tabs[i].scene.document.header.point_display_size = v;
self.tabs[i].scene.invalidate_point_dependencies();
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("PDSIZE set to {v:.4}"));
.push_output(crate::tf!("PDSIZE set to {v:.4}").as_ref());
} else {
self.command_line.push_error(
"Usage: PDSIZE [value] (>0 absolute size, <0 percent of viewport, 0 default)",
@ -2087,19 +2087,19 @@ impl OpenCADStudio {
_ => Err(()),
};
match parsed {
Err(_) => self.command_line.push_error("Usage: LWDISPLAY [ON|OFF]"),
Err(_) => self.command_line.push_error(crate::t!("Usage: LWDISPLAY [ON|OFF]").as_ref()),
Ok(Some(v)) => {
self.push_undo_snapshot(i, "LWDISPLAY");
self.tabs[i].scene.document.header.lineweight_display = v;
// No retessellate — the wire shader honours the flag via uniforms.
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("LWDISPLAY {}", if v { "ON" } else { "OFF" }));
.push_output(crate::tf!("LWDISPLAY {}", if v { "ON" } else { "OFF" }).as_ref());
}
Ok(None) => {
let v = self.tabs[i].scene.document.header.lineweight_display;
self.command_line
.push_output(&format!("LWDISPLAY = {}", if v { "ON" } else { "OFF" }));
.push_output(crate::tf!("LWDISPLAY = {}", if v { "ON" } else { "OFF" }).as_ref());
}
}
}
@ -2121,7 +2121,7 @@ impl OpenCADStudio {
.header
.current_entity_linetype_scale;
self.command_line
.push_output(&format!("CELTSCALE = {v:.4}"));
.push_output(crate::tf!("CELTSCALE = {v:.4}").as_ref());
} else if let Ok(v) = val_str.parse::<f64>() {
if v > 0.0 {
self.tabs[i]
@ -2131,13 +2131,13 @@ impl OpenCADStudio {
.current_entity_linetype_scale = v;
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("CELTSCALE set to {v:.4}"));
.push_output(crate::tf!("CELTSCALE set to {v:.4}").as_ref());
} else {
self.command_line
.push_error("CELTSCALE: value must be positive.");
.push_error(crate::t!("CELTSCALE: value must be positive.").as_ref());
}
} else {
self.command_line.push_error("Usage: CELTSCALE [value]");
self.command_line.push_error(crate::t!("Usage: CELTSCALE [value]").as_ref());
}
}
@ -2166,7 +2166,7 @@ impl OpenCADStudio {
.collect();
if selected_handles.is_empty() {
self.command_line
.push_error("SCALETEXT: select Text/MText entities first.");
.push_error(crate::t!("SCALETEXT: select Text/MText entities first.").as_ref());
} else {
let (use_absolute, value) = match (
parts.first().map(|s| s.to_uppercase()).as_deref(),
@ -2179,7 +2179,7 @@ impl OpenCADStudio {
if let Some(val) = value {
if val <= 0.0 {
self.command_line
.push_error("SCALETEXT: value must be positive.");
.push_error(crate::t!("SCALETEXT: value must be positive.").as_ref());
} else {
self.push_undo_snapshot(i, "SCALETEXT");
let mut count = 0usize;
@ -2206,17 +2206,17 @@ impl OpenCADStudio {
}
if count > 0 {
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SCALETEXT: scaled {count} text entity(ies)."
));
).as_ref());
} else {
self.command_line
.push_error("SCALETEXT: no Text/MText in selection.");
.push_error(crate::t!("SCALETEXT: no Text/MText in selection.").as_ref());
}
}
} else {
self.command_line
.push_info("Usage: SCALETEXT <factor> or SCALETEXT H <height>");
.push_info(crate::t!("Usage: SCALETEXT <factor> or SCALETEXT H <height>").as_ref());
}
}
}

View file

@ -4,7 +4,7 @@ impl OpenCADStudio {
pub(super) fn dispatch_view(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
match cmd {
"DONATE" => {
self.command_line.push_info("Opening Patreon page...");
self.command_line.push_info(crate::t!("Opening Patreon page...").as_ref());
return Some(crate::sys::open_url(
"https://patreon.com/HakanSeven12",
self.main_window,
@ -12,7 +12,7 @@ impl OpenCADStudio {
}
"WEBVERSION" => {
self.command_line.push_info("Opening OCS Web...");
self.command_line.push_info(crate::t!("Opening OCS Web...").as_ref());
return Some(crate::sys::open_url(
"https://hakanseven12.github.io/OpenCADStudio/",
self.main_window,
@ -21,7 +21,7 @@ impl OpenCADStudio {
"HELP" => {
self.command_line
.push_info("Opening OCS Discussions for help and questions...");
.push_info(crate::t!("Opening OCS Discussions for help and questions...").as_ref());
return Some(crate::sys::open_url(
"https://github.com/HakanSeven12/OpenCADStudio/discussions",
self.main_window,
@ -41,78 +41,78 @@ impl OpenCADStudio {
.map(|p| p.display().to_string())
.unwrap_or_else(|| "(unsaved)".to_string());
self.command_line
.push_output(&format!("Drawing: {}", path_label));
.push_output(crate::tf!("Drawing: {}", path_label).as_ref());
self.command_line
.push_output(&format!(" Created (Julian): {:.6}", h.create_date_julian));
.push_output(crate::tf!(" Created (Julian): {:.6}", h.create_date_julian).as_ref());
self.command_line
.push_output(&format!(" Updated (Julian): {:.6}", h.update_date_julian));
.push_output(crate::tf!(" Updated (Julian): {:.6}", h.update_date_julian).as_ref());
self.command_line
.push_output(&format!(" Total edit time: {:.4}", h.total_editing_time));
.push_output(crate::tf!(" Total edit time: {:.4}", h.total_editing_time).as_ref());
self.command_line
.push_output(&format!(" User elapsed: {:.4}", h.user_elapsed_time));
self.command_line.push_output(&format!(
.push_output(crate::tf!(" User elapsed: {:.4}", h.user_elapsed_time).as_ref());
self.command_line.push_output(crate::tf!(
" Last saved by: {}",
if h.last_saved_by.is_empty() {
"(unknown)"
} else {
&h.last_saved_by
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Fingerprint GUID: {}",
if h.fingerprint_guid.is_empty() {
"(none)"
} else {
&h.fingerprint_guid
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Version GUID: {}",
if h.version_guid.is_empty() {
"(none)"
} else {
&h.version_guid
}
));
).as_ref());
self.command_line
.push_output(&format!(" Code page: {}", h.code_page));
self.command_line.push_output(&format!(
.push_output(crate::tf!(" Code page: {}", h.code_page).as_ref());
self.command_line.push_output(crate::tf!(
" Menu name: {}",
if h.menu_name.is_empty() {
"(none)"
} else {
&h.menu_name
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Hyperlink base: {}",
if h.hyperlink_base.is_empty() {
"(none)"
} else {
&h.hyperlink_base
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Project name: {}",
if h.project_name.is_empty() {
"(none)"
} else {
&h.project_name
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Stylesheet: {}",
if h.stylesheet.is_empty() {
"(none)"
} else {
&h.stylesheet
}
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Required versions: {:#018x}",
h.required_versions
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" Measurement: {} ({})",
h.measurement,
if h.measurement == 1 {
@ -120,23 +120,23 @@ impl OpenCADStudio {
} else {
"Imperial"
}
));
).as_ref());
self.command_line
.push_output(&format!(" Proxy graphics: {}", h.proxy_graphics));
.push_output(crate::tf!(" Proxy graphics: {}", h.proxy_graphics).as_ref());
self.command_line
.push_output(&format!(" Tree depth: {}", h.tree_depth));
self.command_line.push_output(&format!(
.push_output(crate::tf!(" Tree depth: {}", h.tree_depth).as_ref());
self.command_line.push_output(crate::tf!(
" User vars (int): {} {} {} {} {}",
h.user_int1, h.user_int2, h.user_int3, h.user_int4, h.user_int5
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" User vars (real): {:.6} {:.6} {:.6} {:.6} {:.6}",
h.user_real1, h.user_real2, h.user_real3, h.user_real4, h.user_real5
));
self.command_line.push_output(&format!(
).as_ref());
self.command_line.push_output(crate::tf!(
" User timer: {}",
if h.user_timer { "On" } else { "Off" }
));
).as_ref());
}
// Edit a USERI1..USERI5 / USERR1..USERR5 slot. Lets the user
@ -174,9 +174,9 @@ impl OpenCADStudio {
_ => h.user_real5 = val,
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!("USERR{n} = {val}"));
self.command_line.push_output(crate::tf!("USERR{n} = {val}").as_ref());
} else {
self.command_line.push_info("Usage: USERR <1-5> <real>");
self.command_line.push_info(crate::t!("Usage: USERR <1-5> <real>").as_ref());
}
}
(Some(n @ 1..=5), v, false) => {
@ -189,14 +189,14 @@ impl OpenCADStudio {
_ => h.user_int5 = val,
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!("USERI{n} = {val}"));
self.command_line.push_output(crate::tf!("USERI{n} = {val}").as_ref());
} else {
self.command_line.push_info("Usage: USERI <1-5> <integer>");
self.command_line.push_info(crate::t!("Usage: USERI <1-5> <integer>").as_ref());
}
}
_ => self
.command_line
.push_info("Usage: USERI <1-5> <int> | USERR <1-5> <real>"),
.push_info(crate::t!("Usage: USERI <1-5> <int> | USERR <1-5> <real>").as_ref()),
}
}
@ -213,7 +213,7 @@ impl OpenCADStudio {
"https://github.com/HakanSeven12/OpenCADStudio/issues/new?body={}",
crate::sys::percent_encode(&body)
);
self.command_line.push_info("Opening feedback page...");
self.command_line.push_info(crate::t!("Opening feedback page...").as_ref());
return Some(crate::sys::open_url(&url, self.main_window));
}
@ -226,7 +226,7 @@ impl OpenCADStudio {
}
"CHANGELOG" => {
self.command_line.push_info("Opening release notes...");
self.command_line.push_info(crate::t!("Opening release notes...").as_ref());
return Some(crate::sys::open_url(
"https://github.com/HakanSeven12/OpenCADStudio/releases",
self.main_window,
@ -266,12 +266,12 @@ impl OpenCADStudio {
let text: String = keys.iter().map(|(k, v)| format!("{k} {v}\n")).collect();
let count = self.shortcut_overrides.len();
match std::fs::write(path, text) {
Ok(()) => self.command_line.push_output(&format!(
Ok(()) => self.command_line.push_output(crate::tf!(
"CUIEXPORT: wrote {count} shortcut(s) to \"{path}\"."
)),
).as_ref()),
Err(e) => self
.command_line
.push_error(&format!("CUIEXPORT: cannot write \"{path}\": {e}")),
.push_error(crate::tf!("CUIEXPORT: cannot write \"{path}\": {e}").as_ref()),
}
}
@ -308,13 +308,13 @@ impl OpenCADStudio {
n += 1;
}
}
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"CUIIMPORT: loaded {n} shortcut(s) from \"{path}\"."
));
).as_ref());
}
Err(e) => self
.command_line
.push_error(&format!("CUIIMPORT: cannot read \"{path}\": {e}")),
.push_error(crate::tf!("CUIIMPORT: cannot read \"{path}\": {e}").as_ref()),
}
}
@ -333,28 +333,28 @@ impl OpenCADStudio {
let key = parts.get(1).map(|s| s.to_uppercase()).unwrap_or_default();
let cmd_str = parts.get(2).map(|s| s.to_uppercase()).unwrap_or_default();
if key.is_empty() || cmd_str.is_empty() {
self.command_line.push_error("Usage: SHORTCUTS SET <key> <command> e.g. SHORTCUTS SET CTRL+D DIST");
self.command_line.push_error(crate::t!("Usage: SHORTCUTS SET <key> <command> e.g. SHORTCUTS SET CTRL+D DIST").as_ref());
} else {
self.shortcut_overrides.insert(key.clone(), cmd_str.clone());
self.command_line
.push_output(&format!("Shortcut set: {key} → {cmd_str}"));
.push_output(crate::tf!("Shortcut set: {key} → {cmd_str}").as_ref());
}
}
"CLEAR" | "DELETE" | "REMOVE" => {
let key = parts.get(1).map(|s| s.to_uppercase()).unwrap_or_default();
if key.is_empty() {
self.command_line.push_error("Usage: SHORTCUTS CLEAR <key>");
self.command_line.push_error(crate::t!("Usage: SHORTCUTS CLEAR <key>").as_ref());
} else if self.shortcut_overrides.remove(&key).is_some() {
self.command_line
.push_output(&format!("Shortcut '{key}' removed."));
.push_output(crate::tf!("Shortcut '{key}' removed.").as_ref());
} else {
self.command_line
.push_error(&format!("Shortcut '{key}' not found."));
.push_error(crate::tf!("Shortcut '{key}' not found.").as_ref());
}
}
_ => {
self.command_line
.push_info("Usage: SHORTCUTS LIST | SET <key> <cmd> | CLEAR <key>");
.push_info(crate::t!("Usage: SHORTCUTS LIST | SET <key> <cmd> | CLEAR <key>").as_ref());
}
}
}
@ -396,17 +396,17 @@ impl OpenCADStudio {
return Some(Task::none());
}
_ => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"COLORSCHEME: unknown theme '{}'. Type COLORSCHEME LIST for options.",
sub
));
).as_ref());
return Some(Task::none());
}
};
if let Some(t) = theme {
let name = format!("{:?}", t);
self.command_line
.push_output(&format!("Color scheme set to '{name}'."));
.push_output(crate::tf!("Color scheme set to '{name}'.").as_ref());
return Some(Task::done(Message::SetTheme(t)));
}
return Some(Task::none());
@ -421,7 +421,7 @@ impl OpenCADStudio {
"MVIEW" => {
if self.tabs[i].scene.current_layout == "Model" {
self.command_line
.push_error("MVIEW: switch to a paper space layout first.");
.push_error(crate::t!("MVIEW: switch to a paper space layout first.").as_ref());
} else {
use crate::modules::layout::mview::MviewCommand;
let scene = &self.tabs[i].scene;
@ -464,7 +464,7 @@ impl OpenCADStudio {
if sub.is_empty() {
self.awaiting_vports = true;
self.command_line
.push_info("VPORTS Configuration [SIngle/2H/2V/4]:");
.push_info(crate::t!("VPORTS Configuration [SIngle/2H/2V/4]:").as_ref());
return Some(self.focus_cmd_input());
}
// Model space: split the tiled viewport layout via pane_grid.
@ -494,11 +494,11 @@ impl OpenCADStudio {
self.tabs[i].scene.set_model_panes(config);
self.tabs[i].scene.camera_generation += 1;
self.command_line
.push_output(&format!("VPORTS: {n} viewport(s)."));
.push_output(crate::tf!("VPORTS: {n} viewport(s).").as_ref());
}
None => {
self.command_line
.push_error("VPORTS: use SINGLE | 2H | 2V | 4.");
.push_error(crate::t!("VPORTS: use SINGLE | 2H | 2V | 4.").as_ref());
}
}
} else if sub.is_empty() {
@ -532,23 +532,23 @@ impl OpenCADStudio {
})
.collect();
if viewports.is_empty() {
self.command_line.push_info("No viewports. Use MVIEW to create one, or VPORTS 2H / 2V / 4 / SINGLE.");
self.command_line.push_info(crate::t!("No viewports. Use MVIEW to create one, or VPORTS 2H / 2V / 4 / SINGLE.").as_ref());
} else {
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{} viewport(s) in layout \"{}\":",
viewports.len(),
scene.current_layout
));
).as_ref());
for (id, center, w, h, scale, is_on, locked) in &viewports {
let state = match (is_on, locked) {
(true, true) => "On, Locked",
(true, false) => "On",
(false, _) => "Off",
};
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
" VP #{id}: {w:.1}×{h:.1} @ ({:.1},{:.1}) scale={scale:.4} [{state}]",
center.x, center.y
));
).as_ref());
}
}
} else {
@ -654,7 +654,7 @@ impl OpenCADStudio {
self.tabs[i].scene.auto_fit_viewport(handle);
}
Err(e) => {
self.command_line.push_error(&format!("VPORTS: {e}"));
self.command_line.push_error(crate::tf!("VPORTS: {e}").as_ref());
}
}
}
@ -686,11 +686,11 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"VPORTS: created {} viewport(s) [{}].",
rects.len(),
sub
));
).as_ref());
}
}
}
@ -700,10 +700,10 @@ impl OpenCADStudio {
let scene = &self.tabs[i].scene;
if scene.current_layout == "Model" {
self.command_line
.push_error("VPLAYER: switch to a paper space layout first.");
.push_error(crate::t!("VPLAYER: switch to a paper space layout first.").as_ref());
} else if scene.active_viewport.is_none() {
self.command_line
.push_error("VPLAYER: enter a viewport first (double-click or MS).");
.push_error(crate::t!("VPLAYER: enter a viewport first (double-click or MS).").as_ref());
} else {
use crate::modules::layout::vplayer::VplayerCommand;
let vp_handle = scene.active_viewport.unwrap();
@ -729,12 +729,12 @@ impl OpenCADStudio {
};
if frozen_names.is_empty() {
self.command_line
.push_info("VPLAYER: no frozen layers in active viewport.");
.push_info(crate::t!("VPLAYER: no frozen layers in active viewport.").as_ref());
} else {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"VPLAYER: frozen layers: {}",
frozen_names.join(", ")
));
).as_ref());
}
let new_cmd = VplayerCommand::new(vp_handle);
self.command_line.push_info(&new_cmd.prompt());
@ -763,7 +763,7 @@ impl OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_info(&format!("{cmd}: no text or dimension objects."));
.push_info(crate::tf!("{cmd}: no text or dimension objects.").as_ref());
return Some(Task::none());
}
self.tabs[i].scene.replace_selection(handles);
@ -802,7 +802,7 @@ impl OpenCADStudio {
.collect();
if selected.is_empty() {
self.command_line
.push_error("DRAWORDER: select entities first.");
.push_error(crate::t!("DRAWORDER: select entities first.").as_ref());
} else {
// Parse relative target handle for ABOVE/UNDER.
let relative_target: Option<(bool, acadrust::Handle)> = match option.as_str() {
@ -940,12 +940,12 @@ impl OpenCADStudio {
}
}
let rel = if above { "above" } else { "below" };
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"DRAWORDER: moved {} entities {} {:x}.",
selected.len(),
rel,
target.value()
));
).as_ref());
} else if let Some(to_front) = to_front_opt {
let (min_eff, max_eff) = fb_baseline.unwrap_or((1, 0));
for (k, h) in selected.iter().enumerate() {
@ -957,11 +957,11 @@ impl OpenCADStudio {
table.add_entry(*h, acadrust::Handle::new(sort));
}
let dir = if to_front { "front" } else { "back" };
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"DRAWORDER: moved {} entities to {}.",
selected.len(),
dir
));
).as_ref());
}
}
// Sort order lives in SortEntitiesTable, which the
@ -974,7 +974,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
} else {
self.command_line.push_info(
"Usage: DRAWORDER F|FRONT | B|BACK | A|ABOVE <handle> | U|UNDER <handle>"
crate::t!("Usage: DRAWORDER F|FRONT | B|BACK | A|ABOVE <handle> | U|UNDER <handle>").as_ref()
);
}
}
@ -1000,7 +1000,7 @@ impl OpenCADStudio {
Some(acadrust::EntityType::Viewport(vp)) => vp.clone(),
_ => {
self.command_line
.push_error("SYNCPVIEWPORTS: master is not a viewport.");
.push_error(crate::t!("SYNCPVIEWPORTS: master is not a viewport.").as_ref());
return Some(Task::none());
}
};
@ -1023,9 +1023,9 @@ impl OpenCADStudio {
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SYNCPVIEWPORTS: synced {n} viewport(s) to the master."
));
).as_ref());
}
// HIDE — hidden-line view of the active viewport.
@ -1088,9 +1088,9 @@ impl CadCommand for DrawOrderRefCommand {
fn prompt(&self) -> String {
if self.above {
"DRAWORDER Select reference object (move selection above):".into()
crate::t!("DRAWORDER Select reference object (move selection above):").into_owned()
} else {
"DRAWORDER Select reference object (move selection under):".into()
crate::t!("DRAWORDER Select reference object (move selection under):").into_owned()
}
}

View file

@ -10,6 +10,7 @@ use crate::ui::{LayerPanel, PropertiesPanel};
use acadrust::tables::Ucs;
use acadrust::{CadDocument, EntityType, Handle};
use iced;
use crate::t;
use std::any::Any;
use std::collections::HashMap;
use std::path::PathBuf;
@ -496,7 +497,13 @@ impl DocumentTab {
.unwrap_or_default()
.to_string_lossy()
.to_string(),
None => self.tab_title.clone(),
None => {
if self.is_start {
t!("Start").into_owned()
} else {
self.tab_title.clone()
}
}
}
}
}

View file

@ -131,9 +131,9 @@ impl OpenCADStudio {
"Replaced 1 occurrence in {}; {remaining} matching object(s) remain.",
match_label(target)
);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"FIND/REPLACE: replaced 1 occurrence of \"{search}\"."
));
).as_ref());
self.refresh_properties();
}
@ -188,9 +188,9 @@ impl OpenCADStudio {
"Replaced {replaced} occurrence(s) in {} object(s).",
changed.len()
);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"FIND/REPLACE: replaced {replaced} occurrence(s) of \"{search}\"."
));
).as_ref());
self.refresh_properties();
}

View file

@ -360,7 +360,7 @@ pub(super) fn next_group_auto_name(scene: &crate::scene::Scene) -> String {
// ── Entity type labels ─────────────────────────────────────────────────────
pub(super) fn entity_type_label(entity: &acadrust::EntityType) -> String {
crate::entities::names::ui_name_or_class(entity)
crate::t!(crate::entities::names::ui_name_or_class(entity)).into_owned()
}
pub(super) fn entity_type_key(entity: &acadrust::EntityType) -> String {

View file

@ -1020,7 +1020,7 @@ impl OpenCADStudio {
let available = self.tabs[i].history.undo_stack.len();
let steps = steps.min(available);
if steps == 0 {
self.command_line.push_info("Nothing to undo.");
self.command_line.push_info(crate::t!("Nothing to undo.").as_ref());
return;
}
@ -1069,7 +1069,7 @@ impl OpenCADStudio {
}
self.finish_history_apply(i, had_full, layer_panel_changed, &changes);
self.command_line
.push_output(&format!("Undo: {last_label}"));
.push_output(crate::tf!("Undo: {last_label}").as_ref());
}
pub(super) fn redo_steps(&mut self, steps: usize) {
@ -1078,7 +1078,7 @@ impl OpenCADStudio {
let available = self.tabs[i].history.redo_stack.len();
let steps = steps.min(available);
if steps == 0 {
self.command_line.push_info("Nothing to redo.");
self.command_line.push_info(crate::t!("Nothing to redo.").as_ref());
return;
}
@ -1124,7 +1124,7 @@ impl OpenCADStudio {
}
self.finish_history_apply(i, had_full, layer_panel_changed, &changes);
self.command_line
.push_output(&format!("Redo: {last_label}"));
.push_output(crate::tf!("Redo: {last_label}").as_ref());
}
}

View file

@ -3019,7 +3019,7 @@ impl OpenCADStudio {
for (id, res) in crate::plugin::external::load_at_startup(&mut app) {
if let Err(e) = res {
app.command_line
.push_error(&format!("Plugin '{id}' failed to load: {e}"));
.push_error(crate::tf!("Plugin '{id}' failed to load: {e}").as_ref());
app.plugin_load_errors.insert(id, e);
}
}

View file

@ -38,7 +38,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 2 {
self.command_line
.push_error("Boolean: select exactly two solids created this session.");
.push_error(crate::t!("Boolean: select exactly two solids created this session.").as_ref());
return Task::none();
}
let a = self.tabs[i].scene.solid_models[&handles[0]].clone();
@ -50,7 +50,7 @@ impl super::OpenCADStudio {
};
let Some(result) = solid_model::boolean(kind, &a, &b) else {
self.command_line
.push_error("Boolean failed — the solids may not overlap.");
.push_error(crate::t!("Boolean failed — the solids may not overlap.").as_ref());
return Task::none();
};
@ -87,7 +87,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 1 {
self.command_line
.push_error("SLICE: select exactly one solid created this session.");
.push_error(crate::t!("SLICE: select exactly one solid created this session.").as_ref());
return Task::none();
}
let solid = self.tabs[i].scene.solid_models[&handles[0]].clone();
@ -105,7 +105,7 @@ impl super::OpenCADStudio {
}
if min[0] > max[0] {
self.command_line
.push_error("SLICE: could not determine the solid's extent.");
.push_error(crate::t!("SLICE: could not determine the solid's extent.").as_ref());
return Task::none();
}
// Generous margin so the box fully spans the solid in the free axes.
@ -123,7 +123,7 @@ impl super::OpenCADStudio {
}
if hi[axis] <= lo[axis] {
self.command_line
.push_error("SLICE: the plane does not cross the solid on the kept side.");
.push_error(crate::t!("SLICE: the plane does not cross the solid on the kept side.").as_ref());
return Task::none();
}
let center = [
@ -134,7 +134,7 @@ impl super::OpenCADStudio {
let halfspace = solid_model::box_solid(center, hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]);
let Some(result) = solid_model::boolean(Bool::Intersect, &solid, &halfspace) else {
self.command_line
.push_error("SLICE failed — the plane may not cross the solid.");
.push_error(crate::t!("SLICE failed — the plane may not cross the solid.").as_ref());
return Task::none();
};
self.push_undo_snapshot(i, "SLICE");
@ -149,10 +149,10 @@ impl super::OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
let ax = ["X", "Y", "Z"][axis];
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SLICE: cut at {ax}={value}, kept the {} half.",
if keep_low { "lower" } else { "upper" }
));
).as_ref());
Task::none()
}
@ -169,7 +169,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 2 {
self.command_line
.push_error("INTERFERE: select exactly two solids created this session.");
.push_error(crate::t!("INTERFERE: select exactly two solids created this session.").as_ref());
return Task::none();
}
let a = self.tabs[i].scene.solid_models[&handles[0]].clone();
@ -184,11 +184,11 @@ impl super::OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output("INTERFERE: created an interference solid from the overlap.");
.push_output(crate::t!("INTERFERE: created an interference solid from the overlap.").as_ref());
}
None => self
.command_line
.push_output("INTERFERE: the selected solids do not overlap."),
.push_output(crate::t!("INTERFERE: the selected solids do not overlap.").as_ref()),
}
Task::none()
}
@ -208,7 +208,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 1 {
self.command_line
.push_error("3DROTATE: select exactly one solid created this session.");
.push_error(crate::t!("3DROTATE: select exactly one solid created this session.").as_ref());
return Task::none();
}
let solid = self.tabs[i].scene.solid_models[&handles[0]].clone();
@ -225,7 +225,7 @@ impl super::OpenCADStudio {
}
if min[0] > max[0] {
self.command_line
.push_error("3DROTATE: could not determine the solid's extent.");
.push_error(crate::t!("3DROTATE: could not determine the solid's extent.").as_ref());
return Task::none();
}
let origin = Point3::new(
@ -250,10 +250,10 @@ impl super::OpenCADStudio {
}
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"3DROTATE: rotated {angle_deg}° about the {} axis.",
["X", "Y", "Z"][axis]
));
).as_ref());
Task::none()
}
@ -280,7 +280,7 @@ impl super::OpenCADStudio {
});
let Some((handle, pts, closed)) = found else {
self.command_line
.push_error("POLYSOLID: select a polyline first.");
.push_error(crate::t!("POLYSOLID: select a polyline first.").as_ref());
return Task::none();
};
let mut segs: Vec<([f64; 2], [f64; 2])> = pts.windows(2).map(|w| (w[0], w[1])).collect();
@ -308,7 +308,7 @@ impl super::OpenCADStudio {
}
let Some(result) = acc else {
self.command_line
.push_error("POLYSOLID: the polyline has no usable segments.");
.push_error(crate::t!("POLYSOLID: the polyline has no usable segments.").as_ref());
return Task::none();
};
self.push_undo_snapshot(i, "POLYSOLID");
@ -322,9 +322,9 @@ impl super::OpenCADStudio {
}
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"POLYSOLID: built a wall solid from {used} segment(s) (width {width}, height {height})."
));
).as_ref());
Task::none()
}
@ -344,7 +344,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 1 {
self.command_line
.push_error("3DMIRROR: select exactly one solid created this session.");
.push_error(crate::t!("3DMIRROR: select exactly one solid created this session.").as_ref());
return Task::none();
}
let solid = self.tabs[i].scene.solid_models[&handles[0]].clone();
@ -361,7 +361,7 @@ impl super::OpenCADStudio {
}
if min[0] > max[0] {
self.command_line
.push_error("3DMIRROR: could not determine the solid's extent.");
.push_error(crate::t!("3DMIRROR: could not determine the solid's extent.").as_ref());
return Task::none();
}
let c = TVec3::new(
@ -390,10 +390,10 @@ impl super::OpenCADStudio {
}
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"3DMIRROR: added a mirror across the {} plane.",
["X", "Y", "Z"][axis]
));
).as_ref());
Task::none()
}
@ -417,7 +417,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 1 {
self.command_line
.push_error("3DALIGN: select exactly one solid created this session.");
.push_error(crate::t!("3DALIGN: select exactly one solid created this session.").as_ref());
return Task::none();
}
// Build a right-handed frame (origin + orthonormal axes) from 3 points.
@ -440,7 +440,7 @@ impl super::OpenCADStudio {
};
let (Some(s), Some(d)) = (frame(src), frame(dst)) else {
self.command_line
.push_error("3DALIGN: each point triple must be non-coincident and non-collinear.");
.push_error(crate::t!("3DALIGN: each point triple must be non-coincident and non-collinear.").as_ref());
return Task::none();
};
let a = (d * s.inverse()).to_cols_array(); // column-major [f64; 16]
@ -462,7 +462,7 @@ impl super::OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output("3DALIGN: aligned the solid to the destination points.");
.push_output(crate::t!("3DALIGN: aligned the solid to the destination points.").as_ref());
Task::none()
}
@ -487,7 +487,7 @@ impl super::OpenCADStudio {
.collect();
if handles.len() != 1 {
self.command_line
.push_error("SECTION: select exactly one solid created this session.");
.push_error(crate::t!("SECTION: select exactly one solid created this session.").as_ref());
return Task::none();
}
let solid = self.tabs[i].scene.solid_models[&handles[0]].clone();
@ -504,7 +504,7 @@ impl super::OpenCADStudio {
}
if min[0] > max[0] {
self.command_line
.push_error("SECTION: could not determine the solid's extent.");
.push_error(crate::t!("SECTION: could not determine the solid's extent.").as_ref());
return Task::none();
}
// Margin so the cutting plane fully spans the solid in the free axes.
@ -546,7 +546,7 @@ impl super::OpenCADStudio {
.collect();
let Ok(face) = builder::try_attach_plane(&[wire]) else {
self.command_line
.push_error("SECTION: could not build the cutting plane.");
.push_error(crate::t!("SECTION: could not build the cutting plane.").as_ref());
return Task::none();
};
let shell: Shell = std::iter::once(face).collect();
@ -556,7 +556,7 @@ impl super::OpenCADStudio {
let segs = solid_mesh.extract_interference(&plane_mesh);
if segs.is_empty() {
self.command_line
.push_output("SECTION: the plane does not cross the solid.");
.push_output(crate::t!("SECTION: the plane does not cross the solid.").as_ref());
return Task::none();
}
self.push_undo_snapshot(i, "SECTION");
@ -569,11 +569,11 @@ impl super::OpenCADStudio {
}
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"SECTION: created {} section line(s) at {}={value}.",
segs.len(),
["X", "Y", "Z"][axis]
));
).as_ref());
Task::none()
}
@ -581,7 +581,7 @@ impl super::OpenCADStudio {
#[cfg(not(feature = "solid3d"))]
pub(super) fn solid_section(&mut self, _axis: usize, _value: f64) -> Task<Message> {
self.command_line
.push_error("SECTION: solid modelling is unavailable in this build.");
.push_error(crate::t!("SECTION: solid modelling is unavailable in this build.").as_ref());
Task::none()
}
@ -604,7 +604,7 @@ impl super::OpenCADStudio {
let n = sides.max(3);
if radius <= 0.0 || height <= 0.0 {
self.command_line
.push_error("PYRAMID: radius and height must be positive.");
.push_error(crate::t!("PYRAMID: radius and height must be positive.").as_ref());
return Task::none();
}
let corners: Vec<Point3> = (0..n)
@ -642,7 +642,7 @@ impl super::OpenCADStudio {
}
if faces.len() < n + 1 {
self.command_line
.push_error("PYRAMID: could not build all faces.");
.push_error(crate::t!("PYRAMID: could not build all faces.").as_ref());
return Task::none();
}
let shell = Shell::from(faces);
@ -655,12 +655,12 @@ impl super::OpenCADStudio {
} = truck_tess::tessellate_shell(&shell)
else {
self.command_line
.push_error("PYRAMID: tessellation failed.");
.push_error(crate::t!("PYRAMID: tessellation failed.").as_ref());
return Task::none();
};
if verts.is_empty() {
self.command_line
.push_error("PYRAMID: tessellation produced no geometry.");
.push_error(crate::t!("PYRAMID: tessellation produced no geometry.").as_ref());
return Task::none();
}
self.push_undo_snapshot(i, "PYRAMID");
@ -682,9 +682,9 @@ impl super::OpenCADStudio {
.insert(new_handle, crate::scene::MeshLodSet::from_single(mesh));
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"PYRAMID: created a {n}-sided pyramid (radius {radius}, height {height})."
));
).as_ref());
Task::none()
}
@ -713,12 +713,12 @@ impl super::OpenCADStudio {
});
let Some((handle, fit)) = found else {
self.command_line
.push_error("SPLINEFIT: select a polyline to fit a spline through.");
.push_error(crate::t!("SPLINEFIT: select a polyline to fit a spline through.").as_ref());
return Task::none();
};
if fit.len() < 3 {
self.command_line
.push_error("SPLINEFIT: need at least 3 points.");
.push_error(crate::t!("SPLINEFIT: need at least 3 points.").as_ref());
return Task::none();
}
let n = fit.len();
@ -756,7 +756,7 @@ impl super::OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("SPLINEFIT: fit a spline through {n} points."));
.push_output(crate::tf!("SPLINEFIT: fit a spline through {n} points.").as_ref());
Task::none()
}
@ -776,7 +776,7 @@ impl super::OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("FLATSHOT: select a solid created this session.");
.push_error(crate::t!("FLATSHOT: select a solid created this session.").as_ref());
return Task::none();
}
self.push_undo_snapshot(i, "FLATSHOT");
@ -797,7 +797,7 @@ impl super::OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("FLATSHOT: created {n} projected edge(s) at Z=0."));
.push_output(crate::tf!("FLATSHOT: created {n} projected edge(s) at Z=0.").as_ref());
Task::none()
}
@ -816,7 +816,7 @@ impl super::OpenCADStudio {
.collect();
if handles.is_empty() {
self.command_line
.push_error("CONVTOSURFACE: select a solid created this session.");
.push_error(crate::t!("CONVTOSURFACE: select a solid created this session.").as_ref());
return Task::none();
}
let mut surfaces: Vec<Surface> = Vec::new();
@ -848,7 +848,7 @@ impl super::OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("CONVTOSURFACE: converted {n} solid(s) to surface(s)."));
.push_output(crate::tf!("CONVTOSURFACE: converted {n} solid(s) to surface(s).").as_ref());
Task::none()
}
}

View file

@ -595,7 +595,7 @@ mod tests {
}
impl ocs_plugin_api::host::InteractiveCommand for PlacePoint {
fn prompt(&self) -> String {
"Pick a point".into()
crate::t!("Pick a point").into_owned()
}
fn on_point(&mut self, pt: [f64; 3]) -> ocs_plugin_api::host::CommandStep {
use ocs_plugin_api::host::CommandStep;
@ -632,7 +632,7 @@ mod tests {
struct PickThenMark;
impl ocs_plugin_api::host::InteractiveCommand for PickThenMark {
fn prompt(&self) -> String {
"Pick an object".into()
crate::t!("Pick an object").into_owned()
}
fn on_point(&mut self, _pt: [f64; 3]) -> ocs_plugin_api::host::CommandStep {
ocs_plugin_api::host::CommandStep::Cancel

View file

@ -4,6 +4,7 @@ use crate::io::linetypes;
use crate::scene::view::dispatch;
use crate::ui;
use acadrust::{EntityType, Handle};
use crate::t;
/// Above this many selected objects the Properties panel skips per-entity
/// property aggregation (which is O(n) per row, plus an O(n²) group filter) and
@ -259,30 +260,30 @@ impl OpenCADStudio {
};
let sections = vec![
PropSection {
title: "General".to_string(),
title: t!("General").into_owned(),
props: vec![
read_only("AC Version", doc.version.as_str().to_string()),
read_only(t!("AC Version").as_ref(), doc.version.as_str().to_string()),
Property {
label: "Color".to_string(),
label: t!("Color").into_owned(),
field: "color",
value: PropValue::ColorChoice(header.current_entity_color),
},
Property {
label: "Layer".to_string(),
label: t!("Layer").into_owned(),
field: "layer",
value: PropValue::LayerChoice(current_layer),
},
Property {
label: "Linetype".to_string(),
label: t!("Linetype").into_owned(),
field: "linetype",
value: PropValue::LinetypeChoice(current_linetype),
},
read_only(
"Linetype scale",
t!("Linetype scale").as_ref(),
format_length(header.current_entity_linetype_scale),
),
Property {
label: "Lineweight".to_string(),
label: t!("Lineweight").into_owned(),
field: "line_weight",
value: PropValue::LwChoice(
acadrust::types::LineWeight::from_value(
@ -290,21 +291,21 @@ impl OpenCADStudio {
),
),
},
read_only("Transparency", "ByLayer".to_string()),
read_only("Thickness", format_length(header.thickness)),
read_only(t!("Transparency").as_ref(), "ByLayer".to_string()),
read_only(t!("Thickness").as_ref(), format_length(header.thickness)),
],
},
PropSection {
title: "3D Visualization".to_string(),
props: vec![read_only("Material", material)],
title: t!("3D Visualization").into_owned(),
props: vec![read_only(t!("Material").as_ref(), material)],
},
PropSection {
title: "Plot style".to_string(),
title: t!("Plot style").into_owned(),
props: vec![
read_only("Plot style", plot_style.to_string()),
read_only("Plot style table", plot_table.clone()),
read_only(t!("Plot style").as_ref(), plot_style.to_string()),
read_only(t!("Plot style table").as_ref(), plot_table.clone()),
read_only(
"Plot table attached to",
t!("Plot table attached to").as_ref(),
if plot_table == "None" {
"None".to_string()
} else {
@ -312,7 +313,7 @@ impl OpenCADStudio {
},
),
read_only(
"Plot table type",
t!("Plot table type").as_ref(),
if header.plotstyle_mode {
"Named plot styles".to_string()
} else {
@ -322,39 +323,39 @@ impl OpenCADStudio {
],
},
PropSection {
title: "View".to_string(),
title: t!("View").into_owned(),
props: vec![
read_only("Center X", format_length(camera.target.x)),
read_only("Center Y", format_length(camera.target.y)),
read_only("Center Z", format_length(camera.target.z)),
read_only("Height", format_length(view_height)),
read_only("Width", format_length(view_width)),
read_only(t!("Center X").as_ref(), format_length(camera.target.x)),
read_only(t!("Center Y").as_ref(), format_length(camera.target.y)),
read_only(t!("Center Z").as_ref(), format_length(camera.target.z)),
read_only(t!("Height").as_ref(), format_length(view_height)),
read_only(t!("Width").as_ref(), format_length(view_width)),
],
},
PropSection {
title: "Misc".to_string(),
title: t!("Misc").into_owned(),
props: vec![
read_only("Annotation scale", annotation_scale),
read_only(t!("Annotation scale").as_ref(), annotation_scale),
read_only(
"UCS icon On",
t!("UCS icon On").as_ref(),
if self.show_ucs_icon { "Yes" } else { "No" }.to_string(),
),
read_only(
"UCS icon at origin",
t!("UCS icon at origin").as_ref(),
if self.ucs_icon_at_origin { "Yes" } else { "No" }
.to_string(),
),
read_only(
"UCS per viewport",
t!("UCS per viewport").as_ref(),
if ucs_per_viewport { "Yes" } else { "No" }.to_string(),
),
read_only("UCS Name", ucs_name),
read_only("Visual Style", tab.visual_style.clone()),
read_only(t!("UCS Name").as_ref(), ucs_name),
read_only(t!("Visual Style").as_ref(), tab.visual_style.clone()),
],
},
];
ui::PropertiesPanel {
title: "No selection".to_string(),
title: t!("No selection").into_owned(),
sections,
layer_combo: iced::widget::combo_box::State::new(layer_names.clone()),
linetype_combo: iced::widget::combo_box::State::new(
@ -435,61 +436,61 @@ impl OpenCADStudio {
{
use crate::entities::common::ro_prop;
sections.push(crate::scene::model::object::PropSection {
title: "Material Details".to_string(),
title: t!("Material Details").into_owned(),
props: vec![
ro_prop("Name", "mat_name", material.name.clone()),
ro_prop(t!("Name").as_ref(), "mat_name", material.name.clone()),
ro_prop(
"Description",
t!("Description").as_ref(),
"mat_description",
material.description.clone(),
),
ro_prop(
"Ambient",
t!("Ambient").as_ref(),
"mat_ambient",
material_color_text(&material.ambient_color),
),
ro_prop(
"Diffuse",
t!("Diffuse").as_ref(),
"mat_diffuse",
material_color_text(&material.diffuse_color),
),
ro_prop(
"Specular",
t!("Specular").as_ref(),
"mat_specular",
material_color_text(&material.specular_color),
),
ro_prop(
"Gloss",
t!("Gloss").as_ref(),
"mat_gloss",
format!("{:.3}", material.specular_gloss_factor),
),
ro_prop(
"Opacity",
t!("Opacity").as_ref(),
"mat_opacity",
format!("{:.3}", material.opacity_percent),
),
ro_prop(
"Reflectivity",
t!("Reflectivity").as_ref(),
"mat_reflectivity",
format!("{:.3}", material.reflectivity),
),
ro_prop(
"Translucence",
t!("Translucence").as_ref(),
"mat_translucence",
format!("{:.3}", material.translucence),
),
ro_prop(
"Refraction",
t!("Refraction").as_ref(),
"mat_refraction",
format!("{:.3}", material.refraction_index),
),
ro_prop(
"Self Illumination",
t!("Self Illumination").as_ref(),
"mat_self_illumination",
format!("{:.3}", material.self_illumination),
),
ro_prop(
"Luminance",
t!("Luminance").as_ref(),
"mat_luminance",
format!(
"{:.3} (mode {})",
@ -497,42 +498,42 @@ impl OpenCADStudio {
),
),
ro_prop(
"Diffuse Map",
t!("Diffuse Map").as_ref(),
"mat_diffuse_map",
material_map_text(&material.diffuse_map),
),
ro_prop(
"Specular Map",
t!("Specular Map").as_ref(),
"mat_specular_map",
material_map_text(&material.specular_map),
),
ro_prop(
"Reflection Map",
t!("Reflection Map").as_ref(),
"mat_reflection_map",
material_map_text(&material.reflection_map),
),
ro_prop(
"Opacity Map",
t!("Opacity Map").as_ref(),
"mat_opacity_map",
material_map_text(&material.opacity_map),
),
ro_prop(
"Bump Map",
t!("Bump Map").as_ref(),
"mat_bump_map",
material_map_text(&material.bump_map),
),
ro_prop(
"Refraction Map",
t!("Refraction Map").as_ref(),
"mat_refraction_map",
material_map_text(&material.refraction_map),
),
ro_prop(
"Normal Map",
t!("Normal Map").as_ref(),
"mat_normal_map",
material_map_text(&material.normal_map),
),
ro_prop(
"Render Flags",
t!("Render Flags").as_ref(),
"mat_render_flags",
format!(
"illumination {}; channels {}; mode {}; two-sided {}",
@ -543,7 +544,7 @@ impl OpenCADStudio {
),
),
ro_prop(
"Advanced",
t!("Advanced").as_ref(),
"mat_advanced",
format!(
"normal {:.3}; bump {:.3}; reflect {:.3}; transmit {:.3}",
@ -578,16 +579,16 @@ impl OpenCADStudio {
}
use crate::entities::common::ro_prop;
sections.push(crate::scene::model::object::PropSection {
title: "Color Book".to_string(),
title: t!("Color Book").into_owned(),
props: vec![
ro_prop("Book", "book_color_book", book.book_name.clone()),
ro_prop(t!("Book").as_ref(), "book_color_book", book.book_name.clone()),
ro_prop(
"Color Name",
t!("Color Name").as_ref(),
"book_color_name",
book.color_name.clone(),
),
ro_prop(
"Color",
t!("Color").as_ref(),
"book_color_value",
format!("{:?}", book.color),
),
@ -616,25 +617,25 @@ impl OpenCADStudio {
};
use crate::entities::common::ro_prop;
sections.push(crate::scene::model::object::PropSection {
title: format!("{scope} Visual Style"),
title: t!("%{scope} Visual Style", scope = scope).into_owned(),
props: vec![
ro_prop(
"Handle",
t!("Handle").as_ref(),
"vs_handle",
format!("{:X}", handle.value()),
),
ro_prop(
"Description",
t!("Description").as_ref(),
"vs_description",
style.description.clone(),
),
ro_prop(
"Type",
t!("Type").as_ref(),
"vs_type",
style.style_type.to_string(),
),
ro_prop(
"Face",
t!("Face").as_ref(),
"vs_face",
format!(
"lighting {}; quality {}; color {}; modifiers {}",
@ -645,7 +646,7 @@ impl OpenCADStudio {
),
),
ro_prop(
"Edges",
t!("Edges").as_ref(),
"vs_edges",
format!(
"model {}; style {}",
@ -653,17 +654,17 @@ impl OpenCADStudio {
),
),
ro_prop(
"Extended Lighting",
t!("Extended Lighting").as_ref(),
"vs_extended_lighting",
style.extended_lighting_model.to_string(),
),
ro_prop(
"Internal",
t!("Internal").as_ref(),
"vs_internal",
style.internal_use_only.to_string(),
),
ro_prop(
"Property Bag",
t!("Property Bag").as_ref(),
"vs_properties",
visual_style_properties_text(style),
),
@ -692,22 +693,22 @@ impl OpenCADStudio {
let metrics = mesh.metrics;
let mut props = vec![
ro_prop(
"Vertices",
t!("Vertices").as_ref(),
"mesh_vertices",
metrics.vertices.to_string(),
),
ro_prop(
"Triangles",
t!("Triangles").as_ref(),
"mesh_triangles",
metrics.triangles.to_string(),
),
ro_prop(
"Surface Area",
t!("Surface Area").as_ref(),
"mesh_surface_area",
format!("{:.6}", metrics.surface_area),
),
ro_prop(
"Centroid",
t!("Centroid").as_ref(),
"mesh_centroid",
format!(
"{:.6}, {:.6}, {:.6}",
@ -717,7 +718,7 @@ impl OpenCADStudio {
),
),
ro_prop(
"Tessellation",
t!("Tessellation").as_ref(),
"mesh_complete",
if mesh.complete { "Complete" } else { "Partial" },
),
@ -733,14 +734,14 @@ impl OpenCADStudio {
props.insert(
3,
ro_prop(
"Volume",
t!("Volume").as_ref(),
"mesh_volume",
format!("{:.6}", metrics.volume),
),
);
}
sections.push(crate::scene::model::object::PropSection {
title: "Mass Properties".to_string(),
title: t!("Mass Properties").into_owned(),
props,
});
}
@ -770,7 +771,7 @@ impl OpenCADStudio {
continue;
};
let toggle = crate::scene::model::object::Property {
label: "Uniform scale".into(),
label: t!("Uniform scale").into_owned(),
field: "ins_uniform",
value: crate::scene::model::object::PropValue::BoolToggle {
field: "ins_uniform",
@ -787,7 +788,7 @@ impl OpenCADStudio {
.position(|p| p.field == "x_scale")
.unwrap_or(xi.min(section.props.len()));
section.props[xi] = crate::entities::common::edit_prop(
"Scale",
t!("Scale").as_ref(),
"u_scale",
ins.x_scale(),
);
@ -975,7 +976,7 @@ impl OpenCADStudio {
if let Some(geom) = sections.last_mut() {
geom.props.push(crate::scene::model::object::Property {
label: "Frozen Layers".to_string(),
label: t!("Frozen Layers").into_owned(),
field: "frozen_layers",
value: crate::scene::model::object::PropValue::EditText(
frozen_names.join(", "),
@ -983,7 +984,7 @@ impl OpenCADStudio {
});
if !ucs_names.is_empty() {
geom.props.push(crate::scene::model::object::Property {
label: "UCS Name".to_string(),
label: t!("UCS Name").into_owned(),
field: "vp_ucs_name",
value: crate::scene::model::object::PropValue::Choice {
selected: current_ucs,
@ -993,7 +994,7 @@ impl OpenCADStudio {
}
if !view_names.is_empty() {
geom.props.push(crate::scene::model::object::Property {
label: "Named View".to_string(),
label: t!("Named View").into_owned(),
field: "vp_named_view",
value: crate::scene::model::object::PropValue::Choice {
selected: String::new(),
@ -1385,7 +1386,7 @@ impl OpenCADStudio {
&mut sections,
anchor,
crate::entities::common::ro_prop(
"Annotative",
t!("Annotative").as_ref(),
"annotative",
"No",
),
@ -1430,7 +1431,7 @@ impl OpenCADStudio {
&mut sections,
anno_field,
crate::entities::common::ro_prop(
"Annotative scale",
t!("Annotative scale").as_ref(),
"annotative_scale",
doc.header.current_annotation_scale.clone(),
),
@ -1443,7 +1444,7 @@ impl OpenCADStudio {
let label = group_names.join(", ");
if let Some(general) = sections.first_mut() {
general.props.push(crate::scene::model::object::Property {
label: "Group".to_string(),
label: t!("Group").into_owned(),
field: "group",
value: crate::scene::model::object::PropValue::ReadOnly(label),
});
@ -1460,7 +1461,7 @@ impl OpenCADStudio {
.map(|br| br.flags.is_xref || br.flags.is_xref_overlay)
.unwrap_or(false);
if is_xref {
"External Reference".to_string()
t!("External Reference").into_owned()
} else {
entity_type_label(entity)
}
@ -1474,7 +1475,13 @@ impl OpenCADStudio {
.filter_map(|prop| match &prop.value {
crate::scene::model::object::PropValue::Choice { options, .. } => Some((
prop.field.to_string(),
iced::widget::combo_box::State::new(options.clone()),
iced::widget::combo_box::State::new(
options
.iter()
.cloned()
.map(ui::properties::LocalizedChoice::new)
.collect(),
),
)),
_ => None,
})
@ -1495,7 +1502,7 @@ impl OpenCADStudio {
// for seconds at tens of thousands of objects. Above the cap show a
// count-only panel; bulk edits still go through the ribbon.
n if n > MAX_PROP_AGGREGATE => ui::PropertiesPanel {
title: format!("{} objects selected", n),
title: t!("%{count} objects selected", count = n).into_owned(),
layer_combo: iced::widget::combo_box::State::new(layer_names.clone()),
linetype_combo: iced::widget::combo_box::State::new(linetype_items.clone()),
lineweight_combo: iced::widget::combo_box::State::new(
@ -1529,13 +1536,19 @@ impl OpenCADStudio {
.filter_map(|prop| match &prop.value {
crate::scene::model::object::PropValue::Choice { options, .. } => Some((
prop.field.to_string(),
iced::widget::combo_box::State::new(options.clone()),
iced::widget::combo_box::State::new(
options
.iter()
.cloned()
.map(ui::properties::LocalizedChoice::new)
.collect(),
),
)),
_ => None,
})
.collect(),
sections,
title: format!("{} objects selected", selected.len()),
title: t!("%{count} objects selected", count = selected.len()).into_owned(),
selection_group_combo: iced::widget::combo_box::State::new(groups.clone()),
selection_groups: groups,
selected_group: active_group,
@ -1998,7 +2011,7 @@ impl OpenCADStudio {
}
Err(e) => {
self.command_line
.push_error(&format!("Viewport could not be added: {e}"));
.push_error(crate::tf!("Viewport could not be added: {e}").as_ref());
None
}
}
@ -2037,7 +2050,7 @@ pub(super) fn build_selection_groups(
selected: &[(Handle, &EntityType)],
) -> Vec<ui::properties::SelectionGroup> {
let mut groups = vec![ui::properties::SelectionGroup {
label: format!("All({})", selected.len()),
label: format!("{} ({})", t!("All").into_owned(), selected.len()),
handles: selected.iter().map(|(handle, _)| *handle).collect(),
}];
@ -2052,7 +2065,7 @@ pub(super) fn build_selection_groups(
for (kind, handles) in by_type {
groups.push(ui::properties::SelectionGroup {
label: format!("{}({})", title_case_word(&kind), handles.len()),
label: format!("{}({})", t!(title_case_word(&kind)), handles.len()),
handles,
});
}

View file

@ -593,7 +593,7 @@ impl OpenCADStudio {
self.load_style_bufs(kind);
self.after_style_change(kind);
self.command_line
.push_output(&format!("Style '{name}' created."));
.push_output(crate::tf!("Style '{name}' created.").as_ref());
}
pub(super) fn style_copy(&mut self, kind: StyleKind) {
@ -608,19 +608,19 @@ impl OpenCADStudio {
self.load_style_bufs(kind);
self.after_style_change(kind);
self.command_line
.push_output(&format!("Style '{name}' created."));
.push_output(crate::tf!("Style '{name}' created.").as_ref());
}
pub(super) fn style_delete(&mut self, kind: StyleKind) {
let name = self.style_selected(kind);
if name.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error("Cannot delete the Standard style.");
.push_error(crate::t!("Cannot delete the Standard style.").as_ref());
return;
}
if self.style_in_use(kind, &name) {
self.command_line
.push_error("Cannot delete a style that is current or in use.");
.push_error(crate::t!("Cannot delete a style that is current or in use.").as_ref());
return;
}
if !self.remove_style_storage(kind, &name) {
@ -635,7 +635,7 @@ impl OpenCADStudio {
self.load_style_bufs(kind);
self.after_style_change(kind);
self.command_line
.push_output(&format!("Style '{name}' deleted."));
.push_output(crate::tf!("Style '{name}' deleted.").as_ref());
}
/// Begin inline rename of the double-clicked style.
@ -659,12 +659,12 @@ impl OpenCADStudio {
}
if old.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error("Cannot rename the Standard style.");
.push_error(crate::t!("Cannot rename the Standard style.").as_ref());
return;
}
if self.style_exists(kind, &new) {
self.command_line
.push_error(&format!("Style '{new}' already exists."));
.push_error(crate::tf!("Style '{new}' already exists.").as_ref());
return;
}
self.rename_style_storage(kind, &old, &new);
@ -674,7 +674,7 @@ impl OpenCADStudio {
self.load_style_bufs(kind);
self.after_style_change(kind);
self.command_line
.push_output(&format!("Renamed '{old}' → '{new}'."));
.push_output(crate::tf!("Renamed '{old}' → '{new}'.").as_ref());
}
pub(super) fn style_rename_cancel(&mut self) {

View file

@ -224,10 +224,10 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
let raw = crate::app::expr_eval::eval_to_string(self.command_line.input.trim());
self.command_line.input.clear();
let Ok(v) = raw.parse::<f64>() else {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"{}: expected a number, got \"{raw}\"",
pending.label
));
).as_ref());
return Task::none();
};
let i = self.active_tab;
@ -443,9 +443,9 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
return self.apply_cmd_result(result);
}
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Expected coordinates (x,y) or a number, got: \"{text}\""
));
).as_ref());
return self.focus_cmd_input();
}
if let Some(cmd) = self.command_line.submit() {
@ -519,7 +519,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
}
// Esc cancels a pending system-variable value prompt.
if self.pending_setvar.take().is_some() {
self.command_line.push_info("*Cancel*");
self.command_line.push_info(crate::t!("*Cancel*").as_ref());
return Task::none();
}
// UCS icon: Esc ends any grip drag and clears the selection
@ -548,7 +548,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
sel.middle_down = false;
sel.middle_last_pos = None;
}
self.command_line.push_output("PAN ended.");
self.command_line.push_output(crate::t!("PAN ended.").as_ref());
return Task::none();
}
// Grip popup intercepts Escape — dismisses the menu
@ -738,7 +738,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
names.retain(|n| n != "0" && *n != current);
if names.len() < before {
self.command_line
.push_info("Layer \"0\" and the current layer can't be deleted — skipped.");
.push_info(crate::t!("Layer \"0\" and the current layer can't be deleted — skipped.").as_ref());
}
if names.is_empty() {
return Task::none();
@ -971,7 +971,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
action: item.action,
label,
});
self.command_line.push_info(&format!("{label}:"));
self.command_line.push_info(crate::tf!("{label}:").as_ref());
return self.focus_cmd_input();
}
// Break at vertex replaces the entity with the split pieces —
@ -993,11 +993,11 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
self.tabs[i].dirty = true;
self.refresh_selected_grips();
self.refresh_properties();
self.command_line.push_output("Polyline broken at vertex.");
self.command_line.push_output(crate::t!("Polyline broken at vertex.").as_ref());
}
None => self
.command_line
.push_error("Cannot break at this vertex."),
.push_error(crate::t!("Cannot break at this vertex.").as_ref()),
}
return Task::none();
}
@ -1042,7 +1042,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
self.tabs[i].dirty = dirty_before;
self.refresh_selected_grips();
self.refresh_properties();
self.command_line.push_error("Cannot add a vertex here.");
self.command_line.push_error(crate::t!("Cannot add a vertex here.").as_ref());
return Task::none();
}
self.tabs[i]
@ -1069,7 +1069,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
grip_world,
));
self.command_line
.push_info("Specify new vertex location:");
.push_info(crate::t!("Specify new vertex location:").as_ref());
} else {
if let Some(entity) =
self.tabs[i].scene.document.get_entity_mut(popup.handle)
@ -1083,7 +1083,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
self.refresh_selected_grips();
self.refresh_properties();
self.command_line
.push_error("Cannot place the new vertex.");
.push_error(crate::t!("Cannot place the new vertex.").as_ref());
}
return Task::none();
}
@ -2084,9 +2084,9 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
// The block's layer may have been locked while the editor was open —
// refuse to write attributes to a locked-layer block.
if let Some(layer) = self.tabs[i].scene.locked_layer_name(handle) {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Object is on locked layer \"{layer}\" — unlock the layer to edit its attributes."
));
).as_ref());
return Task::none();
}
// Snapshot the working copy so the document can be mutated while the

View file

@ -116,7 +116,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
if self.tabs[self.active_tab].is_start && !matches!(event, ModuleEvent::Command(_)) {
self.ribbon.close_dropdown();
self.command_line
.push_info("No drawing open — use New or Open first.");
.push_info(crate::t!("No drawing open — use New or Open first.").as_ref());
return Task::none();
}
// Dismiss any open dropdown / collapsed-panel flyout on tool use,
@ -141,13 +141,13 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
}
ModuleEvent::OpenFileDialog => {
self.command_line
.push_info("Open DWG/DXF: not yet implemented.");
.push_info(crate::t!("Open DWG/DXF: not yet implemented.").as_ref());
}
ModuleEvent::ClearModels => {
let i = self.active_tab;
self.tabs[i].scene.clear();
self.tabs[i].properties = PropertiesPanel::empty();
self.command_line.push_output("Scene cleared.");
self.command_line.push_output(crate::t!("Scene cleared.").as_ref());
}
ModuleEvent::SetWireframe(w) => {
let i = self.active_tab;
@ -265,7 +265,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
if self.active_save_jobs.contains_key(&self.tabs[idx].id) {
self.command_line
.push_info("Save already running for this drawing.");
.push_info(crate::t!("Save already running for this drawing.").as_ref());
return Task::none();
}

View file

@ -659,7 +659,10 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
.is_some_and(|(loaded, current)| loaded != current)
{
self.command_line.push_error_once(
"Drawing changed on disk while it was opening; Save will require conflict resolution.",
crate::t!(
"Drawing changed on disk while it was opening; Save will require conflict resolution."
)
.as_ref(),
);
}
self.tabs[i].disk_fingerprint =
@ -667,9 +670,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
match crate::io::edit_lock::EditLease::acquire(path) {
Ok(lease) => {
if let Some(warning) = lease.platform_warning() {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Edit lease active; {warning}. External-change checks remain active."
));
).as_ref());
}
self.tabs[i].edit_lease = Some(lease);
self.tabs[i].edit_lock_conflict = false;
@ -677,16 +680,16 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
Err(crate::io::edit_lock::EditLeaseError::Locked(error)) => {
self.tabs[i].edit_lease = None;
self.tabs[i].edit_lock_conflict = true;
self.command_line.push_error_once(&format!(
self.command_line.push_error_once(crate::tf!(
"Opened read-only against other editors: {error}"
));
).as_ref());
}
Err(crate::io::edit_lock::EditLeaseError::Unavailable(error)) => {
self.tabs[i].edit_lease = None;
self.tabs[i].edit_lock_conflict = false;
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{error}. External-change checks remain active."
));
).as_ref());
}
}
}
@ -718,22 +721,22 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
Some(Ok(warning)) => {
self.tabs[i].edit_lock_conflict = false;
if let Some(warning) = warning {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{warning}. External-change checks remain active."
));
).as_ref());
}
}
Some(Err(crate::io::edit_lock::EditLeaseError::Locked(error))) => {
self.tabs[i].edit_lock_conflict = true;
self.command_line.push_error_once(&format!(
self.command_line.push_error_once(crate::tf!(
"Saved, but the refreshed drawing is locked by another editor: {error}"
));
).as_ref());
}
Some(Err(crate::io::edit_lock::EditLeaseError::Unavailable(error))) => {
self.tabs[i].edit_lock_conflict = false;
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{error}. External-change checks remain active."
));
).as_ref());
}
None => self.install_native_edit_guard(i, path, None),
}
@ -765,9 +768,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
return Err(crate::io::SaveFailure::file_in_use(error));
}
Err(crate::io::edit_lock::EditLeaseError::Unavailable(error)) => {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{error}. External-change checks remain active."
));
).as_ref());
None
}
}
@ -829,9 +832,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let warning = lease.platform_warning().map(str::to_owned);
self.tabs[i].edit_lock_conflict = false;
if let Some(warning) = warning {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{warning}. External-change checks remain active."
));
).as_ref());
}
return Ok(());
}
@ -840,9 +843,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
}
Err(crate::io::edit_lock::EditLeaseError::Unavailable(error)) => {
self.tabs[i].edit_lock_conflict = false;
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{error}. External-change checks remain active."
));
).as_ref());
return Ok(());
}
}
@ -854,18 +857,18 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.tabs[i].edit_lease = Some(lease);
self.tabs[i].edit_lock_conflict = false;
if let Some(warning) = warning {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{warning}. External-change checks remain active."
));
).as_ref());
}
Ok(())
}
Err(crate::io::edit_lock::EditLeaseError::Locked(error)) => Err(error),
Err(crate::io::edit_lock::EditLeaseError::Unavailable(error)) => {
self.tabs[i].edit_lock_conflict = false;
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{error}. External-change checks remain active."
));
).as_ref());
Ok(())
}
}
@ -883,34 +886,34 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let timings = caches.timings;
let entity_count = doc.entities().count();
self.command_line
.push_output(&format!("Opened \"{name}\" — {entity_count} entities"));
.push_output(crate::tf!("Opened \"{name}\" — {entity_count} entities").as_ref());
if caches.corrupt_dropped > 0 {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Warning: {} corrupt entities dropped (parser junk — bad normals / counts)",
caches.corrupt_dropped
));
).as_ref());
}
if caches.xref_dropped > 0 {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Warning: {} corrupt xref entities dropped",
caches.xref_dropped
));
).as_ref());
}
for info in &caches.xrefs {
match info.status {
crate::io::xref::XrefStatus::Loaded => {
self.command_line
.push_output(&format!("XREF Loaded \"{}\"", info.name));
.push_output(crate::tf!("XREF Loaded \"{}\"", info.name).as_ref());
}
crate::io::xref::XrefStatus::NotFound => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"XREF Not found: \"{}\" ({})",
info.name, info.path
));
).as_ref());
}
crate::io::xref::XrefStatus::Unloaded => {
self.command_line
.push_info(&format!("XREF Unloaded (skipped): \"{}\"", info.name));
.push_info(crate::tf!("XREF Unloaded (skipped): \"{}\"", info.name).as_ref());
}
}
}
@ -982,10 +985,10 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let total_ms = open_started
.map(|s| s.elapsed().as_millis() as u32)
.unwrap_or(0);
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
" parse {}ms · purge {}ms · caches {}ms · xref {}ms · total {}ms",
timings.parse_ms, timings.purge_ms, timings.caches_ms, timings.xref_ms, total_ms
));
).as_ref());
// Caches were built on the background thread inside open_path().
self.tabs[i].scene.local_extent_max = caches.local_extent_max;
@ -1209,7 +1212,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
if self.active_save_jobs.contains_key(&tab_id) {
if purpose != crate::app::SavePurpose::Autosave {
self.command_line
.push_info("Save already running for this drawing.");
.push_info(crate::t!("Save already running for this drawing.").as_ref());
}
return Task::none();
}
@ -1218,12 +1221,12 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
&& self.tabs[i].edit_lock_conflict
{
let error = "Drawing edit lock is held by another editor.".to_string();
self.command_line.push_error_once(&format!(
self.command_line.push_error_once(crate::tf!(
"Unable to save \"{}\": {error}",
path.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.display().to_string())
));
).as_ref());
self.pending_save_failure = Some(crate::app::PendingSaveFailure {
tab_id,
path,
@ -1248,12 +1251,12 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.pending_save_leases.insert(tab_id, lease);
}
Err(crate::io::edit_lock::EditLeaseError::Locked(error)) => {
self.command_line.push_error_once(&format!(
self.command_line.push_error_once(crate::tf!(
"Unable to save \"{}\": {error}",
path.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.display().to_string())
));
).as_ref());
self.pending_save_failure = Some(crate::app::PendingSaveFailure {
tab_id,
path,
@ -1268,9 +1271,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
return Task::none();
}
Err(crate::io::edit_lock::EditLeaseError::Unavailable(error)) => {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{error}. External-change checks remain active."
));
).as_ref());
}
}
}
@ -1424,9 +1427,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| outcome.path.display().to_string());
self.command_line.push_error_once(&format!(
self.command_line.push_error_once(crate::tf!(
"Save stopped: \"{file_name}\" changed outside Open CAD Studio."
));
).as_ref());
self.pending_external_change = Some(crate::app::PendingExternalChange {
tab_id: outcome.tab_id,
path: outcome.path.clone(),
@ -1445,9 +1448,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| outcome.path.display().to_string());
self.command_line.push_error_once(&format!(
self.command_line.push_error_once(crate::tf!(
"Unable to save \"{file_name}\": file is in use by another application."
));
).as_ref());
self.pending_save_failure = Some(crate::app::PendingSaveFailure {
tab_id: outcome.tab_id,
path: outcome.path.clone(),
@ -1470,7 +1473,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
return Task::none();
}
self.command_line
.push_error(&format!("Save failed: {error}"));
.push_error(crate::tf!("Save failed: {error}").as_ref());
return match outcome.continuation {
crate::app::SaveContinuation::CloseTab => {
self.pending_close = Some(crate::app::PendingClose::Tab(i));
@ -1496,7 +1499,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let mut tasks = Vec::new();
match outcome.purpose {
crate::app::SavePurpose::Autosave => {
self.command_line.push_output("Autosaved 1 drawing");
self.command_line.push_output(crate::t!("Autosaved 1 drawing").as_ref());
}
crate::app::SavePurpose::Manual | crate::app::SavePurpose::SaveAs => {
let path_changed = outcome.set_current_path
@ -1507,7 +1510,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
!native_paths_match(current, &outcome.path)
});
self.command_line
.push_output(&format!("Saved: {}", outcome.path.display()));
.push_output(crate::tf!("Saved: {}", outcome.path.display()).as_ref());
self.recent_thumbs.remove(&outcome.path);
if let Some(previous) = outcome.previous_autosave {
if previous != outcome.path {
@ -1594,7 +1597,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.pending_save_failure = Some(failure);
self.restore_failed_save_continuation(continuation, i);
self.command_line
.push_error_once(&format!("Unable to acquire edit lock: {error}"));
.push_error_once(crate::tf!("Unable to acquire edit lock: {error}").as_ref());
self.active_modal = Some(crate::app::ModalKind::FileInUse);
return Task::none();
}
@ -1690,7 +1693,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
Err(error) => {
self.close_active_modal();
self.command_line
.push_error(&format!("Reload failed: {error}"));
.push_error(crate::tf!("Reload failed: {error}").as_ref());
return Task::none();
}
};
@ -1709,7 +1712,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
pub(super) fn on_save_file(&mut self) -> Task<Message> {
if self.read_only {
self.command_line
.push_error("Read-only session (--read-only): saving is disabled.");
.push_error(crate::t!("Read-only session (--read-only): saving is disabled.").as_ref());
return Task::none();
}
let i = self.active_tab;
@ -1859,11 +1862,11 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
},
Message::WebRecentStored,
);
self.command_line.push_output(&format!("Saved: {filename}"));
self.command_line.push_output(crate::tf!("Saved: {filename}").as_ref());
true
}
Err(e) => {
self.command_line.push_error(&format!("Save failed: {e}"));
self.command_line.push_error(crate::tf!("Save failed: {e}").as_ref());
false
}
};
@ -2163,10 +2166,10 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.tabs[i].dirty = true;
self.tabs[i].scene.bump_geometry_no_blocks();
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Page setup: {w:.1}×{h:.1} mm area={plot_area} \
center={center} rot={rotation}°"
));
).as_ref());
}
}
@ -2178,7 +2181,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.direct_plot_params()
else {
self.command_line
.push_error("Nothing to plot: model space contains no printable geometry.");
.push_error(crate::t!("Nothing to plot: model space contains no printable geometry.").as_ref());
return Task::none();
};
let plot_style = self.dialog_plot_style(&self.plot_dialog);
@ -2221,7 +2224,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
job
else {
self.command_line
.push_error("Plot area is empty. Pick a larger window.");
.push_error(crate::t!("Plot area is empty. Pick a larger window.").as_ref());
return Task::none();
};
let plot_style = self.dialog_plot_style(&self.plot_dialog);
@ -2533,12 +2536,12 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.direct_plot_params()
else {
self.command_line
.push_error("Nothing to plot: model space contains no printable geometry.");
.push_error(crate::t!("Nothing to plot: model space contains no printable geometry.").as_ref());
return Task::none();
};
let plot_style = self.dialog_plot_style(&self.plot_dialog);
let options = self.plot_print_options(&self.plot_dialog, group_splits);
self.command_line.push_info("Sending to system printer…");
self.command_line.push_info(crate::t!("Sending to system printer…").as_ref());
background_task(
move || {
iced::futures::executor::block_on(
@ -2561,7 +2564,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let i = self.active_tab;
if self.tabs[i].scene.current_layout != "Model" {
self.command_line
.push_error("Quick print works in model space.");
.push_error(crate::t!("Quick print works in model space.").as_ref());
return Task::none();
}
let set: std::collections::HashSet<acadrust::Handle> = handles.into_iter().collect();
@ -2593,12 +2596,12 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
};
if !any {
self.command_line
.push_error("Selection has no printable geometry.");
.push_error(crate::t!("Selection has no printable geometry.").as_ref());
return Task::none();
}
if !(x1 > x0 && y1 > y0) {
self.command_line
.push_error("Selection has no printable area.");
.push_error(crate::t!("Selection has no printable area.").as_ref());
return Task::none();
}
// Small margin so the outermost strokes aren't clipped flush to the edge.
@ -2786,7 +2789,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
match crate::io::print_to_printer::open_printer_properties(
self.plot_dialog.printer.as_deref(),
) {
Ok(()) => self.command_line.push_info("Opened printer properties."),
Ok(()) => self.command_line.push_info(crate::t!("Opened printer properties.").as_ref()),
Err(error) => self.command_line.push_error(&error),
}
Task::none()
@ -2924,7 +2927,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
}
M::SetCurrent => {
self.apply_dialog_to_layout();
self.command_line.push_info("Page setup applied to the layout.");
self.command_line.push_info(crate::t!("Page setup applied to the layout.").as_ref());
Task::none()
}
M::NewSetup => {
@ -3327,10 +3330,10 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
fn on_plot_dlg_commit(&mut self, preview: bool) -> Task<Message> {
let d = self.plot_dialog.clone();
if d.style_missing {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Plot style table '{}' is not loaded.",
d.style_name
));
).as_ref());
return Task::none();
}
// Remember the user's print preferences across sessions.
@ -3365,7 +3368,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
)) = job
else {
self.command_line
.push_error("Plot area is empty. Pick a larger window.");
.push_error(crate::t!("Plot area is empty. Pick a larger window.").as_ref());
self.active_modal = Some(crate::app::ModalKind::Plot);
return Task::none();
};
@ -3436,7 +3439,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
}
let opts = self.plot_print_options(&d, group_splits);
self.command_line.push_info("Sending to system printer…");
self.command_line.push_info(crate::t!("Sending to system printer…").as_ref());
let work = move || {
iced::futures::executor::block_on(
crate::io::print_to_printer::print_wires_with(
@ -3692,7 +3695,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
entry.screening = sc.min(100);
}
self.command_line
.push_output(&format!("Plot style ACI {aci} updated."));
.push_output(crate::tf!("Plot style ACI {aci} updated.").as_ref());
}
} else {
// No table loaded: create an identity table and apply.
@ -3714,7 +3717,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
}
self.active_plot_style = Some(table);
self.command_line
.push_output(&format!("Created new CTB table, ACI {aci} updated."));
.push_output(crate::tf!("Created new CTB table, ACI {aci} updated.").as_ref());
}
Task::none()
}
@ -3722,7 +3725,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
pub(super) fn on_plot_style_panel_save(&mut self) -> Task<Message> {
if self.active_plot_style.is_none() {
self.command_line
.push_error("No plot style table loaded. Load or create one first.");
.push_error(crate::t!("No plot style table loaded. Load or create one first.").as_ref());
return Task::none();
}
let default_name = self

View file

@ -284,7 +284,7 @@ impl OpenCADStudio {
Err(e) => {
crate::scene::text::web_font::insert(script, None);
self.command_line
.push_error(&format!("Font load failed ({script:?}): {e}"));
.push_error(crate::tf!("Font load failed ({script:?}): {e}").as_ref());
}
}
Task::none()
@ -323,10 +323,10 @@ impl OpenCADStudio {
return match std::fs::metadata(&path) {
Ok(m) => self.update(Message::OpenPathPicked(Some((path, m.len())))),
Err(_) => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Recent file no longer exists: {}",
path.display()
));
).as_ref());
Task::none()
}
};
@ -489,7 +489,7 @@ impl OpenCADStudio {
.map(|(_, _, l)| *l)
.unwrap_or("Snap");
self.command_line
.push_info(&format!("Snap override: {label} (next pick only)."));
.push_info(crate::tf!("Snap override: {label} (next pick only).").as_ref());
Task::none()
}
@ -507,10 +507,10 @@ impl OpenCADStudio {
.map(|e| e.to_string_lossy().to_lowercase())
.unwrap_or_default();
if !matches!(ext.as_str(), "dwg" | "dxf" | "bak" | "sv$") {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Unsupported file type: {}",
path.display()
));
).as_ref());
return Task::none();
}
// Already open → switch to its tab; a load in progress →
@ -563,7 +563,7 @@ impl OpenCADStudio {
});
let size_label = format_size(size_bytes);
self.command_line
.push_info(&format!("Opening \"{name}\" ({size_label})…"));
.push_info(crate::tf!("Opening \"{name}\" ({size_label})…").as_ref());
let model_bg = self.default_bg_color.unwrap_or([
33.0 / 255.0,
40.0 / 255.0,
@ -579,7 +579,7 @@ impl OpenCADStudio {
Message::OpenCancel => {
if let Some(p) = self.opening.take() {
self.command_line
.push_info(&format!("Open cancelled: \"{}\"", p.name));
.push_info(crate::tf!("Open cancelled: \"{}\"", p.name).as_ref());
}
self.drain_pending_open()
}
@ -593,7 +593,7 @@ impl OpenCADStudio {
// we suppress the noise.
let was_open = self.opening.take().is_some();
if was_open && e != "Cancelled" {
self.command_line.push_error(&format!("Open failed: {e}"));
self.command_line.push_error(crate::tf!("Open failed: {e}").as_ref());
}
// A drawing that fails to parse must not strand the ones queued
// behind it.
@ -604,9 +604,9 @@ impl OpenCADStudio {
Message::WebRecentStored(result) => match result {
Ok(path) => self.push_recent(path),
Err(error) => {
self.command_line.push_error(&format!(
self.command_line.push_error(crate::tf!(
"Saved download, but recent copy could not be stored: {error}"
));
).as_ref());
Task::none()
}
},
@ -625,7 +625,7 @@ impl OpenCADStudio {
.unwrap_or(&path_str)
.to_string();
self.command_line
.push_output(&format!("IMAGE \"{short}\": {pw}×{ph} px"));
.push_output(crate::tf!("IMAGE \"{short}\": {pw}×{ph} px").as_ref());
let cmd = ImageCommand::new(path_str, pw, ph);
let i = self.active_tab;
self.command_line.push_info(&cmd.prompt());
@ -635,7 +635,7 @@ impl OpenCADStudio {
Message::ImagePickResult(Err(e)) => {
if e != "Cancelled" {
self.command_line.push_error(&format!("IMAGE: {e}"));
self.command_line.push_error(crate::tf!("IMAGE: {e}").as_ref());
}
Task::none()
}
@ -671,7 +671,7 @@ impl OpenCADStudio {
Message::XAttachPickResult(Err(e)) => {
if e != "Cancelled" {
self.command_line.push_error(&format!("XATTACH: {e}"));
self.command_line.push_error(crate::tf!("XATTACH: {e}").as_ref());
}
Task::none()
}
@ -701,13 +701,13 @@ impl OpenCADStudio {
Message::WblockWriteFinished(block_name, path, result) => {
match result {
Ok(()) => self.command_line.push_output(&format!(
Ok(()) => self.command_line.push_output(crate::tf!(
"WBLOCK Saved \"{block_name}\" → \"{}\"",
path.display()
)),
).as_ref()),
Err(error) => self
.command_line
.push_error(&format!("WBLOCK save failed: {error}")),
.push_error(crate::tf!("WBLOCK save failed: {error}").as_ref()),
}
Task::none()
}
@ -739,11 +739,11 @@ impl OpenCADStudio {
.map(|n| n.to_string_lossy().into_owned())
.unwrap_or_else(|| path.to_string_lossy().into_owned());
self.command_line
.push_output(&format!("DATAEXTRACTION {rows} rows → \"{fname}\""));
.push_output(crate::tf!("DATAEXTRACTION {rows} rows → \"{fname}\"").as_ref());
}
Err(e) => self
.command_line
.push_error(&format!("DATAEXTRACTION: write failed: {e}")),
.push_error(crate::tf!("DATAEXTRACTION: write failed: {e}").as_ref()),
}
Task::none()
}
@ -754,7 +754,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].scene.meshes.is_empty() {
self.command_line
.push_error("STLOUT: no 3D mesh data in this drawing.");
.push_error(crate::t!("STLOUT: no 3D mesh data in this drawing.").as_ref());
return Task::none();
}
Task::perform(
@ -780,8 +780,8 @@ impl OpenCADStudio {
match result {
Ok(()) => self
.command_line
.push_output(&format!("STLOUT: exported to \"{}\"", path.display())),
Err(error) => self.command_line.push_error(&format!("STLOUT: {error}")),
.push_output(crate::tf!("STLOUT: exported to \"{}\"", path.display()).as_ref()),
Err(error) => self.command_line.push_error(crate::tf!("STLOUT: {error}").as_ref()),
}
Task::none()
}
@ -791,7 +791,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].scene.meshes.is_empty() {
self.command_line
.push_error("STEPOUT: no 3D mesh data in this drawing.");
.push_error(crate::t!("STEPOUT: no 3D mesh data in this drawing.").as_ref());
return Task::none();
}
Task::perform(
@ -817,8 +817,8 @@ impl OpenCADStudio {
match result {
Ok(()) => self
.command_line
.push_output(&format!("STEPOUT: exported to \"{}\"", path.display())),
Err(error) => self.command_line.push_error(&format!("STEPOUT: {error}")),
.push_output(crate::tf!("STEPOUT: exported to \"{}\"", path.display()).as_ref()),
Err(error) => self.command_line.push_error(crate::tf!("STEPOUT: {error}").as_ref()),
}
Task::none()
}
@ -843,11 +843,11 @@ impl OpenCADStudio {
Message::ObjImportFinished(tab_id, path, result) => {
match result {
Err(error) => self.command_line.push_error(&format!("IMPORTOBJ: {error}")),
Err(error) => self.command_line.push_error(crate::tf!("IMPORTOBJ: {error}").as_ref()),
Ok(mut mesh) => {
let Some(i) = self.tabs.iter().position(|tab| tab.id == tab_id) else {
self.command_line
.push_info("IMPORTOBJ: target drawing was closed.");
.push_info(crate::t!("IMPORTOBJ: target drawing was closed.").as_ref());
return Task::none();
};
let file_stem = path
@ -864,9 +864,9 @@ impl OpenCADStudio {
.meshes
.insert(handle, crate::scene::MeshLodSet::from_single(mesh));
self.tabs[i].dirty = true;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"IMPORTOBJ: imported \"{file_stem}\" as mesh."
));
).as_ref());
}
}
}
@ -878,7 +878,7 @@ impl OpenCADStudio {
Message::SaveAs => {
if self.read_only {
self.command_line
.push_error("Read-only session (--read-only): saving is disabled.");
.push_error(crate::t!("Read-only session (--read-only): saving is disabled.").as_ref());
return Task::none();
}
let i = self.active_tab;
@ -924,7 +924,7 @@ impl OpenCADStudio {
.layers
.sync_with_viewports(&doc_layers, vp_info);
self.command_line
.push_output("Scene cleared. Standard linetypes loaded.");
.push_output(crate::t!("Scene cleared. Standard linetypes loaded.").as_ref());
self.tabs[i].current_path = None;
self.tabs[i].dirty = true;
self.sync_ribbon_layers();
@ -988,7 +988,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if !crate::plugin::try_dispatch(self, i, &line) {
self.command_line
.push_error(&format!("No plugin handled: {command}"));
.push_error(crate::tf!("No plugin handled: {command}").as_ref());
}
}
Task::none()
@ -1138,7 +1138,7 @@ impl OpenCADStudio {
let Some(path) = self.tabs.get(idx).and_then(|tab| tab.current_path.clone())
else {
self.command_line
.push_error("Save the drawing before copying its file path.");
.push_error(crate::t!("Save the drawing before copying its file path.").as_ref());
return Task::none();
};
let full_path = path.canonicalize().unwrap_or_else(|_| {
@ -1151,7 +1151,7 @@ impl OpenCADStudio {
}
});
self.command_line
.push_output(&format!("Copied path: {}", full_path.display()));
.push_output(crate::tf!("Copied path: {}", full_path.display()).as_ref());
return iced::clipboard::write(full_path.to_string_lossy().into_owned())
.discard();
}
@ -1159,7 +1159,7 @@ impl OpenCADStudio {
{
let _ = idx;
self.command_line
.push_error("Full file paths are unavailable in the web application.");
.push_error(crate::t!("Full file paths are unavailable in the web application.").as_ref());
Task::none()
}
}
@ -1170,16 +1170,16 @@ impl OpenCADStudio {
let Some(path) = self.tabs.get(idx).and_then(|tab| tab.current_path.clone())
else {
self.command_line
.push_error("Save the drawing before opening its file location.");
.push_error(crate::t!("Save the drawing before opening its file location.").as_ref());
return Task::none();
};
match crate::sys::reveal_in_file_manager(&path) {
Ok(()) => self
.command_line
.push_output(&format!("Opened file location: {}", path.display())),
.push_output(crate::tf!("Opened file location: {}", path.display()).as_ref()),
Err(error) => self
.command_line
.push_error(&format!("Could not open file location: {error}")),
.push_error(crate::tf!("Could not open file location: {error}").as_ref()),
}
Task::none()
}
@ -1187,7 +1187,7 @@ impl OpenCADStudio {
{
let _ = idx;
self.command_line
.push_error("File locations are unavailable in the web application.");
.push_error(crate::t!("File locations are unavailable in the web application.").as_ref());
Task::none()
}
}
@ -1442,7 +1442,7 @@ impl OpenCADStudio {
self.ribbon.close_dropdown();
if self.tabs[i].is_start {
self.command_line
.push_info("Open or create a drawing to manage layer states.");
.push_info(crate::t!("Open or create a drawing to manage layer states.").as_ref());
return Task::none();
}
let mut names: Vec<String> = self.tabs[i]
@ -1482,7 +1482,7 @@ impl OpenCADStudio {
let name = self.layer_state_name_buf.trim().to_string();
if name.is_empty() {
self.command_line
.push_error("Layer state name cannot be empty.");
.push_error(crate::t!("Layer state name cannot be empty.").as_ref());
return Task::none();
}
let old_name = self.layer_state_selected.clone();
@ -1499,7 +1499,7 @@ impl OpenCADStudio {
});
if duplicate {
self.command_line
.push_error(&format!("Layer state \"{name}\" already exists."));
.push_error(crate::tf!("Layer state \"{name}\" already exists.").as_ref());
return Task::none();
}
@ -1520,7 +1520,7 @@ impl OpenCADStudio {
self.layer_state_selected = Some(name.clone());
self.layer_state_name_buf = name.clone();
self.command_line
.push_output(&format!("LAYERSTATE: saved \"{name}\" in the drawing."));
.push_output(crate::tf!("LAYERSTATE: saved \"{name}\" in the drawing.").as_ref());
Task::none()
}
Message::LayerStateManagerRestore => {
@ -1553,9 +1553,9 @@ impl OpenCADStudio {
.invalidate_layer_dependencies(&layer_names);
self.tabs[i].dirty = true;
self.refresh_layer_panel();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"LAYERSTATE: restored \"{name}\" ({restored} layer(s))."
));
).as_ref());
Task::none()
}
Message::LayerStateManagerDelete => {
@ -1576,7 +1576,7 @@ impl OpenCADStudio {
names.sort_by_key(|name| name.to_lowercase());
self.load_layer_state_editor(names.into_iter().next());
self.command_line
.push_output(&format!("LAYERSTATE: deleted \"{name}\"."));
.push_output(crate::tf!("LAYERSTATE: deleted \"{name}\".").as_ref());
}
Task::none()
}
@ -1587,7 +1587,7 @@ impl OpenCADStudio {
};
let Some(state) = self.tabs[i].scene.document.layer_state(&name) else {
self.command_line
.push_error(&format!("Layer state \"{name}\" was not found."));
.push_error(crate::tf!("Layer state \"{name}\" was not found.").as_ref());
return Task::none();
};
self.layer_state_edit_draft = Some(state);
@ -1730,7 +1730,7 @@ impl OpenCADStudio {
let name = draft.name.trim().to_string();
if name.is_empty() {
self.command_line
.push_error("Layer state name cannot be empty.");
.push_error(crate::t!("Layer state name cannot be empty.").as_ref());
return Task::none();
}
let old_name = self.layer_state_selected.clone();
@ -1747,7 +1747,7 @@ impl OpenCADStudio {
});
if duplicate {
self.command_line
.push_error(&format!("Layer state \"{name}\" already exists."));
.push_error(crate::tf!("Layer state \"{name}\" already exists.").as_ref());
return Task::none();
}
let Some(state) = self.layer_state_edit_draft.take() else {
@ -1775,7 +1775,7 @@ impl OpenCADStudio {
self.layer_state_edit_color_open = None;
self.active_modal = Some(super::ModalKind::LayerStateManager);
self.command_line
.push_output(&format!("LAYERSTATE: updated \"{name}\"."));
.push_output(crate::tf!("LAYERSTATE: updated \"{name}\".").as_ref());
Task::none()
}
Message::LayerStateEditorCancel => {
@ -1829,11 +1829,11 @@ impl OpenCADStudio {
self.tabs[i].scene.invalidate_layer_dependencies(&targets);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{} layer(s) turned {}",
targets.len(),
if on { "on" } else { "off" }
));
).as_ref());
self.sync_ribbon_layers();
}
}
@ -1869,11 +1869,11 @@ impl OpenCADStudio {
// Lock state affects editability, not rendered geometry.
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{} layer(s) {}",
targets.len(),
if locked { "locked" } else { "unlocked" }
));
).as_ref());
self.sync_ribbon_layers();
}
}
@ -1904,11 +1904,11 @@ impl OpenCADStudio {
self.tabs[i].scene.invalidate_layer_dependencies(&targets);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"{} layer(s) {}",
targets.len(),
if frozen { "frozen" } else { "thawed" }
));
).as_ref());
self.sync_ribbon_layers();
}
}
@ -2300,7 +2300,7 @@ impl OpenCADStudio {
self.tabs[i].scene.camera.borrow_mut().home_view(r_ucs);
}
self.tabs[i].scene.camera_generation += 1;
self.command_line.push_output("View: Home");
self.command_line.push_output(crate::t!("View: Home").as_ref());
Task::none()
}
@ -2351,11 +2351,11 @@ impl OpenCADStudio {
let mut changed = false;
if name.is_empty() || name == "WCS" {
self.tabs[i].active_ucs = None;
self.command_line.push_output("UCS: World");
self.command_line.push_output(crate::t!("UCS: World").as_ref());
changed = true;
} else if let Some(named) = self.tabs[i].scene.document.ucss.get(&name).cloned() {
self.tabs[i].active_ucs = Some(named);
self.command_line.push_output(&format!("UCS: {}", name));
self.command_line.push_output(crate::tf!("UCS: {}", name).as_ref());
changed = true;
}
if changed {
@ -2511,7 +2511,7 @@ impl OpenCADStudio {
_ => "live",
};
self.command_line
.push_output(&format!("COORDS = {mode} ({label})"));
.push_output(crate::tf!("COORDS = {mode} ({label})").as_ref());
}
Task::none()
}
@ -2700,11 +2700,11 @@ impl OpenCADStudio {
self.active_modal = Some(crate::app::ModalKind::AnnoObjectScale);
} else {
self.command_line
.push_info("The selected object does not support annotation scales.");
.push_info(crate::t!("The selected object does not support annotation scales.").as_ref());
}
} else {
self.command_line
.push_info("Select one object first, then run OBJECTSCALE.");
.push_info(crate::t!("Select one object first, then run OBJECTSCALE.").as_ref());
}
Task::none()
}
@ -3341,7 +3341,7 @@ impl OpenCADStudio {
let to_move: Vec<_> = self.tabs[i].scene.selected.iter().cloned().collect();
if to_move.is_empty() {
self.command_line
.push_error("DRAWORDER: select entities first.");
.push_error(crate::t!("DRAWORDER: select entities first.").as_ref());
} else {
use crate::command::CadCommand;
let cmd = super::commands::DrawOrderRefCommand::new(to_move, above);
@ -3356,7 +3356,7 @@ impl OpenCADStudio {
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
let added = self.tabs[i].scene.select_similar();
self.command_line
.push_output(&format!("Select Similar: {} added.", added));
.push_output(crate::tf!("Select Similar: {} added.", added).as_ref());
self.refresh_properties();
Task::none()
}
@ -3366,7 +3366,7 @@ impl OpenCADStudio {
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
let count = self.tabs[i].scene.invert_selection();
self.command_line
.push_output(&format!("Invert Selection: {} object(s) selected.", count));
.push_output(crate::tf!("Invert Selection: {} object(s) selected.", count).as_ref());
self.refresh_properties();
Task::none()
}
@ -3441,7 +3441,7 @@ impl OpenCADStudio {
state.append,
);
self.command_line
.push_output(&format!("QSELECT: {} object(s) selected.", matched));
.push_output(crate::tf!("QSELECT: {} object(s) selected.", matched).as_ref());
self.refresh_properties();
Task::none()
}
@ -4023,7 +4023,7 @@ impl OpenCADStudio {
if self.tabs[i].scene.delete_layout(&name) {
self.layout_rename_state = None;
self.command_line
.push_output(&format!("Layout \"{name}\" silindi"));
.push_output(crate::tf!("Layout \"{name}\" silindi").as_ref());
self.tabs[i].dirty = true;
}
Task::batch([cancel_task, switch_task])
@ -4061,7 +4061,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].is_start {
self.command_line
.push_info("Open or create a drawing to manage layouts.");
.push_info(crate::t!("Open or create a drawing to manage layouts.").as_ref());
return Task::none();
}
let current = self.tabs[i].scene.current_layout.clone();
@ -4097,9 +4097,9 @@ impl OpenCADStudio {
let new_name = self.layout_manager_rename_buf.trim().to_string();
if old_name == "Model" {
self.command_line
.push_error("Cannot rename the Model layout.");
.push_error(crate::t!("Cannot rename the Model layout.").as_ref());
} else if new_name.is_empty() {
self.command_line.push_error("Layout name cannot be empty.");
self.command_line.push_error(crate::t!("Layout name cannot be empty.").as_ref());
} else if new_name == old_name {
// no-op
} else {
@ -4111,7 +4111,7 @@ impl OpenCADStudio {
self.layout_manager_selected = new_name.clone();
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Layout renamed: '{old_name}' → '{new_name}'"));
.push_output(crate::tf!("Layout renamed: '{old_name}' → '{new_name}'").as_ref());
}
Task::none()
}
@ -4119,7 +4119,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].is_start {
self.command_line
.push_info("Open or create a drawing to add a layout.");
.push_info(crate::t!("Open or create a drawing to add a layout.").as_ref());
return Task::none();
}
let existing = self.tabs[i].scene.layout_names();
@ -4134,9 +4134,9 @@ impl OpenCADStudio {
self.layout_manager_selected = name.clone();
self.layout_manager_rename_buf = name.clone();
self.command_line
.push_output(&format!("Layout '{name}' created."));
.push_output(crate::tf!("Layout '{name}' created.").as_ref());
}
Err(e) => self.command_line.push_error(&format!("LAYOUT: {e}")),
Err(e) => self.command_line.push_error(crate::tf!("LAYOUT: {e}").as_ref()),
}
Task::none()
}
@ -4145,7 +4145,7 @@ impl OpenCADStudio {
let name = self.layout_manager_selected.clone();
if name == "Model" {
self.command_line
.push_error("Cannot delete the Model layout.");
.push_error(crate::t!("Cannot delete the Model layout.").as_ref());
Task::none()
} else {
let deleting_current = self.tabs[i].scene.current_layout == name;
@ -4165,7 +4165,7 @@ impl OpenCADStudio {
self.layout_manager_selected = "Model".to_string();
self.layout_manager_rename_buf = String::new();
self.command_line
.push_output(&format!("Layout '{name}' deleted."));
.push_output(crate::tf!("Layout '{name}' deleted.").as_ref());
Task::batch([cancel_task, switch_task])
}
}
@ -4209,7 +4209,7 @@ impl OpenCADStudio {
let task = self.on_layout_switch(name.clone());
if self.tabs[self.active_tab].scene.current_layout == name {
self.command_line
.push_output(&format!("Switched to layout '{name}'."));
.push_output(crate::tf!("Switched to layout '{name}'.").as_ref());
}
task
}
@ -4273,10 +4273,10 @@ impl OpenCADStudio {
}
Message::AliasEditorApply => {
self.apply_alias_editor_rows();
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"{} alias(es) applied.",
self.command_aliases.len()
));
).as_ref());
Task::none()
}
@ -4334,7 +4334,7 @@ impl OpenCADStudio {
}
Err(error) => self
.command_line
.push_error(&format!("Unable to change UI language: {error}")),
.push_error(crate::tf!("Unable to change UI language: {error}").as_ref()),
}
Task::none()
}
@ -4959,7 +4959,7 @@ impl OpenCADStudio {
let phase = Instant::now();
self.refresh_properties();
let properties_ms = phase.elapsed().as_secs_f64() * 1000.0;
self.command_line.push_output("MSPACE");
self.command_line.push_output(crate::t!("MSPACE").as_ref());
if perf {
crate::perf_record!(
"[perf] viewport-enter total={:.2}ms normalize={:.2}ms display={:.2}ms ucs={:.2}ms properties={:.2}ms handle={}",
@ -4996,7 +4996,7 @@ impl OpenCADStudio {
// Paper space has no UCS — drop the viewport's UCS.
self.tabs[i].refresh_active_ucs();
self.refresh_properties();
self.command_line.push_output("PSPACE");
self.command_line.push_output(crate::t!("PSPACE").as_ref());
if context_changed {
self.sync_dyn_fields();
}
@ -5007,7 +5007,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].scene.current_layout == "Model" {
self.command_line
.push_error("MS is only available in paper space layouts.");
.push_error(crate::t!("MS is only available in paper space layouts.").as_ref());
return Task::none();
}
if self.tabs[i].scene.active_viewport.is_some() {
@ -5018,7 +5018,7 @@ impl OpenCADStudio {
Some(handle) => Task::done(Message::EnterViewport(handle)),
None => {
self.command_line
.push_error("No viewport found in this layout.");
.push_error(crate::t!("No viewport found in this layout.").as_ref());
Task::none()
}
}
@ -5163,7 +5163,7 @@ impl OpenCADStudio {
Ok(msg) => self.command_line.push_info(&msg),
Err(err) => self
.command_line
.push_error(&format!("Could not set default app: {err}")),
.push_error(crate::tf!("Could not set default app: {err}").as_ref()),
}
Task::none()
}
@ -5252,11 +5252,11 @@ impl OpenCADStudio {
Message::PrintToPrinter => self.on_print_to_printer(),
Message::PrintResult(Ok(printer)) => {
self.command_line
.push_info(&format!("Sent to printer: {printer}"));
.push_info(crate::tf!("Sent to printer: {printer}").as_ref());
Task::none()
}
Message::PrintResult(Err(e)) => {
self.command_line.push_error(&format!("Print failed: {e}"));
self.command_line.push_error(crate::tf!("Print failed: {e}").as_ref());
Task::none()
}
@ -5273,7 +5273,7 @@ impl OpenCADStudio {
}
self.plot_dialog.style_name = table.name.clone();
self.plot_dialog.style_missing = false;
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Plot style '{}' loaded ({} color entries).",
table.name,
table
@ -5281,7 +5281,7 @@ impl OpenCADStudio {
.iter()
.filter(|e| e.color.is_some())
.count()
));
).as_ref());
self.active_plot_style = Some(table);
self.plot_dialog.plot_styles = crate::io::plot_style::available_ctb_names();
Task::none()
@ -5291,7 +5291,7 @@ impl OpenCADStudio {
self.active_plot_style = None;
self.plot_dialog.style_name.clear();
self.plot_dialog.style_missing = false;
self.command_line.push_output("Plot style table cleared.");
self.command_line.push_output(crate::t!("Plot style table cleared.").as_ref());
Task::none()
}
@ -5383,12 +5383,12 @@ impl OpenCADStudio {
self.plot_dialog.style_missing = false;
self.plot_dialog.plot_styles =
crate::io::plot_style::available_ctb_names();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Plot style table saved to \"{}\".",
path.display()
));
).as_ref());
}
Err(e) => self.command_line.push_error(&format!("Save error: {e}")),
Err(e) => self.command_line.push_error(crate::tf!("Save error: {e}").as_ref()),
}
}
Task::none()
@ -5416,7 +5416,7 @@ impl OpenCADStudio {
self.tabs[i].scene.document.header.current_text_style_name = name.clone();
self.sync_ribbon_styles();
self.command_line
.push_output(&format!("Current text style: {}", name));
.push_output(crate::tf!("Current text style: {}", name).as_ref());
}
Task::none()
}
@ -5716,7 +5716,7 @@ impl OpenCADStudio {
self.tabs[i].scene.document.header.current_table_style_name = name.clone();
self.ribbon.active_table_style = name.clone();
self.command_line
.push_output(&format!("Current table style: {name}"));
.push_output(crate::tf!("Current table style: {name}").as_ref());
}
Task::none()
}
@ -5745,7 +5745,7 @@ impl OpenCADStudio {
// Staged: persists on Apply.
self.tabs[i].scene.document.header.multiline_style = name.clone();
self.command_line
.push_output(&format!("Current multiline style: {}", name));
.push_output(crate::tf!("Current multiline style: {}", name).as_ref());
}
Task::none()
}
@ -5878,10 +5878,10 @@ impl OpenCADStudio {
self.tabs[i].scene.document.header.current_dimstyle_name =
self.dimstyle_selected.clone();
self.sync_ribbon_styles();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Current dim style set to '{}'.",
self.dimstyle_selected
));
).as_ref());
Task::none()
}
Message::DimStyleDialogDelete => {

View file

@ -368,7 +368,7 @@ impl OpenCADStudio {
ds.dimalt = self.ds_dimalt;
ds.dimapost = self.ds_dimapost.clone();
self.command_line
.push_output(&format!("DimStyle '{}' updated.", self.dimstyle_selected));
.push_output(crate::tf!("DimStyle '{}' updated.", self.dimstyle_selected).as_ref());
}
/// Update a single string buffer field.
@ -687,7 +687,7 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
self.tabs[i].active_mleader_style = name.clone();
self.ribbon.active_mleader_style = name.clone();
self.command_line
.push_output(&format!("Current multileader style: {}", name));
.push_output(crate::tf!("Current multileader style: {}", name).as_ref());
}
Task::none()
}

View file

@ -515,7 +515,7 @@ impl OpenCADStudio {
if self.tabs[i].scene.set_active_viewport_render_mode(mode) {
self.tabs[i].scene.bump_geometry_no_blocks();
self.command_line
.push_output(&format!("Viewport visual style: {label}"));
.push_output(crate::tf!("Viewport visual style: {label}").as_ref());
return Task::none();
}
self.tabs[i].render_mode = mode;
@ -533,7 +533,7 @@ impl OpenCADStudio {
// pipeline keys its upload cache off `geometry_epoch`.
self.tabs[i].scene.bump_geometry_no_blocks();
self.command_line
.push_output(&format!("Visual style: {label}"));
.push_output(crate::tf!("Visual style: {label}").as_ref());
Task::none()
}
@ -2616,7 +2616,7 @@ impl OpenCADStudio {
.as_mut()
.map(|c| c.on_structure_pick(pick.handle, center));
self.command_line
.push_info(&format!("{} acquired.", pick.label));
.push_info(crate::tf!("{} acquired.", pick.label).as_ref());
result
} else {
let msg = self.tabs[i]
@ -2745,7 +2745,7 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = Some(cmd);
} else {
self.command_line
.push_error("HATCHEDIT: not a hatch entity.");
.push_error(crate::t!("HATCHEDIT: not a hatch entity.").as_ref());
self.tabs[i].active_cmd = None;
}
}
@ -2772,7 +2772,7 @@ impl OpenCADStudio {
}
result
} else {
self.command_line.push_info("Nothing found at that point.");
self.command_line.push_info(crate::t!("Nothing found at that point.").as_ref());
None
}
} else if self.tabs[i]
@ -2787,7 +2787,7 @@ impl OpenCADStudio {
.as_mut()
.map(|c| c.on_tangent_point(obj, pick_wcs))
} else {
self.command_line.push_info("Select a tangent object.");
self.command_line.push_info(crate::t!("Select a tangent object.").as_ref());
None
}
} else if !self.command_point_allowed(i, world_pt) {
@ -3250,9 +3250,9 @@ impl OpenCADStudio {
// `selection_just_completed`, or a
// gather command (MOVE's "select
// objects") would wrongly finish.
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Object is on locked layer \"{layer}\" — unlock the layer to select or edit it."
));
).as_ref());
} else {
// Individual picks accumulate (issue #47):
// each plain click adds to the selection,
@ -3513,9 +3513,9 @@ impl OpenCADStudio {
// Locked layer: double-click must not open any editor
// (text / attribute / in-place block edit).
if let Some(layer) = self.tabs[i].scene.locked_layer_name(handle) {
self.command_line.push_info(&format!(
self.command_line.push_info(crate::tf!(
"Object is on locked layer \"{layer}\" — unlock the layer to edit it."
));
).as_ref());
return Task::none();
}
// Any text-bearing entity opens its in-place editor
@ -3693,7 +3693,7 @@ impl OpenCADStudio {
self.tabs[i]
.scene
.record_nav_perf(crate::scene::NavPerfOp::Zoom, now);
self.command_line.push_output("Zoom Extents");
self.command_line.push_output(crate::t!("Zoom Extents").as_ref());
}
Task::none()
}
@ -3891,7 +3891,7 @@ impl OpenCADStudio {
}
self.tabs[i].scene.camera_generation += 1;
self.command_line
.push_output(&format!("View: {}", region.label()));
.push_output(crate::tf!("View: {}", region.label()).as_ref());
Task::none()
}
@ -4094,7 +4094,7 @@ impl OpenCADStudio {
.position(|session| session.block_name == name)
else {
self.command_line
.push_error(&format!("BEDIT: block tab \"{name}\" is not open."));
.push_error(crate::tf!("BEDIT: block tab \"{name}\" is not open.").as_ref());
return Task::none();
};
if self.tabs[i].active_block_edit == Some(target_index) {
@ -4156,7 +4156,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].is_start {
self.command_line
.push_info("Open or create a drawing to switch layouts.");
.push_info(crate::t!("Open or create a drawing to switch layouts.").as_ref());
return Task::none();
}
let perf = crate::perf::enabled();
@ -4270,7 +4270,7 @@ impl OpenCADStudio {
let i = self.active_tab;
if self.tabs[i].is_start {
self.command_line
.push_info("Open or create a drawing to add a layout.");
.push_info(crate::t!("Open or create a drawing to add a layout.").as_ref());
return Task::none();
}
let cancel_task = self.cancel_active_command_for_space_change();
@ -4310,15 +4310,15 @@ impl OpenCADStudio {
self.tabs[i].scene.ensure_sheet_viewport(&new_name);
let switch_task = self.on_layout_switch(new_name.clone());
self.tabs[i].scene.fit_all();
self.command_line.push_output(&format!(
self.command_line.push_output(crate::tf!(
"Layout \"{new_name}\" created — use MVIEW to add a viewport"
));
).as_ref());
self.tabs[i].dirty = true;
return Task::batch([cancel_task, switch_task]);
}
Err(e) => self
.command_line
.push_error(&format!("Failed to create layout: {e}")),
.push_error(crate::tf!("Failed to create layout: {e}").as_ref()),
}
cancel_task
}
@ -4342,7 +4342,7 @@ impl OpenCADStudio {
.is_some()
{
self.command_line
.push_error(&format!("\"{}\" name already in use", new_name));
.push_error(crate::tf!("\"{}\" name already in use", new_name).as_ref());
} else {
self.push_undo_snapshot(i, "BLOCK RENAME");
if self.tabs[i].scene.rename_block(&orig, &new_name) {
@ -4358,10 +4358,10 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Block \"{orig}\" → \"{new_name}\""));
.push_output(crate::tf!("Block \"{orig}\" → \"{new_name}\"").as_ref());
} else {
self.command_line
.push_error(&format!("Could not rename block \"{orig}\""));
.push_error(crate::tf!("Could not rename block \"{orig}\"").as_ref());
}
}
return Task::none();
@ -4373,7 +4373,7 @@ impl OpenCADStudio {
.any(|n| *n == new_name);
if exists {
self.command_line
.push_error(&format!("\"{}\" name already in use", new_name));
.push_error(crate::tf!("\"{}\" name already in use", new_name).as_ref());
} else {
self.push_undo_snapshot(i, "LAYOUT RENAME");
self.tabs[i].scene.rename_layout(&orig, &new_name);
@ -4382,7 +4382,7 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.command_line
.push_output(&format!("Layout \"{orig}\" → \"{new_name}\""));
.push_output(crate::tf!("Layout \"{orig}\" → \"{new_name}\"").as_ref());
}
}
}

View file

@ -14,6 +14,7 @@ use iced::widget::{
use iced::window;
use iced::{keyboard, Background, Border, Color, Element, Fill, Subscription, Task, Theme};
use iced_aw::ContextMenu;
use crate::t;
mod controls;
mod modal;
@ -1210,7 +1211,7 @@ impl OpenCADStudio {
let copy_btn = button(
row![
crate::ui::icons::themed_primary(crate::ui::icons::COPY, 11.0),
text("Copy").size(11),
text(t!("Copy")).size(11),
]
.spacing(4)
.align_y(iced::Center),
@ -1221,7 +1222,7 @@ impl OpenCADStudio {
let clear_btn = button(
row![
crate::ui::icons::themed_danger(crate::ui::icons::TRASH, 11.0),
text("Clear").size(11),
text(t!("Clear")).size(11),
]
.spacing(4)
.align_y(iced::Center),
@ -1230,7 +1231,7 @@ impl OpenCADStudio {
.style(perf_button_style)
.padding([2, 6]);
let header = row![
text("PERF").size(12).style(|theme: &Theme| iced::widget::text::Style {
text(t!("PERF")).size(12).style(|theme: &Theme| iced::widget::text::Style {
color: Some(theme.palette().success.base.color),
}),
Space::new().width(iced::Length::Fill),

View file

@ -1,6 +1,8 @@
use super::super::{Message, OpenCADStudio};
use crate::t;
use iced::widget::{button, column, container, row, text, Space};
use iced::{Background, Element, Fill, Fit, Theme};
use std::borrow::Cow;
impl OpenCADStudio {
/// Title shown in the active modal's title bar. Keep in sync with the
@ -221,7 +223,7 @@ impl OpenCADStudio {
)
} else {
automatic_flow(ex, |flow| {
container(text("The selected layer state is no longer available."))
container(text(t!("The selected layer state is no longer available.")))
.padding(16)
.width(flow.width)
.height(flow.height)
@ -941,12 +943,12 @@ fn automatic_flow<'a>(
)
}
fn dialog_button(
label: &'static str,
fn dialog_button<'a>(
label: impl Into<Cow<'a, str>>,
message: Message,
style: fn(&Theme, button::Status) -> button::Style,
) -> Element<'static, Message> {
button(text(label).size(13))
) -> Element<'a, Message> {
button(text(label.into()).size(13))
.on_press(message)
.style(style)
.padding([6, 18])
@ -980,7 +982,7 @@ fn save_as_dialog_window<'a>(
.iter()
.copied()
.find(|&s| s == format);
let label = |s: &'static str| text(s).size(11).style(dialog_muted_text_style);
let label = |s: Cow<'static, str>| text(s).size(11).style(dialog_muted_text_style);
let field_width = if matches!(sizing.width, iced::Length::Fill) {
Fill
} else {
@ -988,7 +990,7 @@ fn save_as_dialog_window<'a>(
};
let mut items: Vec<Element<'a, Message>> = Vec::new();
items.push(text("Save Drawing As").size(14).into());
items.push(text(t!("Save Drawing As")).size(14).into());
items.push(Space::new().height(12).into());
// Web has no native file dialog, so the file name is typed here. On native
@ -997,7 +999,7 @@ fn save_as_dialog_window<'a>(
{
items.push(
row![
label("File name:").width(70),
label(t!("File name:")).width(70),
iced::widget::text_input("drawing.dwg", filename)
.on_input(Message::SaveDialogFilenameChanged)
.size(13)
@ -1016,7 +1018,7 @@ fn save_as_dialog_window<'a>(
items.push(
row![
label("Format:").width(70),
label(t!("Format:")).width(70),
iced::widget::pick_list(
sel_fmt,
crate::io::SAVE_FORMAT_OPTIONS,
@ -1034,9 +1036,9 @@ fn save_as_dialog_window<'a>(
items.push(
row![
Space::new().width(Fit),
dialog_button("Save as...", Message::SaveDialogConfirm, button::primary),
dialog_button(t!("Save as..."), Message::SaveDialogConfirm, button::primary),
Space::new().width(8),
dialog_button("Cancel", Message::SaveDialogCancel, button::secondary),
dialog_button(t!("Cancel"), Message::SaveDialogCancel, button::secondary),
]
.into(),
);
@ -1058,18 +1060,21 @@ fn unsaved_changes_dialog_window(
name: &str,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'static, Message> {
let body_text = format!("Do you want to save changes to \"{}\"?", name);
let body_text = t!(
"Do you want to save changes to \"%{name}\"?",
name = name
);
container(
column![
text(body_text).size(13),
iced::widget::Space::new().height(20),
row![
dialog_button("Save", Message::UnsavedDialogSave, button::primary),
dialog_button(t!("Save"), Message::UnsavedDialogSave, button::primary),
iced::widget::Space::new().width(8),
dialog_button("Discard", Message::UnsavedDialogDiscard, button::danger),
dialog_button(t!("Discard"), Message::UnsavedDialogDiscard, button::danger),
iced::widget::Space::new().width(8),
dialog_button("Cancel", Message::UnsavedDialogCancel, button::secondary),
dialog_button(t!("Cancel"), Message::UnsavedDialogCancel, button::secondary),
],
]
.spacing(0),
@ -1090,19 +1095,18 @@ fn file_in_use_dialog_window(
let file_name = std::path::Path::new(path)
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| "Drawing".to_string());
let heading = format!("\"{file_name}\" could not be saved.");
let path_line = format!("Path: {path}");
let details = format!("Details: {error}");
.unwrap_or_else(|| t!("Drawing").into_owned());
let heading = t!("\"%{file_name}\" could not be saved.", file_name = file_name);
let path_line = t!("Path: %{path}", path = path);
let details = t!("Details: %{error}", error = error);
container(
column![
text(heading).size(14),
Space::new().height(8),
text(
"The file is open or being used by another application. \
Close it there and retry, or save this drawing under a different name."
)
text(t!(
"The file is open or being used by another application. Close it there and retry, or save this drawing under a different name."
))
.size(13)
.width(Fit),
Space::new().height(12),
@ -1112,19 +1116,19 @@ fn file_in_use_dialog_window(
Space::new().height(18),
row![
dialog_button(
"Retry",
t!("Retry"),
Message::SaveFileInUseRetry,
button::primary
),
Space::new().width(8),
dialog_button(
"Save As",
t!("Save As"),
Message::SaveFileInUseSaveAs,
button::secondary
),
Space::new().width(8),
dialog_button(
"Cancel",
t!("Cancel"),
Message::SaveFileInUseCancel,
button::secondary
),
@ -1147,18 +1151,17 @@ fn external_change_dialog_window(
let file_name = std::path::Path::new(path)
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| "Drawing".to_string());
let heading = format!("\"{file_name}\" was changed by another application.");
let path_line = format!("Path: {path}");
.unwrap_or_else(|| t!("Drawing").into_owned());
let heading = t!("\"%{file_name}\" was changed by another application.", file_name = file_name);
let path_line = t!("Path: %{path}", path = path);
container(
column![
text(heading).size(14),
Space::new().height(8),
text(
"Saving now could destroy those external changes. Reload the disk copy, \
save your local work elsewhere, or explicitly overwrite it."
)
text(t!(
"Saving now could destroy those external changes. Reload the disk copy, save your local work elsewhere, or explicitly overwrite it."
))
.size(13)
.width(Fit),
Space::new().height(12),
@ -1166,25 +1169,25 @@ fn external_change_dialog_window(
Space::new().height(18),
row![
dialog_button(
"Reload from Disk",
t!("Reload from Disk"),
Message::ExternalChangeReload,
button::primary
),
Space::new().width(8),
dialog_button(
"Save As",
t!("Save As"),
Message::ExternalChangeSaveAs,
button::secondary
),
Space::new().width(8),
dialog_button(
"Overwrite",
t!("Overwrite"),
Message::ExternalChangeOverwrite,
button::danger
),
Space::new().width(8),
dialog_button(
"Cancel",
t!("Cancel"),
Message::ExternalChangeCancel,
button::secondary
),
@ -1209,10 +1212,11 @@ fn aec_drop_dialog_window(
src_version: &str,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'static, Message> {
let body_text = format!(
"This drawing contains {count} AEC/Civil objects that \"{target}\" \
cannot store, so they will not be saved.\n\n\
To keep them, save in the source version ({src_version})."
let body_text = t!(
"This drawing contains %{count} AEC/Civil objects that \"%{target}\" cannot store, so they will not be saved.\n\nTo keep them, save in the source version (%{src_version}).",
count = count,
target = target,
src_version = src_version,
);
container(
@ -1221,14 +1225,14 @@ fn aec_drop_dialog_window(
iced::widget::Space::new().height(20),
row![
dialog_button(
"Save in source version",
t!("Save in source version"),
Message::AecDropSameVersion,
button::primary
),
iced::widget::Space::new().width(8),
dialog_button("Save anyway", Message::AecDropProceed, button::warning),
dialog_button(t!("Save anyway"), Message::AecDropProceed, button::warning),
iced::widget::Space::new().width(8),
dialog_button("Back", Message::AecDropBack, button::secondary),
dialog_button(t!("Back"), Message::AecDropBack, button::secondary),
],
]
.spacing(0),
@ -1249,16 +1253,25 @@ fn layer_delete_warning_window(
count: usize,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'static, Message> {
let obj = if count == 1 { "object" } else { "objects" };
let subject = if names.len() == 1 {
format!("Layer \"{}\"", names[0])
let obj = if count == 1 { t!("object") } else { t!("objects") };
let has = if names.len() == 1 { t!("has") } else { t!("hold") };
let those = if count == 1 {
t!("that object")
} else {
format!("{} selected layers", names.len())
t!("those objects")
};
let body_text = format!(
"{subject} still {} {count} {obj}.\n\nDeleting will also remove {} from the drawing. Continue?",
if names.len() == 1 { "has" } else { "hold" },
if count == 1 { "that object" } else { "those objects" }
let subject = if names.len() == 1 {
t!("Layer \"%{name}\"", name = names[0]).into_owned()
} else {
t!("%{count} selected layers", count = names.len()).into_owned()
};
let body_text = t!(
"%{subject} still %{has} %{count} %{obj}.\n\nDeleting will also remove %{those} from the drawing. Continue?",
subject = subject,
has = has,
count = count,
obj = obj,
those = those,
);
container(
@ -1267,12 +1280,12 @@ fn layer_delete_warning_window(
iced::widget::Space::new().height(20),
row![
dialog_button(
"Delete Objects",
t!("Delete Objects"),
Message::LayerDeleteConfirm,
button::danger
),
iced::widget::Space::new().width(8),
dialog_button("Cancel", Message::CloseModal, button::secondary),
dialog_button(t!("Cancel"), Message::CloseModal, button::secondary),
],
]
.spacing(0),
@ -1293,19 +1306,19 @@ fn default_assoc_dialog_window(
) -> Element<'static, Message> {
container(
column![
text("Make Open CAD Studio your default CAD app?")
text(t!("Make Open CAD Studio your default CAD app?"))
.size(15),
iced::widget::Space::new().height(10),
text("Open .dwg and .dxf drawings in Open CAD Studio by default. You can change this later in your system settings.")
text(t!("Open .dwg and .dxf drawings in Open CAD Studio by default. You can change this later in your system settings."))
.size(12)
.style(dialog_muted_text_style),
iced::widget::Space::new().height(22),
row![
iced::widget::Space::new().width(Fit),
dialog_button("Not now", Message::AssocPromptNo, button::secondary),
dialog_button(t!("Not now"), Message::AssocPromptNo, button::secondary),
iced::widget::Space::new().width(8),
dialog_button(
"Yes, set as default",
t!("Yes, set as default"),
Message::AssocPromptYes,
button::primary
),

View file

@ -4,6 +4,7 @@ use iced::widget::{
Space,
};
use iced::{Background, Border, Color, Element, Fill, Theme};
use crate::t;
pub(super) fn position_canvas_overlay<'a>(
anchor: iced::Point,
@ -28,7 +29,7 @@ pub(super) fn text_inline_overlay(
ed: &super::super::text_inline::TextInlineState,
canvas: (f32, f32),
) -> Element<'_, Message> {
let field = text_input("Text", &ed.value)
let field = text_input(t!("Text").as_ref(), &ed.value)
.id(iced::widget::Id::new(TEXT_INLINE_ID))
.on_input(Message::TextInlineInput)
.on_submit(Message::TextInlineOk)
@ -366,7 +367,7 @@ pub(super) fn mtext_editor_overlay<'a>(
crate::ui::modal::modal(
iced::widget::Space::new().width(Fill).height(Fill),
"Text Editor",
t!("Text Editor"),
content,
Message::MTextCancel,
modal_offset,
@ -577,7 +578,7 @@ fn mtext_editor_content<'a>(
f64::from(writing_area_px / preview_scale).max(slider_min * 2.0);
let width_slider = column![
row![
text(format!("Width: {:.3}", ed.rect_width)).size(11),
text(t!("Width: %{value}", value = format!("{:.3}", ed.rect_width))).size(11),
Space::new().width(width),
text(format!("{:.0}%", ed.rect_width / slider_max * 100.0)).size(11),
]
@ -709,7 +710,7 @@ fn mtext_editor_content<'a>(
let action_bar = container(
row![
iced::widget::Space::new().width(width),
crate::ui::style::style_manager::tb_button("Apply", Message::MTextApply, true),
crate::ui::style::style_manager::tb_button(t!("Apply"), Message::MTextApply, true),
]
.align_y(iced::Alignment::Center),
)
@ -784,13 +785,13 @@ pub(super) fn viewport_context_menu_overlay(
let mut items: Vec<Element<'static, Message>> = Vec::new();
if has_cmd {
items.push(item("Cancel".to_string(), Message::CommandEscape));
items.push(item("Enter".to_string(), Message::CommandFinalize));
items.push(item(t!("Cancel").into_owned(), Message::CommandEscape));
items.push(item(t!("Enter").into_owned(), Message::CommandFinalize));
} else {
if !last_cmds.is_empty() {
let last = last_cmds[0].clone();
items.push(item(
format!("Repeat {last}"),
t!("Repeat %{last}", last = last).into_owned(),
Message::Command(last.to_uppercase()),
));
if last_cmds.len() > 1 {
@ -802,13 +803,13 @@ pub(super) fn viewport_context_menu_overlay(
items.push(sep());
}
if has_selection {
items.push(item("Delete".to_string(), Message::DeleteSelected));
items.push(item(t!("Delete").into_owned(), Message::DeleteSelected));
items.push(item(
"Move".to_string(),
t!("Move").into_owned(),
Message::Command("MOVE".to_string()),
));
items.push(item(
"Copy".to_string(),
t!("Copy").into_owned(),
Message::Command("COPY".to_string()),
));
items.push(sep());
@ -820,7 +821,7 @@ pub(super) fn viewport_context_menu_overlay(
items.push(
button(
row![
text("Draw Order").size(12),
text(t!("Draw Order").into_owned()).size(12),
iced::widget::Space::new().width(Fill),
do_caret,
]
@ -834,51 +835,51 @@ pub(super) fn viewport_context_menu_overlay(
);
if draworder_open {
items.push(subitem(
"Bring to Front".to_string(),
t!("Bring to Front").into_owned(),
Message::Command("DRAWORDER F".to_string()),
));
items.push(subitem(
"Send to Back".to_string(),
t!("Send to Back").into_owned(),
Message::Command("DRAWORDER B".to_string()),
));
items.push(subitem(
"Bring Above Object".to_string(),
t!("Bring Above Object").into_owned(),
Message::DrawOrderPickRef(true),
));
items.push(subitem(
"Send Under Object".to_string(),
t!("Send Under Object").into_owned(),
Message::DrawOrderPickRef(false),
));
}
items.push(sep());
items.push(item(
"Isolate Objects".to_string(),
t!("Isolate Objects").into_owned(),
Message::Command("ISOLATEOBJECTS".to_string()),
));
items.push(item(
"Hide Objects".to_string(),
t!("Hide Objects").into_owned(),
Message::Command("HIDEOBJECTS".to_string()),
));
items.push(sep());
items.push(item("Select Similar".to_string(), Message::SelectSimilar));
items.push(item(t!("Select Similar").into_owned(), Message::SelectSimilar));
items.push(item(
"Invert Selection".to_string(),
t!("Invert Selection").into_owned(),
Message::InvertSelection,
));
}
if isolation_active {
items.push(item(
"End Object Isolation".to_string(),
t!("End Object Isolation").into_owned(),
Message::Command("UNISOLATEOBJECTS".to_string()),
));
}
items.push(item(
"Select All".to_string(),
t!("Select All").into_owned(),
Message::Command("SELECTALL".to_string()),
));
items.push(item("Quick Select...".to_string(), Message::QSelectOpen));
items.push(item(t!("Quick Select...").into_owned(), Message::QSelectOpen));
items.push(item(
"Zoom Extents".to_string(),
t!("Zoom Extents").into_owned(),
Message::Command("ZOOM EXTENTS".to_string()),
));
}
@ -1020,7 +1021,7 @@ pub(super) fn qselect_overlay<'a>(
crate::ui::modal::modal(
Space::new().width(Fill).height(Fill),
"Quick Select",
t!("Quick Select"),
content,
Message::QSelectClose,
modal_offset,
@ -1081,13 +1082,13 @@ fn qselect_content<'a>(
iced::Length::Shrink
};
let label = |s: &'static str| {
let label = |s: std::borrow::Cow<'static, str>| {
text(s)
.size(12)
.width(iced::Length::Fixed(90.0))
};
let btn = |lbl: &'static str, msg: Message, primary: bool| {
let btn = |lbl: std::borrow::Cow<'static, str>, msg: Message, primary: bool| {
button(text(lbl).size(12))
.on_press(msg)
.style(move |theme: &Theme, st| {
@ -1124,7 +1125,7 @@ fn qselect_content<'a>(
let panel_body = column![
row![
label("Object type:"),
label(t!("Object type:")),
iced::widget::pick_list(
Some(type_sel),
type_options,
@ -1144,7 +1145,7 @@ fn qselect_content<'a>(
.width(sizing.width),
Space::new().height(6),
row![
label("Property:"),
label(t!("Property:")),
iced::widget::pick_list(
Some(prop_sel),
prop_options,
@ -1164,7 +1165,7 @@ fn qselect_content<'a>(
.width(sizing.width),
Space::new().height(6),
row![
label("Operator:"),
label(t!("Operator:")),
iced::widget::pick_list(
Some(state.operator),
op_options,
@ -1177,7 +1178,7 @@ fn qselect_content<'a>(
.spacing(8)
.width(sizing.width),
Space::new().height(6),
row![label("Value:"), value_input,]
row![label(t!("Value:")), value_input,]
.align_y(iced::Alignment::Center)
.spacing(8)
.width(sizing.width),
@ -1187,15 +1188,15 @@ fn qselect_content<'a>(
.on_toggle(Message::QSelectSetAppend)
.size(14),
Space::new().width(6),
text("Append to current selection").size(12),
text(t!("Append to current selection")).size(12),
]
.align_y(iced::Alignment::Center),
Space::new().height(14),
row![
Space::new().width(field_width),
btn("Cancel", Message::QSelectClose, false),
btn(t!("Cancel"), Message::QSelectClose, false),
Space::new().width(8),
btn("Apply", Message::QSelectApply, true),
btn(t!("Apply"), Message::QSelectApply, true),
]
.align_y(iced::Alignment::Center),
]