feat(segmented_button): add FileNav style with related widget improvements
This commit is contained in:
parent
8412dd5939
commit
c10695600b
3 changed files with 100 additions and 57 deletions
|
|
@ -18,6 +18,8 @@ pub enum SegmentedButton {
|
||||||
Control,
|
Control,
|
||||||
/// Navigation bar style
|
/// Navigation bar style
|
||||||
NavBar,
|
NavBar,
|
||||||
|
/// File browser
|
||||||
|
FileNav,
|
||||||
/// Or implement any custom theme of your liking.
|
/// Or implement any custom theme of your liking.
|
||||||
Custom(Box<dyn Fn(&Theme) -> Appearance>),
|
Custom(Box<dyn Fn(&Theme) -> Appearance>),
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +71,7 @@ impl StyleSheet for Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentedButton::NavBar => Appearance {
|
SegmentedButton::NavBar | SegmentedButton::FileNav => Appearance {
|
||||||
active_width: 0.0,
|
active_width: 0.0,
|
||||||
..horizontal::tab_bar(cosmic, container)
|
..horizontal::tab_bar(cosmic, container)
|
||||||
},
|
},
|
||||||
|
|
@ -124,7 +126,7 @@ impl StyleSheet for Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentedButton::NavBar => Appearance {
|
SegmentedButton::NavBar | SegmentedButton::FileNav => Appearance {
|
||||||
active_width: 0.0,
|
active_width: 0.0,
|
||||||
..vertical::tab_bar(cosmic, container)
|
..vertical::tab_bar(cosmic, container)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ where
|
||||||
/ num as f32;
|
/ num as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
let segmetned_control = matches!(self.style, crate::theme::SegmentedButton::Control);
|
let is_control = matches!(self.style, crate::theme::SegmentedButton::Control);
|
||||||
|
|
||||||
Box::new(
|
Box::new(
|
||||||
self.model
|
self.model
|
||||||
|
|
@ -93,7 +93,7 @@ where
|
||||||
let button_bounds = ItemBounds::Button(key, layout_bounds);
|
let button_bounds = ItemBounds::Button(key, layout_bounds);
|
||||||
let mut divider = None;
|
let mut divider = None;
|
||||||
|
|
||||||
if self.dividers && segmetned_control && nth + 1 < num {
|
if self.dividers && is_control && nth + 1 < num {
|
||||||
divider = Some(ItemBounds::Divider(
|
divider = Some(ItemBounds::Divider(
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
|
|
@ -143,7 +143,7 @@ where
|
||||||
let max_size = limits.height(Length::Fixed(max_height)).resolve(
|
let max_size = limits.height(Length::Fixed(max_height)).resolve(
|
||||||
Length::Fill,
|
Length::Fill,
|
||||||
max_height,
|
max_height,
|
||||||
Size::new(f32::MAX, max_height),
|
Size::new(limits.max().width, max_height),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut visible_width = 0.0;
|
let mut visible_width = 0.0;
|
||||||
|
|
@ -152,7 +152,7 @@ where
|
||||||
for (button_size, _actual_size) in &state.internal_layout {
|
for (button_size, _actual_size) in &state.internal_layout {
|
||||||
visible_width += button_size.width;
|
visible_width += button_size.width;
|
||||||
|
|
||||||
if max_size.width >= visible_width {
|
if max_size.width - spacing >= visible_width {
|
||||||
state.buttons_visible += 1;
|
state.buttons_visible += 1;
|
||||||
} else {
|
} else {
|
||||||
visible_width = max_size.width - max_height;
|
visible_width = max_size.width - max_height;
|
||||||
|
|
|
||||||
|
|
@ -619,20 +619,19 @@ where
|
||||||
|
|
||||||
for key in self.model.order.iter().copied() {
|
for key in self.model.order.iter().copied() {
|
||||||
if let Some(text) = self.model.text.get(key) {
|
if let Some(text) = self.model.text.get(key) {
|
||||||
let (font, button_state) = if self.button_is_focused(state, key) {
|
let font = if self.button_is_focused(state, key) {
|
||||||
(self.font_active, 0)
|
self.font_active
|
||||||
} else if state.show_context.is_some() || self.button_is_hovered(state, key) {
|
} else if state.show_context.is_some() || self.button_is_hovered(state, key) {
|
||||||
(self.font_hovered, 1)
|
self.font_hovered
|
||||||
} else if self.model.is_active(key) {
|
} else if self.model.is_active(key) {
|
||||||
(self.font_active, 2)
|
self.font_active
|
||||||
} else {
|
} else {
|
||||||
(self.font_inactive, 3)
|
self.font_inactive
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
text.hash(&mut hasher);
|
text.hash(&mut hasher);
|
||||||
font.hash(&mut hasher);
|
font.hash(&mut hasher);
|
||||||
button_state.hash(&mut hasher);
|
|
||||||
let text_hash = hasher.finish();
|
let text_hash = hasher.finish();
|
||||||
|
|
||||||
if let Some(prev_hash) = state.text_hashes.insert(key, text_hash) {
|
if let Some(prev_hash) = state.text_hashes.insert(key, text_hash) {
|
||||||
|
|
@ -1293,6 +1292,15 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let rad_0 = THEME.lock().unwrap().cosmic().corner_radii.radius_0;
|
||||||
|
|
||||||
|
let divider_background = Background::Color(
|
||||||
|
crate::theme::active()
|
||||||
|
.cosmic()
|
||||||
|
.primary_component_divider()
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
// Draw each of the items in the widget.
|
// Draw each of the items in the widget.
|
||||||
let mut nth = 0;
|
let mut nth = 0;
|
||||||
self.variant_bounds(state, bounds).for_each(move |item| {
|
self.variant_bounds(state, bounds).for_each(move |item| {
|
||||||
|
|
@ -1337,7 +1345,7 @@ where
|
||||||
let key_is_active = self.model.is_active(key);
|
let key_is_active = self.model.is_active(key);
|
||||||
let key_is_focused = state.focused_visible && self.button_is_focused(state, key);
|
let key_is_focused = state.focused_visible && self.button_is_focused(state, key);
|
||||||
let key_is_hovered = self.button_is_hovered(state, key);
|
let key_is_hovered = self.button_is_hovered(state, key);
|
||||||
let status_appearance = if self.button_is_pressed(state, key) && key_is_hovered {
|
let status_appearance = if self.button_is_pressed(state, key) {
|
||||||
appearance.pressed
|
appearance.pressed
|
||||||
} else if key_is_hovered || menu_open() {
|
} else if key_is_hovered || menu_open() {
|
||||||
appearance.hover
|
appearance.hover
|
||||||
|
|
@ -1355,11 +1363,87 @@ where
|
||||||
status_appearance.middle
|
status_appearance.middle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Draw the active hint on tabs
|
||||||
|
if appearance.active_width > 0.0 {
|
||||||
|
let active_width = if key_is_active {
|
||||||
|
appearance.active_width
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.fill_quad(
|
||||||
|
renderer::Quad {
|
||||||
|
bounds: if Self::VERTICAL {
|
||||||
|
Rectangle {
|
||||||
|
x: bounds.x + bounds.width - active_width,
|
||||||
|
width: active_width,
|
||||||
|
..bounds
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Rectangle {
|
||||||
|
y: bounds.y + bounds.height - active_width,
|
||||||
|
height: active_width,
|
||||||
|
..bounds
|
||||||
|
}
|
||||||
|
},
|
||||||
|
border: Border {
|
||||||
|
radius: rad_0.into(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
shadow: Shadow::default(),
|
||||||
|
},
|
||||||
|
appearance.active.text_color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let original_bounds = bounds;
|
||||||
|
bounds.x += f32::from(self.button_padding[0]);
|
||||||
|
bounds.width -= f32::from(self.button_padding[0]) - f32::from(self.button_padding[2]);
|
||||||
|
let mut indent_padding = 0.0;
|
||||||
|
|
||||||
|
// Adjust bounds by indent
|
||||||
|
if let Some(indent) = self.model.indent(key) {
|
||||||
|
if indent > 0 {
|
||||||
|
let adjustment = f32::from(indent) * f32::from(self.indent_spacing);
|
||||||
|
bounds.x += adjustment;
|
||||||
|
bounds.width -= adjustment;
|
||||||
|
|
||||||
|
// Draw indent line
|
||||||
|
if let crate::theme::SegmentedButton::FileNav = self.style {
|
||||||
|
if indent > 1 {
|
||||||
|
indent_padding = 7.0;
|
||||||
|
renderer.fill_quad(
|
||||||
|
renderer::Quad {
|
||||||
|
bounds: Rectangle {
|
||||||
|
x: bounds.x - self.indent_spacing as f32 + indent_padding,
|
||||||
|
width: 1.0,
|
||||||
|
..bounds
|
||||||
|
},
|
||||||
|
border: Border {
|
||||||
|
radius: rad_0.into(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
shadow: Shadow::default(),
|
||||||
|
},
|
||||||
|
divider_background,
|
||||||
|
);
|
||||||
|
indent_padding += 4.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render the background of the button.
|
// Render the background of the button.
|
||||||
if key_is_focused || status_appearance.background.is_some() {
|
if key_is_focused || status_appearance.background.is_some() {
|
||||||
renderer.fill_quad(
|
renderer.fill_quad(
|
||||||
renderer::Quad {
|
renderer::Quad {
|
||||||
bounds,
|
bounds: Rectangle {
|
||||||
|
x: bounds.x - f32::from(self.button_padding[0]) + indent_padding,
|
||||||
|
width: bounds.width + f32::from(self.button_padding[0])
|
||||||
|
- f32::from(self.button_padding[2])
|
||||||
|
- indent_padding,
|
||||||
|
..bounds
|
||||||
|
},
|
||||||
border: if key_is_focused {
|
border: if key_is_focused {
|
||||||
Border {
|
Border {
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
|
|
@ -1377,49 +1461,6 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the active hint on tabs
|
|
||||||
if appearance.active_width > 0.0 {
|
|
||||||
let rad_0 = THEME.lock().unwrap().cosmic().corner_radii.radius_0;
|
|
||||||
let active_width = if key_is_active {
|
|
||||||
appearance.active_width
|
|
||||||
} else {
|
|
||||||
1.0
|
|
||||||
};
|
|
||||||
let mut bounds = bounds;
|
|
||||||
|
|
||||||
if Self::VERTICAL {
|
|
||||||
bounds.x += bounds.height - active_width;
|
|
||||||
bounds.width = active_width;
|
|
||||||
} else {
|
|
||||||
bounds.y += bounds.height - active_width;
|
|
||||||
bounds.height = active_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.fill_quad(
|
|
||||||
renderer::Quad {
|
|
||||||
bounds,
|
|
||||||
border: Border {
|
|
||||||
radius: rad_0.into(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
shadow: Shadow::default(),
|
|
||||||
},
|
|
||||||
appearance.active.text_color,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let original_bounds = bounds;
|
|
||||||
|
|
||||||
bounds.x += f32::from(self.button_padding[0]);
|
|
||||||
bounds.width -= f32::from(self.button_padding[0]) - f32::from(self.button_padding[2]);
|
|
||||||
|
|
||||||
// Adjust bounds by indent
|
|
||||||
if let Some(indent) = self.model.indent(key) {
|
|
||||||
let adjustment = f32::from(indent) * f32::from(self.indent_spacing);
|
|
||||||
bounds.x += adjustment;
|
|
||||||
bounds.width -= adjustment;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Align contents of the button to the requested `button_alignment`.
|
// Align contents of the button to the requested `button_alignment`.
|
||||||
{
|
{
|
||||||
let actual_width = state.internal_layout[nth].1.width;
|
let actual_width = state.internal_layout[nth].1.width;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue