feat(ribbon): degrade tool panels per-panel from the right instead of all at once
The tool area no longer swaps every panel between a full and a compact row together. CollapsePanels is now the whole tool area: it measures each panel at full, compact and collapsed widths and degrades from the right — first shrinking a panel's large buttons to compact icon columns one panel at a time until the row fits, then (only if all-compact still overflows) collapsing the rightmost panels to their ▾ flyout buttons. Left panels stay full as long as possible. Removes the global DensitySwap full/compact/collapse variant selection and the now-unused build_tool_groups / tool_divider helpers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
39043e6e56
commit
5164dc1387
2 changed files with 123 additions and 189 deletions
|
|
@ -1,12 +1,11 @@
|
||||||
//! Collapsing ribbon panels.
|
//! Adaptive ribbon panels.
|
||||||
//!
|
//!
|
||||||
//! Given a list of panels (each with an inline element, a collapsed title
|
//! Lays the active module's panels on one row. When they don't all fit, panels
|
||||||
//! button, and a full flyout), this widget lays out as many inline panels as
|
//! degrade **from the right**: first a panel's large buttons shrink to compact
|
||||||
//! fit the width from the left and collapses the rest into their title buttons.
|
//! icon columns, then — if it still doesn't fit — the panel collapses to a title
|
||||||
//! Clicking a collapsed button opens that panel's flyout as an overlay anchored
|
//! button whose click opens the full panel as a flyout overlay.
|
||||||
//! just below the button.
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use iced::advanced::layout::{self, Layout};
|
use iced::advanced::layout::{self, Layout};
|
||||||
use iced::advanced::widget::{self, Widget};
|
use iced::advanced::widget::{self, Widget};
|
||||||
|
|
@ -15,67 +14,71 @@ use iced::{Element, Event, Length, Point, Rectangle, Renderer, Size, Theme, Vect
|
||||||
|
|
||||||
use crate::app::Message;
|
use crate::app::Message;
|
||||||
|
|
||||||
/// One ribbon panel in its three renderings.
|
/// One panel in its four renderings.
|
||||||
pub struct Panel<'a> {
|
pub struct Panel<'a> {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub inline: Element<'a, Message>,
|
pub full: Element<'a, Message>,
|
||||||
|
pub compact: Element<'a, Message>,
|
||||||
pub button: Element<'a, Message>,
|
pub button: Element<'a, Message>,
|
||||||
pub flyout: Element<'a, Message>,
|
pub flyout: Element<'a, Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Per-panel degradation level; also the offset of the shown element within the
|
||||||
|
// panel's 4 trees ([full, compact, button, flyout]).
|
||||||
|
const FULL: u8 = 0;
|
||||||
|
const COMPACT: u8 = 1;
|
||||||
|
const COLLAPSED: u8 = 2;
|
||||||
|
|
||||||
pub struct CollapsePanels<'a> {
|
pub struct CollapsePanels<'a> {
|
||||||
panels: Vec<Panel<'a>>,
|
panels: Vec<Panel<'a>>,
|
||||||
/// Title of the panel whose flyout is open (if any).
|
/// Title of the panel whose flyout is open (if any).
|
||||||
open: Option<String>,
|
open: Option<String>,
|
||||||
/// Row height (a full ribbon tool-area height).
|
/// Row height (a full ribbon tool-area height).
|
||||||
row_h: f32,
|
row_h: f32,
|
||||||
/// Number of panels shown inline from the left; set during layout.
|
/// Chosen degradation level per panel; set during layout.
|
||||||
split: Cell<usize>,
|
levels: RefCell<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CollapsePanels<'a> {
|
impl<'a> CollapsePanels<'a> {
|
||||||
pub fn new(panels: Vec<Panel<'a>>, open: Option<String>, row_h: f32) -> Self {
|
pub fn new(panels: Vec<Panel<'a>>, open: Option<String>, row_h: f32) -> Self {
|
||||||
|
let n = panels.len();
|
||||||
Self {
|
Self {
|
||||||
panels,
|
panels,
|
||||||
open,
|
open,
|
||||||
row_h,
|
row_h,
|
||||||
split: Cell::new(0),
|
levels: RefCell::new(vec![FULL; n]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Element used inline for panel `i` given the split `k`.
|
fn shown(&self, i: usize, level: u8) -> &Element<'a, Message> {
|
||||||
fn shown(&self, i: usize, k: usize) -> &Element<'a, Message> {
|
match level {
|
||||||
if i < k {
|
FULL => &self.panels[i].full,
|
||||||
&self.panels[i].inline
|
COMPACT => &self.panels[i].compact,
|
||||||
} else {
|
_ => &self.panels[i].button,
|
||||||
&self.panels[i].button
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shown_mut(&mut self, i: usize, k: usize) -> &mut Element<'a, Message> {
|
fn shown_mut(&mut self, i: usize, level: u8) -> &mut Element<'a, Message> {
|
||||||
if i < k {
|
match level {
|
||||||
&mut self.panels[i].inline
|
FULL => &mut self.panels[i].full,
|
||||||
} else {
|
COMPACT => &mut self.panels[i].compact,
|
||||||
&mut self.panels[i].button
|
_ => &mut self.panels[i].button,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tree index of the element shown inline for panel `i` given split `k`.
|
fn levels_snapshot(&self, n: usize) -> Vec<u8> {
|
||||||
fn shown_tree(i: usize, k: usize) -> usize {
|
let mut v = self.levels.borrow().clone();
|
||||||
// trees are laid out [inline_0, button_0, flyout_0, inline_1, …]
|
v.resize(n, FULL);
|
||||||
if i < k {
|
v
|
||||||
3 * i
|
|
||||||
} else {
|
|
||||||
3 * i + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
fn children(&self) -> Vec<widget::Tree> {
|
fn children(&self) -> Vec<widget::Tree> {
|
||||||
let mut v = Vec::with_capacity(self.panels.len() * 3);
|
let mut v = Vec::with_capacity(self.panels.len() * 4);
|
||||||
for p in &self.panels {
|
for p in &self.panels {
|
||||||
v.push(widget::Tree::new(&p.inline));
|
v.push(widget::Tree::new(&p.full));
|
||||||
|
v.push(widget::Tree::new(&p.compact));
|
||||||
v.push(widget::Tree::new(&p.button));
|
v.push(widget::Tree::new(&p.button));
|
||||||
v.push(widget::Tree::new(&p.flyout));
|
v.push(widget::Tree::new(&p.flyout));
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +88,8 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
fn diff(&self, tree: &mut widget::Tree) {
|
fn diff(&self, tree: &mut widget::Tree) {
|
||||||
let mut refs: Vec<&dyn Widget<Message, Theme, Renderer>> = Vec::new();
|
let mut refs: Vec<&dyn Widget<Message, Theme, Renderer>> = Vec::new();
|
||||||
for p in &self.panels {
|
for p in &self.panels {
|
||||||
refs.push(p.inline.as_widget());
|
refs.push(p.full.as_widget());
|
||||||
|
refs.push(p.compact.as_widget());
|
||||||
refs.push(p.button.as_widget());
|
refs.push(p.button.as_widget());
|
||||||
refs.push(p.flyout.as_widget());
|
refs.push(p.flyout.as_widget());
|
||||||
}
|
}
|
||||||
|
|
@ -103,57 +107,69 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let max_w = limits.max().width;
|
let max_w = limits.max().width;
|
||||||
let natural =
|
let natural = layout::Limits::new(Size::ZERO, Size::new(f32::INFINITY, f32::INFINITY));
|
||||||
layout::Limits::new(Size::ZERO, Size::new(f32::INFINITY, f32::INFINITY));
|
|
||||||
let n = self.panels.len();
|
let n = self.panels.len();
|
||||||
|
|
||||||
// Measure every inline panel and every collapsed button.
|
// Measure each panel at all three densities.
|
||||||
let mut inline_w = vec![0.0f32; n];
|
let mut full_w = vec![0.0f32; n];
|
||||||
|
let mut compact_w = vec![0.0f32; n];
|
||||||
let mut button_w = vec![0.0f32; n];
|
let mut button_w = vec![0.0f32; n];
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let inline_node = self.panels[i].inline.as_widget_mut().layout(
|
full_w[i] = self.panels[i].full.as_widget_mut()
|
||||||
&mut tree.children[3 * i],
|
.layout(&mut tree.children[4 * i], renderer, &natural)
|
||||||
renderer,
|
.size()
|
||||||
&natural,
|
.width;
|
||||||
);
|
compact_w[i] = self.panels[i].compact.as_widget_mut()
|
||||||
let button_node = self.panels[i].button.as_widget_mut().layout(
|
.layout(&mut tree.children[4 * i + 1], renderer, &natural)
|
||||||
&mut tree.children[3 * i + 1],
|
.size()
|
||||||
renderer,
|
.width;
|
||||||
&natural,
|
button_w[i] = self.panels[i].button.as_widget_mut()
|
||||||
);
|
.layout(&mut tree.children[4 * i + 2], renderer, &natural)
|
||||||
inline_w[i] = inline_node.size().width;
|
.size()
|
||||||
button_w[i] = button_node.size().width;
|
.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand a prefix of panels from the left while the row still fits with
|
let width_of = |lv: u8, i: usize| -> f32 {
|
||||||
// the remaining panels collapsed to buttons.
|
match lv {
|
||||||
let all_buttons: f32 = button_w.iter().sum();
|
FULL => full_w[i],
|
||||||
let mut used = all_buttons;
|
COMPACT => compact_w[i],
|
||||||
let mut k = 0;
|
_ => button_w[i],
|
||||||
for i in 0..n {
|
}
|
||||||
let candidate = used - button_w[i] + inline_w[i];
|
};
|
||||||
if candidate <= max_w {
|
let total = |levels: &[u8]| -> f32 { (0..n).map(|i| width_of(levels[i], i)).sum() };
|
||||||
used = candidate;
|
|
||||||
k = i + 1;
|
// Start all full; degrade from the RIGHT. Phase 1 shrinks large panels
|
||||||
} else {
|
// to compact one at a time; phase 2 (only if compact still overflows)
|
||||||
|
// collapses them to buttons.
|
||||||
|
let mut levels = vec![FULL; n];
|
||||||
|
for i in (0..n).rev() {
|
||||||
|
if total(&levels) <= max_w {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
levels[i] = COMPACT;
|
||||||
}
|
}
|
||||||
self.split.set(k);
|
for i in (0..n).rev() {
|
||||||
|
if total(&levels) <= max_w {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
levels[i] = COLLAPSED;
|
||||||
|
}
|
||||||
|
*self.levels.borrow_mut() = levels.clone();
|
||||||
|
|
||||||
// Place the chosen element for each panel left-to-right.
|
// Place the chosen element for each panel left-to-right.
|
||||||
let mut children: Vec<layout::Node> = Vec::with_capacity(n);
|
let mut children: Vec<layout::Node> = Vec::with_capacity(n);
|
||||||
let mut x = 0.0f32;
|
let mut x = 0.0f32;
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let tree_idx = Self::shown_tree(i, k);
|
let level = levels[i];
|
||||||
let node = self.shown_mut(i, k).as_widget_mut().layout(
|
let tree_idx = 4 * i + level as usize;
|
||||||
|
let node = self.shown_mut(i, level).as_widget_mut().layout(
|
||||||
&mut tree.children[tree_idx],
|
&mut tree.children[tree_idx],
|
||||||
renderer,
|
renderer,
|
||||||
&natural,
|
&natural,
|
||||||
);
|
);
|
||||||
let h = node.size().height;
|
let h = node.size().height;
|
||||||
let y = ((self.row_h - h) / 2.0).max(0.0);
|
|
||||||
let w = node.size().width;
|
let w = node.size().width;
|
||||||
|
let y = ((self.row_h - h) / 2.0).max(0.0);
|
||||||
children.push(node.move_to(Point::new(x, y)));
|
children.push(node.move_to(Point::new(x, y)));
|
||||||
x += w;
|
x += w;
|
||||||
}
|
}
|
||||||
|
|
@ -172,10 +188,11 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
let k = self.split.get();
|
let levels = self.levels_snapshot(self.panels.len());
|
||||||
for (i, child_layout) in layout.children().enumerate() {
|
for (i, child_layout) in layout.children().enumerate() {
|
||||||
let tree_idx = Self::shown_tree(i, k);
|
let level = levels[i];
|
||||||
self.shown_mut(i, k).as_widget_mut().update(
|
let tree_idx = 4 * i + level as usize;
|
||||||
|
self.shown_mut(i, level).as_widget_mut().update(
|
||||||
&mut tree.children[tree_idx],
|
&mut tree.children[tree_idx],
|
||||||
event,
|
event,
|
||||||
child_layout,
|
child_layout,
|
||||||
|
|
@ -196,11 +213,12 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
let k = self.split.get();
|
let levels = self.levels_snapshot(self.panels.len());
|
||||||
let mut interaction = mouse::Interaction::default();
|
let mut interaction = mouse::Interaction::default();
|
||||||
for (i, child_layout) in layout.children().enumerate() {
|
for (i, child_layout) in layout.children().enumerate() {
|
||||||
let tree_idx = Self::shown_tree(i, k);
|
let level = levels[i];
|
||||||
let it = self.shown(i, k).as_widget().mouse_interaction(
|
let tree_idx = 4 * i + level as usize;
|
||||||
|
let it = self.shown(i, level).as_widget().mouse_interaction(
|
||||||
&tree.children[tree_idx],
|
&tree.children[tree_idx],
|
||||||
child_layout,
|
child_layout,
|
||||||
cursor,
|
cursor,
|
||||||
|
|
@ -221,10 +239,11 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
operation: &mut dyn widget::Operation,
|
operation: &mut dyn widget::Operation,
|
||||||
) {
|
) {
|
||||||
let k = self.split.get();
|
let levels = self.levels_snapshot(self.panels.len());
|
||||||
for (i, child_layout) in layout.children().enumerate() {
|
for (i, child_layout) in layout.children().enumerate() {
|
||||||
let tree_idx = Self::shown_tree(i, k);
|
let level = levels[i];
|
||||||
self.shown_mut(i, k).as_widget_mut().operate(
|
let tree_idx = 4 * i + level as usize;
|
||||||
|
self.shown_mut(i, level).as_widget_mut().operate(
|
||||||
&mut tree.children[tree_idx],
|
&mut tree.children[tree_idx],
|
||||||
child_layout,
|
child_layout,
|
||||||
renderer,
|
renderer,
|
||||||
|
|
@ -243,10 +262,11 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
let k = self.split.get();
|
let levels = self.levels_snapshot(self.panels.len());
|
||||||
for (i, child_layout) in layout.children().enumerate() {
|
for (i, child_layout) in layout.children().enumerate() {
|
||||||
let tree_idx = Self::shown_tree(i, k);
|
let level = levels[i];
|
||||||
self.shown(i, k).as_widget().draw(
|
let tree_idx = 4 * i + level as usize;
|
||||||
|
self.shown(i, level).as_widget().draw(
|
||||||
&tree.children[tree_idx],
|
&tree.children[tree_idx],
|
||||||
renderer,
|
renderer,
|
||||||
theme,
|
theme,
|
||||||
|
|
@ -266,11 +286,11 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
||||||
let k = self.split.get();
|
let levels = self.levels_snapshot(self.panels.len());
|
||||||
let open_id = self.open.clone()?;
|
let open_id = self.open.clone()?;
|
||||||
let p = self.panels.iter().position(|pan| pan.id == open_id)?;
|
let p = self.panels.iter().position(|pan| pan.id == open_id)?;
|
||||||
// Only collapsed panels (index >= k) show a flyout.
|
// Only a collapsed panel shows a flyout.
|
||||||
if p < k {
|
if levels.get(p).copied().unwrap_or(FULL) != COLLAPSED {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,7 +300,7 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||||
|
|
||||||
Some(overlay::Element::new(Box::new(FlyoutOverlay {
|
Some(overlay::Element::new(Box::new(FlyoutOverlay {
|
||||||
flyout: &mut self.panels[p].flyout,
|
flyout: &mut self.panels[p].flyout,
|
||||||
tree: &mut tree.children[3 * p + 2],
|
tree: &mut tree.children[4 * p + 3],
|
||||||
anchor,
|
anchor,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
@ -352,9 +372,6 @@ impl overlay::Overlay<Message, Theme, Renderer> for FlyoutOverlay<'_, '_> {
|
||||||
let child = layout.children().next().unwrap();
|
let child = layout.children().next().unwrap();
|
||||||
let vp = child.bounds();
|
let vp = child.bounds();
|
||||||
|
|
||||||
// Close when a press lands outside the flyout. Capture the event so the
|
|
||||||
// press doesn't also reach the collapsed button underneath (which would
|
|
||||||
// immediately re-open the flyout).
|
|
||||||
if let Event::Mouse(mouse::Event::ButtonPressed(_)) = event {
|
if let Event::Mouse(mouse::Event::ButtonPressed(_)) = event {
|
||||||
if !cursor.is_over(vp) {
|
if !cursor.is_over(vp) {
|
||||||
shell.publish(Message::CloseRibbonDropdown);
|
shell.publish(Message::CloseRibbonDropdown);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ mod widgets;
|
||||||
use widgets::{StyleContext, *};
|
use widgets::{StyleContext, *};
|
||||||
mod collapse;
|
mod collapse;
|
||||||
use collapse::{CollapsePanels, Panel};
|
use collapse::{CollapsePanels, Panel};
|
||||||
use crate::ui::wrap_bar::{DensitySwap, WrapBar, WrapFlow};
|
use crate::ui::wrap_bar::{WrapBar, WrapFlow};
|
||||||
|
|
||||||
// ── Ribbon state ───────────────────────────────────────────────────────────
|
// ── Ribbon state ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -468,47 +468,30 @@ impl Ribbon {
|
||||||
active_table_style: self.active_table_style.clone(),
|
active_table_style: self.active_table_style.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Adaptive tool area, widest→narrowest:
|
// Adaptive tool area: panels sit on one row; when they don't all
|
||||||
// 1. full — full-size panels on one row
|
// fit they degrade from the right — a panel's large buttons first
|
||||||
// 2. compact — large buttons shrink to icon-only columns
|
// shrink to compact icon columns, then it collapses to a ▾ flyout
|
||||||
// 3. collapse — panels that still don't fit collapse to title
|
// button. See `CollapsePanels`.
|
||||||
// buttons that open the full panel as a flyout
|
|
||||||
// DensitySwap shows the widest variant that fits the width.
|
|
||||||
let build = |compact: bool| {
|
|
||||||
build_tool_groups(
|
|
||||||
compact,
|
|
||||||
&groups,
|
|
||||||
&self.active_tool,
|
|
||||||
&self.open_dropdown,
|
|
||||||
&self.last_cmd,
|
|
||||||
self.wireframe,
|
|
||||||
self.ortho_mode,
|
|
||||||
&self.layer_infos,
|
|
||||||
&self.active_layer,
|
|
||||||
self.active_color,
|
|
||||||
&self.active_linetype,
|
|
||||||
self.active_lineweight,
|
|
||||||
&style_ctx,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let full: Element<'_, Message> = build(false)
|
|
||||||
.into_iter()
|
|
||||||
.fold(row![].spacing(0).height(Length::Fixed(TOOL_BAR_H)), |r, w| {
|
|
||||||
r.push(w)
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
let compact: Element<'_, Message> = build(true)
|
|
||||||
.into_iter()
|
|
||||||
.fold(row![].spacing(0).height(Length::Fixed(TOOL_BAR_H)), |r, w| {
|
|
||||||
r.push(w)
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let panels: Vec<Panel<'_>> = groups
|
let panels: Vec<Panel<'_>> = groups
|
||||||
.iter()
|
.iter()
|
||||||
.map(|g| Panel {
|
.map(|g| Panel {
|
||||||
id: g.title.to_string(),
|
id: g.title.to_string(),
|
||||||
inline: render_group(
|
full: render_group(
|
||||||
|
false,
|
||||||
|
g,
|
||||||
|
&self.active_tool,
|
||||||
|
&self.open_dropdown,
|
||||||
|
&self.last_cmd,
|
||||||
|
self.wireframe,
|
||||||
|
self.ortho_mode,
|
||||||
|
&self.layer_infos,
|
||||||
|
&self.active_layer,
|
||||||
|
self.active_color,
|
||||||
|
&self.active_linetype,
|
||||||
|
self.active_lineweight,
|
||||||
|
&style_ctx,
|
||||||
|
),
|
||||||
|
compact: render_group(
|
||||||
true,
|
true,
|
||||||
g,
|
g,
|
||||||
&self.active_tool,
|
&self.active_tool,
|
||||||
|
|
@ -565,12 +548,7 @@ impl Ribbon {
|
||||||
.into(),
|
.into(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let collapse: Element<'_, Message> =
|
CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H).into()
|
||||||
CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H).into();
|
|
||||||
|
|
||||||
DensitySwap::new(vec![full, compact, collapse])
|
|
||||||
.report_height(self.tool_bar_h.clone())
|
|
||||||
.into()
|
|
||||||
} else {
|
} else {
|
||||||
text("").into()
|
text("").into()
|
||||||
};
|
};
|
||||||
|
|
@ -1179,67 +1157,6 @@ impl Ribbon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the active module's ribbon panels as a list of group elements (with
|
|
||||||
/// 1px dividers between them). When `compact`, large tools/dropdowns are drawn
|
|
||||||
/// as small icon columns so each panel is narrower; the combo groups (layer /
|
|
||||||
/// properties / style) always stay full. Each panel is a fixed `TOOL_BAR_H`
|
|
||||||
/// tall so the list can be laid out in a row or flex-wrapped across rows.
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn build_tool_groups<'a>(
|
|
||||||
compact: bool,
|
|
||||||
groups: &[RibbonGroup],
|
|
||||||
active_tool: &Option<String>,
|
|
||||||
open_dd: &Option<String>,
|
|
||||||
last_cmd: &HashMap<&'static str, &'static str>,
|
|
||||||
wireframe: bool,
|
|
||||||
ortho_mode: bool,
|
|
||||||
layer_infos: &'a [LayerInfo],
|
|
||||||
active_layer: &'a str,
|
|
||||||
active_color: AcadColor,
|
|
||||||
active_linetype: &'a str,
|
|
||||||
active_lineweight: LineWeight,
|
|
||||||
style_ctx: &StyleContext,
|
|
||||||
) -> Vec<Element<'a, Message>> {
|
|
||||||
let mut widgets: Vec<Element<Message>> = Vec::new();
|
|
||||||
let mut first_group = true;
|
|
||||||
|
|
||||||
for group in groups {
|
|
||||||
if !first_group {
|
|
||||||
widgets.push(tool_divider());
|
|
||||||
}
|
|
||||||
first_group = false;
|
|
||||||
widgets.push(render_group(
|
|
||||||
compact,
|
|
||||||
group,
|
|
||||||
active_tool,
|
|
||||||
open_dd,
|
|
||||||
last_cmd,
|
|
||||||
wireframe,
|
|
||||||
ortho_mode,
|
|
||||||
layer_infos,
|
|
||||||
active_layer,
|
|
||||||
active_color,
|
|
||||||
active_linetype,
|
|
||||||
active_lineweight,
|
|
||||||
style_ctx,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
widgets
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A 1px vertical divider between ribbon panels, full tool-area height.
|
|
||||||
fn tool_divider<'a>() -> Element<'a, Message> {
|
|
||||||
container(text(""))
|
|
||||||
.width(1)
|
|
||||||
.height(Length::Fixed(TOOL_BAR_H))
|
|
||||||
.style(|_: &Theme| container::Style {
|
|
||||||
background: Some(Background::Color(BORDER_DARK)),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Render a single ribbon panel (tools + group label), fixed `TOOL_BAR_H` tall.
|
/// Render a single ribbon panel (tools + group label), fixed `TOOL_BAR_H` tall.
|
||||||
/// When `compact`, large tools/dropdowns are drawn as small icon columns.
|
/// When `compact`, large tools/dropdowns are drawn as small icon columns.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue