feat: add style selector comboboxes to Annotate ribbon tab
New StyleComboGroup RibbonItem renders a dropdown combobox for selecting text style, dimension style, multileader style, or table style. Ribbon groups in the Annotate tab now match the reference layout: each group has a large tool on the left and a style combobox with tool rows on the right. Each combobox shows the active style name, opens a scrollable item list on click, and has an optional "Manage…" row that fires the style manager command (STYLE / DIMSTYLE / MLEADERSTYLE / TABLESTYLE). Style state is synced from the document on every layer refresh via sync_ribbon_styles(). RibbonStyleChanged message propagates selections back to the acadrust document header and the active_mleader_style field. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
08b9a21d31
commit
bd68114bde
7 changed files with 431 additions and 36 deletions
|
|
@ -39,5 +39,53 @@ impl H7CAD {
|
|||
.collect();
|
||||
self.tabs[i].layers.sync_linetypes(lt_items.clone());
|
||||
self.ribbon.set_available_linetypes(lt_items);
|
||||
self.sync_ribbon_styles();
|
||||
}
|
||||
|
||||
pub(super) fn sync_ribbon_styles(&mut self) {
|
||||
let i = self.active_tab;
|
||||
let doc = &self.tabs[i].scene.document;
|
||||
|
||||
let text_names: Vec<String> = doc.text_styles.iter().map(|s| s.name.clone()).collect();
|
||||
let active_text = doc.header.current_text_style_name.clone();
|
||||
let active_text = if text_names.contains(&active_text) { active_text } else {
|
||||
text_names.first().cloned().unwrap_or_else(|| "Standard".to_string())
|
||||
};
|
||||
|
||||
let dim_names: Vec<String> = doc.dim_styles.iter().map(|s| s.name.clone()).collect();
|
||||
let active_dim = doc.header.current_dimstyle_name.clone();
|
||||
let active_dim = if dim_names.contains(&active_dim) { active_dim } else {
|
||||
dim_names.first().cloned().unwrap_or_else(|| "Standard".to_string())
|
||||
};
|
||||
|
||||
let mleader_names: Vec<String> = doc.objects.values().filter_map(|o| {
|
||||
if let acadrust::objects::ObjectType::MultiLeaderStyle(mls) = o {
|
||||
Some(mls.name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
let active_mleader = self.tabs[i].active_mleader_style.clone();
|
||||
let active_mleader = if mleader_names.contains(&active_mleader) { active_mleader } else {
|
||||
mleader_names.first().cloned().unwrap_or_else(|| "Standard".to_string())
|
||||
};
|
||||
|
||||
let table_names: Vec<String> = doc.objects.values().filter_map(|o| {
|
||||
if let acadrust::objects::ObjectType::TableStyle(ts) = o {
|
||||
Some(ts.name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
let active_table = table_names.first().cloned().unwrap_or_else(|| "Standard".to_string());
|
||||
|
||||
let active_mleader2 = active_mleader.clone();
|
||||
let active_table2 = active_table.clone();
|
||||
self.ribbon.set_styles(
|
||||
text_names, &active_text,
|
||||
dim_names, &active_dim,
|
||||
mleader_names, &active_mleader2,
|
||||
table_names, &active_table2,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,6 +295,8 @@ pub enum Message {
|
|||
RibbonLinetypeChanged(String),
|
||||
/// User changed the active lineweight in the Properties toolbar.
|
||||
RibbonLineweightChanged(LineWeight),
|
||||
/// User selected a style from a style combobox in the ribbon.
|
||||
RibbonStyleChanged { key: crate::modules::StyleKey, name: String },
|
||||
|
||||
// ── Properties panel ──────────────────────────────────────────────────
|
||||
/// User selected a layer from the layer pick_list in the Properties panel.
|
||||
|
|
|
|||
|
|
@ -1929,6 +1929,43 @@ impl H7CAD {
|
|||
Task::none()
|
||||
}
|
||||
|
||||
Message::RibbonStyleChanged { key, name } => {
|
||||
use crate::modules::StyleKey;
|
||||
self.ribbon.close_dropdown();
|
||||
match key {
|
||||
StyleKey::TextStyle => {
|
||||
self.ribbon.active_text_style = name.clone();
|
||||
let i = self.active_tab;
|
||||
let found = self.tabs[i].scene.document.text_styles.iter()
|
||||
.find(|s| s.name == name)
|
||||
.map(|ts| ts.handle);
|
||||
if let Some(h) = found {
|
||||
self.tabs[i].scene.document.header.current_text_style_handle = h;
|
||||
self.tabs[i].scene.document.header.current_text_style_name = name;
|
||||
}
|
||||
}
|
||||
StyleKey::DimStyle => {
|
||||
self.ribbon.active_dim_style = name.clone();
|
||||
let i = self.active_tab;
|
||||
let found = self.tabs[i].scene.document.dim_styles.get(&name)
|
||||
.map(|ds| ds.handle);
|
||||
if let Some(h) = found {
|
||||
self.tabs[i].scene.document.header.current_dimstyle_handle = h;
|
||||
self.tabs[i].scene.document.header.current_dimstyle_name = name;
|
||||
}
|
||||
}
|
||||
StyleKey::MLeaderStyle => {
|
||||
self.ribbon.active_mleader_style = name.clone();
|
||||
let i = self.active_tab;
|
||||
self.tabs[i].active_mleader_style = name;
|
||||
}
|
||||
StyleKey::TableStyle => {
|
||||
self.ribbon.active_table_style = name;
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::PropLayerChanged(layer) => {
|
||||
let i = self.active_tab;
|
||||
let handles = self.property_target_handles(i);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ pub mod table_cmd;
|
|||
pub mod text;
|
||||
pub mod tolerance_cmd;
|
||||
|
||||
use crate::modules::{CadModule, RibbonGroup, RibbonItem};
|
||||
use crate::modules::{CadModule, RibbonGroup, RibbonItem, StyleKey};
|
||||
|
||||
pub struct AnnotateModule;
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ impl CadModule for AnnotateModule {
|
|||
tools: vec![
|
||||
RibbonItem::LargeDropdown {
|
||||
id: "ANNOTATE_TEXT",
|
||||
label: "Text",
|
||||
label: "Multiline\nText",
|
||||
icon: mtext::ICON,
|
||||
items: vec![
|
||||
(mtext::tool().id, mtext::tool().label, mtext::tool().icon),
|
||||
|
|
@ -54,18 +54,21 @@ impl CadModule for AnnotateModule {
|
|||
],
|
||||
default: "MTEXT",
|
||||
},
|
||||
RibbonItem::Tool(crate::modules::ToolDef {
|
||||
id: "STYLE",
|
||||
label: "Text Style",
|
||||
icon: crate::modules::IconKind::Svg(include_bytes!("../../../assets/icons/text_style.svg")),
|
||||
event: crate::modules::ModuleEvent::Command("STYLE".to_string()),
|
||||
}),
|
||||
RibbonItem::Tool(crate::modules::ToolDef {
|
||||
id: "FIND",
|
||||
label: "Find",
|
||||
icon: crate::modules::IconKind::Svg(include_bytes!("../../../assets/icons/find.svg")),
|
||||
event: crate::modules::ModuleEvent::Command("FIND".to_string()),
|
||||
}),
|
||||
RibbonItem::StyleComboGroup {
|
||||
style_key: StyleKey::TextStyle,
|
||||
combo_id: "TEXT_STYLE_COMBO",
|
||||
manager_cmd: Some("STYLE"),
|
||||
rows: vec![
|
||||
vec![
|
||||
crate::modules::ToolDef {
|
||||
id: "FIND",
|
||||
label: "Find",
|
||||
icon: crate::modules::IconKind::Svg(include_bytes!("../../../assets/icons/find.svg")),
|
||||
event: crate::modules::ModuleEvent::Command("FIND".to_string()),
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// ── Dimensions ───────────────────────────────────────────────
|
||||
|
|
@ -87,20 +90,26 @@ impl CadModule for AnnotateModule {
|
|||
],
|
||||
default: "DIMLINEAR",
|
||||
},
|
||||
RibbonItem::Tool(dim_continue::tool()),
|
||||
RibbonItem::Tool(dim_baseline::tool()),
|
||||
RibbonItem::Tool(tolerance_cmd::tool()),
|
||||
RibbonItem::Tool(dimedit::tool()),
|
||||
RibbonItem::Tool(dimtedit::tool()),
|
||||
RibbonItem::Tool(dimbreak::tool()),
|
||||
RibbonItem::Tool(dimspace::tool()),
|
||||
RibbonItem::Tool(dimjogline::tool()),
|
||||
RibbonItem::Tool(crate::modules::ToolDef {
|
||||
id: "DIMSTYLE",
|
||||
label: "Dim Style",
|
||||
icon: crate::modules::IconKind::Svg(include_bytes!("../../../assets/icons/dim_style.svg")),
|
||||
event: crate::modules::ModuleEvent::Command("DIMSTYLE".to_string()),
|
||||
}),
|
||||
RibbonItem::StyleComboGroup {
|
||||
style_key: StyleKey::DimStyle,
|
||||
combo_id: "DIM_STYLE_COMBO",
|
||||
manager_cmd: Some("DIMSTYLE"),
|
||||
rows: vec![
|
||||
vec![
|
||||
qdim::tool(),
|
||||
dim_continue::tool(),
|
||||
dim_baseline::tool(),
|
||||
],
|
||||
vec![
|
||||
tolerance_cmd::tool(),
|
||||
dimedit::tool(),
|
||||
dimtedit::tool(),
|
||||
dimbreak::tool(),
|
||||
dimspace::tool(),
|
||||
dimjogline::tool(),
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// ── Leaders ──────────────────────────────────────────────────
|
||||
|
|
@ -117,10 +126,21 @@ impl CadModule for AnnotateModule {
|
|||
],
|
||||
default: "MLEADER",
|
||||
},
|
||||
RibbonItem::Tool(mleader_edit::tool_add()),
|
||||
RibbonItem::Tool(mleader_edit::tool_remove()),
|
||||
RibbonItem::Tool(mleader_edit::tool_align()),
|
||||
RibbonItem::Tool(mleader_edit::tool_collect()),
|
||||
RibbonItem::StyleComboGroup {
|
||||
style_key: StyleKey::MLeaderStyle,
|
||||
combo_id: "MLEADER_STYLE_COMBO",
|
||||
manager_cmd: Some("MLEADERSTYLE"),
|
||||
rows: vec![
|
||||
vec![
|
||||
mleader_edit::tool_add(),
|
||||
mleader_edit::tool_remove(),
|
||||
],
|
||||
vec![
|
||||
mleader_edit::tool_align(),
|
||||
mleader_edit::tool_collect(),
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// ── Tables ───────────────────────────────────────────────────
|
||||
|
|
@ -128,6 +148,12 @@ impl CadModule for AnnotateModule {
|
|||
title: "Tables",
|
||||
tools: vec![
|
||||
RibbonItem::LargeTool(table_cmd::tool()),
|
||||
RibbonItem::StyleComboGroup {
|
||||
style_key: StyleKey::TableStyle,
|
||||
combo_id: "TABLE_STYLE_COMBO",
|
||||
manager_cmd: Some("TABLESTYLE"),
|
||||
rows: vec![],
|
||||
},
|
||||
],
|
||||
},
|
||||
// ── Markup ───────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -79,6 +79,27 @@ pub enum RibbonItem {
|
|||
LayerComboGroup { row2: Vec<ToolDef>, row3: Vec<ToolDef> },
|
||||
/// Match Properties (large button) + Color / Linetype / Lineweight combos on the right.
|
||||
PropertiesGroup { match_prop: ToolDef },
|
||||
/// A style selector combobox (text / dim / mleader / table style) with
|
||||
/// optional small tool rows below it.
|
||||
StyleComboGroup {
|
||||
/// Which style domain this combo controls.
|
||||
style_key: StyleKey,
|
||||
/// Unique dropdown id (must be unique across the ribbon).
|
||||
combo_id: &'static str,
|
||||
/// Optional command to run when the user opens the style manager.
|
||||
manager_cmd: Option<&'static str>,
|
||||
/// Small tool rows rendered below the combo (0–2 rows).
|
||||
rows: Vec<Vec<ToolDef>>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Identifies which style list a `StyleComboGroup` refers to.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum StyleKey {
|
||||
TextStyle,
|
||||
DimStyle,
|
||||
MLeaderStyle,
|
||||
TableStyle,
|
||||
}
|
||||
|
||||
impl From<ToolDef> for RibbonItem {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::ui::properties::{LinetypeItem, color_picker_dropdown, lw_options};
|
|||
use crate::app::Message;
|
||||
|
||||
mod widgets;
|
||||
use widgets::*;
|
||||
use widgets::{StyleContext, *};
|
||||
|
||||
// ── Ribbon state ───────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -43,6 +43,15 @@ pub struct Ribbon {
|
|||
pub available_linetypes: Vec<LinetypeItem>,
|
||||
/// Whether the full ACI palette is expanded inside the color picker overlay.
|
||||
pub prop_color_palette_open: bool,
|
||||
// ── Style selector state ──────────────────────────────────────────────
|
||||
pub text_style_names: Vec<String>,
|
||||
pub active_text_style: String,
|
||||
pub dim_style_names: Vec<String>,
|
||||
pub active_dim_style: String,
|
||||
pub mleader_style_names: Vec<String>,
|
||||
pub active_mleader_style: String,
|
||||
pub table_style_names: Vec<String>,
|
||||
pub active_table_style: String,
|
||||
}
|
||||
|
||||
/// Per-layer display data shown in the ribbon layer dropdown.
|
||||
|
|
@ -82,9 +91,34 @@ impl Ribbon {
|
|||
art: String::new(),
|
||||
}],
|
||||
prop_color_palette_open: false,
|
||||
text_style_names: vec!["Standard".to_string()],
|
||||
active_text_style: "Standard".to_string(),
|
||||
dim_style_names: vec!["Standard".to_string()],
|
||||
active_dim_style: "Standard".to_string(),
|
||||
mleader_style_names: vec!["Standard".to_string()],
|
||||
active_mleader_style: "Standard".to_string(),
|
||||
table_style_names: vec!["Standard".to_string()],
|
||||
active_table_style: "Standard".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_styles(
|
||||
&mut self,
|
||||
text: Vec<String>, active_text: &str,
|
||||
dim: Vec<String>, active_dim: &str,
|
||||
mleader: Vec<String>, active_mleader: &str,
|
||||
table: Vec<String>, active_table: &str,
|
||||
) {
|
||||
self.text_style_names = text;
|
||||
self.active_text_style = active_text.to_string();
|
||||
self.dim_style_names = dim;
|
||||
self.active_dim_style = active_dim.to_string();
|
||||
self.mleader_style_names = mleader;
|
||||
self.active_mleader_style = active_mleader.to_string();
|
||||
self.table_style_names = table;
|
||||
self.active_table_style = active_table.to_string();
|
||||
}
|
||||
|
||||
pub fn set_layers(&mut self, infos: Vec<LayerInfo>, active: &str) {
|
||||
self.active_layer = active.to_string();
|
||||
self.layer_names = infos.iter().map(|l| l.name.clone()).collect();
|
||||
|
|
@ -274,6 +308,16 @@ impl Ribbon {
|
|||
let active_color = self.active_color;
|
||||
let active_linetype = &self.active_linetype;
|
||||
let active_lineweight = self.active_lineweight;
|
||||
let style_ctx = StyleContext {
|
||||
text_style_names: self.text_style_names.clone(),
|
||||
active_text_style: self.active_text_style.clone(),
|
||||
dim_style_names: self.dim_style_names.clone(),
|
||||
active_dim_style: self.active_dim_style.clone(),
|
||||
mleader_style_names: self.mleader_style_names.clone(),
|
||||
active_mleader_style: self.active_mleader_style.clone(),
|
||||
table_style_names: self.table_style_names.clone(),
|
||||
active_table_style: self.active_table_style.clone(),
|
||||
};
|
||||
|
||||
let mut widgets: Vec<Element<Message>> = Vec::new();
|
||||
let mut first_group = true;
|
||||
|
|
@ -303,6 +347,7 @@ impl Ribbon {
|
|||
| RibbonItem::LargeDropdown { .. }
|
||||
| RibbonItem::LayerComboGroup { .. }
|
||||
| RibbonItem::PropertiesGroup { .. }
|
||||
| RibbonItem::StyleComboGroup { .. }
|
||||
);
|
||||
|
||||
if is_large {
|
||||
|
|
@ -319,6 +364,7 @@ impl Ribbon {
|
|||
active_color,
|
||||
active_linetype,
|
||||
active_lineweight,
|
||||
&style_ctx,
|
||||
));
|
||||
} else {
|
||||
small_buf.push(render_small(
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ use std::time::Duration;
|
|||
|
||||
use acadrust::types::{Color as AcadColor, LineWeight};
|
||||
use iced::widget::tooltip::Position as TipPos;
|
||||
use iced::widget::{button, column, container, row, svg, text, tooltip};
|
||||
use iced::widget::{button, column, container, row, scrollable, svg, text, tooltip};
|
||||
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Theme};
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::modules::{IconKind, ModuleEvent, RibbonGroup, RibbonItem, ToolDef};
|
||||
use crate::modules::{IconKind, ModuleEvent, RibbonGroup, RibbonItem, StyleKey, ToolDef};
|
||||
use crate::ui::properties::{LwItem, acad_color_display};
|
||||
|
||||
use super::LayerInfo;
|
||||
|
|
@ -70,6 +70,38 @@ pub(super) const ICON_COLOR: Color = Color { r: 0.25, g: 0.75, b: 0.45, a: 1.0 }
|
|||
pub(super) const LABEL_ON: Color = Color { r: 0.92, g: 0.92, b: 0.92, a: 1.0 };
|
||||
pub(super) const LABEL_OFF: Color = Color { r: 0.72, g: 0.72, b: 0.72, a: 1.0 };
|
||||
|
||||
// ── Style context (passed from Ribbon to render_large) ────────────────────
|
||||
|
||||
pub(super) struct StyleContext {
|
||||
pub text_style_names: Vec<String>,
|
||||
pub active_text_style: String,
|
||||
pub dim_style_names: Vec<String>,
|
||||
pub active_dim_style: String,
|
||||
pub mleader_style_names: Vec<String>,
|
||||
pub active_mleader_style: String,
|
||||
pub table_style_names: Vec<String>,
|
||||
pub active_table_style: String,
|
||||
}
|
||||
|
||||
impl StyleContext {
|
||||
fn names_for(&self, key: StyleKey) -> &[String] {
|
||||
match key {
|
||||
StyleKey::TextStyle => &self.text_style_names,
|
||||
StyleKey::DimStyle => &self.dim_style_names,
|
||||
StyleKey::MLeaderStyle => &self.mleader_style_names,
|
||||
StyleKey::TableStyle => &self.table_style_names,
|
||||
}
|
||||
}
|
||||
fn active_for(&self, key: StyleKey) -> &str {
|
||||
match key {
|
||||
StyleKey::TextStyle => &self.active_text_style,
|
||||
StyleKey::DimStyle => &self.active_dim_style,
|
||||
StyleKey::MLeaderStyle => &self.active_mleader_style,
|
||||
StyleKey::TableStyle => &self.active_table_style,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Layout helpers ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Flush up-to-3 small items as a vertical column into the group row.
|
||||
|
|
@ -260,7 +292,7 @@ pub(super) fn render_small<'a>(
|
|||
|
||||
// ── Large item renderer ────────────────────────────────────────────────────
|
||||
|
||||
/// Render a full-height large button (LargeTool, LargeDropdown, or LayerCombo).
|
||||
/// Render a full-height large button (LargeTool, LargeDropdown, LayerCombo, StyleCombo).
|
||||
pub(super) fn render_large<'a>(
|
||||
item: RibbonItem,
|
||||
active_tool: &Option<String>,
|
||||
|
|
@ -273,6 +305,7 @@ pub(super) fn render_large<'a>(
|
|||
active_color: AcadColor,
|
||||
active_linetype: &'a str,
|
||||
active_lineweight: LineWeight,
|
||||
style_ctx: &StyleContext,
|
||||
) -> Element<'a, Message> {
|
||||
match item {
|
||||
RibbonItem::LargeTool(t) => {
|
||||
|
|
@ -595,6 +628,185 @@ pub(super) fn render_large<'a>(
|
|||
.into()
|
||||
}
|
||||
|
||||
RibbonItem::StyleComboGroup { style_key, combo_id, manager_cmd, rows } => {
|
||||
const STYLE_COMBO_W: f32 = LARGE_W * 2.3;
|
||||
let names: Vec<String> = style_ctx.names_for(style_key).to_vec();
|
||||
let active: String = style_ctx.active_for(style_key).to_string();
|
||||
let is_open = open_dd.as_deref() == Some(combo_id);
|
||||
|
||||
// ── combo button ──
|
||||
let combo_btn = button(
|
||||
row![
|
||||
container(text(active.clone()).size(11).color(Color::WHITE))
|
||||
.width(Fill)
|
||||
.clip(true),
|
||||
text(if is_open { "▲" } else { "▾" })
|
||||
.size(9)
|
||||
.color(Color { r: 0.7, g: 0.7, b: 0.7, a: 1.0 }),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::ToggleRibbonDropdown(combo_id.to_string()))
|
||||
.style(move |_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match (is_open, status) {
|
||||
(true, _) => Color { r: 0.14, g: 0.14, b: 0.14, a: 1.0 },
|
||||
(_, button::Status::Hovered) => Color { r: 0.26, g: 0.26, b: 0.26, a: 1.0 },
|
||||
_ => Color { r: 0.18, g: 0.18, b: 0.18, a: 1.0 },
|
||||
})),
|
||||
border: Border {
|
||||
radius: 3.0.into(),
|
||||
width: 1.0,
|
||||
color: if is_open {
|
||||
Color { r: 0.45, g: 0.65, b: 0.90, a: 1.0 }
|
||||
} else {
|
||||
Color { r: 0.35, g: 0.35, b: 0.35, a: 1.0 }
|
||||
},
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.padding([3, 8])
|
||||
.width(Fill);
|
||||
|
||||
// ── style items panel (when open) ──
|
||||
let items_panel: Element<Message> = if is_open {
|
||||
let items_col: Vec<Element<Message>> = names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
let is_sel = name.as_str() == active.as_str();
|
||||
let n = name.clone();
|
||||
let key = style_key;
|
||||
button(
|
||||
row![
|
||||
text(if is_sel { "✓" } else { " " })
|
||||
.size(10)
|
||||
.color(if is_sel {
|
||||
Color { r: 0.2, g: 0.8, b: 0.4, a: 1.0 }
|
||||
} else {
|
||||
Color::TRANSPARENT
|
||||
}),
|
||||
text(name).size(11).color(Color::WHITE),
|
||||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::RibbonStyleChanged { key, name: n })
|
||||
.style(move |_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => {
|
||||
Color { r: 0.28, g: 0.28, b: 0.28, a: 1.0 }
|
||||
}
|
||||
_ if is_sel => Color { r: 0.20, g: 0.35, b: 0.55, a: 1.0 },
|
||||
_ => Color { r: 0.16, g: 0.16, b: 0.16, a: 1.0 },
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.padding([4, 10])
|
||||
.width(Fill)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Optional "Open Manager…" row
|
||||
let mut full_col = items_col;
|
||||
if let Some(mgr_cmd) = manager_cmd {
|
||||
full_col.push(
|
||||
button(
|
||||
text(format!("Manage…")).size(10)
|
||||
.color(Color { r: 0.5, g: 0.8, b: 1.0, a: 1.0 }),
|
||||
)
|
||||
.on_press(Message::Command(mgr_cmd.to_string()))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered => Color { r: 0.24, g: 0.24, b: 0.24, a: 1.0 },
|
||||
_ => Color { r: 0.13, g: 0.13, b: 0.13, a: 1.0 },
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.padding([4, 10])
|
||||
.width(Fill)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
container(
|
||||
scrollable(
|
||||
container(column(full_col).spacing(1))
|
||||
.width(Fill)
|
||||
.padding(4),
|
||||
)
|
||||
.height(Length::Shrink),
|
||||
)
|
||||
.max_height(180.0)
|
||||
.width(Length::Fixed(STYLE_COMBO_W))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
Color { r: 0.14, g: 0.14, b: 0.14, a: 0.98 },
|
||||
)),
|
||||
border: Border {
|
||||
color: Color { r: 0.35, g: 0.35, b: 0.35, a: 1.0 },
|
||||
width: 1.0,
|
||||
radius: 4.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).height(0).into()
|
||||
};
|
||||
|
||||
// ── tool rows below combo ──
|
||||
let make_tool_row = |tools: Vec<ToolDef>| -> Element<Message> {
|
||||
let btns: Vec<Element<Message>> = tools
|
||||
.into_iter()
|
||||
.map(|t| {
|
||||
let is_active = active_tool.as_deref() == Some(t.id);
|
||||
let tip = t.label;
|
||||
let event = t.event.clone();
|
||||
let icon_el: Element<Message> = match t.icon {
|
||||
IconKind::Glyph(g) => text(g).size(13).color(Color::WHITE).into(),
|
||||
IconKind::Svg(bytes) => iced::widget::svg(
|
||||
iced::widget::svg::Handle::from_memory(bytes),
|
||||
)
|
||||
.width(16)
|
||||
.height(16)
|
||||
.into(),
|
||||
};
|
||||
let msg = module_event_to_message(event);
|
||||
tooltip(
|
||||
button(icon_el)
|
||||
.on_press(msg)
|
||||
.style(move |_: &Theme, status| tool_btn_style(is_active, status))
|
||||
.padding([2, 5]),
|
||||
make_tip(tip.to_string()),
|
||||
TipPos::Bottom,
|
||||
)
|
||||
.gap(4.0)
|
||||
.delay(Duration::from_millis(400))
|
||||
.style(tip_style)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
row(btns).spacing(2).align_y(iced::Center).into()
|
||||
};
|
||||
|
||||
let mut col_items: Vec<Element<Message>> = vec![
|
||||
container(row![combo_btn, items_panel].spacing(0))
|
||||
.width(Fill)
|
||||
.into(),
|
||||
];
|
||||
for row_tools in rows {
|
||||
col_items.push(make_tool_row(row_tools));
|
||||
}
|
||||
|
||||
container(column(col_items).spacing(3).align_x(iced::Left))
|
||||
.width(Length::Fixed(STYLE_COMBO_W))
|
||||
.height(Fill)
|
||||
.align_y(iced::Center)
|
||||
.padding(Padding { top: 4.0, bottom: 4.0, left: 4.0, right: 4.0 })
|
||||
.into()
|
||||
}
|
||||
|
||||
_ => text("").into(),
|
||||
}
|
||||
}
|
||||
|
|
@ -636,6 +848,7 @@ pub(super) fn compute_dropdown_left(
|
|||
| RibbonItem::LargeDropdown { .. }
|
||||
| RibbonItem::LayerComboGroup { .. }
|
||||
| RibbonItem::PropertiesGroup { .. }
|
||||
| RibbonItem::StyleComboGroup { .. }
|
||||
);
|
||||
let id: &str = match item {
|
||||
RibbonItem::LargeTool(t) => t.id,
|
||||
|
|
@ -644,11 +857,13 @@ pub(super) fn compute_dropdown_left(
|
|||
RibbonItem::Dropdown { id, .. } => *id,
|
||||
RibbonItem::LayerComboGroup { .. } => LAYER_COMBO_ID,
|
||||
RibbonItem::PropertiesGroup { match_prop } => match_prop.id,
|
||||
RibbonItem::StyleComboGroup { combo_id, .. } => combo_id,
|
||||
};
|
||||
let item_w = match item {
|
||||
RibbonItem::LargeTool(_) | RibbonItem::LargeDropdown { .. } => LARGE_W,
|
||||
RibbonItem::LayerComboGroup { .. } => LARGE_W * 2.5,
|
||||
RibbonItem::PropertiesGroup { .. } => LARGE_W + 4.0 + 130.0,
|
||||
RibbonItem::StyleComboGroup { .. } => LARGE_W * 2.3,
|
||||
RibbonItem::Dropdown { .. } => SMALL_W + ARROW_W,
|
||||
_ => SMALL_W,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue