Graphic Attributes: quieter swatches, Enter in linetype scale, undo names

- Colour swatches carry no *VARIES* or ByBlock text; the L / B / C / V
  button already shows that.
- A separator sits between "Create Layer with active settings" and the
  "Create fills on the current layer" checkbox.
- The linetype scale field is a plain text field like the Properties
  panel: the first click selects its value, Enter applies it (decimal
  comma and expressions accepted) instead of repeating the last command.
  This drops the iced_aw number_input feature again.
- Undo/redo name fill changes "Fill change" and linetype changes
  "Linetype", in all 21 locales.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
This commit is contained in:
Claude committed 2026-10-07 19:01:25 +00:00
1 parent c21a1e6538
commit 33a105a619
27 files changed
+168 -108

No files matched your search

+85 -3
View File
@@ -219,7 +219,11 @@ impl OpenCADStudio {
use GraphicAttributesMsg as M;
if !matches!(
message,
M::ToggleMenu(_) | M::HatchPatternSearch(_) | M::HatchPatternFocus(_) | M::Gradient(_)
M::ToggleMenu(_)
| M::HatchPatternSearch(_)
| M::HatchPatternFocus(_)
| M::LineLinetypeScaleInput(_)
| M::Gradient(_)
) {
self.graphic_attributes.open_menu = None;
}
@@ -253,6 +257,19 @@ impl OpenCADStudio {
M::LineLinetype(linetype) => self.on_line_linetype(linetype),
M::LineLineweight(lineweight) => self.on_line_lineweight(lineweight),
M::LineLinetypeScale(scale) => self.on_line_linetype_scale(scale),
M::LineLinetypeScaleInput(value) => {
self.graphic_attributes.linetype_scale_input = Some(value);
Task::none()
}
M::LineLinetypeScaleSubmit => {
match self.graphic_attributes.linetype_scale_input.take() {
Some(typed) => {
let value = crate::app::expr_eval::eval_number(&typed.replace(',', "."));
value.map_or_else(Task::none, |scale| self.on_line_linetype_scale(scale))
}
None => Task::none(),
}
}
M::LineTransparency(transparency) => self.on_line_transparency(transparency),
M::FillColor(color) => self.on_solid_fill_color(color),
M::FillTransparency(transparency) => self.on_fill_transparency(transparency),
@@ -731,7 +748,7 @@ impl OpenCADStudio {
);
}
let selected = selected.as_slice();
let pending = self.begin_undo(i, crate::t!("Graphic Attributes"), selected.len(), true);
let pending = self.begin_undo(i, crate::t!("Fill change"), selected.len(), true);
let mut changed = false;
for handle in to_close {
let Some(mut entity) = self.tabs[i].scene.document.get_entity(*handle).cloned() else {
@@ -920,7 +937,7 @@ impl OpenCADStudio {
if !self.has_selection() {
return self.on_ribbon_linetype_changed(linetype);
}
self.edit_graphic_part(Part::Line, &crate::t!("Line linetype"), |entity| {
self.edit_graphic_part(Part::Line, &crate::t!("Linetype"), |entity| {
crate::scene::view::dispatch::apply_common_prop(entity, "linetype", &linetype);
});
Task::none()
@@ -1604,4 +1621,69 @@ mod tests {
Some((DockSide::Right, 0))
);
}
fn output_since(app: &OpenCADStudio, start: usize) -> String {
app.command_line.history[start..]
.iter()
.map(|entry| entry.text.as_str())
.collect::<Vec<_>>()
.join("\n")
}
#[test]
fn undo_names_fill_and_linetype_changes() {
let mut app = fresh();
let boundary = add_closed_square(&mut app, 0.0);
select(&mut app, &[boundary]);
let _ = app.update(ga(GraphicAttributesMsg::Fill(GraphicAttribute::Solid)));
let start = app.command_line.history.len();
let _ = app.update(Message::Undo);
assert!(output_since(&app, start).contains("Undo: Fill change"));
let _ = app.update(ga(GraphicAttributesMsg::LineLinetype("Continuous".into())));
let start = app.command_line.history.len();
let _ = app.update(Message::Undo);
assert!(output_since(&app, start).contains("Undo: Linetype"));
}
#[test]
fn typed_linetype_scale_is_applied_on_enter() {
let mut app = fresh();
let i = app.active_tab;
let line = app.tabs[i].scene.add_entity(EntityType::Line(Line::new()));
select(&mut app, &[line]);
// Enter without typing changes nothing.
let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScaleSubmit));
assert_eq!(common(&app, line).linetype_scale, 1.0);
// Typing alone does not apply; Enter does, with a decimal comma too.
let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScaleInput("0,35".into())));
assert_eq!(common(&app, line).linetype_scale, 1.0);
let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScaleSubmit));
assert_eq!(common(&app, line).linetype_scale, 0.35);
assert!(app.graphic_attributes.linetype_scale_input.is_none());
// Invalid or non-positive input is dropped.
for typed in ["abc", "0", "-2"] {
let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScaleInput(typed.into())));
let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScaleSubmit));
assert_eq!(common(&app, line).linetype_scale, 0.35);
}
}
#[test]
fn clicking_the_linetype_scale_field_selects_it_once() {
let mut app = fresh();
let field = iced::widget::Id::new(palette::LINETYPE_SCALE_FIELD);
let _ = app.update(Message::PropSyncActive(Some(field.clone())));
assert!(app.graphic_attributes.linetype_scale_focused);
// Focus elsewhere drops unsubmitted text.
app.graphic_attributes.linetype_scale_input = Some("3".into());
let _ = app.update(Message::PropSyncActive(None));
assert!(!app.graphic_attributes.linetype_scale_focused);
assert!(app.graphic_attributes.linetype_scale_input.is_none());
}
}
+16 -1
View File
@@ -6887,13 +6887,28 @@ impl OpenCADStudio {
Message::PropAttrCommit(tag) => self.on_prop_attr_commit(tag),
Message::PropPointerPressed => {
if !self.dock_panel_visible(crate::ui::dock::PanelId::Properties) {
if !self.dock_panel_visible(crate::ui::dock::PanelId::Properties)
&& !self.dock_panel_visible(crate::ui::dock::PanelId::GraphicAttributes)
{
return Task::none();
}
crate::ui::properties::sync_active_field_task()
}
Message::PropSyncActive(focused) => {
// The Graphic Attributes linetype scale field behaves like a
// Properties field: the first click selects its value.
let scale_field = iced::widget::Id::new(
crate::ui::window::graphic_attributes::LINETYPE_SCALE_FIELD,
);
if focused.as_ref() == Some(&scale_field) {
if !std::mem::replace(&mut self.graphic_attributes.linetype_scale_focused, true) {
return iced::widget::operation::select_all(scale_field);
}
return Task::none();
}
self.graphic_attributes.linetype_scale_focused = false;
self.graphic_attributes.linetype_scale_input = None;
let panel = &mut self.tabs[self.active_tab].properties;
if let Some(id) = focused.as_ref() {
if let Some(key) = panel.prop_field_key_for_id(id) {