feat(segmented_button): variable-width horizontal button when width is Shrink
This commit is contained in:
parent
3aef16bf9e
commit
d5b2a2e87c
3 changed files with 213 additions and 149 deletions
|
|
@ -3,12 +3,13 @@
|
||||||
|
|
||||||
//! Implementation details for the horizontal layout of a segmented button.
|
//! Implementation details for the horizontal layout of a segmented button.
|
||||||
|
|
||||||
use super::model::{Model, Selectable};
|
use super::model::{Entity, Model, Selectable};
|
||||||
use super::style::StyleSheet;
|
use super::style::StyleSheet;
|
||||||
use super::widget::{LocalState, SegmentedButton, SegmentedVariant};
|
use super::widget::{LocalState, SegmentedButton, SegmentedVariant};
|
||||||
|
|
||||||
use iced::{Length, Rectangle, Size};
|
use iced::{Length, Rectangle, Size};
|
||||||
use iced_core::layout;
|
use iced_core::layout;
|
||||||
|
use iced_core::text::Renderer;
|
||||||
|
|
||||||
/// Horizontal [`SegmentedButton`].
|
/// Horizontal [`SegmentedButton`].
|
||||||
pub type HorizontalSegmentedButton<'a, SelectionMode, Message> =
|
pub type HorizontalSegmentedButton<'a, SelectionMode, Message> =
|
||||||
|
|
@ -48,34 +49,40 @@ where
|
||||||
&self,
|
&self,
|
||||||
state: &LocalState,
|
state: &LocalState,
|
||||||
mut bounds: Rectangle,
|
mut bounds: Rectangle,
|
||||||
nth: usize,
|
) -> impl Iterator<Item = (Entity, Rectangle)> {
|
||||||
) -> Option<Rectangle> {
|
|
||||||
let num = state.buttons_visible;
|
let num = state.buttons_visible;
|
||||||
|
let spacing = f32::from(self.spacing);
|
||||||
|
let mut homogenous_width = 0.0;
|
||||||
|
|
||||||
// Do not display tabs that are currently hidden due to width constraints.
|
if Length::Shrink != self.width || state.collapsed {
|
||||||
if state.collapsed && nth < state.buttons_offset {
|
if state.collapsed {
|
||||||
return None;
|
bounds.x += 16.0;
|
||||||
}
|
bounds.width -= 32.0;
|
||||||
|
|
||||||
if num != 0 {
|
|
||||||
let offset_width;
|
|
||||||
(bounds.x, offset_width) = if state.collapsed {
|
|
||||||
(bounds.x + 16.0, 32.0)
|
|
||||||
} else {
|
|
||||||
(bounds.x, 0.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
let spacing = f32::from(self.spacing);
|
|
||||||
bounds.width = ((num as f32).mul_add(-spacing, bounds.width - offset_width) + spacing)
|
|
||||||
/ num as f32;
|
|
||||||
|
|
||||||
if nth != state.buttons_offset {
|
|
||||||
let pos = (nth - state.buttons_offset) as f32;
|
|
||||||
bounds.x += pos.mul_add(bounds.width, pos * spacing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
homogenous_width =
|
||||||
|
((num as f32).mul_add(-spacing, bounds.width) + spacing) / num as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(bounds)
|
self.model
|
||||||
|
.order
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.enumerate()
|
||||||
|
.skip(state.buttons_offset)
|
||||||
|
.take(state.buttons_visible)
|
||||||
|
.map(move |(nth, key)| {
|
||||||
|
let mut this_bounds = bounds;
|
||||||
|
|
||||||
|
if !state.collapsed && Length::Shrink == self.width {
|
||||||
|
this_bounds.width = state.internal_layout[nth].width;
|
||||||
|
} else {
|
||||||
|
this_bounds.width = homogenous_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
bounds.x += this_bounds.width + spacing;
|
||||||
|
(key, this_bounds)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
|
@ -87,27 +94,92 @@ where
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let limits = limits.width(self.width);
|
let num = self.model.order.len();
|
||||||
let (mut width, height) = self.max_button_dimensions(state, renderer, limits.max());
|
let mut total_width = 0.0;
|
||||||
|
|
||||||
let num = self.model.items.len();
|
|
||||||
let spacing = f32::from(self.spacing);
|
let spacing = f32::from(self.spacing);
|
||||||
|
let limits = limits.width(self.width);
|
||||||
|
let size;
|
||||||
|
|
||||||
if num != 0 {
|
if state.known_length != num {
|
||||||
width = (num as f32).mul_add(width, num as f32 * spacing) - spacing;
|
if state.known_length > num {
|
||||||
|
state.buttons_offset -= state.buttons_offset.min(state.known_length - num);
|
||||||
|
} else {
|
||||||
|
state.buttons_offset += num - state.known_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.known_length = num;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = limits
|
if let Length::Shrink = self.width {
|
||||||
.height(Length::Fixed(height))
|
// Buttons will be rendered at their smallest widths possible.
|
||||||
.resolve(Size::new(width, height));
|
state.internal_layout.clear();
|
||||||
|
|
||||||
let actual_width = size.width as usize;
|
let font = renderer.default_font();
|
||||||
let minimum_width = self.minimum_button_width as usize * self.model.items.len();
|
let mut total_height = 0.0f32;
|
||||||
|
|
||||||
state.buttons_visible = num;
|
for &button in &self.model.order {
|
||||||
state.collapsed = actual_width < minimum_width;
|
let (mut width, height) = self.button_dimensions(state, font, button);
|
||||||
if state.collapsed {
|
width = f32::from(self.minimum_button_width).max(width);
|
||||||
state.buttons_visible = (actual_width / self.minimum_button_width as usize).min(num);
|
total_width += width + spacing;
|
||||||
|
total_height = total_height.max(height);
|
||||||
|
|
||||||
|
state.internal_layout.push(Size::new(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the max available width for placing buttons into.
|
||||||
|
let max_size = limits
|
||||||
|
.height(Length::Fixed(total_height))
|
||||||
|
.resolve(Size::new(f32::MAX, total_height));
|
||||||
|
|
||||||
|
let mut visible_width = 32.0;
|
||||||
|
state.buttons_visible = 0;
|
||||||
|
|
||||||
|
for button_size in &state.internal_layout {
|
||||||
|
visible_width += button_size.width;
|
||||||
|
|
||||||
|
if max_size.width >= visible_width {
|
||||||
|
state.buttons_visible += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
visible_width += spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.collapsed = num > 1 && state.buttons_visible != num;
|
||||||
|
|
||||||
|
// If collapsed, use the maximum width available.
|
||||||
|
visible_width = if state.collapsed {
|
||||||
|
max_size.width - 32.0
|
||||||
|
} else {
|
||||||
|
total_width
|
||||||
|
};
|
||||||
|
|
||||||
|
size = limits
|
||||||
|
.height(Length::Fixed(total_height))
|
||||||
|
.resolve(Size::new(visible_width, total_height));
|
||||||
|
} else {
|
||||||
|
// Buttons will be rendered with equal widths.
|
||||||
|
state.buttons_visible = self.model.items.len();
|
||||||
|
let (width, height) = self.max_button_dimensions(state, renderer, limits.max());
|
||||||
|
let total_width = (state.buttons_visible as f32) * (width + spacing);
|
||||||
|
|
||||||
|
size = limits
|
||||||
|
.height(Length::Fixed(height))
|
||||||
|
.resolve(Size::new(total_width, height));
|
||||||
|
|
||||||
|
let actual_width = size.width as usize;
|
||||||
|
let minimum_width = state.buttons_visible * self.minimum_button_width as usize;
|
||||||
|
state.collapsed = actual_width < minimum_width;
|
||||||
|
|
||||||
|
if state.collapsed {
|
||||||
|
state.buttons_visible =
|
||||||
|
(actual_width / self.minimum_button_width as usize).min(state.buttons_visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !state.collapsed {
|
||||||
|
state.buttons_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
layout::Node::new(size)
|
layout::Node::new(size)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
//! Implementation details for the vertical layout of a segmented button.
|
//! Implementation details for the vertical layout of a segmented button.
|
||||||
|
|
||||||
use super::model::{Model, Selectable};
|
use super::model::{Entity, Model, Selectable};
|
||||||
use super::style::StyleSheet;
|
use super::style::StyleSheet;
|
||||||
use super::widget::{LocalState, SegmentedButton, SegmentedVariant};
|
use super::widget::{LocalState, SegmentedButton, SegmentedVariant};
|
||||||
|
|
||||||
|
|
@ -47,21 +47,22 @@ where
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
fn variant_button_bounds(
|
fn variant_button_bounds(
|
||||||
&self,
|
&self,
|
||||||
_state: &LocalState,
|
state: &LocalState,
|
||||||
mut bounds: Rectangle,
|
mut bounds: Rectangle,
|
||||||
nth: usize,
|
) -> impl Iterator<Item = (Entity, Rectangle)> {
|
||||||
) -> Option<Rectangle> {
|
let spacing = f32::from(self.spacing);
|
||||||
let num = self.model.items.len();
|
|
||||||
if num != 0 {
|
|
||||||
let spacing = f32::from(self.spacing);
|
|
||||||
bounds.height = (bounds.height - (num as f32 * spacing) + spacing) / num as f32;
|
|
||||||
|
|
||||||
if nth != 0 {
|
self.model
|
||||||
bounds.y += (nth as f32 * bounds.height) + (nth as f32 * spacing);
|
.order
|
||||||
}
|
.iter()
|
||||||
}
|
.copied()
|
||||||
|
.enumerate()
|
||||||
Some(bounds)
|
.map(move |(_nth, key)| {
|
||||||
|
let mut this_bounds = bounds;
|
||||||
|
this_bounds.height = state.internal_layout[0].height;
|
||||||
|
bounds.y += this_bounds.height + spacing;
|
||||||
|
(key, this_bounds)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
|
@ -73,8 +74,10 @@ where
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
|
state.internal_layout.clear();
|
||||||
let limits = limits.width(self.width);
|
let limits = limits.width(self.width);
|
||||||
let (width, mut height) = self.max_button_dimensions(state, renderer, limits.max());
|
let (width, mut height) = self.max_button_dimensions(state, renderer, limits.max());
|
||||||
|
state.internal_layout.push(Size::new(width, height));
|
||||||
|
|
||||||
let num = self.model.items.len();
|
let num = self.model.items.len();
|
||||||
let spacing = f32::from(self.spacing);
|
let spacing = f32::from(self.spacing);
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,12 @@ pub trait SegmentedVariant {
|
||||||
style: &crate::theme::SegmentedButton,
|
style: &crate::theme::SegmentedButton,
|
||||||
) -> super::Appearance;
|
) -> super::Appearance;
|
||||||
|
|
||||||
/// Calculates the bounds for the given button by its position.
|
/// Calculates the bounds for visible buttons.
|
||||||
fn variant_button_bounds(
|
fn variant_button_bounds(
|
||||||
&self,
|
&self,
|
||||||
state: &LocalState,
|
state: &LocalState,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
position: usize,
|
) -> impl Iterator<Item = (Entity, Rectangle)>;
|
||||||
) -> Option<Rectangle>;
|
|
||||||
|
|
||||||
/// Calculates the layout of this variant.
|
/// Calculates the layout of this variant.
|
||||||
fn variant_layout(
|
fn variant_layout(
|
||||||
|
|
@ -137,6 +136,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emitted when a tab is pressed.
|
||||||
pub fn on_activate<T>(mut self, on_activate: T) -> Self
|
pub fn on_activate<T>(mut self, on_activate: T) -> Self
|
||||||
where
|
where
|
||||||
T: Fn(Entity) -> Message + 'static,
|
T: Fn(Entity) -> Message + 'static,
|
||||||
|
|
@ -145,6 +145,7 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emitted when a tab close button is pressed.
|
||||||
pub fn on_close<T>(mut self, on_close: T) -> Self
|
pub fn on_close<T>(mut self, on_close: T) -> Self
|
||||||
where
|
where
|
||||||
T: Fn(Entity) -> Message + 'static,
|
T: Fn(Entity) -> Message + 'static,
|
||||||
|
|
@ -293,6 +294,65 @@ where
|
||||||
state.buttons_offset < self.model.order.len() - state.buttons_visible
|
state.buttons_offset < self.model.order.len() - state.buttons_visible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn button_dimensions(
|
||||||
|
&self,
|
||||||
|
state: &mut LocalState,
|
||||||
|
font: crate::font::Font,
|
||||||
|
button: Entity,
|
||||||
|
) -> (f32, f32) {
|
||||||
|
let mut width = 0.0f32;
|
||||||
|
let mut height = 0.0f32;
|
||||||
|
|
||||||
|
// Add text to measurement if text was given.
|
||||||
|
if let Some((text, entry)) = self
|
||||||
|
.model
|
||||||
|
.text
|
||||||
|
.get(button)
|
||||||
|
.zip(state.paragraphs.entry(button))
|
||||||
|
{
|
||||||
|
let paragraph = entry.or_insert_with(|| {
|
||||||
|
crate::Paragraph::with_text(Text {
|
||||||
|
content: text,
|
||||||
|
size: iced::Pixels(self.font_size),
|
||||||
|
bounds: Size::INFINITY,
|
||||||
|
font,
|
||||||
|
horizontal_alignment: alignment::Horizontal::Left,
|
||||||
|
vertical_alignment: alignment::Vertical::Center,
|
||||||
|
shaping: Shaping::Advanced,
|
||||||
|
line_height: self.line_height,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let size = paragraph.min_bounds();
|
||||||
|
width += size.width;
|
||||||
|
height += size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add indent to measurement if found.
|
||||||
|
if let Some(indent) = self.model.indent(button) {
|
||||||
|
width = f32::from(indent).mul_add(f32::from(self.indent_spacing), width);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add icon to measurement if icon was given.
|
||||||
|
if let Some(icon) = self.model.icon(button) {
|
||||||
|
height = height.max(f32::from(icon.size));
|
||||||
|
width += f32::from(icon.size) + f32::from(self.button_spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add close button to measurement if found.
|
||||||
|
if self.model.is_closable(button) {
|
||||||
|
height = height.max(f32::from(self.close_icon.size));
|
||||||
|
width += f32::from(self.close_icon.size) + f32::from(self.button_spacing) + 8.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add button padding to the max size found
|
||||||
|
width += f32::from(self.button_padding[0]) + f32::from(self.button_padding[2]);
|
||||||
|
height += f32::from(self.button_padding[1]) + f32::from(self.button_padding[3]);
|
||||||
|
height = height.max(f32::from(self.button_height));
|
||||||
|
|
||||||
|
(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn max_button_dimensions(
|
pub(super) fn max_button_dimensions(
|
||||||
&self,
|
&self,
|
||||||
state: &mut LocalState,
|
state: &mut LocalState,
|
||||||
|
|
@ -304,58 +364,12 @@ where
|
||||||
let font = renderer.default_font();
|
let font = renderer.default_font();
|
||||||
|
|
||||||
for key in self.model.order.iter().copied() {
|
for key in self.model.order.iter().copied() {
|
||||||
let mut button_width = 0.0f32;
|
let (button_width, button_height) = self.button_dimensions(state, font, key);
|
||||||
let mut button_height = 0.0f32;
|
|
||||||
|
|
||||||
// Add text to measurement if text was given.
|
|
||||||
if let Some((text, entry)) = self.model.text.get(key).zip(state.paragraphs.entry(key)) {
|
|
||||||
let paragraph = entry.or_insert_with(|| {
|
|
||||||
crate::Paragraph::with_text(Text {
|
|
||||||
content: text,
|
|
||||||
size: iced::Pixels(self.font_size),
|
|
||||||
bounds: Size::INFINITY,
|
|
||||||
font,
|
|
||||||
horizontal_alignment: alignment::Horizontal::Left,
|
|
||||||
vertical_alignment: alignment::Vertical::Center,
|
|
||||||
shaping: Shaping::Advanced,
|
|
||||||
line_height: self.line_height,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let Size { width, height } = paragraph.min_bounds();
|
|
||||||
|
|
||||||
button_width = width;
|
|
||||||
button_height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add indent to measurement if found.
|
|
||||||
if let Some(indent) = self.model.indent(key) {
|
|
||||||
button_width =
|
|
||||||
f32::from(indent).mul_add(f32::from(self.indent_spacing), button_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add icon to measurement if icon was given.
|
|
||||||
if let Some(icon) = self.model.icon(key) {
|
|
||||||
button_height = button_height.max(f32::from(icon.size));
|
|
||||||
button_width += f32::from(icon.size) + f32::from(self.button_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add close button to measurement if found.
|
|
||||||
if self.model.is_closable(key) {
|
|
||||||
button_height = button_height.max(f32::from(self.close_icon.size));
|
|
||||||
button_width +=
|
|
||||||
f32::from(self.close_icon.size) + f32::from(self.button_spacing) + 8.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
height = height.max(button_height);
|
height = height.max(button_height);
|
||||||
width = width.max(button_width);
|
width = width.max(button_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add button padding to the max size found
|
|
||||||
width += f32::from(self.button_padding[0]) + f32::from(self.button_padding[2]);
|
|
||||||
height += f32::from(self.button_padding[1]) + f32::from(self.button_padding[3]);
|
|
||||||
height = height.max(f32::from(self.button_height));
|
|
||||||
|
|
||||||
(width, height)
|
(width, height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -373,9 +387,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> tree::State {
|
fn state(&self) -> tree::State {
|
||||||
// update the paragraphs for the model
|
|
||||||
tree::State::new(LocalState {
|
tree::State::new(LocalState {
|
||||||
first: self.model.order.iter().copied().next().unwrap_or_default(),
|
|
||||||
paragraphs: SecondaryMap::new(),
|
paragraphs: SecondaryMap::new(),
|
||||||
..LocalState::default()
|
..LocalState::default()
|
||||||
})
|
})
|
||||||
|
|
@ -478,19 +490,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nth, key) in self
|
for (key, bounds) in self
|
||||||
.model
|
.variant_button_bounds(state, bounds)
|
||||||
.order
|
.collect::<Vec<_>>()
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.enumerate()
|
|
||||||
.skip(state.buttons_offset)
|
|
||||||
.take(state.buttons_visible)
|
|
||||||
{
|
{
|
||||||
let Some(bounds) = self.variant_button_bounds(state, bounds, nth) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
if cursor_position.is_over(bounds) {
|
if cursor_position.is_over(bounds) {
|
||||||
if self.model.items[key].enabled {
|
if self.model.items[key].enabled {
|
||||||
// Record that the mouse is hovering over this button.
|
// Record that the mouse is hovering over this button.
|
||||||
|
|
@ -689,19 +692,7 @@ where
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
if cursor_position.is_over(bounds) {
|
if cursor_position.is_over(bounds) {
|
||||||
for (nth, key) in self
|
for (key, bounds) in self.variant_button_bounds(state, bounds) {
|
||||||
.model
|
|
||||||
.order
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.enumerate()
|
|
||||||
.skip(state.buttons_offset)
|
|
||||||
.take(state.buttons_visible)
|
|
||||||
{
|
|
||||||
let Some(bounds) = self.variant_button_bounds(state, bounds, nth) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
if cursor_position.is_over(bounds) {
|
if cursor_position.is_over(bounds) {
|
||||||
return if self.model.items[key].enabled {
|
return if self.model.items[key].enabled {
|
||||||
iced_core::mouse::Interaction::Pointer
|
iced_core::mouse::Interaction::Pointer
|
||||||
|
|
@ -827,19 +818,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw each of the items in the widget.
|
// Draw each of the items in the widget.
|
||||||
for (nth, key) in self
|
for (nth, (key, mut bounds)) in self.variant_button_bounds(state, bounds).enumerate() {
|
||||||
.model
|
|
||||||
.order
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.enumerate()
|
|
||||||
.skip(state.buttons_offset)
|
|
||||||
.take(state.buttons_visible)
|
|
||||||
{
|
|
||||||
let Some(mut bounds) = self.variant_button_bounds(state, bounds, nth) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let key_is_active = self.model.is_active(key);
|
let key_is_active = self.model.is_active(key);
|
||||||
let key_is_hovered = state.hovered == key;
|
let key_is_hovered = state.hovered == key;
|
||||||
|
|
||||||
|
|
@ -970,7 +949,15 @@ where
|
||||||
bounds.position(),
|
bounds.position(),
|
||||||
status_appearance.text_color,
|
status_appearance.text_color,
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: bounds.width - close_icon_width,
|
width: {
|
||||||
|
let width = bounds.width - close_icon_width;
|
||||||
|
// TODO: determine cause of differences here.
|
||||||
|
if self.model.icon(key).is_some() {
|
||||||
|
width - f32::from(self.button_spacing)
|
||||||
|
} else {
|
||||||
|
width - 12.0
|
||||||
|
}
|
||||||
|
},
|
||||||
..original_bounds
|
..original_bounds
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1026,20 +1013,22 @@ where
|
||||||
/// State that is maintained by each individual widget.
|
/// State that is maintained by each individual widget.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LocalState {
|
pub struct LocalState {
|
||||||
/// Whether buttons need to be collapsed to preserve minimum width
|
|
||||||
pub(super) collapsed: bool,
|
|
||||||
/// Defines how many buttons to show at a time.
|
/// Defines how many buttons to show at a time.
|
||||||
pub(super) buttons_visible: usize,
|
pub(super) buttons_visible: usize,
|
||||||
/// Button visibility offset, when collapsed.
|
/// Button visibility offset, when collapsed.
|
||||||
pub(super) buttons_offset: usize,
|
pub(super) buttons_offset: usize,
|
||||||
/// The first focusable key.
|
/// Whether buttons need to be collapsed to preserve minimum width
|
||||||
first: Entity,
|
pub(super) collapsed: bool,
|
||||||
/// If the widget is focused or not.
|
/// If the widget is focused or not.
|
||||||
focused: bool,
|
focused: bool,
|
||||||
/// The key inside the widget that is currently focused.
|
/// The key inside the widget that is currently focused.
|
||||||
focused_item: Focus,
|
focused_item: Focus,
|
||||||
/// The ID of the button that is being hovered. Defaults to null.
|
/// The ID of the button that is being hovered. Defaults to null.
|
||||||
hovered: Entity,
|
hovered: Entity,
|
||||||
|
/// Last known length of the model.
|
||||||
|
pub(super) known_length: usize,
|
||||||
|
/// Dimensions of internal buttons when shrinking
|
||||||
|
pub(super) internal_layout: Vec<Size>,
|
||||||
/// The paragraphs for each text.
|
/// The paragraphs for each text.
|
||||||
paragraphs: SecondaryMap<Entity, crate::Paragraph>,
|
paragraphs: SecondaryMap<Entity, crate::Paragraph>,
|
||||||
/// Time since last tab activation from wheel movements.
|
/// Time since last tab activation from wheel movements.
|
||||||
|
|
@ -1131,7 +1120,7 @@ fn draw_icon<Message: 'static>(
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget::<Message, Renderer>::draw(
|
Widget::<Message, Renderer>::draw(
|
||||||
Element::<Message>::from(icon.clone()).as_widget(),
|
Element::<Message>::from(icon).as_widget(),
|
||||||
&Tree::empty(),
|
&Tree::empty(),
|
||||||
renderer,
|
renderer,
|
||||||
theme,
|
theme,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue