forked from 1b-agent/opencadstudio-upstream
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:
27 files changed
+168
-108
No files matched your search
@@ -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
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user