diff --git a/src/app/mod.rs b/src/app/mod.rs index 84ca3716b..e10cf2e08 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -309,6 +309,14 @@ pub(super) struct OpenCADStudio { mls_default_text: String, mls_line_color: String, mls_text_color: String, + mls_description: String, + mls_line_weight: String, + mls_align_space: String, + mls_block_color: String, + mls_block_rotation: String, + mls_block_scale_x: String, + mls_block_scale_y: String, + mls_block_scale_z: String, // ── TableStyle Dialog ───────────────────────────────────────────────── tablestyle_selected: String, @@ -448,6 +456,7 @@ pub(super) struct OpenCADStudio { ds_dimfrac: String, ds_dimaunit: String, ds_dimadec: String, + ds_dimunit: String, ds_dimazin: String, // Alternate units ds_dimalt: bool, @@ -533,6 +542,7 @@ pub enum DsField { Dimfrac, Dimaunit, Dimadec, + Dimunit, Dimazin, Dimalt, Dimaltf, @@ -1058,6 +1068,12 @@ pub enum Message { field: &'static str, value: String, }, + /// Set an Option field (linetype / arrowhead / text style / block) + /// from a dropdown of record names ("None" clears it). + MLeaderStyleSetHandle { + field: &'static str, + value: String, + }, MLeaderStyleApply, // ── DimStyle Dialog ─────────────────────────────────────────────────── DimStyleDialogOpen, @@ -1251,6 +1267,14 @@ impl OpenCADStudio { mls_default_text: String::new(), mls_line_color: String::new(), mls_text_color: String::new(), + mls_description: String::new(), + mls_line_weight: String::new(), + mls_align_space: String::new(), + mls_block_color: String::new(), + mls_block_rotation: String::new(), + mls_block_scale_x: String::new(), + mls_block_scale_y: String::new(), + mls_block_scale_z: String::new(), // DimStyle dialog dimstyle_selected: "Standard".to_string(), dimstyle_tab: 0, @@ -1311,6 +1335,7 @@ impl OpenCADStudio { ds_dimfrac: "0".to_string(), ds_dimaunit: "0".to_string(), ds_dimadec: "0".to_string(), + ds_dimunit: "2".to_string(), ds_dimazin: "0".to_string(), ds_dimalt: false, ds_dimaltf: "25.4".to_string(), diff --git a/src/app/update.rs b/src/app/update.rs index fd2c27178..c4b51b6af 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -6277,6 +6277,14 @@ impl OpenCADStudio { "default_text" => self.mls_default_text = value, "line_color" => self.mls_line_color = value, "text_color" => self.mls_text_color = value, + "description" => self.mls_description = value, + "line_weight" => self.mls_line_weight = value, + "align_space" => self.mls_align_space = value, + "block_color" => self.mls_block_color = value, + "block_rotation" => self.mls_block_rotation = value, + "block_scale_x" => self.mls_block_scale_x = value, + "block_scale_y" => self.mls_block_scale_y = value, + "block_scale_z" => self.mls_block_scale_z = value, _ => {} } Task::none() @@ -6290,6 +6298,10 @@ impl OpenCADStudio { "text_frame" => s.text_frame = !s.text_frame, "text_always_left" => s.text_always_left = !s.text_always_left, "annotative" => s.is_annotative = !s.is_annotative, + "enable_block_scale" => s.enable_block_scale = !s.enable_block_scale, + "enable_block_rotation" => { + s.enable_block_rotation = !s.enable_block_rotation + } _ => {} } self.push_undo_snapshot(i, "MLEADERSTYLE EDIT"); @@ -6300,8 +6312,32 @@ impl OpenCADStudio { } Message::MLeaderStyleSetEnum { field, value } => { use acadrust::objects::{ - LeaderContentType, MultiLeaderPathType, TextAlignmentType, TextAngleType, + BlockContentConnectionType, LeaderContentType, LeaderDrawOrderType, + MultiLeaderDrawOrderType, MultiLeaderPathType, TextAlignmentType, + TextAngleType, TextAttachmentDirectionType, TextAttachmentType, }; + // Parse a TextAttachmentType from its debug name. + fn parse_att(v: &str) -> TextAttachmentType { + match v { + "TopOfTopLine" => TextAttachmentType::TopOfTopLine, + "MiddleOfText" => TextAttachmentType::MiddleOfText, + "MiddleOfBottomLine" => TextAttachmentType::MiddleOfBottomLine, + "BottomOfBottomLine" => TextAttachmentType::BottomOfBottomLine, + "BottomLine" => TextAttachmentType::BottomLine, + "BottomOfTopLineUnderlineBottomLine" => { + TextAttachmentType::BottomOfTopLineUnderlineBottomLine + } + "BottomOfTopLineUnderlineTopLine" => { + TextAttachmentType::BottomOfTopLineUnderlineTopLine + } + "BottomOfTopLineUnderlineAll" => { + TextAttachmentType::BottomOfTopLineUnderlineAll + } + "CenterOfText" => TextAttachmentType::CenterOfText, + "CenterOfTextOverline" => TextAttachmentType::CenterOfTextOverline, + _ => TextAttachmentType::MiddleOfTopLine, + } + } let i = self.active_tab; if let Some(s) = self.mleaderstyle_mut(i) { match field { @@ -6336,6 +6372,73 @@ impl OpenCADStudio { _ => TextAlignmentType::Left, }; } + "text_left_attachment" => s.text_left_attachment = parse_att(&value), + "text_right_attachment" => s.text_right_attachment = parse_att(&value), + "text_top_attachment" => s.text_top_attachment = parse_att(&value), + "text_bottom_attachment" => s.text_bottom_attachment = parse_att(&value), + "text_attachment_direction" => { + s.text_attachment_direction = match value.as_str() { + "Vertical" => TextAttachmentDirectionType::Vertical, + _ => TextAttachmentDirectionType::Horizontal, + }; + } + "block_content_connection" => { + s.block_content_connection = match value.as_str() { + "BasePoint" => BlockContentConnectionType::BasePoint, + _ => BlockContentConnectionType::BlockExtents, + }; + } + "leader_draw_order" => { + s.leader_draw_order = match value.as_str() { + "LeaderTailFirst" => LeaderDrawOrderType::LeaderTailFirst, + _ => LeaderDrawOrderType::LeaderHeadFirst, + }; + } + "multileader_draw_order" => { + s.multileader_draw_order = match value.as_str() { + "LeaderFirst" => MultiLeaderDrawOrderType::LeaderFirst, + _ => MultiLeaderDrawOrderType::ContentFirst, + }; + } + _ => {} + } + self.push_undo_snapshot(i, "MLEADERSTYLE EDIT"); + self.tabs[i].dirty = true; + self.tabs[i].scene.bump_geometry(); + } + Task::none() + } + Message::MLeaderStyleSetHandle { field, value } => { + let i = self.active_tab; + let doc = &self.tabs[i].scene.document; + let handle: Option = if value == "None" { + None + } else { + match field { + "line_type_handle" => doc + .line_types + .iter() + .find(|lt| lt.name == value) + .map(|lt| lt.handle), + "text_style_handle" => doc + .text_styles + .iter() + .find(|t| t.name == value) + .map(|t| t.handle), + "arrowhead_handle" | "block_content_handle" => doc + .block_records + .iter() + .find(|b| b.name == value) + .map(|b| b.handle), + _ => None, + } + }; + if let Some(s) = self.mleaderstyle_mut(i) { + match field { + "line_type_handle" => s.line_type_handle = handle, + "text_style_handle" => s.text_style_handle = handle, + "arrowhead_handle" => s.arrowhead_handle = handle, + "block_content_handle" => s.block_content_handle = handle, _ => {} } self.push_undo_snapshot(i, "MLEADERSTYLE EDIT"); @@ -6373,6 +6476,14 @@ impl OpenCADStudio { self.mls_line_color.parse::().ok(), self.mls_text_color.parse::().ok(), ); + let desc = self.mls_description.clone(); + let lw = self.mls_line_weight.parse::().ok(); + let align = self.mls_align_space.parse::().ok(); + let bclr = self.mls_block_color.parse::().ok(); + let brot = self.mls_block_rotation.parse::().ok(); + let bsx = self.mls_block_scale_x.parse::().ok(); + let bsy = self.mls_block_scale_y.parse::().ok(); + let bsz = self.mls_block_scale_z.parse::().ok(); if let Some(s) = self.mleaderstyle_mut(i) { if let Some(v) = ld { s.landing_distance = v; @@ -6408,6 +6519,28 @@ impl OpenCADStudio { if let Some(v) = tc { s.text_color = acadrust::types::Color::from_index(v); } + s.description = desc; + if let Some(v) = lw { + s.line_weight = acadrust::types::LineWeight::from_value(v); + } + if let Some(v) = align { + s.align_space = v; + } + if let Some(v) = bclr { + s.block_content_color = acadrust::types::Color::from_index(v); + } + if let Some(v) = brot { + s.block_content_rotation = v; + } + if let Some(v) = bsx { + s.block_content_scale_x = v; + } + if let Some(v) = bsy { + s.block_content_scale_y = v; + } + if let Some(v) = bsz { + s.block_content_scale_z = v; + } self.push_undo_snapshot(i, "MLEADERSTYLE EDIT"); self.tabs[i].dirty = true; self.tabs[i].scene.bump_geometry(); @@ -7067,6 +7200,18 @@ impl OpenCADStudio { .index() .map(|c| c.to_string()) .unwrap_or_default(); + self.mls_description = s.description.clone(); + self.mls_line_weight = s.line_weight.value().to_string(); + self.mls_align_space = format!("{:.4}", s.align_space); + self.mls_block_color = s + .block_content_color + .index() + .map(|c| c.to_string()) + .unwrap_or_default(); + self.mls_block_rotation = format!("{:.4}", s.block_content_rotation); + self.mls_block_scale_x = format!("{:.4}", s.block_content_scale_x); + self.mls_block_scale_y = format!("{:.4}", s.block_content_scale_y); + self.mls_block_scale_z = format!("{:.4}", s.block_content_scale_z); } /// Populate all edit buffers from the currently selected dim style. @@ -7132,6 +7277,7 @@ impl OpenCADStudio { self.ds_dimfrac = format!("{}", ds.dimfrac); self.ds_dimaunit = format!("{}", ds.dimaunit); self.ds_dimadec = format!("{}", ds.dimadec); + self.ds_dimunit = format!("{}", ds.dimunit); self.ds_dimazin = format!("{}", ds.dimazin); self.ds_dimalt = ds.dimalt; self.ds_dimaltf = format!("{}", ds.dimaltf); @@ -7216,6 +7362,7 @@ impl OpenCADStudio { set_i16!(dimfrac, self.ds_dimfrac); set_i16!(dimaunit, self.ds_dimaunit); set_i16!(dimadec, self.ds_dimadec); + set_i16!(dimunit, self.ds_dimunit); set_i16!(dimazin, self.ds_dimazin); set_f64!(dimaltf, self.ds_dimaltf); set_i16!(dimaltd, self.ds_dimaltd); @@ -7288,6 +7435,7 @@ impl OpenCADStudio { Dimfrac => self.ds_dimfrac = val, Dimaunit => self.ds_dimaunit = val, Dimadec => self.ds_dimadec = val, + Dimunit => self.ds_dimunit = val, Dimazin => self.ds_dimazin = val, Dimaltf => self.ds_dimaltf = val, Dimaltd => self.ds_dimaltd = val, diff --git a/src/app/view.rs b/src/app/view.rs index ba974ff47..7f3075453 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -186,6 +186,56 @@ impl OpenCADStudio { None } }); + let doc = &tab.scene.document; + let mut block_opts: Vec = vec!["None".to_string()]; + block_opts.extend(doc.block_records.iter().map(|b| b.name.clone())); + let mut lt_opts: Vec = vec!["None".to_string()]; + lt_opts.extend(doc.line_types.iter().map(|lt| lt.name.clone())); + let mut textstyle_opts: Vec = vec!["None".to_string()]; + textstyle_opts.extend(doc.text_styles.iter().map(|t| t.name.clone())); + let opt_block = |h: Option| -> String { + match h { + Some(h) => doc + .block_records + .iter() + .find(|b| b.handle == h) + .map(|b| b.name.clone()) + .unwrap_or_else(|| "None".to_string()), + None => "None".to_string(), + } + }; + let opt_lt = |h: Option| -> String { + match h { + Some(h) => doc + .line_types + .iter() + .find(|lt| lt.handle == h) + .map(|lt| lt.name.clone()) + .unwrap_or_else(|| "None".to_string()), + None => "None".to_string(), + } + }; + let opt_ts = |h: Option| -> String { + match h { + Some(h) => doc + .text_styles + .iter() + .find(|t| t.handle == h) + .map(|t| t.name.clone()) + .unwrap_or_else(|| "None".to_string()), + None => "None".to_string(), + } + }; + let (line_type_name, arrowhead_name, text_style_name, block_content_name) = + match selected_style { + Some(s) => ( + opt_lt(s.line_type_handle), + opt_block(s.arrowhead_handle), + opt_ts(s.text_style_handle), + opt_block(s.block_content_handle), + ), + None => Default::default(), + }; return crate::ui::mleaderstyle::view_window(crate::ui::mleaderstyle::MLeaderStyleView { styles, selected: &self.mleaderstyle_selected, @@ -203,6 +253,21 @@ impl OpenCADStudio { default_text: &self.mls_default_text, line_color: &self.mls_line_color, text_color: &self.mls_text_color, + description: &self.mls_description, + line_weight: &self.mls_line_weight, + align_space: &self.mls_align_space, + block_color: &self.mls_block_color, + block_rotation: &self.mls_block_rotation, + block_scale_x: &self.mls_block_scale_x, + block_scale_y: &self.mls_block_scale_y, + block_scale_z: &self.mls_block_scale_z, + block_opts, + lt_opts, + textstyle_opts, + line_type_name, + arrowhead_name, + text_style_name, + block_content_name, }); } if Some(window_id) == self.layout_manager_window { @@ -346,6 +411,7 @@ impl OpenCADStudio { dimfrac: &self.ds_dimfrac, dimaunit: &self.ds_dimaunit, dimadec: &self.ds_dimadec, + dimunit: &self.ds_dimunit, dimazin: &self.ds_dimazin, dimalt: self.ds_dimalt, dimaltf: &self.ds_dimaltf, diff --git a/src/ui/dimstyle.rs b/src/ui/dimstyle.rs index f600c946b..b4fa60835 100644 --- a/src/ui/dimstyle.rs +++ b/src/ui/dimstyle.rs @@ -120,6 +120,7 @@ pub struct DimStyleValues<'a> { pub dimfrac: &'a str, pub dimaunit: &'a str, pub dimadec: &'a str, + pub dimunit: &'a str, pub dimazin: &'a str, pub dimalt: bool, pub dimaltf: &'a str, @@ -560,6 +561,7 @@ pub fn view_window<'a>( row![lbl("Fraction format (DIMFRAC)"), mk_field(DsField::Dimfrac, vals.dimfrac)].spacing(8).align_y(iced::Center), row![lbl("Angular unit (DIMAUNIT)"), mk_field(DsField::Dimaunit, vals.dimaunit)].spacing(8).align_y(iced::Center), row![lbl("Angular decimals (DIMADEC)"), mk_field(DsField::Dimadec, vals.dimadec)].spacing(8).align_y(iced::Center), + row![lbl("Unit format (DIMUNIT)"), mk_field(DsField::Dimunit, vals.dimunit)].spacing(8).align_y(iced::Center), row![lbl("Angular zero supp (DIMAZIN)"), mk_field(DsField::Dimazin, vals.dimazin)].spacing(8).align_y(iced::Center), text("Fit").size(11).color(ACCENT), row![lbl("Fit (DIMATFIT)"), mk_field(DsField::Dimatfit, vals.dimatfit)].spacing(8).align_y(iced::Center), diff --git a/src/ui/mleaderstyle.rs b/src/ui/mleaderstyle.rs index 3b76724e6..c99c4e619 100644 --- a/src/ui/mleaderstyle.rs +++ b/src/ui/mleaderstyle.rs @@ -145,6 +145,22 @@ pub struct MLeaderStyleView<'a> { pub default_text: &'a str, pub line_color: &'a str, pub text_color: &'a str, + pub description: &'a str, + pub line_weight: &'a str, + pub align_space: &'a str, + pub block_color: &'a str, + pub block_rotation: &'a str, + pub block_scale_x: &'a str, + pub block_scale_y: &'a str, + pub block_scale_z: &'a str, + // Handle dropdown option lists + currently-selected record names. + pub block_opts: Vec, + pub lt_opts: Vec, + pub textstyle_opts: Vec, + pub line_type_name: String, + pub arrowhead_name: String, + pub text_style_name: String, + pub block_content_name: String, } fn section<'a>(label: &'static str) -> Element<'a, Message> { @@ -188,6 +204,46 @@ fn enum_row<'a>( .into() } +/// The 11 horizontal text-attachment variants (debug names). +const ATTACH_OPTS: [&str; 11] = [ + "TopOfTopLine", + "MiddleOfTopLine", + "MiddleOfText", + "MiddleOfBottomLine", + "BottomOfBottomLine", + "BottomLine", + "BottomOfTopLineUnderlineBottomLine", + "BottomOfTopLineUnderlineTopLine", + "BottomOfTopLineUnderlineAll", + "CenterOfText", + "CenterOfTextOverline", +]; + +fn opts(list: &[&str]) -> Vec { + list.iter().map(|s| s.to_string()).collect() +} + +/// Dropdown for an Option field (linetype / arrowhead / text style / +/// block content). Options are record names; "None" clears the handle. +fn handle_row<'a>( + label: &'static str, + options: Vec, + selected: String, + field: &'static str, +) -> Element<'a, Message> { + row![ + text(label).size(11).color(DIM).width(150), + pick_list(options, Some(selected), move |value| { + Message::MLeaderStyleSetHandle { field, value } + }) + .text_size(11) + .width(190), + ] + .spacing(8) + .align_y(iced::Center) + .into() +} + fn chk<'a>(label: &'static str, val: bool, field: &'static str) -> Element<'a, Message> { checkbox(val) .label(label) @@ -277,18 +333,29 @@ pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> { text(s.name.clone()).size(11), ] .spacing(8), + num_row("Description:", "", v.description, "description"), // Leader Format section("Leader Format"), enum_row( "Path type:", - ["Invisible", "StraightLineSegments", "Spline"] - .iter() - .map(|s| s.to_string()) - .collect(), + opts(&["Invisible", "StraightLineSegments", "Spline"]), format!("{:?}", s.path_type), "path_type" ), num_row("Line color (ACI):", "256", v.line_color, "line_color"), + num_row("Line weight:", "-2", v.line_weight, "line_weight"), + handle_row( + "Line type:", + v.lt_opts.clone(), + v.line_type_name.clone(), + "line_type_handle" + ), + handle_row( + "Arrowhead block:", + v.block_opts.clone(), + v.arrowhead_name.clone(), + "arrowhead_handle" + ), num_row("Arrowhead size:", "0.18", v.arrowhead_size, "arrowhead_size"), num_row("Break gap size:", "0.125", v.break_gap, "break_gap"), // Leader Structure @@ -301,41 +368,106 @@ pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> { num_row("First seg. angle:", "0", v.first_seg_angle, "first_seg_angle"), num_row("Second seg. angle:", "0", v.second_seg_angle, "second_seg_angle"), num_row("Scale factor:", "1.0", v.scale_factor, "scale_factor"), + num_row("Align space:", "4.0", v.align_space, "align_space"), + enum_row( + "Leader draw order:", + opts(&["LeaderHeadFirst", "LeaderTailFirst"]), + format!("{:?}", s.leader_draw_order), + "leader_draw_order" + ), + enum_row( + "Multileader draw order:", + opts(&["ContentFirst", "LeaderFirst"]), + format!("{:?}", s.multileader_draw_order), + "multileader_draw_order" + ), chk("Annotative", s.is_annotative, "annotative"), // Content section("Content"), enum_row( "Content type:", - ["None", "Block", "MText", "Tolerance"] - .iter() - .map(|s| s.to_string()) - .collect(), + opts(&["None", "Block", "MText", "Tolerance"]), format!("{:?}", s.content_type), "content_type" ), num_row("Default text:", "", v.default_text, "default_text"), + handle_row( + "Text style:", + v.textstyle_opts.clone(), + v.text_style_name.clone(), + "text_style_handle" + ), num_row("Text height:", "0.18", v.text_height, "text_height"), num_row("Text color (ACI):", "256", v.text_color, "text_color"), enum_row( "Text angle:", - ["ParallelToLastLeaderLine", "Horizontal", "Optimized"] - .iter() - .map(|s| s.to_string()) - .collect(), + opts(&["ParallelToLastLeaderLine", "Horizontal", "Optimized"]), format!("{:?}", s.text_angle_type), "text_angle_type" ), enum_row( "Text alignment:", - ["Left", "Center", "Right"] - .iter() - .map(|s| s.to_string()) - .collect(), + opts(&["Left", "Center", "Right"]), format!("{:?}", s.text_alignment), "text_alignment" ), + enum_row( + "Left attachment:", + opts(&ATTACH_OPTS), + format!("{:?}", s.text_left_attachment), + "text_left_attachment" + ), + enum_row( + "Right attachment:", + opts(&ATTACH_OPTS), + format!("{:?}", s.text_right_attachment), + "text_right_attachment" + ), + enum_row( + "Top attachment:", + opts(&ATTACH_OPTS), + format!("{:?}", s.text_top_attachment), + "text_top_attachment" + ), + enum_row( + "Bottom attachment:", + opts(&ATTACH_OPTS), + format!("{:?}", s.text_bottom_attachment), + "text_bottom_attachment" + ), + enum_row( + "Attachment direction:", + opts(&["Horizontal", "Vertical"]), + format!("{:?}", s.text_attachment_direction), + "text_attachment_direction" + ), chk("Text frame", s.text_frame, "text_frame"), chk("Text always left", s.text_always_left, "text_always_left"), + // Block Content + section("Block Content"), + handle_row( + "Block:", + v.block_opts.clone(), + v.block_content_name.clone(), + "block_content_handle" + ), + num_row("Block color (ACI):", "256", v.block_color, "block_color"), + enum_row( + "Block connection:", + opts(&["BlockExtents", "BasePoint"]), + format!("{:?}", s.block_content_connection), + "block_content_connection" + ), + num_row("Block rotation:", "0", v.block_rotation, "block_rotation"), + num_row("Block scale X:", "1.0", v.block_scale_x, "block_scale_x"), + num_row("Block scale Y:", "1.0", v.block_scale_y, "block_scale_y"), + num_row("Block scale Z:", "1.0", v.block_scale_z, "block_scale_z"), + chk("Enable block scale", s.enable_block_scale, "enable_block_scale"), + chk( + "Enable block rotation", + s.enable_block_rotation, + "enable_block_rotation" + ), button(text("Apply").size(11)) .on_press(Message::MLeaderStyleApply) .style(btn_s(true))