feat(segmented-button): Configurable background and hover styling
This commit is contained in:
parent
f84410608b
commit
3454483345
3 changed files with 93 additions and 24 deletions
|
|
@ -13,8 +13,16 @@ use iced::{
|
|||
event, mouse, touch, Background, Color, Element, Event, Length, Point, Rectangle, Size,
|
||||
};
|
||||
use iced_core::BorderRadius;
|
||||
use iced_native::widget::tree;
|
||||
use iced_native::{layout, renderer, widget::Tree, Clipboard, Layout, Shell, Widget};
|
||||
|
||||
/// State that is maintained by the widget internally.
|
||||
#[derive(Default)]
|
||||
struct PrivateWidgetState {
|
||||
/// The ID of the button that is being hovered. Defaults to null.
|
||||
hovered: Key,
|
||||
}
|
||||
|
||||
/// A linear set of options for choosing between.
|
||||
#[derive(Setters)]
|
||||
pub struct SegmentedButton<'a, Message, Renderer>
|
||||
|
|
@ -73,6 +81,14 @@ where
|
|||
Renderer::Theme: StyleSheet,
|
||||
Message: 'static + Clone,
|
||||
{
|
||||
fn tag(&self) -> tree::Tag {
|
||||
tree::Tag::of::<PrivateWidgetState>()
|
||||
}
|
||||
|
||||
fn state(&self) -> tree::State {
|
||||
tree::State::new(PrivateWidgetState::default())
|
||||
}
|
||||
|
||||
fn width(&self) -> Length {
|
||||
self.width
|
||||
}
|
||||
|
|
@ -101,7 +117,7 @@ where
|
|||
|
||||
fn on_event(
|
||||
&mut self,
|
||||
_tree: &mut Tree,
|
||||
tree: &mut Tree,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
|
|
@ -110,6 +126,7 @@ where
|
|||
shell: &mut Shell<'_, Message>,
|
||||
) -> event::Status {
|
||||
let bounds = layout.bounds();
|
||||
let state = tree.state.downcast_mut::<PrivateWidgetState>();
|
||||
|
||||
if bounds.contains(cursor_position) {
|
||||
let button_width = bounds.width / self.state.buttons.len() as f32;
|
||||
|
|
@ -119,6 +136,9 @@ where
|
|||
bounds.x += num as f32 * button_width;
|
||||
|
||||
if bounds.contains(cursor_position) {
|
||||
// Record that the mouse is hovering over this button.
|
||||
state.hovered = key;
|
||||
|
||||
if let Some(on_activate) = self.on_activate.as_ref() {
|
||||
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
||||
| Event::Touch(touch::Event::FingerLifted { .. }) = event
|
||||
|
|
@ -129,6 +149,8 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state.hovered = Key::default();
|
||||
}
|
||||
|
||||
event::Status::Ignored
|
||||
|
|
@ -151,7 +173,7 @@ where
|
|||
|
||||
fn draw(
|
||||
&self,
|
||||
_tree: &Tree,
|
||||
tree: &Tree,
|
||||
renderer: &mut Renderer,
|
||||
theme: &<Renderer as iced_native::Renderer>::Theme,
|
||||
_style: &renderer::Style,
|
||||
|
|
@ -159,9 +181,23 @@ where
|
|||
_cursor_position: iced::Point,
|
||||
_viewport: &iced::Rectangle,
|
||||
) {
|
||||
let state = tree.state.downcast_ref::<PrivateWidgetState>();
|
||||
let appearance = theme.appearance(&self.style);
|
||||
let bounds = layout.bounds();
|
||||
let button_width = bounds.width / self.state.buttons.len() as f32;
|
||||
let button_amount = self.state.buttons.len();
|
||||
let button_width = bounds.width / button_amount as f32;
|
||||
|
||||
if let Some(background) = appearance.background {
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds,
|
||||
border_radius: appearance.border_radius,
|
||||
border_width: appearance.border_width,
|
||||
border_color: appearance.border_color,
|
||||
},
|
||||
background,
|
||||
);
|
||||
}
|
||||
|
||||
for (num, (key, content)) in self.state.buttons.iter().enumerate() {
|
||||
let mut bounds = bounds;
|
||||
|
|
@ -170,6 +206,8 @@ where
|
|||
|
||||
let button_appearance = if self.state.active == key {
|
||||
appearance.button_active
|
||||
} else if state.hovered == key {
|
||||
appearance.button_hover
|
||||
} else {
|
||||
appearance.button_inactive
|
||||
};
|
||||
|
|
@ -182,7 +220,13 @@ where
|
|||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds,
|
||||
border_radius: button_appearance.border_radius,
|
||||
border_radius: if num == 0 {
|
||||
button_appearance.border_radius_first
|
||||
} else if num + 1 == button_amount {
|
||||
button_appearance.border_radius_last
|
||||
} else {
|
||||
button_appearance.border_radius_middle
|
||||
},
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,16 +6,23 @@ use iced_core::{Background, BorderRadius, Color};
|
|||
/// The appearance of a [`SegmentedButton`].
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Appearance {
|
||||
pub background: Option<Background>,
|
||||
pub border_color: Color,
|
||||
pub border_radius: BorderRadius,
|
||||
pub border_width: f32,
|
||||
pub button_active: ButtonAppearance,
|
||||
pub button_inactive: ButtonAppearance,
|
||||
pub button_hover: ButtonAppearance,
|
||||
}
|
||||
|
||||
/// The appearance of a button in the [`SegmentedButton`]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ButtonAppearance {
|
||||
pub background: Option<Background>,
|
||||
pub border_radius: BorderRadius,
|
||||
pub border_bottom: Option<(f32, Color)>,
|
||||
pub border_radius_first: BorderRadius,
|
||||
pub border_radius_middle: BorderRadius,
|
||||
pub border_radius_last: BorderRadius,
|
||||
pub text_color: Color,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue