diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 4cbc7e9ba..35ceea96d 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -1184,6 +1184,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "Could not set default app: {err}" => Some(("common", "could-not-set-default-app-err")), "Creased Edges" => Some(("properties", "creased-edges")), "Create Block" => Some(("insert", "create-block")), + "Block Editor" => Some(("ribbon-tab", "block-editor")), "Created new CTB table, ACI {aci} updated." => Some(("file", "created-new-ctb-table-aci-aci-updated")), "Croppings" => Some(("properties", "croppings")), "Crossing" => Some(("common", "crossing")), diff --git a/src/modules/insert/mod.rs b/src/modules/insert/mod.rs index a8677fe3c..7a2e8fb14 100644 --- a/src/modules/insert/mod.rs +++ b/src/modules/insert/mod.rs @@ -32,7 +32,10 @@ pub(crate) mod xattach; pub(crate) mod xclip; pub(crate) mod xref_cmd; -use crate::modules::{CadModule, IconKind, RibbonGroup, RibbonItem}; +use crate::modules::{CadModule, IconKind, RibbonGroup, RibbonItem, ToolDef}; + +/// Insert > Block Definition: the Create Block / Write Block split button. +pub(crate) const CREATE_BLOCK_DROPDOWN: &str = "CREATE_BLOCK_DROPDOWN"; const FRAMES_ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/underlay_frames.svg")); @@ -85,10 +88,26 @@ impl CadModule for InsertModule { RibbonGroup { title: "Block Definition", tools: vec![ - RibbonItem::LargeTool(create_block::tool()), + // Split button: the face runs the last one chosen. + RibbonItem::LargeDropdown { + id: CREATE_BLOCK_DROPDOWN, + label: "Create Block", + icon: create_block::tool().icon, + items: vec![ + ("BLOCK", "Create Block", create_block::tool().icon), + ("WBLOCK", "Write Block", wblock::tool().icon), + ], + default: "BLOCK", + }, RibbonItem::LargeTool(attdef::tool()), - RibbonItem::LargeTool(attman::tool()), - RibbonItem::LargeTool(edit_block::tool()), + RibbonItem::LargeTool(ToolDef { + label: "Manage Attributes", + ..attman::tool() + }), + RibbonItem::LargeTool(ToolDef { + label: "Block Editor", + ..edit_block::tool() + }), ], }, // ── Reference ──────────────────────────────────────────────────── diff --git a/src/ui/ribbon/draw_panel.rs b/src/ui/ribbon/draw_panel.rs index df4f071e6..564c5420d 100644 --- a/src/ui/ribbon/draw_panel.rs +++ b/src/ui/ribbon/draw_panel.rs @@ -123,6 +123,8 @@ const REFERENCE_TOOLS: &[Tool] = &[Tool { options: &[], }]; pub(super) const REFERENCE_PANEL_ID: &str = "reference_extension"; +/// Insert > Block Definition slide-out: its tools are listed with labels. +const BLOCK_DEFINITION_PANEL_ID: &str = "block_definition_extension"; const fn icon_tool(command: &'static str, label: &'static str, icon: &'static [u8]) -> Tool { Tool { @@ -201,7 +203,7 @@ const PANELS: &[Panel] = &[ tools: HOME_BLOCK_TOOLS, }, Panel { - id: "block_definition_extension", + id: BLOCK_DEFINITION_PANEL_ID, anchor: None, title_id: "block_definition_extension_title", title: "Block Definition", @@ -490,11 +492,58 @@ fn reference_overlay<'a>(ribbon: &Ribbon, panel: Panel, win: (f32, f32)) -> Elem dropdown_backdrop(position_ribbon_dropdown(body.into(), false, left, top)) } +/// A slide-out listing each tool as icon and label, one per row. +fn labeled_overlay<'a>(ribbon: &Ribbon, panel: Panel, win: (f32, f32)) -> Element<'a, Message> { + let width: f32 = 200.0_f32.min((win.0 - 8.0).max(120.0)); + let (_, x, anchor_top) = ribbon.dd_anchor(panel.id, width, win.0); + let left = x.clamp(0.0, (win.0 - width).max(0.0)); + let top = anchor_top.min((win.1 - 80.0).max(0.0)); + let rows = panel.tools.iter().map(|tool| { + let active = tool_is_active(tool, ribbon.active_tool.as_deref()); + let item = button( + row![ + make_icon(IconKind::Svg(tool.icon), 16.0), + keytips::label_anchor( + || keytips::label_id(&keytips::item_anchor(panel.id, tool.command)), + text(t!(tool.label)).size(11), + ), + ] + .spacing(6) + .align_y(iced::Center), + ) + .on_press(Message::DropdownSelectItem { + dropdown_id: panel.id, + cmd: tool.command, + }) + .style(move |theme: &Theme, status| { + if active { + tool_btn_style(theme, true, status) + } else { + popup_row_style(theme, status) + } + }) + .width(Fill) + .padding([3, 6]); + keytips::anchor_with(|| keytips::item_anchor(panel.id, tool.command), item) + }); + let body = container(column(rows.collect::>()).spacing(2).padding(6)) + .width(width) + .style(|theme: &Theme| { + let mut style = popup_panel_style(theme); + style.border.color = theme.palette().primary.base.color; + style + }); + dropdown_backdrop(position_ribbon_dropdown(body.into(), false, left, top)) +} + pub(super) fn overlay<'a>(ribbon: &Ribbon, id: &str, win: (f32, f32)) -> Element<'a, Message> { let panel = panel_for_dropdown(id).expect("registered ribbon extension"); if panel.id == REFERENCE_PANEL_ID { return reference_overlay(ribbon, panel, win); } + if panel.id == BLOCK_DEFINITION_PANEL_ID { + return labeled_overlay(ribbon, panel, win); + } let tools = panel.tools; let width = (7.0 * (CELL + GAP) - GAP + 12.0).min((win.0 - 8.0).max(CELL + 12.0)); let (_, x, anchor_top) = ribbon.dd_anchor(panel.id, width, win.0); diff --git a/src/ui/ribbon/keytips.rs b/src/ui/ribbon/keytips.rs index cb674772d..46be79e68 100644 --- a/src/ui/ribbon/keytips.rs +++ b/src/ui/ribbon/keytips.rs @@ -386,7 +386,9 @@ const CODES: &[(&str, &str, &str)] = &[ ("insert", "ATTEDIT_DROPDOWN", "AE"), ("insert", "ATTMODE_DROPDOWN", "AT"), ("insert", "Block Definition", "BD"), - ("insert", "BLOCK", "BC"), + ("insert", "CREATE_BLOCK_DROPDOWN", "BC"), + ("CREATE_BLOCK_DROPDOWN", "BLOCK", "BC"), + ("CREATE_BLOCK_DROPDOWN", "WBLOCK", "WB"), ("insert", "ATTDEF", "AD"), ("insert", "ATTMAN", "AM"), ("insert", "BEDIT", "BE"),