From 8b8f7563ad33dafeadf6238e377748cdec17d67a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 10 Sep 2019 19:41:49 +0200 Subject: Switch to workspace layout --- src/widget/slider.rs | 241 --------------------------------------------------- 1 file changed, 241 deletions(-) delete mode 100644 src/widget/slider.rs (limited to 'src/widget/slider.rs') diff --git a/src/widget/slider.rs b/src/widget/slider.rs deleted file mode 100644 index cdec9ec4..00000000 --- a/src/widget/slider.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! Display an interactive selector of a single value from a range of values. -//! -//! A [`Slider`] has some local [`State`]. -//! -//! [`Slider`]: struct.Slider.html -//! [`State`]: struct.State.html -use std::hash::Hash; -use std::ops::RangeInclusive; - -use crate::input::{mouse, ButtonState}; -use crate::{ - Element, Event, Hasher, Layout, MouseCursor, Node, Point, Rectangle, Style, - Widget, -}; - -/// An horizontal bar and a handle that selects a single value from a range of -/// values. -/// -/// A [`Slider`] will try to fill the horizontal space of its container. -/// -/// It implements [`Widget`] when the associated `Renderer` implements the -/// [`slider::Renderer`] trait. -/// -/// [`Slider`]: struct.Slider.html -/// [`Widget`]: ../trait.Widget.html -/// [`slider::Renderer`]: trait.Renderer.html -/// -/// # Example -/// ``` -/// use iced::{slider, Slider}; -/// -/// pub enum Message { -/// SliderChanged(f32), -/// } -/// -/// let state = &mut slider::State::new(); -/// let value = 50.0; -/// -/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged); -/// ``` -/// -/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) -pub struct Slider<'a, Message> { - state: &'a mut State, - range: RangeInclusive, - value: f32, - on_change: Box Message>, - style: Style, -} - -impl<'a, Message> std::fmt::Debug for Slider<'a, Message> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Slider") - .field("state", &self.state) - .field("range", &self.range) - .field("value", &self.value) - .field("style", &self.style) - .finish() - } -} - -impl<'a, Message> Slider<'a, Message> { - /// Creates a new [`Slider`]. - /// - /// It expects: - /// * the local [`State`] of the [`Slider`] - /// * an inclusive range of possible values - /// * the current value of the [`Slider`] - /// * a function that will be called when the [`Slider`] is dragged. - /// It receives the new value of the [`Slider`] and must produce a - /// `Message`. - /// - /// [`Slider`]: struct.Slider.html - /// [`State`]: struct.State.html - pub fn new( - state: &'a mut State, - range: RangeInclusive, - value: f32, - on_change: F, - ) -> Self - where - F: 'static + Fn(f32) -> Message, - { - Slider { - state, - value: value.max(*range.start()).min(*range.end()), - range, - on_change: Box::new(on_change), - style: Style::default().min_width(100).fill_width(), - } - } - - /// Sets the width of the [`Slider`] in pixels. - /// - /// [`Slider`]: struct.Slider.html - pub fn width(mut self, width: u16) -> Self { - self.style = self.style.width(width); - self - } -} - -impl<'a, Message, Renderer> Widget for Slider<'a, Message> -where - Renderer: self::Renderer, -{ - fn node(&self, _renderer: &Renderer) -> Node { - Node::new(self.style.height(25)) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - ) { - let mut change = || { - let bounds = layout.bounds(); - - if cursor_position.x <= bounds.x { - messages.push((self.on_change)(*self.range.start())); - } else if cursor_position.x >= bounds.x + bounds.width { - messages.push((self.on_change)(*self.range.end())); - } else { - let percent = (cursor_position.x - bounds.x) / bounds.width; - let value = (self.range.end() - self.range.start()) * percent - + self.range.start(); - - messages.push((self.on_change)(value)); - } - }; - - match event { - Event::Mouse(mouse::Event::Input { - button: mouse::Button::Left, - state, - }) => match state { - ButtonState::Pressed => { - if layout.bounds().contains(cursor_position) { - change(); - self.state.is_dragging = true; - } - } - ButtonState::Released => { - self.state.is_dragging = false; - } - }, - Event::Mouse(mouse::Event::CursorMoved { .. }) => { - if self.state.is_dragging { - change(); - } - } - _ => {} - } - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> MouseCursor { - renderer.draw( - cursor_position, - layout.bounds(), - self.state, - self.range.clone(), - self.value, - ) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.style.hash(state); - } -} - -/// The local state of a [`Slider`]. -/// -/// [`Slider`]: struct.Slider.html -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct State { - is_dragging: bool, -} - -impl State { - /// Creates a new [`State`]. - /// - /// [`State`]: struct.State.html - pub fn new() -> State { - State::default() - } - - /// Returns whether the associated [`Slider`] is currently being dragged or - /// not. - /// - /// [`Slider`]: struct.Slider.html - pub fn is_dragging(&self) -> bool { - self.is_dragging - } -} - -/// The renderer of a [`Slider`]. -/// -/// Your [renderer] will need to implement this trait before being -/// able to use a [`Slider`] in your user interface. -/// -/// [`Slider`]: struct.Slider.html -/// [renderer]: ../../renderer/index.html -pub trait Renderer { - /// Draws a [`Slider`]. - /// - /// It receives: - /// * the current cursor position - /// * the bounds of the [`Slider`] - /// * the local state of the [`Slider`] - /// * the range of values of the [`Slider`] - /// * the current value of the [`Slider`] - /// - /// [`Slider`]: struct.Slider.html - /// [`State`]: struct.State.html - /// [`Class`]: enum.Class.html - fn draw( - &mut self, - cursor_position: Point, - bounds: Rectangle, - state: &State, - range: RangeInclusive, - value: f32, - ) -> MouseCursor; -} - -impl<'a, Message, Renderer> From> - for Element<'a, Message, Renderer> -where - Renderer: self::Renderer, - Message: 'static, -{ - fn from(slider: Slider<'a, Message>) -> Element<'a, Message, Renderer> { - Element::new(slider) - } -} -- cgit From a97401aed2a173260a4abfdb65a77975ce6c0f01 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 14 Sep 2019 19:16:06 +0200 Subject: Rethink workspace structure --- src/widget/slider.rs | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/widget/slider.rs (limited to 'src/widget/slider.rs') diff --git a/src/widget/slider.rs b/src/widget/slider.rs new file mode 100644 index 00000000..cdec9ec4 --- /dev/null +++ b/src/widget/slider.rs @@ -0,0 +1,241 @@ +//! Display an interactive selector of a single value from a range of values. +//! +//! A [`Slider`] has some local [`State`]. +//! +//! [`Slider`]: struct.Slider.html +//! [`State`]: struct.State.html +use std::hash::Hash; +use std::ops::RangeInclusive; + +use crate::input::{mouse, ButtonState}; +use crate::{ + Element, Event, Hasher, Layout, MouseCursor, Node, Point, Rectangle, Style, + Widget, +}; + +/// An horizontal bar and a handle that selects a single value from a range of +/// values. +/// +/// A [`Slider`] will try to fill the horizontal space of its container. +/// +/// It implements [`Widget`] when the associated `Renderer` implements the +/// [`slider::Renderer`] trait. +/// +/// [`Slider`]: struct.Slider.html +/// [`Widget`]: ../trait.Widget.html +/// [`slider::Renderer`]: trait.Renderer.html +/// +/// # Example +/// ``` +/// use iced::{slider, Slider}; +/// +/// pub enum Message { +/// SliderChanged(f32), +/// } +/// +/// let state = &mut slider::State::new(); +/// let value = 50.0; +/// +/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged); +/// ``` +/// +/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) +pub struct Slider<'a, Message> { + state: &'a mut State, + range: RangeInclusive, + value: f32, + on_change: Box Message>, + style: Style, +} + +impl<'a, Message> std::fmt::Debug for Slider<'a, Message> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Slider") + .field("state", &self.state) + .field("range", &self.range) + .field("value", &self.value) + .field("style", &self.style) + .finish() + } +} + +impl<'a, Message> Slider<'a, Message> { + /// Creates a new [`Slider`]. + /// + /// It expects: + /// * the local [`State`] of the [`Slider`] + /// * an inclusive range of possible values + /// * the current value of the [`Slider`] + /// * a function that will be called when the [`Slider`] is dragged. + /// It receives the new value of the [`Slider`] and must produce a + /// `Message`. + /// + /// [`Slider`]: struct.Slider.html + /// [`State`]: struct.State.html + pub fn new( + state: &'a mut State, + range: RangeInclusive, + value: f32, + on_change: F, + ) -> Self + where + F: 'static + Fn(f32) -> Message, + { + Slider { + state, + value: value.max(*range.start()).min(*range.end()), + range, + on_change: Box::new(on_change), + style: Style::default().min_width(100).fill_width(), + } + } + + /// Sets the width of the [`Slider`] in pixels. + /// + /// [`Slider`]: struct.Slider.html + pub fn width(mut self, width: u16) -> Self { + self.style = self.style.width(width); + self + } +} + +impl<'a, Message, Renderer> Widget for Slider<'a, Message> +where + Renderer: self::Renderer, +{ + fn node(&self, _renderer: &Renderer) -> Node { + Node::new(self.style.height(25)) + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec, + ) { + let mut change = || { + let bounds = layout.bounds(); + + if cursor_position.x <= bounds.x { + messages.push((self.on_change)(*self.range.start())); + } else if cursor_position.x >= bounds.x + bounds.width { + messages.push((self.on_change)(*self.range.end())); + } else { + let percent = (cursor_position.x - bounds.x) / bounds.width; + let value = (self.range.end() - self.range.start()) * percent + + self.range.start(); + + messages.push((self.on_change)(value)); + } + }; + + match event { + Event::Mouse(mouse::Event::Input { + button: mouse::Button::Left, + state, + }) => match state { + ButtonState::Pressed => { + if layout.bounds().contains(cursor_position) { + change(); + self.state.is_dragging = true; + } + } + ButtonState::Released => { + self.state.is_dragging = false; + } + }, + Event::Mouse(mouse::Event::CursorMoved { .. }) => { + if self.state.is_dragging { + change(); + } + } + _ => {} + } + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + cursor_position: Point, + ) -> MouseCursor { + renderer.draw( + cursor_position, + layout.bounds(), + self.state, + self.range.clone(), + self.value, + ) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.style.hash(state); + } +} + +/// The local state of a [`Slider`]. +/// +/// [`Slider`]: struct.Slider.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct State { + is_dragging: bool, +} + +impl State { + /// Creates a new [`State`]. + /// + /// [`State`]: struct.State.html + pub fn new() -> State { + State::default() + } + + /// Returns whether the associated [`Slider`] is currently being dragged or + /// not. + /// + /// [`Slider`]: struct.Slider.html + pub fn is_dragging(&self) -> bool { + self.is_dragging + } +} + +/// The renderer of a [`Slider`]. +/// +/// Your [renderer] will need to implement this trait before being +/// able to use a [`Slider`] in your user interface. +/// +/// [`Slider`]: struct.Slider.html +/// [renderer]: ../../renderer/index.html +pub trait Renderer { + /// Draws a [`Slider`]. + /// + /// It receives: + /// * the current cursor position + /// * the bounds of the [`Slider`] + /// * the local state of the [`Slider`] + /// * the range of values of the [`Slider`] + /// * the current value of the [`Slider`] + /// + /// [`Slider`]: struct.Slider.html + /// [`State`]: struct.State.html + /// [`Class`]: enum.Class.html + fn draw( + &mut self, + cursor_position: Point, + bounds: Rectangle, + state: &State, + range: RangeInclusive, + value: f32, + ) -> MouseCursor; +} + +impl<'a, Message, Renderer> From> + for Element<'a, Message, Renderer> +where + Renderer: self::Renderer, + Message: 'static, +{ + fn from(slider: Slider<'a, Message>) -> Element<'a, Message, Renderer> { + Element::new(slider) + } +} -- cgit From 655978f480c32bc696f0d5fe2fff834bfbf238ea Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 15 Sep 2019 18:53:13 +0200 Subject: Draft nodes for missing widgets --- src/widget/slider.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/widget/slider.rs') diff --git a/src/widget/slider.rs b/src/widget/slider.rs index cdec9ec4..8a0cea01 100644 --- a/src/widget/slider.rs +++ b/src/widget/slider.rs @@ -6,6 +6,7 @@ //! [`State`]: struct.State.html use std::hash::Hash; use std::ops::RangeInclusive; +use std::rc::Rc; use crate::input::{mouse, ButtonState}; use crate::{ @@ -42,9 +43,12 @@ use crate::{ /// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) pub struct Slider<'a, Message> { state: &'a mut State, - range: RangeInclusive, - value: f32, - on_change: Box Message>, + /// The range of the slider + pub range: RangeInclusive, + /// The current value of the slider + pub value: f32, + /// The function to produce messages on change + pub on_change: Rc Message>>, style: Style, } @@ -85,7 +89,7 @@ impl<'a, Message> Slider<'a, Message> { state, value: value.max(*range.start()).min(*range.end()), range, - on_change: Box::new(on_change), + on_change: Rc::new(Box::new(on_change)), style: Style::default().min_width(100).fill_width(), } } -- cgit From f9de39ddaa3020a9585b1648afb0ead45dfd7aa9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 19 Sep 2019 15:01:12 +0200 Subject: Unify `web` and `ggez` tour examples :tada: --- src/widget/slider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/widget/slider.rs') diff --git a/src/widget/slider.rs b/src/widget/slider.rs index 8a0cea01..fb6db8c9 100644 --- a/src/widget/slider.rs +++ b/src/widget/slider.rs @@ -107,7 +107,7 @@ impl<'a, Message, Renderer> Widget for Slider<'a, Message> where Renderer: self::Renderer, { - fn node(&self, _renderer: &Renderer) -> Node { + fn node(&self, _renderer: &mut Renderer) -> Node { Node::new(self.style.height(25)) } -- cgit From b9e0f7494881ad7cdfbcbc16878ecc6ef717753f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 20 Sep 2019 19:15:31 +0200 Subject: Create `iced_core` and `iced_native` --- src/widget/slider.rs | 245 --------------------------------------------------- 1 file changed, 245 deletions(-) delete mode 100644 src/widget/slider.rs (limited to 'src/widget/slider.rs') diff --git a/src/widget/slider.rs b/src/widget/slider.rs deleted file mode 100644 index fb6db8c9..00000000 --- a/src/widget/slider.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! Display an interactive selector of a single value from a range of values. -//! -//! A [`Slider`] has some local [`State`]. -//! -//! [`Slider`]: struct.Slider.html -//! [`State`]: struct.State.html -use std::hash::Hash; -use std::ops::RangeInclusive; -use std::rc::Rc; - -use crate::input::{mouse, ButtonState}; -use crate::{ - Element, Event, Hasher, Layout, MouseCursor, Node, Point, Rectangle, Style, - Widget, -}; - -/// An horizontal bar and a handle that selects a single value from a range of -/// values. -/// -/// A [`Slider`] will try to fill the horizontal space of its container. -/// -/// It implements [`Widget`] when the associated `Renderer` implements the -/// [`slider::Renderer`] trait. -/// -/// [`Slider`]: struct.Slider.html -/// [`Widget`]: ../trait.Widget.html -/// [`slider::Renderer`]: trait.Renderer.html -/// -/// # Example -/// ``` -/// use iced::{slider, Slider}; -/// -/// pub enum Message { -/// SliderChanged(f32), -/// } -/// -/// let state = &mut slider::State::new(); -/// let value = 50.0; -/// -/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged); -/// ``` -/// -/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) -pub struct Slider<'a, Message> { - state: &'a mut State, - /// The range of the slider - pub range: RangeInclusive, - /// The current value of the slider - pub value: f32, - /// The function to produce messages on change - pub on_change: Rc Message>>, - style: Style, -} - -impl<'a, Message> std::fmt::Debug for Slider<'a, Message> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Slider") - .field("state", &self.state) - .field("range", &self.range) - .field("value", &self.value) - .field("style", &self.style) - .finish() - } -} - -impl<'a, Message> Slider<'a, Message> { - /// Creates a new [`Slider`]. - /// - /// It expects: - /// * the local [`State`] of the [`Slider`] - /// * an inclusive range of possible values - /// * the current value of the [`Slider`] - /// * a function that will be called when the [`Slider`] is dragged. - /// It receives the new value of the [`Slider`] and must produce a - /// `Message`. - /// - /// [`Slider`]: struct.Slider.html - /// [`State`]: struct.State.html - pub fn new( - state: &'a mut State, - range: RangeInclusive, - value: f32, - on_change: F, - ) -> Self - where - F: 'static + Fn(f32) -> Message, - { - Slider { - state, - value: value.max(*range.start()).min(*range.end()), - range, - on_change: Rc::new(Box::new(on_change)), - style: Style::default().min_width(100).fill_width(), - } - } - - /// Sets the width of the [`Slider`] in pixels. - /// - /// [`Slider`]: struct.Slider.html - pub fn width(mut self, width: u16) -> Self { - self.style = self.style.width(width); - self - } -} - -impl<'a, Message, Renderer> Widget for Slider<'a, Message> -where - Renderer: self::Renderer, -{ - fn node(&self, _renderer: &mut Renderer) -> Node { - Node::new(self.style.height(25)) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - ) { - let mut change = || { - let bounds = layout.bounds(); - - if cursor_position.x <= bounds.x { - messages.push((self.on_change)(*self.range.start())); - } else if cursor_position.x >= bounds.x + bounds.width { - messages.push((self.on_change)(*self.range.end())); - } else { - let percent = (cursor_position.x - bounds.x) / bounds.width; - let value = (self.range.end() - self.range.start()) * percent - + self.range.start(); - - messages.push((self.on_change)(value)); - } - }; - - match event { - Event::Mouse(mouse::Event::Input { - button: mouse::Button::Left, - state, - }) => match state { - ButtonState::Pressed => { - if layout.bounds().contains(cursor_position) { - change(); - self.state.is_dragging = true; - } - } - ButtonState::Released => { - self.state.is_dragging = false; - } - }, - Event::Mouse(mouse::Event::CursorMoved { .. }) => { - if self.state.is_dragging { - change(); - } - } - _ => {} - } - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> MouseCursor { - renderer.draw( - cursor_position, - layout.bounds(), - self.state, - self.range.clone(), - self.value, - ) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.style.hash(state); - } -} - -/// The local state of a [`Slider`]. -/// -/// [`Slider`]: struct.Slider.html -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct State { - is_dragging: bool, -} - -impl State { - /// Creates a new [`State`]. - /// - /// [`State`]: struct.State.html - pub fn new() -> State { - State::default() - } - - /// Returns whether the associated [`Slider`] is currently being dragged or - /// not. - /// - /// [`Slider`]: struct.Slider.html - pub fn is_dragging(&self) -> bool { - self.is_dragging - } -} - -/// The renderer of a [`Slider`]. -/// -/// Your [renderer] will need to implement this trait before being -/// able to use a [`Slider`] in your user interface. -/// -/// [`Slider`]: struct.Slider.html -/// [renderer]: ../../renderer/index.html -pub trait Renderer { - /// Draws a [`Slider`]. - /// - /// It receives: - /// * the current cursor position - /// * the bounds of the [`Slider`] - /// * the local state of the [`Slider`] - /// * the range of values of the [`Slider`] - /// * the current value of the [`Slider`] - /// - /// [`Slider`]: struct.Slider.html - /// [`State`]: struct.State.html - /// [`Class`]: enum.Class.html - fn draw( - &mut self, - cursor_position: Point, - bounds: Rectangle, - state: &State, - range: RangeInclusive, - value: f32, - ) -> MouseCursor; -} - -impl<'a, Message, Renderer> From> - for Element<'a, Message, Renderer> -where - Renderer: self::Renderer, - Message: 'static, -{ - fn from(slider: Slider<'a, Message>) -> Element<'a, Message, Renderer> { - Element::new(slider) - } -} -- cgit