Skip to content

Commit

Permalink
feat(slider): add breakpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
mmstick committed Feb 21, 2024
1 parent 53a8cc1 commit a9d545c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
9 changes: 9 additions & 0 deletions style/src/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ pub struct Appearance {
pub rail: Rail,
/// The appearance of the [`Handle`] of the slider.
pub handle: Handle,
/// The appearance of breakpoints.
pub breakpoint: Breakpoint,
}

/// The appearance of slider breakpoints.
#[derive(Debug, Clone, Copy)]
pub struct Breakpoint {
/// The color of the slider breakpoint.
pub color: Color,
}

/// The appearance of a slider rail
Expand Down
3 changes: 3 additions & 0 deletions style/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,9 @@ impl slider::StyleSheet for Theme {
border_color: palette.primary.base.color,
..handle
},
breakpoint: slider::Breakpoint {
color: palette.background.weak.text,
},
}
}
Slider::Custom(custom) => custom.active(self),
Expand Down
56 changes: 50 additions & 6 deletions widget/src/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use crate::core::touch;
use crate::core::widget::tree::{self, Tree};
use crate::core::widget::Id;
use crate::core::{
Border, Clipboard, Element, Layout, Length, Pixels, Point, Rectangle,
Shell, Size, Widget,
Border, Clipboard, Color, Element, Layout, Length, Pixels, Point,
Rectangle, Shell, Size, Widget,
};

use std::ops::RangeInclusive;

use iced_renderer::core::{border::Radius, Degrees, Radians};
pub use iced_style::slider::{
Appearance, Handle, HandleShape, Rail, StyleSheet,
Appearance, Handle, HandleShape, Rail, RailBackground, StyleSheet,
};

#[cfg(feature = "a11y")]
Expand Down Expand Up @@ -48,6 +48,7 @@ use std::borrow::Cow;
///
/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true)
#[allow(missing_debug_implementations)]
#[must_use]
pub struct Slider<'a, T, Message, Theme = crate::Theme>
where
Theme: StyleSheet,
Expand All @@ -62,6 +63,7 @@ where
range: RangeInclusive<T>,
step: T,
value: T,
breakpoints: &'a [T],
on_change: Box<dyn Fn(T) -> Message + 'a>,
on_release: Option<Message>,
width: Length,
Expand Down Expand Up @@ -113,6 +115,7 @@ where
value,
range,
step: T::from(1),
breakpoints: &[],
on_change: Box::new(on_change),
on_release: None,
width: Length::Fill,
Expand All @@ -121,12 +124,20 @@ where
}
}

/// Defines breakpoints to visibly mark on the slider.
///
/// The slider will gravitate towards a breakpoint when near it.
pub fn breakpoints(mut self, breakpoints: &'a [T]) -> Self {
self.breakpoints = breakpoints;
self
}

/// Sets the release message of the [`Slider`].
/// This is called when the mouse is released from the slider.
///
/// Typically, the user's interaction with the slider is finished when this message is produced.
/// This is useful if you need to spawn a long-running task from the slider's result, where
/// the default on_change message could create too many events.
/// the default `on_change` message could create too many events.
pub fn on_release(mut self, on_release: Message) -> Self {
self.on_release = Some(on_release);
self
Expand Down Expand Up @@ -266,6 +277,7 @@ where
tree.state.downcast_ref::<State>(),
self.value,
&self.range,
self.breakpoints,
theme,
&self.style,
);
Expand Down Expand Up @@ -475,6 +487,7 @@ pub fn draw<T, Theme, Renderer>(
state: &State,
value: T,
range: &RangeInclusive<T>,
breakpoints: &[T],
theme: &Theme,
style: &Theme::Style,
) where
Expand All @@ -492,6 +505,7 @@ pub fn draw<T, Theme, Renderer>(
} else {
theme.active(style)
};

let border_width = style
.handle
.border_width
Expand Down Expand Up @@ -539,8 +553,38 @@ pub fn draw<T, Theme, Renderer>(

let rail_y = bounds.y + bounds.height / 2.0;

// Draw the breakpoint indicators beneath the slider.
const BREAKPOINT_WIDTH: f32 = 2.0;
for &value in breakpoints {
let value: f64 = value.into();
let offset = if range_start >= range_end {
0.0
} else {
(bounds.width - BREAKPOINT_WIDTH) * (value as f32 - range_start)
/ (range_end - range_start)
};

renderer.fill_quad(
renderer::Quad {
bounds: Rectangle {
x: bounds.x + offset,
y: rail_y + 6.0,
width: BREAKPOINT_WIDTH,
height: 8.0,
},
border: Border {
radius: 0.0.into(),
width: 0.0,
color: Color::TRANSPARENT,
},
..renderer::Quad::default()
},
crate::core::Background::Color(style.breakpoint.color),
);
}

match style.rail.colors {
iced_style::slider::RailBackground::Pair(l, r) => {
RailBackground::Pair(l, r) => {
// rail
renderer.fill_quad(
renderer::Quad {
Expand Down Expand Up @@ -571,7 +615,7 @@ pub fn draw<T, Theme, Renderer>(
r,
);
}
iced_style::slider::RailBackground::Gradient {
RailBackground::Gradient {
mut gradient,
auto_angle,
} => renderer.fill_quad(
Expand Down

0 comments on commit a9d545c

Please sign in to comment.