feat(styles): green ✓ for current style + resolve it from DWG files
- The current-style marker is now a green ✓ in its own fixed-width column so names stay aligned; rendered as a separate coloured glyph rather than baked into the label string. - Resolve the current text / dimension / multiline style from the handle the DWG header stores into the name the app reads (fix_current_style_names on load). DXF already provides these as names ($TEXTSTYLE / $DIMSTYLE / $CMLSTYLE); DWG only stores handles, so the marker previously always fell back to "Standard". Only overrides when the handle resolves. Note: table and multileader current styles are not surfaced by the file reader (no header name/handle exposed), so those markers still default to the app's active selection until acadrust exposes them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
885bacd0f6
commit
b3ba3a53d1
3 changed files with 56 additions and 13 deletions
|
|
@ -99,6 +99,7 @@ pub fn load_file(path: &Path) -> Result<CadDocument, String> {
|
||||||
.read()
|
.read()
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
fix_viewport_status_flags(&mut doc);
|
fix_viewport_status_flags(&mut doc);
|
||||||
|
fix_current_style_names(&mut doc);
|
||||||
Ok(doc)
|
Ok(doc)
|
||||||
}
|
}
|
||||||
"dxf" => {
|
"dxf" => {
|
||||||
|
|
@ -108,6 +109,7 @@ pub fn load_file(path: &Path) -> Result<CadDocument, String> {
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
fix_dxf_dimension_rotations(&mut doc);
|
fix_dxf_dimension_rotations(&mut doc);
|
||||||
fix_viewport_status_flags(&mut doc);
|
fix_viewport_status_flags(&mut doc);
|
||||||
|
fix_current_style_names(&mut doc);
|
||||||
Ok(doc)
|
Ok(doc)
|
||||||
}
|
}
|
||||||
_ => Err(format!("Unsupported file format: .{ext}")),
|
_ => Err(format!("Unsupported file format: .{ext}")),
|
||||||
|
|
@ -235,6 +237,38 @@ pub fn save(doc: &CadDocument, path: &Path) -> Result<(), String> {
|
||||||
|
|
||||||
// ── Post-load fixups ──────────────────────────────────────────────────────
|
// ── Post-load fixups ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Resolve the current text / dimension / multiline style from the handle the
|
||||||
|
// DWG header stores into the *name* the app reads. DXF stores these as names
|
||||||
|
// directly ($TEXTSTYLE / $DIMSTYLE / $CMLSTYLE), but DWG only stores handles,
|
||||||
|
// so without this the current-style markers (and any code keyed on the name)
|
||||||
|
// fall back to "Standard". Only overrides when the handle resolves, leaving the
|
||||||
|
// DXF-provided names intact.
|
||||||
|
fn fix_current_style_names(doc: &mut CadDocument) {
|
||||||
|
use acadrust::objects::ObjectType;
|
||||||
|
|
||||||
|
let h = doc.header.current_text_style_handle;
|
||||||
|
if h.is_valid() {
|
||||||
|
if let Some(name) = doc.text_styles.iter().find(|s| s.handle == h).map(|s| s.name.clone()) {
|
||||||
|
doc.header.current_text_style_name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let h = doc.header.current_dimstyle_handle;
|
||||||
|
if h.is_valid() {
|
||||||
|
if let Some(name) = doc.dim_styles.iter().find(|s| s.handle == h).map(|s| s.name.clone()) {
|
||||||
|
doc.header.current_dimstyle_name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let h = doc.header.current_multiline_style_handle;
|
||||||
|
if h.is_valid() {
|
||||||
|
if let Some(name) = doc.objects.values().find_map(|o| match o {
|
||||||
|
ObjectType::MLineStyle(s) if s.handle == h => Some(s.name.clone()),
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
doc.header.multiline_style = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Corrupt-entity guard ──────────────────────────────────────────────────
|
// ── Corrupt-entity guard ──────────────────────────────────────────────────
|
||||||
//
|
//
|
||||||
// acadrust's DWG parser occasionally desynchronises on certain files and
|
// acadrust's DWG parser occasionally desynchronises on certain files and
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
//! carries both `on_press` (select) and `on_double_click` (rename) itself.
|
//! carries both `on_press` (select) and `on_double_click` (rename) itself.
|
||||||
|
|
||||||
use crate::app::{Message, StyleKind};
|
use crate::app::{Message, StyleKind};
|
||||||
use iced::widget::{container, mouse_area, text, text_input};
|
use iced::widget::{container, mouse_area, row, text, text_input};
|
||||||
use iced::{Background, Color, Element, Fill, Theme};
|
use iced::{Background, Color, Element, Fill, Theme};
|
||||||
|
|
||||||
/// Shared id for the inline rename field, so the rename-start handler can focus
|
/// Shared id for the inline rename field, so the rename-start handler can focus
|
||||||
|
|
@ -30,13 +30,19 @@ const ACTIVE: Color = Color {
|
||||||
b: 0.70,
|
b: 0.70,
|
||||||
a: 1.0,
|
a: 1.0,
|
||||||
};
|
};
|
||||||
|
const CURRENT_CHECK: Color = Color {
|
||||||
|
r: 0.30,
|
||||||
|
g: 0.82,
|
||||||
|
b: 0.36,
|
||||||
|
a: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
/// One row of the style list. Renders an editable `text_input` when `name` is
|
/// One row of the style list. Renders an editable `text_input` when `name` is
|
||||||
/// the style being renamed (`rename_active`), otherwise a selectable row whose
|
/// the style being renamed (`rename_active`), otherwise a selectable row whose
|
||||||
/// double click starts the rename.
|
/// double click starts the rename. The current style gets a green ✓.
|
||||||
pub fn item<'a>(
|
pub fn item<'a>(
|
||||||
name: &str,
|
name: &str,
|
||||||
label: String,
|
is_current: bool,
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
kind: StyleKind,
|
kind: StyleKind,
|
||||||
on_select: Message,
|
on_select: Message,
|
||||||
|
|
@ -53,7 +59,16 @@ pub fn item<'a>(
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
let row = container(text(label).size(11).color(TEXT))
|
// Fixed-width ✓ column keeps every name left-aligned whether or not the
|
||||||
|
// row is current.
|
||||||
|
let check = if is_current {
|
||||||
|
text("✓").size(11).color(CURRENT_CHECK)
|
||||||
|
} else {
|
||||||
|
text("").size(11)
|
||||||
|
};
|
||||||
|
let label = row![check.width(14), text(name.to_string()).size(11).color(TEXT)]
|
||||||
|
.align_y(iced::Center);
|
||||||
|
let cell = container(label)
|
||||||
.padding([4, 8])
|
.padding([4, 8])
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.style(move |_: &Theme| container::Style {
|
.style(move |_: &Theme| container::Style {
|
||||||
|
|
@ -61,7 +76,7 @@ pub fn item<'a>(
|
||||||
text_color: Some(TEXT),
|
text_color: Some(TEXT),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
mouse_area(row)
|
mouse_area(cell)
|
||||||
.on_press(on_select)
|
.on_press(on_select)
|
||||||
.on_double_click(Message::StyleRenameStart(kind, name.to_string()))
|
.on_double_click(Message::StyleRenameStart(kind, name.to_string()))
|
||||||
.into()
|
.into()
|
||||||
|
|
|
||||||
|
|
@ -114,16 +114,10 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| {
|
.map(|name| {
|
||||||
let is_sel = name.as_str() == s.selected;
|
let is_sel = name.as_str() == s.selected;
|
||||||
// Mark the current style with a leading ✓; pad the rest so names
|
let is_current = s.current == Some(name.as_str());
|
||||||
// line up.
|
|
||||||
let label = if s.current == Some(name.as_str()) {
|
|
||||||
format!("✓ {name}")
|
|
||||||
} else {
|
|
||||||
format!(" {name}")
|
|
||||||
};
|
|
||||||
crate::ui::style_list::item(
|
crate::ui::style_list::item(
|
||||||
name,
|
name,
|
||||||
label,
|
is_current,
|
||||||
is_sel,
|
is_sel,
|
||||||
s.kind,
|
s.kind,
|
||||||
(s.on_select)(name.clone()),
|
(s.on_select)(name.clone()),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue