From ce309db37b8eb9860ae1f1be1710fb39e7a9edea Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 4 Mar 2024 03:57:03 +0100 Subject: Try new approach to theming for `Slider` --- widget/src/slider.rs | 548 ++++++++++++++++++++++----------------------------- 1 file changed, 238 insertions(+), 310 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 65bc1772..ce02a0a6 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -17,7 +17,7 @@ use crate::core::{ use std::ops::RangeInclusive; pub use iced_style::slider::{ - Appearance, Handle, HandleShape, Rail, StyleSheet, + Appearance, Handle, HandleShape, Rail, Status, StyleSheet, }; /// An horizontal bar and a handle that selects a single value from a range of @@ -58,7 +58,7 @@ where on_release: Option, width: Length, height: f32, - style: Theme::Style, + style: fn(&Theme, Status) -> Appearance, } impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> @@ -104,7 +104,7 @@ where on_release: None, width: Length::Fill, height: Self::DEFAULT_HEIGHT, - style: Default::default(), + style: Theme::default(), } } @@ -140,8 +140,8 @@ where } /// Sets the style of the [`Slider`]. - pub fn style(mut self, style: impl Into) -> Self { - self.style = style.into(); + pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { + self.style = style; self } @@ -173,7 +173,7 @@ where } fn state(&self) -> tree::State { - tree::State::new(State::new()) + tree::State::new(State::default()) } fn size(&self) -> Size { @@ -203,355 +203,283 @@ where shell: &mut Shell<'_, Message>, _viewport: &Rectangle, ) -> event::Status { - update( - event, - layout, - cursor, - shell, - tree.state.downcast_mut::(), - &mut self.value, - self.default, - &self.range, - self.step, - self.shift_step, - self.on_change.as_ref(), - &self.on_release, - ) - } + let state = tree.state.downcast_mut::(); - fn draw( - &self, - tree: &Tree, - renderer: &mut Renderer, - theme: &Theme, - _style: &renderer::Style, - layout: Layout<'_>, - cursor: mouse::Cursor, - _viewport: &Rectangle, - ) { - draw( - renderer, - layout, - cursor, - tree.state.downcast_ref::(), - self.value, - &self.range, - theme, - &self.style, - ); - } + let is_dragging = state.is_dragging; + let current_value = self.value; - fn mouse_interaction( - &self, - tree: &Tree, - layout: Layout<'_>, - cursor: mouse::Cursor, - _viewport: &Rectangle, - _renderer: &Renderer, - ) -> mouse::Interaction { - mouse_interaction(layout, cursor, tree.state.downcast_ref::()) - } -} + let locate = |cursor_position: Point| -> Option { + let bounds = layout.bounds(); + let new_value = if cursor_position.x <= bounds.x { + Some(*self.range.start()) + } else if cursor_position.x >= bounds.x + bounds.width { + Some(*self.range.end()) + } else { + let step = if state.keyboard_modifiers.shift() { + self.shift_step.unwrap_or(self.step) + } else { + self.step + } + .into(); -impl<'a, T, Message, Theme, Renderer> From> - for Element<'a, Message, Theme, Renderer> -where - T: Copy + Into + num_traits::FromPrimitive + 'a, - Message: Clone + 'a, - Theme: StyleSheet + 'a, - Renderer: crate::core::Renderer + 'a, -{ - fn from( - slider: Slider<'a, T, Message, Theme>, - ) -> Element<'a, Message, Theme, Renderer> { - Element::new(slider) - } -} + let start = (*self.range.start()).into(); + let end = (*self.range.end()).into(); -/// Processes an [`Event`] and updates the [`State`] of a [`Slider`] -/// accordingly. -pub fn update( - event: Event, - layout: Layout<'_>, - cursor: mouse::Cursor, - shell: &mut Shell<'_, Message>, - state: &mut State, - value: &mut T, - default: Option, - range: &RangeInclusive, - step: T, - shift_step: Option, - on_change: &dyn Fn(T) -> Message, - on_release: &Option, -) -> event::Status -where - T: Copy + Into + num_traits::FromPrimitive, - Message: Clone, -{ - let is_dragging = state.is_dragging; - let current_value = *value; + let percent = f64::from(cursor_position.x - bounds.x) + / f64::from(bounds.width); - let locate = |cursor_position: Point| -> Option { - let bounds = layout.bounds(); - let new_value = if cursor_position.x <= bounds.x { - Some(*range.start()) - } else if cursor_position.x >= bounds.x + bounds.width { - Some(*range.end()) - } else { + let steps = (percent * (end - start) / step).round(); + let value = steps * step + start; + + T::from_f64(value) + }; + + new_value + }; + + let increment = |value: T| -> Option { let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) + self.shift_step.unwrap_or(self.step) } else { - step + self.step } .into(); - let start = (*range.start()).into(); - let end = (*range.end()).into(); + let steps = (value.into() / step).round(); + let new_value = step * (steps + 1.0); - let percent = f64::from(cursor_position.x - bounds.x) - / f64::from(bounds.width); - - let steps = (percent * (end - start) / step).round(); - let value = steps * step + start; + if new_value > (*self.range.end()).into() { + return Some(*self.range.end()); + } - T::from_f64(value) + T::from_f64(new_value) }; - new_value - }; - - let increment = |value: T| -> Option { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - - let steps = (value.into() / step).round(); - let new_value = step * (steps + 1.0); - - if new_value > (*range.end()).into() { - return Some(*range.end()); - } + let decrement = |value: T| -> Option { + let step = if state.keyboard_modifiers.shift() { + self.shift_step.unwrap_or(self.step) + } else { + self.step + } + .into(); - T::from_f64(new_value) - }; + let steps = (value.into() / step).round(); + let new_value = step * (steps - 1.0); - let decrement = |value: T| -> Option { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); + if new_value < (*self.range.start()).into() { + return Some(*self.range.start()); + } - let steps = (value.into() / step).round(); - let new_value = step * (steps - 1.0); + T::from_f64(new_value) + }; - if new_value < (*range.start()).into() { - return Some(*range.start()); - } + let change = |new_value: T| { + if (self.value.into() - new_value.into()).abs() > f64::EPSILON { + shell.publish((self.on_change)(new_value)); - T::from_f64(new_value) - }; + self.value = new_value; + } + }; - let change = |new_value: T| { - if ((*value).into() - new_value.into()).abs() > f64::EPSILON { - shell.publish((on_change)(new_value)); + match event { + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + if let Some(cursor_position) = + cursor.position_over(layout.bounds()) + { + if state.keyboard_modifiers.command() { + let _ = self.default.map(change); + state.is_dragging = false; + } else { + let _ = locate(cursor_position).map(change); + state.is_dragging = true; + } - *value = new_value; - } - }; - - match event { - Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerPressed { .. }) => { - if let Some(cursor_position) = cursor.position_over(layout.bounds()) - { - if state.keyboard_modifiers.command() { - let _ = default.map(change); - state.is_dragging = false; - } else { - let _ = locate(cursor_position).map(change); - state.is_dragging = true; + return event::Status::Captured; } - - return event::Status::Captured; } - } - Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerLifted { .. }) - | Event::Touch(touch::Event::FingerLost { .. }) => { - if is_dragging { - if let Some(on_release) = on_release.clone() { - shell.publish(on_release); - } - state.is_dragging = false; + Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerLifted { .. }) + | Event::Touch(touch::Event::FingerLost { .. }) => { + if is_dragging { + if let Some(on_release) = self.on_release.clone() { + shell.publish(on_release); + } + state.is_dragging = false; - return event::Status::Captured; + return event::Status::Captured; + } } - } - Event::Mouse(mouse::Event::CursorMoved { .. }) - | Event::Touch(touch::Event::FingerMoved { .. }) => { - if is_dragging { - let _ = cursor.position().and_then(locate).map(change); + Event::Mouse(mouse::Event::CursorMoved { .. }) + | Event::Touch(touch::Event::FingerMoved { .. }) => { + if is_dragging { + let _ = cursor.position().and_then(locate).map(change); - return event::Status::Captured; + return event::Status::Captured; + } } - } - Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => { - if cursor.position_over(layout.bounds()).is_some() { - match key { - Key::Named(key::Named::ArrowUp) => { - let _ = increment(current_value).map(change); + Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => { + if cursor.position_over(layout.bounds()).is_some() { + match key { + Key::Named(key::Named::ArrowUp) => { + let _ = increment(current_value).map(change); + } + Key::Named(key::Named::ArrowDown) => { + let _ = decrement(current_value).map(change); + } + _ => (), } - Key::Named(key::Named::ArrowDown) => { - let _ = decrement(current_value).map(change); - } - _ => (), - } - return event::Status::Captured; + return event::Status::Captured; + } } + Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { + state.keyboard_modifiers = modifiers; + } + _ => {} } - Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { - state.keyboard_modifiers = modifiers; - } - _ => {} + + event::Status::Ignored } - event::Status::Ignored -} + fn draw( + &self, + tree: &Tree, + renderer: &mut Renderer, + theme: &Theme, + _style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + _viewport: &Rectangle, + ) { + let state = tree.state.downcast_ref::(); + let bounds = layout.bounds(); + let is_mouse_over = cursor.is_over(bounds); -/// Draws a [`Slider`]. -pub fn draw( - renderer: &mut Renderer, - layout: Layout<'_>, - cursor: mouse::Cursor, - state: &State, - value: T, - range: &RangeInclusive, - theme: &Theme, - style: &Theme::Style, -) where - T: Into + Copy, - Theme: StyleSheet, - Renderer: crate::core::Renderer, -{ - let bounds = layout.bounds(); - let is_mouse_over = cursor.is_over(bounds); - - let style = if state.is_dragging { - theme.dragging(style) - } else if is_mouse_over { - theme.hovered(style) - } else { - theme.active(style) - }; - - let (handle_width, handle_height, handle_border_radius) = - match style.handle.shape { - HandleShape::Circle { radius } => { - (radius * 2.0, radius * 2.0, radius.into()) - } - HandleShape::Rectangle { - width, - border_radius, - } => (f32::from(width), bounds.height, border_radius), + let style = (self.style)( + theme, + if state.is_dragging { + Status::Dragging + } else if is_mouse_over { + Status::Hovered + } else { + Status::Active + }, + ); + + let (handle_width, handle_height, handle_border_radius) = + match style.handle.shape { + HandleShape::Circle { radius } => { + (radius * 2.0, radius * 2.0, radius.into()) + } + HandleShape::Rectangle { + width, + border_radius, + } => (f32::from(width), bounds.height, border_radius), + }; + + let value = self.value.into() as f32; + let (range_start, range_end) = { + let (start, end) = self.range.clone().into_inner(); + + (start.into() as f32, end.into() as f32) }; - let value = value.into() as f32; - let (range_start, range_end) = { - let (start, end) = range.clone().into_inner(); - - (start.into() as f32, end.into() as f32) - }; - - let offset = if range_start >= range_end { - 0.0 - } else { - (bounds.width - handle_width) * (value - range_start) - / (range_end - range_start) - }; - - let rail_y = bounds.y + bounds.height / 2.0; - - renderer.fill_quad( - renderer::Quad { - bounds: Rectangle { - x: bounds.x, - y: rail_y - style.rail.width / 2.0, - width: offset + handle_width / 2.0, - height: style.rail.width, - }, - border: Border::with_radius(style.rail.border_radius), - ..renderer::Quad::default() - }, - style.rail.colors.0, - ); - - renderer.fill_quad( - renderer::Quad { - bounds: Rectangle { - x: bounds.x + offset + handle_width / 2.0, - y: rail_y - style.rail.width / 2.0, - width: bounds.width - offset - handle_width / 2.0, - height: style.rail.width, + let offset = if range_start >= range_end { + 0.0 + } else { + (bounds.width - handle_width) * (value - range_start) + / (range_end - range_start) + }; + + let rail_y = bounds.y + bounds.height / 2.0; + + renderer.fill_quad( + renderer::Quad { + bounds: Rectangle { + x: bounds.x, + y: rail_y - style.rail.width / 2.0, + width: offset + handle_width / 2.0, + height: style.rail.width, + }, + border: Border::with_radius(style.rail.border_radius), + ..renderer::Quad::default() }, - border: Border::with_radius(style.rail.border_radius), - ..renderer::Quad::default() - }, - style.rail.colors.1, - ); - - renderer.fill_quad( - renderer::Quad { - bounds: Rectangle { - x: bounds.x + offset, - y: rail_y - handle_height / 2.0, - width: handle_width, - height: handle_height, + style.rail.colors.0, + ); + + renderer.fill_quad( + renderer::Quad { + bounds: Rectangle { + x: bounds.x + offset + handle_width / 2.0, + y: rail_y - style.rail.width / 2.0, + width: bounds.width - offset - handle_width / 2.0, + height: style.rail.width, + }, + border: Border::with_radius(style.rail.border_radius), + ..renderer::Quad::default() }, - border: Border { - radius: handle_border_radius, - width: style.handle.border_width, - color: style.handle.border_color, + style.rail.colors.1, + ); + + renderer.fill_quad( + renderer::Quad { + bounds: Rectangle { + x: bounds.x + offset, + y: rail_y - handle_height / 2.0, + width: handle_width, + height: handle_height, + }, + border: Border { + radius: handle_border_radius, + width: style.handle.border_width, + color: style.handle.border_color, + }, + ..renderer::Quad::default() }, - ..renderer::Quad::default() - }, - style.handle.color, - ); + style.handle.color, + ); + } + + fn mouse_interaction( + &self, + tree: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + _viewport: &Rectangle, + _renderer: &Renderer, + ) -> mouse::Interaction { + let state = tree.state.downcast_ref::(); + let bounds = layout.bounds(); + let is_mouse_over = cursor.is_over(bounds); + + if state.is_dragging { + mouse::Interaction::Grabbing + } else if is_mouse_over { + mouse::Interaction::Grab + } else { + mouse::Interaction::default() + } + } } -/// Computes the current [`mouse::Interaction`] of a [`Slider`]. -pub fn mouse_interaction( - layout: Layout<'_>, - cursor: mouse::Cursor, - state: &State, -) -> mouse::Interaction { - let bounds = layout.bounds(); - let is_mouse_over = cursor.is_over(bounds); - - if state.is_dragging { - mouse::Interaction::Grabbing - } else if is_mouse_over { - mouse::Interaction::Grab - } else { - mouse::Interaction::default() +impl<'a, T, Message, Theme, Renderer> From> + for Element<'a, Message, Theme, Renderer> +where + T: Copy + Into + num_traits::FromPrimitive + 'a, + Message: Clone + 'a, + Theme: StyleSheet + 'a, + Renderer: crate::core::Renderer + 'a, +{ + fn from( + slider: Slider<'a, T, Message, Theme>, + ) -> Element<'a, Message, Theme, Renderer> { + Element::new(slider) } } -/// The local state of a [`Slider`]. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct State { +struct State { is_dragging: bool, keyboard_modifiers: keyboard::Modifiers, } - -impl State { - /// Creates a new [`State`]. - pub fn new() -> State { - State::default() - } -} -- cgit From d735209fc32238185ea0f27f1f4d1d0044b90e06 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 5 Mar 2024 21:23:14 +0100 Subject: Move style types of `slider` to `iced_widget` --- widget/src/slider.rs | 140 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 15 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index ce02a0a6..e4dc809e 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -1,6 +1,7 @@ //! Display an interactive selector of a single value from a range of values. //! //! A [`Slider`] has some local [`State`]. +use crate::core::border; use crate::core::event::{self, Event}; use crate::core::keyboard; use crate::core::keyboard::key::{self, Key}; @@ -10,16 +11,13 @@ use crate::core::renderer; use crate::core::touch; use crate::core::widget::tree::{self, Tree}; 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 crate::style::Theme; use std::ops::RangeInclusive; -pub use iced_style::slider::{ - Appearance, Handle, HandleShape, Rail, Status, StyleSheet, -}; - /// An horizontal bar and a handle that selects a single value from a range of /// values. /// @@ -45,10 +43,7 @@ pub use iced_style::slider::{ /// /// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) #[allow(missing_debug_implementations)] -pub struct Slider<'a, T, Message, Theme = crate::Theme> -where - Theme: StyleSheet, -{ +pub struct Slider<'a, T, Message, Theme = crate::Theme> { range: RangeInclusive, step: T, shift_step: Option, @@ -65,7 +60,6 @@ impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> where T: Copy + From + PartialOrd, Message: Clone, - Theme: StyleSheet, { /// The default height of a [`Slider`]. pub const DEFAULT_HEIGHT: f32 = 22.0; @@ -80,6 +74,7 @@ where /// `Message`. pub fn new(range: RangeInclusive, value: T, on_change: F) -> Self where + Theme: Style, F: 'a + Fn(T) -> Message, { let value = if value >= *range.start() { @@ -104,7 +99,7 @@ where on_release: None, width: Length::Fill, height: Self::DEFAULT_HEIGHT, - style: Theme::default(), + style: Theme::style(), } } @@ -165,7 +160,6 @@ impl<'a, T, Message, Theme, Renderer> Widget where T: Copy + Into + num_traits::FromPrimitive, Message: Clone, - Theme: StyleSheet, Renderer: crate::core::Renderer, { fn tag(&self) -> tree::Tag { @@ -359,7 +353,7 @@ where let style = (self.style)( theme, if state.is_dragging { - Status::Dragging + Status::Dragged } else if is_mouse_over { Status::Hovered } else { @@ -468,7 +462,7 @@ impl<'a, T, Message, Theme, Renderer> From> where T: Copy + Into + num_traits::FromPrimitive + 'a, Message: Clone + 'a, - Theme: StyleSheet + 'a, + Theme: 'a, Renderer: crate::core::Renderer + 'a, { fn from( @@ -483,3 +477,119 @@ struct State { is_dragging: bool, keyboard_modifiers: keyboard::Modifiers, } + +/// The possible status of a [`Slider`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Status { + /// The [`Slider`] can be interacted with. + Active, + /// The [`Slider`] is being hovered. + Hovered, + /// The [`Slider`] is being dragged. + Dragged, +} + +/// The appearance of a slider. +#[derive(Debug, Clone, Copy)] +pub struct Appearance { + /// The colors of the rail of the slider. + pub rail: Rail, + /// The appearance of the [`Handle`] of the slider. + pub handle: Handle, +} + +impl Appearance { + /// Changes the [`HandleShape`] of the [`Appearance`] to a circle + /// with the given radius. + pub fn with_circular_handle(mut self, radius: impl Into) -> Self { + self.handle.shape = HandleShape::Circle { + radius: radius.into().0, + }; + self + } +} + +/// The appearance of a slider rail +#[derive(Debug, Clone, Copy)] +pub struct Rail { + /// The colors of the rail of the slider. + pub colors: (Color, Color), + /// The width of the stroke of a slider rail. + pub width: f32, + /// The border radius of the corners of the rail. + pub border_radius: border::Radius, +} + +/// The appearance of the handle of a slider. +#[derive(Debug, Clone, Copy)] +pub struct Handle { + /// The shape of the handle. + pub shape: HandleShape, + /// The [`Color`] of the handle. + pub color: Color, + /// The border width of the handle. + pub border_width: f32, + /// The border [`Color`] of the handle. + pub border_color: Color, +} + +/// The shape of the handle of a slider. +#[derive(Debug, Clone, Copy)] +pub enum HandleShape { + /// A circular handle. + Circle { + /// The radius of the circle. + radius: f32, + }, + /// A rectangular shape. + Rectangle { + /// The width of the rectangle. + width: u16, + /// The border radius of the corners of the rectangle. + border_radius: border::Radius, + }, +} + +/// The definiton of the default style of a [`TextInput`]. +pub trait Style { + /// Returns the default style of a [`TextInput`]. + fn style() -> fn(&Self, Status) -> Appearance; +} + +impl Style for Theme { + fn style() -> fn(&Self, Status) -> Appearance { + default + } +} + +/// The default style of a [`Slider`]. +pub fn default(theme: &Theme, status: Status) -> Appearance { + let palette = theme.extended_palette(); + + let handle = Handle { + shape: HandleShape::Rectangle { + width: 8, + border_radius: 4.0.into(), + }, + color: Color::WHITE, + border_color: Color::WHITE, + border_width: 1.0, + }; + + Appearance { + rail: Rail { + colors: (palette.primary.base.color, palette.secondary.base.color), + width: 4.0, + border_radius: 2.0.into(), + }, + handle: Handle { + color: match status { + Status::Active => palette.background.base.color, + Status::Hovered => palette.primary.weak.color, + Status::Dragged => palette.primary.base.color, + }, + border_color: palette.primary.base.color, + ..handle + }, + } +} -- cgit From 420f49bef5f6938868a84086e729deaa1df9107f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 5 Mar 2024 22:31:01 +0100 Subject: Improve default styling of `Slider` widget --- widget/src/slider.rs | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index e4dc809e..a40f8792 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -62,7 +62,7 @@ where Message: Clone, { /// The default height of a [`Slider`]. - pub const DEFAULT_HEIGHT: f32 = 22.0; + pub const DEFAULT_HEIGHT: f32 = 15.0; /// Creates a new [`Slider`]. /// @@ -566,30 +566,23 @@ impl Style for Theme { pub fn default(theme: &Theme, status: Status) -> Appearance { let palette = theme.extended_palette(); - let handle = Handle { - shape: HandleShape::Rectangle { - width: 8, - border_radius: 4.0.into(), - }, - color: Color::WHITE, - border_color: Color::WHITE, - border_width: 1.0, + let color = match status { + Status::Active => palette.primary.strong.color, + Status::Hovered => palette.primary.base.color, + Status::Dragged => palette.primary.strong.color, }; Appearance { rail: Rail { - colors: (palette.primary.base.color, palette.secondary.base.color), - width: 4.0, - border_radius: 2.0.into(), + colors: (color, palette.secondary.base.color), + width: 6.0, + border_radius: 3.0.into(), }, handle: Handle { - color: match status { - Status::Active => palette.background.base.color, - Status::Hovered => palette.primary.weak.color, - Status::Dragged => palette.primary.base.color, - }, - border_color: palette.primary.base.color, - ..handle + shape: HandleShape::Circle { radius: 7.0 }, + color, + border_color: Color::TRANSPARENT, + border_width: 0.0, }, } } -- cgit From 34e7c6593a9e0f56cee5db18b7258717cf6bc11b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 6 Mar 2024 20:30:58 +0100 Subject: Use `Style` struct pattern instead of trait for all widgets --- widget/src/slider.rs | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index a40f8792..c48fe143 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -53,7 +53,7 @@ pub struct Slider<'a, T, Message, Theme = crate::Theme> { on_release: Option, width: Length, height: f32, - style: fn(&Theme, Status) -> Appearance, + style: Style, } impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> @@ -74,7 +74,7 @@ where /// `Message`. pub fn new(range: RangeInclusive, value: T, on_change: F) -> Self where - Theme: Style, + Style: Default, F: 'a + Fn(T) -> Message, { let value = if value >= *range.start() { @@ -99,7 +99,7 @@ where on_release: None, width: Length::Fill, height: Self::DEFAULT_HEIGHT, - style: Theme::style(), + style: Style::default(), } } @@ -136,7 +136,7 @@ where /// Sets the style of the [`Slider`]. pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self { - self.style = style; + self.style = style.into(); self } @@ -350,7 +350,7 @@ where let bounds = layout.bounds(); let is_mouse_over = cursor.is_over(bounds); - let style = (self.style)( + let style = (self.style.0)( theme, if state.is_dragging { Status::Dragged @@ -550,15 +550,27 @@ pub enum HandleShape { }, } -/// The definiton of the default style of a [`TextInput`]. -pub trait Style { - /// Returns the default style of a [`TextInput`]. - fn style() -> fn(&Self, Status) -> Appearance; +/// The style of a [`Slider`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style(pub(crate) fn(&Theme, Status) -> Appearance); + +impl Clone for Style { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Style {} + +impl Default for Style { + fn default() -> Self { + Style(default) + } } -impl Style for Theme { - fn style() -> fn(&Self, Status) -> Appearance { - default +impl From Appearance> for Style { + fn from(f: fn(&Theme, Status) -> Appearance) -> Self { + Style(f) } } -- cgit From 905f2160e6eb7504f52d9bd62c7bfa42c8ec2902 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 00:14:41 +0100 Subject: Move `Theme` type to `iced_core` --- widget/src/slider.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index c48fe143..463a4f04 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -12,9 +12,8 @@ use crate::core::touch; use crate::core::widget::tree::{self, Tree}; use crate::core::{ Border, Clipboard, Color, Element, Layout, Length, Pixels, Point, - Rectangle, Shell, Size, Widget, + Rectangle, Shell, Size, Theme, Widget, }; -use crate::style::Theme; use std::ops::RangeInclusive; @@ -28,8 +27,7 @@ use std::ops::RangeInclusive; /// /// # Example /// ```no_run -/// # type Slider<'a, T, Message> = -/// # iced_widget::Slider<'a, Message, T, iced_widget::style::Theme>; +/// # type Slider<'a, T, Message> = iced_widget::Slider<'a, Message, T>; /// # /// #[derive(Clone)] /// pub enum Message { -- cgit From 6785a452eea5f6b6f69bac123789245dacbc936e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 00:19:24 +0100 Subject: Fix broken links in documentation --- widget/src/slider.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 463a4f04..79850f63 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -1,6 +1,4 @@ //! Display an interactive selector of a single value from a range of values. -//! -//! A [`Slider`] has some local [`State`]. use crate::core::border; use crate::core::event::{self, Event}; use crate::core::keyboard; -- cgit From 833538ee7f3a60a839304762dfc29b0881d19094 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 20:11:32 +0100 Subject: Leverage `DefaultStyle` traits instead of `Default` --- widget/src/slider.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 79850f63..6449b18e 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -70,7 +70,7 @@ where /// `Message`. pub fn new(range: RangeInclusive, value: T, on_change: F) -> Self where - Style: Default, + Theme: DefaultStyle, F: 'a + Fn(T) -> Message, { let value = if value >= *range.start() { @@ -95,7 +95,7 @@ where on_release: None, width: Length::Fill, height: Self::DEFAULT_HEIGHT, - style: Style::default(), + style: Theme::default_style(), } } @@ -346,7 +346,7 @@ where let bounds = layout.bounds(); let is_mouse_over = cursor.is_over(bounds); - let style = (self.style.0)( + let style = (self.style)( theme, if state.is_dragging { Status::Dragged @@ -547,26 +547,23 @@ pub enum HandleShape { } /// The style of a [`Slider`]. -#[derive(Debug, PartialEq, Eq)] -pub struct Style(pub(crate) fn(&Theme, Status) -> Appearance); +pub type Style = fn(&Theme, Status) -> Appearance; -impl Clone for Style { - fn clone(&self) -> Self { - *self - } +/// The default style of a [`Slider`]. +pub trait DefaultStyle { + /// Returns the default style of a [`Slider`]. + fn default_style() -> Style; } -impl Copy for Style {} - -impl Default for Style { - fn default() -> Self { - Style(default) +impl DefaultStyle for Theme { + fn default_style() -> Style { + default } } -impl From Appearance> for Style { - fn from(f: fn(&Theme, Status) -> Appearance) -> Self { - Style(f) +impl DefaultStyle for Appearance { + fn default_style() -> Style { + |appearance, _status| *appearance } } -- cgit From 7ece5eea509f3595432babfc7729701f2e063b21 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 21:02:17 +0100 Subject: Implement additional helpers for `Border` and `container::Appearance` --- widget/src/slider.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 6449b18e..c37607a8 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -392,7 +392,7 @@ where width: offset + handle_width / 2.0, height: style.rail.width, }, - border: Border::with_radius(style.rail.border_radius), + border: Border::rounded(style.rail.border_radius), ..renderer::Quad::default() }, style.rail.colors.0, @@ -406,7 +406,7 @@ where width: bounds.width - offset - handle_width / 2.0, height: style.rail.width, }, - border: Border::with_radius(style.rail.border_radius), + border: Border::rounded(style.rail.border_radius), ..renderer::Quad::default() }, style.rail.colors.1, -- cgit From 00e7035622fc2cd0abcdb3670c4d1a898213fe42 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 8 Mar 2024 00:01:51 +0100 Subject: Reduce default `Rail::width` of `Slider` widget --- widget/src/slider.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index c37607a8..5c965af8 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -580,8 +580,8 @@ pub fn default(theme: &Theme, status: Status) -> Appearance { Appearance { rail: Rail { colors: (color, palette.secondary.base.color), - width: 6.0, - border_radius: 3.0.into(), + width: 4.0, + border_radius: 2.0.into(), }, handle: Handle { shape: HandleShape::Circle { radius: 7.0 }, -- cgit From 8a98d1e7974a7709fc2dfc59f08b05a05e537c1d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 8 Mar 2024 00:39:42 +0100 Subject: Make default height of `Slider` consistent with `Checkbox` --- widget/src/slider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'widget/src/slider.rs') diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 5c965af8..f3ea9bfd 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -58,7 +58,7 @@ where Message: Clone, { /// The default height of a [`Slider`]. - pub const DEFAULT_HEIGHT: f32 = 15.0; + pub const DEFAULT_HEIGHT: f32 = 16.0; /// Creates a new [`Slider`]. /// -- cgit