diff --git a/src/ui/ribbon/collapse.rs b/src/ui/ribbon/collapse.rs index 52c60c36d..958cd3e0a 100644 --- a/src/ui/ribbon/collapse.rs +++ b/src/ui/ribbon/collapse.rs @@ -9,8 +9,11 @@ use std::cell::RefCell; use iced::advanced::layout::{self, Layout}; use iced::advanced::widget::{self, Widget}; -use iced::advanced::{mouse, overlay, renderer, Clipboard, Shell}; -use iced::{Element, Event, Length, Point, Rectangle, Renderer, Size, Theme, Vector}; +use iced::advanced::{mouse, overlay, renderer, Clipboard, Renderer as _, Shell}; +use iced::{ + Background, Border, Color, Element, Event, Length, Point, Rectangle, Renderer, Shadow, Size, + Theme, Vector, +}; use crate::app::Message; @@ -35,17 +38,20 @@ pub struct CollapsePanels<'a> { open: Option, /// Row height (a full ribbon tool-area height). row_h: f32, + /// Colour of the 1px divider drawn between panels. + divider: Color, /// Chosen degradation level per panel; set during layout. levels: RefCell>, } impl<'a> CollapsePanels<'a> { - pub fn new(panels: Vec>, open: Option, row_h: f32) -> Self { + pub fn new(panels: Vec>, open: Option, row_h: f32, divider: Color) -> Self { let n = panels.len(); Self { panels, open, row_h, + divider, levels: RefCell::new(vec![FULL; n]), } } @@ -276,6 +282,31 @@ impl<'a> Widget for CollapsePanels<'a> { viewport, ); } + + // 1px divider between adjacent panels, except between two collapsed + // panels (whose buttons read better with no line between them). + let bounds: Vec = layout.children().map(|l| l.bounds()).collect(); + let wb = layout.bounds(); + for i in 0..self.panels.len().saturating_sub(1) { + if levels[i] == COLLAPSED && levels[i + 1] == COLLAPSED { + continue; + } + let x = bounds[i + 1].x; + renderer.fill_quad( + renderer::Quad { + bounds: Rectangle { + x, + y: wb.y, + width: 1.0, + height: wb.height, + }, + border: Border::default(), + shadow: Shadow::default(), + snap: true, + }, + Background::Color(self.divider), + ); + } } fn overlay<'b>( diff --git a/src/ui/ribbon/mod.rs b/src/ui/ribbon/mod.rs index 7b174b3ce..93e1d2fcf 100644 --- a/src/ui/ribbon/mod.rs +++ b/src/ui/ribbon/mod.rs @@ -548,7 +548,8 @@ impl Ribbon { .into(), }) .collect(); - CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H).into() + CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H, BORDER_DARK) + .into() } else { text("").into() }; @@ -1202,6 +1203,7 @@ fn render_group<'a>( active_linetype, active_lineweight, style_ctx, + compact, )); } else { small_buf.push(render_small( @@ -1241,6 +1243,7 @@ fn item_id(it: &RibbonItem) -> Option<&'static str> { match it { RibbonItem::Tool(t) | RibbonItem::LargeTool(t) => Some(t.id), RibbonItem::Dropdown { id, .. } | RibbonItem::LargeDropdown { id, .. } => Some(*id), + RibbonItem::PropertiesGroup { match_prop } => Some(match_prop.id), _ => None, } } @@ -1281,9 +1284,24 @@ fn collapse_button<'a>( ) -> Element<'a, Message> { let title = group.title; - // Show the representative tool with a large icon (Tool/Dropdown alike — - // render_large handles every tool-like item). + // Show the representative tool with a large icon. For a Properties panel the + // representative is its Match button, rendered as a large tool. let face: Element<'_, Message> = match representative(group, last_used) { + Some(RibbonItem::PropertiesGroup { match_prop }) => render_large( + &RibbonItem::LargeTool(match_prop.clone()), + active_tool, + open_dd, + last_cmd, + wireframe, + ortho_mode, + layer_infos, + active_layer, + active_color, + active_linetype, + active_lineweight, + style_ctx, + false, + ), Some(item) => render_large( item, active_tool, @@ -1297,6 +1315,7 @@ fn collapse_button<'a>( active_linetype, active_lineweight, style_ctx, + false, ), None => text("").into(), }; diff --git a/src/ui/ribbon/widgets.rs b/src/ui/ribbon/widgets.rs index 9af2f88a0..bc661fcae 100644 --- a/src/ui/ribbon/widgets.rs +++ b/src/ui/ribbon/widgets.rs @@ -584,6 +584,8 @@ pub(super) fn render_large<'a>( active_linetype: &'a str, active_lineweight: LineWeight, style_ctx: &StyleContext, + // When compact, the Properties panel's Match button shrinks to a small icon. + compact: bool, ) -> Element<'a, Message> { match item { // A plain Tool renders large too, so a collapsed panel can show its @@ -765,35 +767,49 @@ pub(super) fn render_large<'a>( } RibbonItem::PropertiesGroup { match_prop } => { - let mp_active = is_active_tool(match_prop.id, active_tool, wireframe, ortho_mode); - let mp_event = match_prop.event.clone(); - let mp_id = match_prop.id.to_string(); - let mp_tip = format!("{}\nCommand: {}", match_prop.label, match_prop.id); - let mp_btn = button( - column![ - make_icon(match_prop.icon, LARGE_ICON), - text(match_prop.label).size(10).color(LABEL_COLOR), - ] - .align_x(iced::Center) - .spacing(3), - ) - .on_press(Message::RibbonToolClick { - tool_id: mp_id, - event: mp_event, - }) - .style(move |_: &Theme, status| tool_btn_style(mp_active, status)) - .width(Length::Fixed(LARGE_W)) - .height(Fill) - .padding(Padding { - top: 6.0, - right: 4.0, - bottom: 4.0, - left: 4.0, - }); - let mp_el = tooltip(mp_btn, make_tip(mp_tip), TipPos::Right) - .gap(6.0) - .delay(Duration::from_millis(400)) - .style(tip_style); + // The Match Properties button is a large icon normally, but shrinks + // to a small icon when the panel is compacted. + let mp_el: Element<'a, Message> = if compact { + render_small( + &RibbonItem::Tool(match_prop.clone()), + active_tool, + open_dd, + last_cmd, + wireframe, + ortho_mode, + ) + } else { + let mp_active = is_active_tool(match_prop.id, active_tool, wireframe, ortho_mode); + let mp_event = match_prop.event.clone(); + let mp_id = match_prop.id.to_string(); + let mp_tip = format!("{}\nCommand: {}", match_prop.label, match_prop.id); + let mp_btn = button( + column![ + make_icon(match_prop.icon, LARGE_ICON), + text(match_prop.label).size(10).color(LABEL_COLOR), + ] + .align_x(iced::Center) + .spacing(3), + ) + .on_press(Message::RibbonToolClick { + tool_id: mp_id, + event: mp_event, + }) + .style(move |_: &Theme, status| tool_btn_style(mp_active, status)) + .width(Length::Fixed(LARGE_W)) + .height(Fill) + .padding(Padding { + top: 6.0, + right: 4.0, + bottom: 4.0, + left: 4.0, + }); + tooltip(mp_btn, make_tip(mp_tip), TipPos::Right) + .gap(6.0) + .delay(Duration::from_millis(400)) + .style(tip_style) + .into() + }; const PROP_W: f32 = 130.0; @@ -1139,7 +1155,7 @@ pub(super) fn render_history_control<'a>( .style(tip_style) }; - row![main_btn, arrow_btn].spacing(0).into() + PosReport::new(dropdown_id, row![main_btn, arrow_btn].spacing(0)).into() } pub(super) fn top_hist_btn_style(