From 48b3b78a3840778eef1035f4585d5ba9dd3d6291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Tue, 7 Jan 2020 01:53:26 +0100 Subject: [PATCH] Implement styling for `ProgressBar` --- examples/progress_bar.rs | 14 +------ examples/styling.rs | 40 ++++++++++++++++--- native/src/renderer/null.rs | 23 +++++++++-- native/src/widget/progress_bar.rs | 49 ++++++++++-------------- src/native.rs | 6 +-- style/src/lib.rs | 1 + style/src/progress_bar.rs | 42 ++++++++++++++++++++ wgpu/src/renderer/widget/progress_bar.rs | 27 +++++++------ wgpu/src/widget.rs | 1 + wgpu/src/widget/progress_bar.rs | 15 ++++++++ 10 files changed, 151 insertions(+), 67 deletions(-) create mode 100644 style/src/progress_bar.rs create mode 100644 wgpu/src/widget/progress_bar.rs diff --git a/examples/progress_bar.rs b/examples/progress_bar.rs index 901428de..43b09928 100644 --- a/examples/progress_bar.rs +++ b/examples/progress_bar.rs @@ -1,7 +1,4 @@ -use iced::{ - slider, Background, Color, Column, Element, Length, ProgressBar, Sandbox, - Settings, Slider, -}; +use iced::{slider, Column, Element, ProgressBar, Sandbox, Settings, Slider}; pub fn main() { Progress::run(Settings::default()) @@ -38,14 +35,7 @@ impl Sandbox for Progress { fn view(&mut self) -> Element { Column::new() .padding(20) - .push( - ProgressBar::new(0.0..=100.0, self.value) - .background(Background::Color(Color::from_rgb( - 0.6, 0.6, 0.6, - ))) - .active_color(Color::from_rgb(0.0, 0.95, 0.0)) - .height(Length::Units(30)), - ) + .push(ProgressBar::new(0.0..=100.0, self.value)) .push(Slider::new( &mut self.progress_bar_slider, 0.0..=100.0, diff --git a/examples/styling.rs b/examples/styling.rs index 215185e3..426e0638 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -1,6 +1,7 @@ use iced::{ button, scrollable, slider, text_input, Button, Column, Container, Element, - Length, Radio, Row, Sandbox, Scrollable, Settings, Slider, Text, TextInput, + Length, ProgressBar, Radio, Row, Sandbox, Scrollable, Settings, Slider, + Text, TextInput, }; pub fn main() { @@ -82,13 +83,17 @@ impl Sandbox for Styling { ) .style(self.theme); + let progress_bar = + ProgressBar::new(0.0..=100.0, self.slider_value).style(self.theme); + let content = Column::new() .spacing(20) .padding(20) .max_width(600) .push(choose_theme) .push(Row::new().spacing(10).push(text_input).push(button)) - .push(slider); + .push(slider) + .push(progress_bar); let scrollable = Scrollable::new(&mut self.scroll) .style(self.theme) @@ -104,7 +109,9 @@ impl Sandbox for Styling { } mod style { - use iced::{button, container, scrollable, slider, text_input}; + use iced::{ + button, container, progress_bar, scrollable, slider, text_input, + }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Theme { @@ -167,6 +174,15 @@ mod style { } } + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::ProgressBar.into(), + } + } + } + mod light { use iced::{button, Background, Color, Vector}; @@ -197,8 +213,8 @@ mod style { mod dark { use iced::{ - button, container, scrollable, slider, text_input, Background, - Color, + button, container, progress_bar, scrollable, slider, text_input, + Background, Color, }; const SURFACE: Color = Color::from_rgb( @@ -268,7 +284,7 @@ mod style { } fn placeholder_color(&self) -> Color { - Color::from_rgb(0.7, 0.7, 0.7) + Color::from_rgb(0.4, 0.4, 0.4) } fn value_color(&self) -> Color { @@ -372,5 +388,17 @@ mod style { } } } + + pub struct ProgressBar; + + impl progress_bar::StyleSheet for ProgressBar { + fn style(&self) -> progress_bar::Style { + progress_bar::Style { + background: Background::Color(SURFACE), + bar: Background::Color(ACTIVE), + border_radius: 10, + } + } + } } } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 72f06a87..b721e29e 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -1,7 +1,7 @@ use crate::{ - button, checkbox, column, radio, row, scrollable, slider, text, text_input, - Color, Element, Font, HorizontalAlignment, Layout, Point, Rectangle, - Renderer, Size, VerticalAlignment, + button, checkbox, column, progress_bar, radio, row, scrollable, slider, + text, text_input, Color, Element, Font, HorizontalAlignment, Layout, Point, + Rectangle, Renderer, Size, VerticalAlignment, }; /// A renderer that does nothing. @@ -196,6 +196,21 @@ impl slider::Renderer for Null { _value: f32, _is_dragging: bool, _style_sheet: &Self::Style, - ) -> Self::Output { + ) { + } +} + +impl progress_bar::Renderer for Null { + type Style = (); + + const DEFAULT_HEIGHT: u16 = 30; + + fn draw( + &self, + _bounds: Rectangle, + _range: std::ops::RangeInclusive, + _value: f32, + _style: &Self::Style, + ) { } } diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index fe517404..0bc860dd 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -1,7 +1,6 @@ //! Provide progress feedback to your users. use crate::{ - layout, Background, Color, Element, Hasher, Layout, Length, Point, - Rectangle, Size, Widget, + layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, }; use std::{hash::Hash, ops::RangeInclusive}; @@ -10,8 +9,9 @@ use std::{hash::Hash, ops::RangeInclusive}; /// /// # Example /// ``` -/// # use iced_native::ProgressBar; +/// # use iced_native::renderer::Null; /// # +/// # pub type ProgressBar = iced_native::ProgressBar; /// let value = 50.0; /// /// ProgressBar::new(0.0..=100.0, value); @@ -19,16 +19,15 @@ use std::{hash::Hash, ops::RangeInclusive}; /// /// ![Progress bar drawn with `iced_wgpu`](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) #[allow(missing_debug_implementations)] -pub struct ProgressBar { +pub struct ProgressBar { range: RangeInclusive, value: f32, width: Length, height: Option, - background: Option, - active_color: Option, + style: Renderer::Style, } -impl ProgressBar { +impl ProgressBar { /// Creates a new [`ProgressBar`]. /// /// It expects: @@ -42,8 +41,7 @@ impl ProgressBar { range, width: Length::Fill, height: None, - background: None, - active_color: None, + style: Renderer::Style::default(), } } @@ -63,24 +61,16 @@ impl ProgressBar { self } - /// Sets the background of the [`ProgressBar`]. + /// Sets the style of the [`ProgressBar`]. /// /// [`ProgressBar`]: struct.ProgressBar.html - pub fn background(mut self, background: Background) -> Self { - self.background = Some(background); - self - } - - /// Sets the active color of the [`ProgressBar`]. - /// - /// [`ProgressBar`]: struct.ProgressBar.html - pub fn active_color(mut self, active_color: Color) -> Self { - self.active_color = Some(active_color); + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); self } } -impl Widget for ProgressBar +impl Widget for ProgressBar where Renderer: self::Renderer, { @@ -119,8 +109,7 @@ where layout.bounds(), self.range.clone(), self.value, - self.background, - self.active_color, + &self.style, ) } @@ -138,6 +127,8 @@ where /// [`ProgressBar`]: struct.ProgressBar.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + type Style: Default; + /// The default height of a [`ProgressBar`]. /// /// [`ProgressBar`]: struct.ProgressBar.html @@ -158,17 +149,19 @@ pub trait Renderer: crate::Renderer { bounds: Rectangle, range: RangeInclusive, value: f32, - background: Option, - active_color: Option, + style: &Self::Style, ) -> Self::Output; } -impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +impl<'a, Message, Renderer> From> + for Element<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: 'static + self::Renderer, Message: 'static, { - fn from(progress_bar: ProgressBar) -> Element<'a, Message, Renderer> { + fn from( + progress_bar: ProgressBar, + ) -> Element<'a, Message, Renderer> { Element::new(progress_bar) } } diff --git a/src/native.rs b/src/native.rs index c2584fdd..5a4db8f6 100644 --- a/src/native.rs +++ b/src/native.rs @@ -34,13 +34,13 @@ pub mod widget { pub use iced_winit::svg::{Handle, Svg}; } - pub use iced_winit::{Checkbox, ProgressBar, Radio, Text}; + pub use iced_winit::{Checkbox, Radio, Text}; #[doc(no_inline)] pub use { button::Button, container::Container, image::Image, - scrollable::Scrollable, slider::Slider, svg::Svg, - text_input::TextInput, + progress_bar::ProgressBar, scrollable::Scrollable, slider::Slider, + svg::Svg, text_input::TextInput, }; /// A container that distributes its contents vertically. diff --git a/style/src/lib.rs b/style/src/lib.rs index 4b8d339e..3f3dc0b0 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -1,5 +1,6 @@ pub mod button; pub mod container; +pub mod progress_bar; pub mod scrollable; pub mod slider; pub mod text_input; diff --git a/style/src/progress_bar.rs b/style/src/progress_bar.rs new file mode 100644 index 00000000..73503fa8 --- /dev/null +++ b/style/src/progress_bar.rs @@ -0,0 +1,42 @@ +//! Provide progress feedback to your users. +use iced_core::{Background, Color}; + +/// The appearance of a progress bar. +#[derive(Debug)] +pub struct Style { + pub background: Background, + pub bar: Background, + pub border_radius: u16, +} + +/// A set of rules that dictate the style of a progress bar. +pub trait StyleSheet { + fn style(&self) -> Style; +} + +struct Default; + +impl StyleSheet for Default { + fn style(&self) -> Style { + Style { + background: Background::Color(Color::from_rgb(0.6, 0.6, 0.6)), + bar: Background::Color(Color::from_rgb(0.3, 0.9, 0.3)), + border_radius: 5, + } + } +} + +impl std::default::Default for Box { + fn default() -> Self { + Box::new(Default) + } +} + +impl From for Box +where + T: 'static + StyleSheet, +{ + fn from(style: T) -> Self { + Box::new(style) + } +} diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs index e9346fda..8bb9db03 100644 --- a/wgpu/src/renderer/widget/progress_bar.rs +++ b/wgpu/src/renderer/widget/progress_bar.rs @@ -1,7 +1,9 @@ -use crate::{Primitive, Renderer}; -use iced_native::{progress_bar, Background, Color, MouseCursor, Rectangle}; +use crate::{progress_bar::StyleSheet, Primitive, Renderer}; +use iced_native::{progress_bar, Color, MouseCursor, Rectangle}; impl progress_bar::Renderer for Renderer { + type Style = Box; + const DEFAULT_HEIGHT: u16 = 30; fn draw( @@ -9,9 +11,10 @@ impl progress_bar::Renderer for Renderer { bounds: Rectangle, range: std::ops::RangeInclusive, value: f32, - background: Option, - active_color: Option, + style_sheet: &Self::Style, ) -> Self::Output { + let style = style_sheet.style(); + let (range_start, range_end) = range.into_inner(); let active_progress_width = bounds.width * ((value - range_start) / (range_end - range_start).max(1.0)); @@ -19,31 +22,27 @@ impl progress_bar::Renderer for Renderer { let background = Primitive::Group { primitives: vec![Primitive::Quad { bounds: Rectangle { ..bounds }, - background: background - .unwrap_or(Background::Color([0.6, 0.6, 0.6].into())) - .into(), - border_radius: 5, + background: style.background, + border_radius: style.border_radius, border_width: 0, border_color: Color::TRANSPARENT, }], }; - let active_progress = Primitive::Quad { + let bar = Primitive::Quad { bounds: Rectangle { width: active_progress_width, ..bounds }, - background: Background::Color( - active_color.unwrap_or([0.0, 0.95, 0.0].into()), - ), - border_radius: 5, + background: style.bar, + border_radius: style.border_radius, border_width: 0, border_color: Color::TRANSPARENT, }; ( Primitive::Group { - primitives: vec![background, active_progress], + primitives: vec![background, bar], }, MouseCursor::OutOfBounds, ) diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index 4b8d339e..3f3dc0b0 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,5 +1,6 @@ pub mod button; pub mod container; +pub mod progress_bar; pub mod scrollable; pub mod slider; pub mod text_input; diff --git a/wgpu/src/widget/progress_bar.rs b/wgpu/src/widget/progress_bar.rs new file mode 100644 index 00000000..34450b5e --- /dev/null +++ b/wgpu/src/widget/progress_bar.rs @@ -0,0 +1,15 @@ +//! Allow your users to perform actions by pressing a button. +//! +//! A [`Button`] has some local [`State`]. +//! +//! [`Button`]: type.Button.html +//! [`State`]: struct.State.html +use crate::Renderer; + +pub use iced_style::progress_bar::{Style, StyleSheet}; + +/// A bar that displays progress. +/// +/// This is an alias of an `iced_native` progress bar with an +/// `iced_wgpu::Renderer`. +pub type ProgressBar = iced_native::ProgressBar;