From c7b170da6d180f80e539910cccb543720fa3713c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 29 Dec 2019 10:57:01 +0100 Subject: Draft `Style` and `StyleSheet` for `Button` --- examples/pokedex.rs | 23 +++++++- examples/stopwatch.rs | 43 ++++++++++---- examples/todos.rs | 51 ++++++++++++++--- examples/tour.rs | 47 +++++++++------- native/src/lib.rs | 2 +- native/src/renderer/null.rs | 11 ++-- native/src/widget/button.rs | 47 ++++++---------- src/lib.rs | 2 +- src/native.rs | 18 +----- wgpu/src/lib.rs | 14 +++-- wgpu/src/renderer.rs | 4 +- wgpu/src/renderer/widget/button.rs | 28 ++++----- wgpu/src/renderer/widget/button/style.rs | 1 + wgpu/src/widget.rs | 1 + wgpu/src/widget/button.rs | 97 ++++++++++++++++++++++++++++++++ 15 files changed, 275 insertions(+), 114 deletions(-) create mode 100644 wgpu/src/renderer/widget/button/style.rs create mode 100644 wgpu/src/widget.rs create mode 100644 wgpu/src/widget/button.rs diff --git a/examples/pokedex.rs b/examples/pokedex.rs index 2d595ec4..0dcf6981 100644 --- a/examples/pokedex.rs +++ b/examples/pokedex.rs @@ -220,7 +220,26 @@ impl From for Error { fn button<'a>(state: &'a mut button::State, text: &str) -> Button<'a, Message> { Button::new(state, Text::new(text).color(Color::WHITE)) - .background(Color::from_rgb(0.11, 0.42, 0.87)) - .border_radius(10) .padding(10) + .style(style::Button::Primary) +} + +mod style { + use iced::{button, Background, Color}; + + pub enum Button { + Primary, + } + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + button::Style { + background: Some(Background::Color(match self { + Button::Primary => Color::from_rgb(0.11, 0.42, 0.87), + })), + border_radius: 12, + shadow_offset: 1.0, + } + } + } } diff --git a/examples/stopwatch.rs b/examples/stopwatch.rs index 7a7f0793..0e0cdba5 100644 --- a/examples/stopwatch.rs +++ b/examples/stopwatch.rs @@ -1,7 +1,6 @@ use iced::{ - button, Align, Application, Background, Button, Color, Column, Command, - Container, Element, HorizontalAlignment, Length, Row, Settings, - Subscription, Text, + button, Align, Application, Button, Color, Column, Command, Container, + Element, HorizontalAlignment, Length, Row, Settings, Subscription, Text, }; use std::time::{Duration, Instant}; @@ -99,7 +98,7 @@ impl Application for Stopwatch { .width(Length::Shrink) .size(40); - let button = |state, label, color: [f32; 3]| { + let button = |state, label, style| { Button::new( state, Text::new(label) @@ -107,22 +106,22 @@ impl Application for Stopwatch { .horizontal_alignment(HorizontalAlignment::Center), ) .min_width(80) - .background(Background::Color(color.into())) - .border_radius(10) .padding(10) + .style(style) }; let toggle_button = { let (label, color) = match self.state { - State::Idle => ("Start", [0.11, 0.42, 0.87]), - State::Ticking { .. } => ("Stop", [0.9, 0.4, 0.4]), + State::Idle => ("Start", style::Button::Primary), + State::Ticking { .. } => ("Stop", style::Button::Destructive), }; button(&mut self.toggle, label, color).on_press(Message::Toggle) }; - let reset_button = button(&mut self.reset, "Reset", [0.7, 0.7, 0.7]) - .on_press(Message::Reset); + let reset_button = + button(&mut self.reset, "Reset", style::Button::Secondary) + .on_press(Message::Reset); let controls = Row::new() .width(Length::Shrink) @@ -180,3 +179,27 @@ mod time { } } } + +mod style { + use iced::{button, Background, Color}; + + pub enum Button { + Primary, + Secondary, + Destructive, + } + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + button::Style { + background: Some(Background::Color(match self { + Button::Primary => Color::from_rgb(0.11, 0.42, 0.87), + Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5), + Button::Destructive => Color::from_rgb(0.8, 0.2, 0.2), + })), + border_radius: 12, + shadow_offset: 1.0, + } + } + } +} diff --git a/examples/todos.rs b/examples/todos.rs index 42e88f65..00edd7fb 100644 --- a/examples/todos.rs +++ b/examples/todos.rs @@ -296,7 +296,8 @@ impl Task { edit_icon().color([0.5, 0.5, 0.5]), ) .on_press(TaskMessage::Edit) - .padding(10), + .padding(10) + .style(style::Button::NoBackground), ) .into() } @@ -331,8 +332,7 @@ impl Task { ) .on_press(TaskMessage::Delete) .padding(10) - .border_radius(5) - .background(Color::from_rgb(0.8, 0.2, 0.2)), + .style(style::Button::Destructive), ) .into() } @@ -361,15 +361,12 @@ impl Controls { let label = Text::new(label).size(16).width(Length::Shrink); let button = if filter == current_filter { Button::new(state, label.color(Color::WHITE)) - .background(Color::from_rgb(0.2, 0.2, 0.7)) + .style(style::Button::FilterSelected) } else { - Button::new(state, label) + Button::new(state, label).style(style::Button::NoBackground) }; - button - .on_press(Message::FilterChanged(filter)) - .padding(8) - .border_radius(10) + button.on_press(Message::FilterChanged(filter)).padding(8) }; Row::new() @@ -562,3 +559,39 @@ impl SavedState { Ok(()) } } + +mod style { + use iced::{button, Background, Color}; + + pub enum Button { + FilterSelected, + NoBackground, + Destructive, + } + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + match self { + Button::FilterSelected => button::Style { + background: Some(Background::Color(Color::from_rgb( + 0.2, 0.2, 0.7, + ))), + border_radius: 10, + shadow_offset: 0.0, + }, + Button::NoBackground => button::Style { + background: None, + border_radius: 0, + shadow_offset: 0.0, + }, + Button::Destructive => button::Style { + background: Some(Background::Color(Color::from_rgb( + 0.8, 0.2, 0.2, + ))), + border_radius: 5, + shadow_offset: 1.0, + }, + } + } + } +} diff --git a/examples/tour.rs b/examples/tour.rs index da05b396..402bf1c4 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -62,8 +62,9 @@ impl Sandbox for Tour { if steps.has_previous() { controls = controls.push( - secondary_button(back_button, "Back") - .on_press(Message::BackPressed), + button(back_button, "Back") + .on_press(Message::BackPressed) + .style(style::Button::Secondary), ); } @@ -71,8 +72,9 @@ impl Sandbox for Tour { if steps.can_continue() { controls = controls.push( - primary_button(next_button, "Next") - .on_press(Message::NextPressed), + button(next_button, "Next") + .on_press(Message::NextPressed) + .style(style::Button::Primary), ); } @@ -697,24 +699,9 @@ fn button<'a, Message>( .horizontal_alignment(HorizontalAlignment::Center), ) .padding(12) - .border_radius(12) .min_width(100) } -fn primary_button<'a, Message>( - state: &'a mut button::State, - label: &str, -) -> Button<'a, Message> { - button(state, label).background(Color::from_rgb(0.11, 0.42, 0.87)) -} - -fn secondary_button<'a, Message>( - state: &'a mut button::State, - label: &str, -) -> Button<'a, Message> { - button(state, label).background(Color::from_rgb(0.4, 0.4, 0.4)) -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Language { Rust, @@ -757,6 +744,28 @@ pub enum Layout { Column, } +mod style { + use iced::{button, Background, Color}; + + pub enum Button { + Primary, + Secondary, + } + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + button::Style { + background: Some(Background::Color(match self { + Button::Primary => Color::from_rgb(0.11, 0.42, 0.87), + Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5), + })), + border_radius: 12, + shadow_offset: 1.0, + } + } + } +} + // This should be gracefully handled by Iced in the future. Probably using our // own proc macro, or maybe the whole process is streamlined by `wasm-pack` at // some point. diff --git a/native/src/lib.rs b/native/src/lib.rs index 8dcacb2b..9d237196 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -34,7 +34,7 @@ //! [`Windowed`]: renderer/trait.Windowed.html //! [`UserInterface`]: struct.UserInterface.html //! [renderer]: renderer/index.html -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![deny(unsafe_code)] diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 43076d61..1be669c2 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, text, text_input, - Background, Color, Element, Font, HorizontalAlignment, Layout, Point, - Rectangle, Renderer, Size, VerticalAlignment, + button, checkbox, column, radio, row, scrollable, text, text_input, Color, + Element, Font, HorizontalAlignment, Layout, Point, Rectangle, Renderer, + Size, VerticalAlignment, }; /// A renderer that does nothing. @@ -117,13 +117,14 @@ impl text_input::Renderer for Null { } impl button::Renderer for Null { + type Style = (); + fn draw( &mut self, _bounds: Rectangle, _cursor_position: Point, _is_pressed: bool, - _background: Option, - _border_radius: u16, + _style: &Self::Style, _content: Self::Output, ) -> Self::Output { } diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index 2881105f..4a7187da 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -6,8 +6,8 @@ //! [`State`]: struct.State.html use crate::{ input::{mouse, ButtonState}, - layout, Background, Clipboard, Element, Event, Hasher, Layout, Length, - Point, Rectangle, Widget, + layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, + Rectangle, Widget, }; use std::hash::Hash; @@ -28,7 +28,7 @@ use std::hash::Hash; /// .on_press(Message::ButtonPressed); /// ``` #[allow(missing_debug_implementations)] -pub struct Button<'a, Message, Renderer> { +pub struct Button<'a, Message, Renderer: self::Renderer> { state: &'a mut State, content: Element<'a, Message, Renderer>, on_press: Option, @@ -37,11 +37,13 @@ pub struct Button<'a, Message, Renderer> { min_width: u32, min_height: u32, padding: u16, - background: Option, - border_radius: u16, + style: Renderer::Style, } -impl<'a, Message, Renderer> Button<'a, Message, Renderer> { +impl<'a, Message, Renderer> Button<'a, Message, Renderer> +where + Renderer: self::Renderer, +{ /// Creates a new [`Button`] with some local [`State`] and the given /// content. /// @@ -60,8 +62,7 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> { min_width: 0, min_height: 0, padding: 0, - background: None, - border_radius: 0, + style: Renderer::Style::default(), } } @@ -105,23 +106,6 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> { self } - /// Sets the [`Background`] of the [`Button`]. - /// - /// [`Button`]: struct.Button.html - /// [`Background`]: ../../struct.Background.html - pub fn background>(mut self, background: T) -> Self { - self.background = Some(background.into()); - self - } - - /// Sets the border radius of the [`Button`]. - /// - /// [`Button`]: struct.Button.html - pub fn border_radius(mut self, border_radius: u16) -> Self { - self.border_radius = border_radius; - self - } - /// Sets the message that will be produced when the [`Button`] is pressed. /// /// [`Button`]: struct.Button.html @@ -129,6 +113,11 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> { self.on_press = Some(msg); self } + + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } } /// The local state of a [`Button`]. @@ -240,8 +229,7 @@ where layout.bounds(), cursor_position, self.state.is_pressed, - self.background, - self.border_radius, + &self.style, content, ) } @@ -260,6 +248,8 @@ where /// [`Button`]: struct.Button.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { + type Style: Default; + /// Draws a [`Button`]. /// /// [`Button`]: struct.Button.html @@ -268,8 +258,7 @@ pub trait Renderer: crate::Renderer + Sized { bounds: Rectangle, cursor_position: Point, is_pressed: bool, - background: Option, - border_radius: u16, + style: &Self::Style, content: Self::Output, ) -> Self::Output; } diff --git a/src/lib.rs b/src/lib.rs index 1ef11378..579ff43d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,7 +174,7 @@ //! [documentation]: https://docs.rs/iced //! [examples]: https://github.com/hecrj/iced/tree/master/examples //! [`Application`]: trait.Application.html -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![deny(unsafe_code)] diff --git a/src/native.rs b/src/native.rs index f06f1c99..cc2068ae 100644 --- a/src/native.rs +++ b/src/native.rs @@ -22,23 +22,7 @@ pub mod widget { //! //! [`TextInput`]: text_input/struct.TextInput.html //! [`text_input::State`]: text_input/struct.State.html - pub mod button { - //! Allow your users to perform actions by pressing a button. - //! - //! A [`Button`] has some local [`State`]. - //! - //! [`Button`]: type.Button.html - //! [`State`]: struct.State.html - - /// A widget that produces a message when clicked. - /// - /// This is an alias of an `iced_native` button with a default - /// `Renderer`. - pub type Button<'a, Message> = - iced_winit::Button<'a, Message, iced_wgpu::Renderer>; - - pub use iced_winit::button::State; - } + pub use iced_wgpu::button; pub mod scrollable { //! Navigate an endless amount of content with a scrollbar. diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9f9ed8db..55f93546 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -19,11 +19,13 @@ //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![deny(unsafe_code)] #![deny(rust_2018_idioms)] +pub mod widget; + mod image; mod primitive; mod quad; @@ -31,9 +33,11 @@ mod renderer; mod text; mod transformation; -pub(crate) use crate::image::Image; -pub(crate) use quad::Quad; -pub(crate) use transformation::Transformation; - pub use primitive::Primitive; pub use renderer::{Renderer, Target}; +#[doc(no_inline)] +pub use widget::*; + +pub(crate) use self::image::Image; +pub(crate) use quad::Quad; +pub(crate) use transformation::Transformation; diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 365ef1ef..4984d4fe 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -22,7 +22,7 @@ pub struct Renderer { device: Device, queue: Queue, quad_pipeline: quad::Pipeline, - image_pipeline: crate::image::Pipeline, + image_pipeline: image::Pipeline, text_pipeline: text::Pipeline, } @@ -63,7 +63,7 @@ impl Renderer { let text_pipeline = text::Pipeline::new(&mut device); let quad_pipeline = quad::Pipeline::new(&mut device); - let image_pipeline = crate::image::Pipeline::new(&mut device); + let image_pipeline = image::Pipeline::new(&mut device); Self { device, diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index 86963053..f3817374 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -1,50 +1,50 @@ -use crate::{Primitive, Renderer}; -use iced_native::{button, Background, MouseCursor, Point, Rectangle}; +use crate::{button::StyleSheet, Primitive, Renderer}; +use iced_native::{Background, MouseCursor, Point, Rectangle}; + +impl iced_native::button::Renderer for Renderer { + type Style = Box; -impl button::Renderer for Renderer { fn draw( &mut self, bounds: Rectangle, cursor_position: Point, is_pressed: bool, - background: Option, - border_radius: u16, + style: &Box, (content, _): Self::Output, ) -> Self::Output { let is_mouse_over = bounds.contains(cursor_position); // TODO: Render proper shadows - // TODO: Make hovering and pressed styles configurable - let shadow_offset = if is_mouse_over { + let styling = if is_mouse_over { if is_pressed { - 0.0 + style.pressed() } else { - 2.0 + style.hovered() } } else { - 1.0 + style.active() }; ( - match background { + match styling.background { None => content, Some(background) => Primitive::Group { primitives: vec![ Primitive::Quad { bounds: Rectangle { x: bounds.x + 1.0, - y: bounds.y + shadow_offset, + y: bounds.y + styling.shadow_offset, ..bounds }, background: Background::Color( [0.0, 0.0, 0.0, 0.5].into(), ), - border_radius, + border_radius: styling.border_radius, }, Primitive::Quad { bounds, background, - border_radius, + border_radius: styling.border_radius, }, content, ], diff --git a/wgpu/src/renderer/widget/button/style.rs b/wgpu/src/renderer/widget/button/style.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/wgpu/src/renderer/widget/button/style.rs @@ -0,0 +1 @@ + diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs new file mode 100644 index 00000000..aa200ca2 --- /dev/null +++ b/wgpu/src/widget.rs @@ -0,0 +1 @@ +pub mod button; diff --git a/wgpu/src/widget/button.rs b/wgpu/src/widget/button.rs new file mode 100644 index 00000000..7827f8b2 --- /dev/null +++ b/wgpu/src/widget/button.rs @@ -0,0 +1,97 @@ +//! 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; +use iced_native::Background; + +pub use iced_native::button::State; + +/// A widget that produces a message when clicked. +/// +/// This is an alias of an `iced_native` button with an `iced_wgpu::Renderer`. +pub type Button<'a, Message> = iced_native::Button<'a, Message, Renderer>; + +#[derive(Debug)] +pub struct Style { + pub shadow_offset: f32, + pub background: Option, + pub border_radius: u16, +} + +pub trait StyleSheet { + fn active(&self) -> Style; + + fn hovered(&self) -> Style { + let active = self.active(); + + Style { + shadow_offset: active.shadow_offset + 1.0, + ..active + } + } + + fn pressed(&self) -> Style { + Style { + shadow_offset: 0.0, + ..self.active() + } + } + + fn disabled(&self) -> Style { + self.active() + } +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Style { + Style { + shadow_offset: 1.0, + background: Some(Background::Color([0.5, 0.5, 0.5].into())), + border_radius: 5, + } + } + + fn hovered(&self) -> Style { + Style { + shadow_offset: 2.0, + background: Some(Background::Color([0.5, 0.5, 0.5].into())), + border_radius: 5, + } + } + + fn pressed(&self) -> Style { + Style { + shadow_offset: 0.0, + background: Some(Background::Color([0.5, 0.5, 0.5].into())), + border_radius: 5, + } + } + + fn disabled(&self) -> Style { + Style { + shadow_offset: 0.0, + background: Some(Background::Color([0.7, 0.7, 0.7].into())), + 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) + } +} -- cgit From f74ab463d44dd0bb025b0cea466d2861576253dd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 29 Dec 2019 12:29:47 +0100 Subject: Add `background_color` to `Settings` --- native/src/renderer.rs | 7 ++++--- native/src/renderer/windowed.rs | 3 ++- src/settings.rs | 18 +++++++++++++++++- wgpu/src/renderer.rs | 18 ++++++++++++------ winit/src/application.rs | 8 ++++++-- winit/src/settings/mod.rs | 15 ++++++++++++++- 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/native/src/renderer.rs b/native/src/renderer.rs index 7a68ada4..023dd42b 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -21,14 +21,15 @@ //! [`checkbox::Renderer`]: ../widget/checkbox/trait.Renderer.html mod debugger; -#[cfg(debug_assertions)] -mod null; mod windowed; pub use debugger::Debugger; +pub use windowed::{Target, Windowed}; + +#[cfg(debug_assertions)] +mod null; #[cfg(debug_assertions)] pub use null::Null; -pub use windowed::{Target, Windowed}; use crate::{layout, Element}; diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs index 813a03f2..89f80bbe 100644 --- a/native/src/renderer/windowed.rs +++ b/native/src/renderer/windowed.rs @@ -1,4 +1,4 @@ -use crate::MouseCursor; +use crate::{Color, MouseCursor}; use raw_window_handle::HasRawWindowHandle; @@ -19,6 +19,7 @@ pub trait Windowed: super::Renderer + Sized { /// top of the GUI on most scenarios. fn draw>( &mut self, + clear_color: Color, output: &Self::Output, overlay: &[T], target: &mut Self::Target, diff --git a/src/settings.rs b/src/settings.rs index 62a1a614..8da8948c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,7 +1,8 @@ //! Configure your application. +use crate::Color; /// The settings of an application. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Settings { /// The [`Window`] settings. /// @@ -9,6 +10,20 @@ pub struct Settings { /// /// [`Window`]: struct.Window.html pub window: Window, + + /// The default background [`Color`] of the application + /// + /// [`Color`]: ../struct.Color.html + pub background_color: Color, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + window: Window::default(), + background_color: Color::WHITE, + } + } } /// The window settings of an application. @@ -44,6 +59,7 @@ impl From for iced_winit::Settings { decorations: settings.window.decorations, platform_specific: Default::default(), }, + background_color: settings.background_color, } } } diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 4984d4fe..47b258ed 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -76,6 +76,7 @@ impl Renderer { fn draw>( &mut self, + clear_color: Color, (primitive, mouse_cursor): &(Primitive, MouseCursor), overlay: &[T], target: &mut Target, @@ -97,11 +98,15 @@ impl Renderer { resolve_target: None, load_op: wgpu::LoadOp::Clear, store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 1.0, - g: 1.0, - b: 1.0, - a: 1.0, + clear_color: { + let [r, g, b, a] = clear_color.into_linear(); + + wgpu::Color { + r: f64::from(r), + g: f64::from(g), + b: f64::from(b), + a: f64::from(a), + } }, }], depth_stencil_attachment: None, @@ -428,11 +433,12 @@ impl Windowed for Renderer { fn draw>( &mut self, + clear_color: Color, output: &Self::Output, overlay: &[T], target: &mut Target, ) -> MouseCursor { - self.draw(output, overlay, target) + self.draw(clear_color, output, overlay, target) } } diff --git a/winit/src/application.rs b/winit/src/application.rs index a8612b1a..50060b11 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -279,8 +279,12 @@ pub trait Application: Sized { resized = false; } - let new_mouse_cursor = - renderer.draw(&primitive, &debug.overlay(), &mut target); + let new_mouse_cursor = renderer.draw( + settings.background_color, + &primitive, + &debug.overlay(), + &mut target, + ); debug.render_finished(); diff --git a/winit/src/settings/mod.rs b/winit/src/settings/mod.rs index 58e3d879..1f9f1502 100644 --- a/winit/src/settings/mod.rs +++ b/winit/src/settings/mod.rs @@ -1,4 +1,5 @@ //! Configure your application. +use crate::Color; #[cfg(target_os = "windows")] #[path = "windows.rs"] @@ -10,12 +11,24 @@ mod platform; pub use platform::PlatformSpecific; /// The settings of an application. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Settings { /// The [`Window`] settings /// /// [`Window`]: struct.Window.html pub window: Window, + + /// The default background color of the application + pub background_color: Color, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + window: Window::default(), + background_color: Color::WHITE, + } + } } /// The window settings of an application. -- cgit From 89a6b8a9a173e767753ec777fd83c912c1be5ea3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 29 Dec 2019 12:31:47 +0100 Subject: Rename `Settings::background_color` to `background` --- src/settings.rs | 6 +++--- winit/src/application.rs | 2 +- winit/src/settings/mod.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/settings.rs b/src/settings.rs index 8da8948c..4ae18a14 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -14,14 +14,14 @@ pub struct Settings { /// The default background [`Color`] of the application /// /// [`Color`]: ../struct.Color.html - pub background_color: Color, + pub background: Color, } impl Default for Settings { fn default() -> Settings { Settings { window: Window::default(), - background_color: Color::WHITE, + background: Color::WHITE, } } } @@ -59,7 +59,7 @@ impl From for iced_winit::Settings { decorations: settings.window.decorations, platform_specific: Default::default(), }, - background_color: settings.background_color, + background: settings.background, } } } diff --git a/winit/src/application.rs b/winit/src/application.rs index 50060b11..56f17573 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -280,7 +280,7 @@ pub trait Application: Sized { } let new_mouse_cursor = renderer.draw( - settings.background_color, + settings.background, &primitive, &debug.overlay(), &mut target, diff --git a/winit/src/settings/mod.rs b/winit/src/settings/mod.rs index 1f9f1502..0384df32 100644 --- a/winit/src/settings/mod.rs +++ b/winit/src/settings/mod.rs @@ -19,14 +19,14 @@ pub struct Settings { pub window: Window, /// The default background color of the application - pub background_color: Color, + pub background: Color, } impl Default for Settings { fn default() -> Settings { Settings { window: Window::default(), - background_color: Color::WHITE, + background: Color::WHITE, } } } -- cgit From 8caa66be2708b1c83e20d905d69902c2567c4692 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 30 Dec 2019 12:14:26 +0100 Subject: Add `Renderer::Defaults` and style inheritance --- examples/custom_widget.rs | 3 +- examples/pokedex.rs | 7 +-- examples/stopwatch.rs | 6 +-- examples/todos.rs | 86 ++++++++++++++++++++------------ examples/tour.rs | 13 +++-- native/src/element.rs | 10 +++- native/src/renderer.rs | 2 + native/src/renderer/debugger.rs | 1 + native/src/renderer/null.rs | 19 ++++++- native/src/user_interface.rs | 58 ++------------------- native/src/widget.rs | 1 + native/src/widget/button.rs | 19 +++---- native/src/widget/checkbox.rs | 2 + native/src/widget/column.rs | 4 +- native/src/widget/container.rs | 2 + native/src/widget/image.rs | 1 + native/src/widget/radio.rs | 2 + native/src/widget/row.rs | 4 +- native/src/widget/scrollable.rs | 8 ++- native/src/widget/slider.rs | 1 + native/src/widget/svg.rs | 1 + native/src/widget/text.rs | 3 ++ native/src/widget/text_input.rs | 1 + wgpu/src/defaults.rs | 27 ++++++++++ wgpu/src/lib.rs | 2 + wgpu/src/renderer.rs | 9 +++- wgpu/src/renderer/widget/button.rs | 27 ++++++++-- wgpu/src/renderer/widget/button/style.rs | 1 - wgpu/src/renderer/widget/column.rs | 3 +- wgpu/src/renderer/widget/row.rs | 3 +- wgpu/src/renderer/widget/text.rs | 3 +- wgpu/src/widget/button.rs | 45 +++++++---------- 32 files changed, 224 insertions(+), 150 deletions(-) create mode 100644 wgpu/src/defaults.rs delete mode 100644 wgpu/src/renderer/widget/button/style.rs diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs index cf2f7792..ca562ead 100644 --- a/examples/custom_widget.rs +++ b/examples/custom_widget.rs @@ -13,7 +13,7 @@ mod circle { layout, Background, Color, Element, Hasher, Layout, Length, MouseCursor, Point, Size, Widget, }; - use iced_wgpu::{Primitive, Renderer}; + use iced_wgpu::{Defaults, Primitive, Renderer}; pub struct Circle { radius: u16, @@ -54,6 +54,7 @@ mod circle { fn draw( &self, _renderer: &mut Renderer, + _defaults: &Defaults, layout: Layout<'_>, _cursor_position: Point, ) -> (Primitive, MouseCursor) { diff --git a/examples/pokedex.rs b/examples/pokedex.rs index 0dcf6981..35d38251 100644 --- a/examples/pokedex.rs +++ b/examples/pokedex.rs @@ -1,6 +1,6 @@ use iced::{ - button, image, Align, Application, Button, Color, Column, Command, - Container, Element, Image, Length, Row, Settings, Text, + button, image, Align, Application, Button, Column, Command, Container, + Element, Image, Length, Row, Settings, Text, }; pub fn main() { @@ -219,7 +219,7 @@ impl From for Error { } fn button<'a>(state: &'a mut button::State, text: &str) -> Button<'a, Message> { - Button::new(state, Text::new(text).color(Color::WHITE)) + Button::new(state, Text::new(text)) .padding(10) .style(style::Button::Primary) } @@ -239,6 +239,7 @@ mod style { })), border_radius: 12, shadow_offset: 1.0, + text_color: Color::WHITE, } } } diff --git a/examples/stopwatch.rs b/examples/stopwatch.rs index 0e0cdba5..99746609 100644 --- a/examples/stopwatch.rs +++ b/examples/stopwatch.rs @@ -1,6 +1,6 @@ use iced::{ - button, Align, Application, Button, Color, Column, Command, Container, - Element, HorizontalAlignment, Length, Row, Settings, Subscription, Text, + button, Align, Application, Button, Column, Command, Container, Element, + HorizontalAlignment, Length, Row, Settings, Subscription, Text, }; use std::time::{Duration, Instant}; @@ -102,7 +102,6 @@ impl Application for Stopwatch { Button::new( state, Text::new(label) - .color(Color::WHITE) .horizontal_alignment(HorizontalAlignment::Center), ) .min_width(80) @@ -199,6 +198,7 @@ mod style { })), border_radius: 12, shadow_offset: 1.0, + text_color: Color::WHITE, } } } diff --git a/examples/todos.rs b/examples/todos.rs index 00edd7fb..ca20183f 100644 --- a/examples/todos.rs +++ b/examples/todos.rs @@ -1,7 +1,7 @@ use iced::{ button, scrollable, text_input, Align, Application, Button, Checkbox, - Color, Column, Command, Container, Element, Font, HorizontalAlignment, - Length, Row, Scrollable, Settings, Text, TextInput, + Column, Command, Container, Element, Font, HorizontalAlignment, Length, + Row, Scrollable, Settings, Text, TextInput, }; use serde::{Deserialize, Serialize}; @@ -291,13 +291,10 @@ impl Task { .align_items(Align::Center) .push(checkbox) .push( - Button::new( - edit_button, - edit_icon().color([0.5, 0.5, 0.5]), - ) - .on_press(TaskMessage::Edit) - .padding(10) - .style(style::Button::NoBackground), + Button::new(edit_button, edit_icon()) + .on_press(TaskMessage::Edit) + .padding(10) + .style(style::Button::Icon), ) .into() } @@ -321,14 +318,9 @@ impl Task { .push( Button::new( delete_button, - Row::new() - .spacing(10) - .push(delete_icon().color(Color::WHITE)) - .push( - Text::new("Delete") - .width(Length::Shrink) - .color(Color::WHITE), - ), + Row::new().spacing(10).push(delete_icon()).push( + Text::new("Delete").width(Length::Shrink), + ), ) .on_press(TaskMessage::Delete) .padding(10) @@ -359,12 +351,10 @@ impl Controls { let filter_button = |state, label, filter, current_filter| { let label = Text::new(label).size(16).width(Length::Shrink); - let button = if filter == current_filter { - Button::new(state, label.color(Color::WHITE)) - .style(style::Button::FilterSelected) - } else { - Button::new(state, label).style(style::Button::NoBackground) - }; + let button = + Button::new(state, label).style(style::Button::Filter { + selected: filter == current_filter, + }); button.on_press(Message::FilterChanged(filter)).padding(8) }; @@ -564,25 +554,38 @@ mod style { use iced::{button, Background, Color}; pub enum Button { - FilterSelected, - NoBackground, + Filter { selected: bool }, + Icon, Destructive, } impl button::StyleSheet for Button { fn active(&self) -> button::Style { match self { - Button::FilterSelected => button::Style { - background: Some(Background::Color(Color::from_rgb( - 0.2, 0.2, 0.7, - ))), - border_radius: 10, - shadow_offset: 0.0, - }, - Button::NoBackground => button::Style { + Button::Filter { selected } => { + if *selected { + button::Style { + background: Some(Background::Color( + Color::from_rgb(0.2, 0.2, 0.7), + )), + border_radius: 10, + shadow_offset: 0.0, + text_color: Color::WHITE, + } + } else { + button::Style { + background: None, + border_radius: 0, + shadow_offset: 0.0, + text_color: Color::BLACK, + } + } + } + Button::Icon => button::Style { background: None, border_radius: 0, shadow_offset: 0.0, + text_color: Color::from_rgb(0.5, 0.5, 0.5), }, Button::Destructive => button::Style { background: Some(Background::Color(Color::from_rgb( @@ -590,7 +593,24 @@ mod style { ))), border_radius: 5, shadow_offset: 1.0, + text_color: Color::WHITE, + }, + } + } + + fn hovered(&self) -> button::Style { + let active = self.active(); + + button::Style { + text_color: match self { + Button::Icon => Color::from_rgb(0.2, 0.2, 0.7), + Button::Filter { selected } if !selected => { + Color::from_rgb(0.2, 0.2, 0.7) + } + _ => active.text_color, }, + shadow_offset: active.shadow_offset + 1.0, + ..active } } } diff --git a/examples/tour.rs b/examples/tour.rs index 402bf1c4..2429ca4f 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -694,9 +694,7 @@ fn button<'a, Message>( ) -> Button<'a, Message> { Button::new( state, - Text::new(label) - .color(Color::WHITE) - .horizontal_alignment(HorizontalAlignment::Center), + Text::new(label).horizontal_alignment(HorizontalAlignment::Center), ) .padding(12) .min_width(100) @@ -761,6 +759,15 @@ mod style { })), border_radius: 12, shadow_offset: 1.0, + text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE), + } + } + + fn hovered(&self) -> button::Style { + button::Style { + text_color: Color::WHITE, + shadow_offset: 2.0, + ..self.active() } } } diff --git a/native/src/element.rs b/native/src/element.rs index 63d2de0c..9b5adb9c 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -235,10 +235,12 @@ where pub fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - self.widget.draw(renderer, layout, cursor_position) + self.widget + .draw(renderer, defaults, layout, cursor_position) } pub(crate) fn hash_layout(&self, state: &mut Hasher) { @@ -316,10 +318,12 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - self.widget.draw(renderer, layout, cursor_position) + self.widget + .draw(renderer, defaults, layout, cursor_position) } fn hash_layout(&self, state: &mut Hasher) { @@ -384,10 +388,12 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { renderer.explain( + defaults, self.element.widget.as_ref(), layout, cursor_position, diff --git a/native/src/renderer.rs b/native/src/renderer.rs index 023dd42b..90cec6c8 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -44,6 +44,8 @@ pub trait Renderer: Sized { /// [`Renderer`]: trait.Renderer.html type Output; + type Defaults: Default; + /// Lays out the elements of a user interface. /// /// You should override this if you need to perform any operations before or diff --git a/native/src/renderer/debugger.rs b/native/src/renderer/debugger.rs index 4cc50661..30f3d9a0 100644 --- a/native/src/renderer/debugger.rs +++ b/native/src/renderer/debugger.rs @@ -17,6 +17,7 @@ pub trait Debugger: super::Renderer { /// [`Element::explain`]: struct.Element.html#method.explain fn explain( &mut self, + defaults: &Self::Defaults, widget: &dyn Widget, layout: Layout<'_>, cursor_position: Point, diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 1be669c2..56d7e472 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -5,16 +5,26 @@ use crate::{ }; /// A renderer that does nothing. +/// +/// It can be useful if you are writing tests! #[derive(Debug, Clone, Copy)] pub struct Null; +impl Null { + pub fn new() -> Null { + Null + } +} + impl Renderer for Null { type Output = (); + type Defaults = (); } impl column::Renderer for Null { fn draw( &mut self, + _defaults: &Self::Defaults, _content: &[Element<'_, Message, Self>], _layout: Layout<'_>, _cursor_position: Point, @@ -25,6 +35,7 @@ impl column::Renderer for Null { impl row::Renderer for Null { fn draw( &mut self, + _defaults: &Self::Defaults, _content: &[Element<'_, Message, Self>], _layout: Layout<'_>, _cursor_position: Point, @@ -49,6 +60,7 @@ impl text::Renderer for Null { fn draw( &mut self, + _defaults: &Self::Defaults, _bounds: Rectangle, _content: &str, _size: u16, @@ -119,13 +131,16 @@ impl text_input::Renderer for Null { impl button::Renderer for Null { type Style = (); - fn draw( + fn draw( &mut self, + _defaults: &Self::Defaults, _bounds: Rectangle, _cursor_position: Point, + _is_disabled: bool, _is_pressed: bool, _style: &Self::Style, - _content: Self::Output, + _content: &Element<'_, Message, Self>, + _content_layout: Layout<'_>, ) -> Self::Output { } } diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 07b936a9..970bf0c1 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -43,24 +43,7 @@ where /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { - /// # pub struct Renderer; - /// # - /// # impl Renderer { - /// # pub fn new() -> Self { Renderer } - /// # } - /// # - /// # impl iced_native::Renderer for Renderer { type Output = (); } - /// # - /// # impl iced_native::column::Renderer for Renderer { - /// # fn draw( - /// # &mut self, - /// # _children: &[iced_native::Element<'_, Message, Self>], - /// # _layout: iced_native::Layout<'_>, - /// # _cursor_position: iced_native::Point, - /// # ) -> Self::Output { - /// # () - /// # } - /// # } + /// # pub use iced_native::renderer::Null as Renderer; /// # } /// # /// # use iced_native::Column; @@ -139,24 +122,7 @@ where /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { - /// # pub struct Renderer; - /// # - /// # impl Renderer { - /// # pub fn new() -> Self { Renderer } - /// # } - /// # - /// # impl iced_native::Renderer for Renderer { type Output = (); } - /// # - /// # impl iced_native::column::Renderer for Renderer { - /// # fn draw( - /// # &mut self, - /// # _children: &[iced_native::Element<'_, Message, Self>], - /// # _layout: iced_native::Layout<'_>, - /// # _cursor_position: iced_native::Point, - /// # ) -> Self::Output { - /// # () - /// # } - /// # } + /// # pub use iced_native::renderer::Null as Renderer; /// # } /// # /// # use iced_native::Column; @@ -241,24 +207,7 @@ where /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { - /// # pub struct Renderer; - /// # - /// # impl Renderer { - /// # pub fn new() -> Self { Renderer } - /// # } - /// # - /// # impl iced_native::Renderer for Renderer { type Output = (); } - /// # - /// # impl iced_native::column::Renderer for Renderer { - /// # fn draw( - /// # &mut self, - /// # _children: &[iced_native::Element<'_, Message, Self>], - /// # _layout: iced_native::Layout<'_>, - /// # _cursor_position: iced_native::Point, - /// # ) -> Self::Output { - /// # () - /// # } - /// # } + /// # pub use iced_native::renderer::Null as Renderer; /// # } /// # /// # use iced_native::Column; @@ -304,6 +253,7 @@ where pub fn draw(&self, renderer: &mut Renderer) -> Renderer::Output { self.root.widget.draw( renderer, + &Renderer::Defaults::default(), Layout::new(&self.layout), self.cursor_position, ) diff --git a/native/src/widget.rs b/native/src/widget.rs index 26889280..4aa7e7f0 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -101,6 +101,7 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output; diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index 4a7187da..75ef2693 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -216,21 +216,19 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - let content = self.content.draw( - renderer, - layout.children().next().unwrap(), - cursor_position, - ); - renderer.draw( + defaults, layout.bounds(), cursor_position, + self.on_press.is_none(), self.state.is_pressed, &self.style, - content, + &self.content, + layout.children().next().unwrap(), ) } @@ -253,13 +251,16 @@ pub trait Renderer: crate::Renderer + Sized { /// Draws a [`Button`]. /// /// [`Button`]: struct.Button.html - fn draw( + fn draw( &mut self, + defaults: &Self::Defaults, bounds: Rectangle, cursor_position: Point, + is_disabled: bool, is_pressed: bool, style: &Self::Style, - content: Self::Output, + content: &Element<'_, Message, Self>, + content_layout: Layout<'_>, ) -> Self::Output; } diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 0dcac712..87a7f629 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -134,6 +134,7 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { @@ -146,6 +147,7 @@ where let label = text::Renderer::draw( renderer, + defaults, label_layout.bounds(), &self.label, text::Renderer::default_size(renderer), diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index 4b5d631c..3418d4b0 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -173,10 +173,11 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - renderer.draw(&self.children, layout, cursor_position) + renderer.draw(defaults, &self.children, layout, cursor_position) } fn hash_layout(&self, state: &mut Hasher) { @@ -213,6 +214,7 @@ pub trait Renderer: crate::Renderer + Sized { /// [`Layout`]: ../layout/struct.Layout.html fn draw( &mut self, + defaults: &Self::Defaults, content: &[Element<'_, Message, Self>], layout: Layout<'_>, cursor_position: Point, diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 74f0e0ef..93804c99 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -147,11 +147,13 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { self.content.draw( renderer, + defaults, layout.children().next().unwrap(), cursor_position, ) diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 20375822..1efe4570 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -95,6 +95,7 @@ where fn draw( &self, renderer: &mut Renderer, + _defaults: &Renderer::Defaults, layout: Layout<'_>, _cursor_position: Point, ) -> Renderer::Output { diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index a9995b86..6ac00770 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -131,6 +131,7 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { @@ -143,6 +144,7 @@ where let label = text::Renderer::draw( renderer, + defaults, label_layout.bounds(), &self.label, text::Renderer::default_size(renderer), diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index 3de65deb..76cca3d0 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -174,10 +174,11 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - renderer.draw(&self.children, layout, cursor_position) + renderer.draw(defaults, &self.children, layout, cursor_position) } fn hash_layout(&self, state: &mut Hasher) { @@ -215,6 +216,7 @@ pub trait Renderer: crate::Renderer + Sized { /// [`Layout`]: ../layout/struct.Layout.html fn draw( &mut self, + defaults: &Self::Defaults, children: &[Element<'_, Message, Self>], layout: Layout<'_>, cursor_position: Point, diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 9fa602d5..9df09b14 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -255,6 +255,7 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { @@ -277,7 +278,12 @@ where Point::new(cursor_position.x, -1.0) }; - self.content.draw(renderer, content_layout, cursor_position) + self.content.draw( + renderer, + defaults, + content_layout, + cursor_position, + ) }; self::Renderer::draw( diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index f446f7e8..ea66a347 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -178,6 +178,7 @@ where fn draw( &self, renderer: &mut Renderer, + _defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 9580f195..f6202f72 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -91,6 +91,7 @@ where fn draw( &self, renderer: &mut Renderer, + _defaults: &Renderer::Defaults, layout: Layout<'_>, _cursor_position: Point, ) -> Renderer::Output { diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs index cf9c9565..3a3db3cd 100644 --- a/native/src/widget/text.rs +++ b/native/src/widget/text.rs @@ -146,10 +146,12 @@ where fn draw( &self, renderer: &mut Renderer, + defaults: &Renderer::Defaults, layout: Layout<'_>, _cursor_position: Point, ) -> Renderer::Output { renderer.draw( + defaults, layout.bounds(), &self.content, self.size.unwrap_or(renderer.default_size()), @@ -209,6 +211,7 @@ pub trait Renderer: crate::Renderer { /// [`VerticalAlignment`]: enum.VerticalAlignment.html fn draw( &mut self, + defaults: &Self::Defaults, bounds: Rectangle, content: &str, size: u16, diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 1d1c32a2..e2114f00 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -343,6 +343,7 @@ where fn draw( &self, renderer: &mut Renderer, + _defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { diff --git a/wgpu/src/defaults.rs b/wgpu/src/defaults.rs new file mode 100644 index 00000000..8de8258b --- /dev/null +++ b/wgpu/src/defaults.rs @@ -0,0 +1,27 @@ +use iced_native::Color; + +#[derive(Debug, Clone, Copy)] +pub struct Defaults { + pub text: Text, +} + +impl Default for Defaults { + fn default() -> Defaults { + Defaults { + text: Text::default(), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct Text { + pub color: Color, +} + +impl Default for Text { + fn default() -> Text { + Text { + color: Color::BLACK, + } + } +} diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 55f93546..786b6872 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -24,6 +24,7 @@ #![deny(unused_results)] #![deny(unsafe_code)] #![deny(rust_2018_idioms)] +pub mod defaults; pub mod widget; mod image; @@ -33,6 +34,7 @@ mod renderer; mod text; mod transformation; +pub use defaults::Defaults; pub use primitive::Primitive; pub use renderer::{Renderer, Target}; #[doc(no_inline)] diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 47b258ed..1b143d90 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,4 +1,6 @@ -use crate::{image, quad, text, Image, Primitive, Quad, Transformation}; +use crate::{ + image, quad, text, Defaults, Image, Primitive, Quad, Transformation, +}; use iced_native::{ renderer::{Debugger, Windowed}, Background, Color, Layout, MouseCursor, Point, Rectangle, Vector, Widget, @@ -411,6 +413,7 @@ impl Renderer { impl iced_native::Renderer for Renderer { type Output = (Primitive, MouseCursor); + type Defaults = Defaults; fn layout<'a, Message>( &mut self, @@ -445,13 +448,15 @@ impl Windowed for Renderer { impl Debugger for Renderer { fn explain( &mut self, + defaults: &Defaults, widget: &dyn Widget, layout: Layout<'_>, cursor_position: Point, color: Color, ) -> Self::Output { let mut primitives = Vec::new(); - let (primitive, cursor) = widget.draw(self, layout, cursor_position); + let (primitive, cursor) = + widget.draw(self, defaults, layout, cursor_position); explain_layout(layout, color, &mut primitives); primitives.push(primitive); diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index f3817374..4fbd90d7 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -1,21 +1,26 @@ -use crate::{button::StyleSheet, Primitive, Renderer}; -use iced_native::{Background, MouseCursor, Point, Rectangle}; +use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer}; +use iced_native::{Background, Element, Layout, MouseCursor, Point, Rectangle}; impl iced_native::button::Renderer for Renderer { type Style = Box; - fn draw( + fn draw( &mut self, + defaults: &Defaults, bounds: Rectangle, cursor_position: Point, + is_disabled: bool, is_pressed: bool, style: &Box, - (content, _): Self::Output, + content: &Element<'_, Message, Self>, + content_layout: Layout<'_>, ) -> Self::Output { let is_mouse_over = bounds.contains(cursor_position); // TODO: Render proper shadows - let styling = if is_mouse_over { + let styling = if is_disabled { + style.disabled() + } else if is_mouse_over { if is_pressed { style.pressed() } else { @@ -25,6 +30,18 @@ impl iced_native::button::Renderer for Renderer { style.active() }; + let (content, _) = content.draw( + self, + &Defaults { + text: defaults::Text { + color: styling.text_color, + }, + ..*defaults + }, + content_layout, + cursor_position, + ); + ( match styling.background { None => content, diff --git a/wgpu/src/renderer/widget/button/style.rs b/wgpu/src/renderer/widget/button/style.rs deleted file mode 100644 index 8b137891..00000000 --- a/wgpu/src/renderer/widget/button/style.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/wgpu/src/renderer/widget/column.rs b/wgpu/src/renderer/widget/column.rs index 6c31af90..95a7463a 100644 --- a/wgpu/src/renderer/widget/column.rs +++ b/wgpu/src/renderer/widget/column.rs @@ -4,6 +4,7 @@ use iced_native::{column, Element, Layout, MouseCursor, Point}; impl column::Renderer for Renderer { fn draw( &mut self, + defaults: &Self::Defaults, content: &[Element<'_, Message, Self>], layout: Layout<'_>, cursor_position: Point, @@ -17,7 +18,7 @@ impl column::Renderer for Renderer { .zip(layout.children()) .map(|(child, layout)| { let (primitive, new_mouse_cursor) = - child.draw(self, layout, cursor_position); + child.draw(self, defaults, layout, cursor_position); if new_mouse_cursor > mouse_cursor { mouse_cursor = new_mouse_cursor; diff --git a/wgpu/src/renderer/widget/row.rs b/wgpu/src/renderer/widget/row.rs index f082dc61..bd9f1a04 100644 --- a/wgpu/src/renderer/widget/row.rs +++ b/wgpu/src/renderer/widget/row.rs @@ -4,6 +4,7 @@ use iced_native::{row, Element, Layout, MouseCursor, Point}; impl row::Renderer for Renderer { fn draw( &mut self, + defaults: &Self::Defaults, children: &[Element<'_, Message, Self>], layout: Layout<'_>, cursor_position: Point, @@ -17,7 +18,7 @@ impl row::Renderer for Renderer { .zip(layout.children()) .map(|(child, layout)| { let (primitive, new_mouse_cursor) = - child.draw(self, layout, cursor_position); + child.draw(self, defaults, layout, cursor_position); if new_mouse_cursor > mouse_cursor { mouse_cursor = new_mouse_cursor; diff --git a/wgpu/src/renderer/widget/text.rs b/wgpu/src/renderer/widget/text.rs index 08a162ba..d61c5523 100644 --- a/wgpu/src/renderer/widget/text.rs +++ b/wgpu/src/renderer/widget/text.rs @@ -27,6 +27,7 @@ impl text::Renderer for Renderer { fn draw( &mut self, + defaults: &Self::Defaults, bounds: Rectangle, content: &str, size: u16, @@ -40,7 +41,7 @@ impl text::Renderer for Renderer { content: content.to_string(), size: f32::from(size), bounds, - color: color.unwrap_or(Color::BLACK), + color: color.unwrap_or(defaults.text.color), font, horizontal_alignment, vertical_alignment, diff --git a/wgpu/src/widget/button.rs b/wgpu/src/widget/button.rs index 7827f8b2..2c4e174f 100644 --- a/wgpu/src/widget/button.rs +++ b/wgpu/src/widget/button.rs @@ -5,7 +5,7 @@ //! [`Button`]: type.Button.html //! [`State`]: struct.State.html use crate::Renderer; -use iced_native::Background; +use iced_native::{Background, Color}; pub use iced_native::button::State; @@ -19,6 +19,7 @@ pub struct Style { pub shadow_offset: f32, pub background: Option, pub border_radius: u16, + pub text_color: Color, } pub trait StyleSheet { @@ -41,7 +42,22 @@ pub trait StyleSheet { } fn disabled(&self) -> Style { - self.active() + let active = self.active(); + + Style { + shadow_offset: 0.0, + background: active.background.map(|background| match background { + Background::Color(color) => Background::Color(Color { + a: color.a * 0.5, + ..color + }), + }), + text_color: Color { + a: active.text_color.a * 0.5, + ..active.text_color + }, + ..active + } } } @@ -53,30 +69,7 @@ impl StyleSheet for Default { shadow_offset: 1.0, background: Some(Background::Color([0.5, 0.5, 0.5].into())), border_radius: 5, - } - } - - fn hovered(&self) -> Style { - Style { - shadow_offset: 2.0, - background: Some(Background::Color([0.5, 0.5, 0.5].into())), - border_radius: 5, - } - } - - fn pressed(&self) -> Style { - Style { - shadow_offset: 0.0, - background: Some(Background::Color([0.5, 0.5, 0.5].into())), - border_radius: 5, - } - } - - fn disabled(&self) -> Style { - Style { - shadow_offset: 0.0, - background: Some(Background::Color([0.7, 0.7, 0.7].into())), - border_radius: 5, + text_color: Color::BLACK, } } } -- cgit From fb9cc0262b30a953e8188897b74abb5106ea1fd8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 31 Dec 2019 11:36:54 +0100 Subject: Draft basic styling for `Container` --- native/src/widget/container.rs | 48 ++++++++++++++++++++++++++++------- wgpu/src/renderer/widget.rs | 1 + wgpu/src/renderer/widget/container.rs | 46 +++++++++++++++++++++++++++++++++ wgpu/src/widget.rs | 1 + wgpu/src/widget/container.rs | 37 +++++++++++++++++++++++++++ winit/src/application.rs | 4 +-- 6 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 wgpu/src/renderer/widget/container.rs create mode 100644 wgpu/src/widget/container.rs diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 93804c99..75c2d6b3 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -3,7 +3,7 @@ use std::hash::Hash; use crate::{ layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, - Widget, + Rectangle, Widget, }; use std::u32; @@ -12,17 +12,21 @@ use std::u32; /// /// It is normally used for alignment purposes. #[allow(missing_debug_implementations)] -pub struct Container<'a, Message, Renderer> { +pub struct Container<'a, Message, Renderer: self::Renderer> { width: Length, height: Length, max_width: u32, max_height: u32, horizontal_alignment: Align, vertical_alignment: Align, + style: Renderer::Style, content: Element<'a, Message, Renderer>, } -impl<'a, Message, Renderer> Container<'a, Message, Renderer> { +impl<'a, Message, Renderer> Container<'a, Message, Renderer> +where + Renderer: self::Renderer, +{ /// Creates an empty [`Container`]. /// /// [`Container`]: struct.Container.html @@ -37,6 +41,7 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> { max_height: u32::MAX, horizontal_alignment: Align::Start, vertical_alignment: Align::Start, + style: Renderer::Style::default(), content: content.into(), } } @@ -78,7 +83,6 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> { /// [`Container`]: struct.Container.html pub fn center_x(mut self) -> Self { self.horizontal_alignment = Align::Center; - self } @@ -87,7 +91,14 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> { /// [`Container`]: struct.Container.html pub fn center_y(mut self) -> Self { self.vertical_alignment = Align::Center; + self + } + /// Sets the style the [`Container`]. + /// + /// [`Container`]: struct.Container.html + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); self } } @@ -95,7 +106,7 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> { impl<'a, Message, Renderer> Widget for Container<'a, Message, Renderer> where - Renderer: crate::Renderer, + Renderer: self::Renderer, { fn width(&self) -> Length { self.width @@ -151,11 +162,13 @@ where layout: Layout<'_>, cursor_position: Point, ) -> Renderer::Output { - self.content.draw( - renderer, + renderer.draw( defaults, - layout.children().next().unwrap(), + layout.bounds(), cursor_position, + &self.style, + &self.content, + layout.children().next().unwrap(), ) } @@ -170,10 +183,27 @@ where } } +pub trait Renderer: crate::Renderer { + type Style: Default; + + /// Draws a [`Container`]. + /// + /// [`Container`]: struct.Container.html + fn draw( + &mut self, + defaults: &Self::Defaults, + bounds: Rectangle, + cursor_position: Point, + style: &Self::Style, + content: &Element<'_, Message, Self>, + content_layout: Layout<'_>, + ) -> Self::Output; +} + impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: 'a + crate::Renderer, + Renderer: 'a + self::Renderer, Message: 'static, { fn from( diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs index 91f107e8..8cf79cb0 100644 --- a/wgpu/src/renderer/widget.rs +++ b/wgpu/src/renderer/widget.rs @@ -1,6 +1,7 @@ mod button; mod checkbox; mod column; +mod container; mod image; mod radio; mod row; diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs new file mode 100644 index 00000000..29c709f8 --- /dev/null +++ b/wgpu/src/renderer/widget/container.rs @@ -0,0 +1,46 @@ +use crate::{container, defaults, Defaults, Primitive, Renderer}; +use iced_native::{Element, Layout, Point, Rectangle}; + +impl iced_native::container::Renderer for Renderer { + type Style = Box; + + fn draw( + &mut self, + defaults: &Defaults, + bounds: Rectangle, + cursor_position: Point, + style_sheet: &Self::Style, + content: &Element<'_, Message, Self>, + content_layout: Layout<'_>, + ) -> Self::Output { + let style = style_sheet.style(); + + let defaults = Defaults { + text: defaults::Text { + color: style.text_color.unwrap_or(defaults.text.color), + }, + ..*defaults + }; + + let (content, mouse_cursor) = + content.draw(self, &defaults, content_layout, cursor_position); + + match style.background { + Some(background) => { + let quad = Primitive::Quad { + bounds, + background, + border_radius: style.border_radius, + }; + + ( + Primitive::Group { + primitives: vec![quad, content], + }, + mouse_cursor, + ) + } + None => (content, mouse_cursor), + } + } +} diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index aa200ca2..c6f34301 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1 +1,2 @@ pub mod button; +pub mod container; diff --git a/wgpu/src/widget/container.rs b/wgpu/src/widget/container.rs new file mode 100644 index 00000000..1fc0ec98 --- /dev/null +++ b/wgpu/src/widget/container.rs @@ -0,0 +1,37 @@ +use iced_native::{Background, Color}; + +#[derive(Debug, Clone, Copy)] +pub struct Style { + pub text_color: Option, + pub background: Option, + pub border_radius: u16, +} + +pub trait StyleSheet { + fn style(&self) -> Style { + Style { + text_color: None, + background: None, + border_radius: 0, + } + } +} + +struct Default; + +impl StyleSheet for Default {} + +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/winit/src/application.rs b/winit/src/application.rs index 56f17573..02fa3780 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -1,5 +1,5 @@ use crate::{ - conversion, + container, conversion, input::{keyboard, mouse}, renderer::{Target, Windowed}, subscription, Cache, Clipboard, Command, Container, Debug, Element, Event, @@ -18,7 +18,7 @@ pub trait Application: Sized { /// The renderer to use to draw the [`Application`]. /// /// [`Application`]: trait.Application.html - type Renderer: Windowed; + type Renderer: Windowed + container::Renderer; /// The type of __messages__ your [`Application`] will produce. /// -- cgit From 649d72e7de88e593255075957e65414ed1b4d0d6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 31 Dec 2019 11:38:35 +0100 Subject: Fix `Widget::draw` for `Space` widget --- native/src/widget/space.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/native/src/widget/space.rs b/native/src/widget/space.rs index 2029c52f..24c94bf6 100644 --- a/native/src/widget/space.rs +++ b/native/src/widget/space.rs @@ -68,6 +68,7 @@ where fn draw( &self, renderer: &mut Renderer, + _defaults: &Renderer::Defaults, layout: Layout<'_>, _cursor_position: Point, ) -> Renderer::Output { -- cgit From 9ab7c47dc7d834ee73bc068f9f34eea4d6946436 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 31 Dec 2019 21:35:42 +0100 Subject: Add `border_width` and `border_color` to `Quad` --- core/src/color.rs | 8 +++++ examples/custom_widget.rs | 2 ++ examples/tour.rs | 2 +- wgpu/src/primitive.rs | 4 +++ wgpu/src/quad.rs | 17 ++++++++-- wgpu/src/renderer.rs | 9 +++-- wgpu/src/renderer/widget/button.rs | 8 ++++- wgpu/src/renderer/widget/checkbox.rs | 44 ++++++++++--------------- wgpu/src/renderer/widget/container.rs | 4 ++- wgpu/src/renderer/widget/radio.rs | 46 +++++++++++--------------- wgpu/src/renderer/widget/scrollable.rs | 8 ++++- wgpu/src/renderer/widget/slider.rs | 58 +++++++++++++++------------------ wgpu/src/renderer/widget/text_input.rs | 33 +++++++------------ wgpu/src/shader/quad.frag | 51 ++++++++++++++++++++++++----- wgpu/src/shader/quad.frag.spv | Bin 3044 -> 4212 bytes wgpu/src/shader/quad.vert | 14 +++++--- wgpu/src/shader/quad.vert.spv | Bin 3020 -> 3372 bytes 17 files changed, 180 insertions(+), 128 deletions(-) diff --git a/core/src/color.rs b/core/src/color.rs index c28e784f..d72651d9 100644 --- a/core/src/color.rs +++ b/core/src/color.rs @@ -25,6 +25,14 @@ impl Color { a: 1.0, }; + /// A color with no opacity. + pub const TRANSPARENT: Color = Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }; + /// Creates a [`Color`] from its RGB8 components. /// /// [`Color`]: struct.Color.html diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs index ca562ead..1f51ee54 100644 --- a/examples/custom_widget.rs +++ b/examples/custom_widget.rs @@ -63,6 +63,8 @@ mod circle { bounds: layout.bounds(), background: Background::Color(Color::BLACK), border_radius: self.radius, + border_width: 0, + border_color: Color::TRANSPARENT, }, MouseCursor::OutOfBounds, ) diff --git a/examples/tour.rs b/examples/tour.rs index c7f866e8..d006d397 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -27,7 +27,7 @@ impl Sandbox for Tour { scroll: scrollable::State::new(), back_button: button::State::new(), next_button: button::State::new(), - debug: false, + debug: true, } } diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 6c61f800..f4609151 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -38,6 +38,10 @@ pub enum Primitive { background: Background, /// The border radius of the quad border_radius: u16, + /// The border width of the quad + border_width: u16, + /// The border color of the quad + border_color: Color, }, /// An image primitive Image { diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index c292dec3..fe3276a3 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -125,9 +125,19 @@ impl Pipeline { }, wgpu::VertexAttributeDescriptor { shader_location: 4, - format: wgpu::VertexFormat::Float, + format: wgpu::VertexFormat::Float4, offset: 4 * (2 + 2 + 4), }, + wgpu::VertexAttributeDescriptor { + shader_location: 5, + format: wgpu::VertexFormat::Float, + offset: 4 * (2 + 2 + 4 + 4), + }, + wgpu::VertexAttributeDescriptor { + shader_location: 6, + format: wgpu::VertexFormat::Float, + offset: 4 * (2 + 2 + 4 + 4 + 1), + }, ], }, ], @@ -233,7 +243,8 @@ impl Pipeline { bounds.x, bounds.y, bounds.width, - bounds.height, + // TODO: Address anti-aliasing adjustments properly + bounds.height + 1, ); render_pass.draw_indexed( @@ -277,7 +288,9 @@ pub struct Quad { pub position: [f32; 2], pub scale: [f32; 2], pub color: [f32; 4], + pub border_color: [f32; 4], pub border_radius: f32, + pub border_width: f32, } impl Quad { diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 1b143d90..efda046b 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -223,6 +223,8 @@ impl Renderer { bounds, background, border_radius, + border_width, + border_color, } => { // TODO: Move some of this computations to the GPU (?) layer.quads.push(Quad { @@ -235,6 +237,8 @@ impl Renderer { Background::Color(color) => color.into_linear(), }, border_radius: *border_radius as f32, + border_width: *border_width as f32, + border_color: border_color.into_linear(), }); } Primitive::Image { handle, bounds } => { @@ -470,11 +474,12 @@ fn explain_layout( color: Color, primitives: &mut Vec, ) { - // TODO: Draw borders instead primitives.push(Primitive::Quad { bounds: layout.bounds(), - background: Background::Color([0.0, 0.0, 0.0, 0.05].into()), + background: Background::Color(Color::TRANSPARENT), border_radius: 0, + border_width: 1, + border_color: [0.6, 0.6, 0.6, 0.5].into(), }); for child in layout.children() { diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index 4fbd90d7..d00a43a5 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -1,5 +1,7 @@ use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer}; -use iced_native::{Background, Element, Layout, MouseCursor, Point, Rectangle}; +use iced_native::{ + Background, Color, Element, Layout, MouseCursor, Point, Rectangle, +}; impl iced_native::button::Renderer for Renderer { type Style = Box; @@ -57,11 +59,15 @@ impl iced_native::button::Renderer for Renderer { [0.0, 0.0, 0.0, 0.5].into(), ), border_radius: styling.border_radius, + border_width: 0, + border_color: Color::TRANSPARENT, }, Primitive::Quad { bounds, background, border_radius: styling.border_radius, + border_width: 0, + border_color: Color::TRANSPARENT, }, content, ], diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs index 54b4b1cc..1ed27ff7 100644 --- a/wgpu/src/renderer/widget/checkbox.rs +++ b/wgpu/src/renderer/widget/checkbox.rs @@ -1,6 +1,6 @@ use crate::{Primitive, Renderer}; use iced_native::{ - checkbox, Background, HorizontalAlignment, MouseCursor, Rectangle, + checkbox, Background, Color, HorizontalAlignment, MouseCursor, Rectangle, VerticalAlignment, }; @@ -18,30 +18,20 @@ impl checkbox::Renderer for Renderer { is_mouse_over: bool, (label, _): Self::Output, ) -> Self::Output { - let (checkbox_border, checkbox_box) = ( - Primitive::Quad { - bounds, - background: Background::Color([0.6, 0.6, 0.6].into()), - border_radius: 6, - }, - Primitive::Quad { - bounds: Rectangle { - x: bounds.x + 1.0, - y: bounds.y + 1.0, - width: bounds.width - 2.0, - height: bounds.height - 2.0, - }, - background: Background::Color( - if is_mouse_over { - [0.90, 0.90, 0.90] - } else { - [0.95, 0.95, 0.95] - } - .into(), - ), - border_radius: 5, - }, - ); + let checkbox = Primitive::Quad { + bounds, + background: Background::Color( + if is_mouse_over { + [0.90, 0.90, 0.90] + } else { + [0.95, 0.95, 0.95] + } + .into(), + ), + border_radius: 5, + border_width: 1, + border_color: Color::from_rgb(0.6, 0.6, 0.6), + }; ( Primitive::Group { @@ -56,9 +46,9 @@ impl checkbox::Renderer for Renderer { vertical_alignment: VerticalAlignment::Center, }; - vec![checkbox_border, checkbox_box, check, label] + vec![checkbox, check, label] } else { - vec![checkbox_border, checkbox_box, label] + vec![checkbox, label] }, }, if is_mouse_over { diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs index 29c709f8..18908571 100644 --- a/wgpu/src/renderer/widget/container.rs +++ b/wgpu/src/renderer/widget/container.rs @@ -1,5 +1,5 @@ use crate::{container, defaults, Defaults, Primitive, Renderer}; -use iced_native::{Element, Layout, Point, Rectangle}; +use iced_native::{Color, Element, Layout, Point, Rectangle}; impl iced_native::container::Renderer for Renderer { type Style = Box; @@ -31,6 +31,8 @@ impl iced_native::container::Renderer for Renderer { bounds, background, border_radius: style.border_radius, + border_width: 0, + border_color: Color::TRANSPARENT, }; ( diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs index 3c00a4c2..aa1dbadc 100644 --- a/wgpu/src/renderer/widget/radio.rs +++ b/wgpu/src/renderer/widget/radio.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{radio, Background, MouseCursor, Rectangle}; +use iced_native::{radio, Background, Color, MouseCursor, Rectangle}; const SIZE: f32 = 28.0; const DOT_SIZE: f32 = SIZE / 2.0; @@ -16,30 +16,20 @@ impl radio::Renderer for Renderer { is_mouse_over: bool, (label, _): Self::Output, ) -> Self::Output { - let (radio_border, radio_box) = ( - Primitive::Quad { - bounds, - background: Background::Color([0.6, 0.6, 0.6].into()), - border_radius: (SIZE / 2.0) as u16, - }, - Primitive::Quad { - bounds: Rectangle { - x: bounds.x + 1.0, - y: bounds.y + 1.0, - width: bounds.width - 2.0, - height: bounds.height - 2.0, - }, - background: Background::Color( - if is_mouse_over { - [0.90, 0.90, 0.90] - } else { - [0.95, 0.95, 0.95] - } - .into(), - ), - border_radius: (SIZE / 2.0 - 1.0) as u16, - }, - ); + let radio = Primitive::Quad { + bounds, + background: Background::Color( + if is_mouse_over { + [0.90, 0.90, 0.90] + } else { + [0.95, 0.95, 0.95] + } + .into(), + ), + border_radius: (SIZE / 2.0) as u16, + border_width: 1, + border_color: Color::from_rgb(0.6, 0.6, 0.6), + }; ( Primitive::Group { @@ -53,11 +43,13 @@ impl radio::Renderer for Renderer { }, background: Background::Color([0.3, 0.3, 0.3].into()), border_radius: (DOT_SIZE / 2.0) as u16, + border_width: 0, + border_color: Color::TRANSPARENT, }; - vec![radio_border, radio_box, radio_circle, label] + vec![radio, radio_circle, label] } else { - vec![radio_border, radio_box, label] + vec![radio, label] }, }, if is_mouse_over { diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs index 6ef57185..42a4a743 100644 --- a/wgpu/src/renderer/widget/scrollable.rs +++ b/wgpu/src/renderer/widget/scrollable.rs @@ -1,5 +1,7 @@ use crate::{Primitive, Renderer}; -use iced_native::{scrollable, Background, MouseCursor, Rectangle, Vector}; +use iced_native::{ + scrollable, Background, Color, MouseCursor, Rectangle, Vector, +}; const SCROLLBAR_WIDTH: u16 = 10; const SCROLLBAR_MARGIN: u16 = 2; @@ -68,6 +70,8 @@ impl scrollable::Renderer for Renderer { [0.0, 0.0, 0.0, 0.7].into(), ), border_radius: 5, + border_width: 0, + border_color: Color::TRANSPARENT, }; if is_mouse_over_scrollbar || state.is_scroller_grabbed() { @@ -83,6 +87,8 @@ impl scrollable::Renderer for Renderer { [0.0, 0.0, 0.0, 0.3].into(), ), border_radius: 5, + border_width: 0, + border_color: Color::TRANSPARENT, }; Primitive::Group { diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs index c73a4e56..386decb5 100644 --- a/wgpu/src/renderer/widget/slider.rs +++ b/wgpu/src/renderer/widget/slider.rs @@ -29,8 +29,10 @@ impl slider::Renderer for Renderer { width: bounds.width, height: 2.0, }, - background: Color::from_rgb(0.6, 0.6, 0.6).into(), + background: Background::Color([0.6, 0.6, 0.6, 0.5].into()), border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, }, Primitive::Quad { bounds: Rectangle { @@ -41,6 +43,8 @@ impl slider::Renderer for Renderer { }, background: Background::Color(Color::WHITE), border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, }, ); @@ -49,41 +53,31 @@ impl slider::Renderer for Renderer { let handle_offset = (bounds.width - HANDLE_WIDTH) * ((value - range_start) / (range_end - range_start).max(1.0)); - let (handle_border, handle) = ( - Primitive::Quad { - bounds: Rectangle { - x: bounds.x + handle_offset.round() - 1.0, - y: rail_y - HANDLE_HEIGHT / 2.0 - 1.0, - width: HANDLE_WIDTH + 2.0, - height: HANDLE_HEIGHT + 2.0, - }, - background: Color::from_rgb(0.6, 0.6, 0.6).into(), - border_radius: 5, - }, - Primitive::Quad { - bounds: Rectangle { - x: bounds.x + handle_offset.round(), - y: rail_y - HANDLE_HEIGHT / 2.0, - width: HANDLE_WIDTH, - height: HANDLE_HEIGHT, - }, - background: Background::Color( - if is_dragging { - [0.85, 0.85, 0.85] - } else if is_mouse_over { - [0.90, 0.90, 0.90] - } else { - [0.95, 0.95, 0.95] - } - .into(), - ), - border_radius: 4, + let handle = Primitive::Quad { + bounds: Rectangle { + x: bounds.x + handle_offset.round(), + y: rail_y - HANDLE_HEIGHT / 2.0, + width: HANDLE_WIDTH, + height: HANDLE_HEIGHT, }, - ); + background: Background::Color( + if is_dragging { + [0.85, 0.85, 0.85] + } else if is_mouse_over { + [0.90, 0.90, 0.90] + } else { + [0.95, 0.95, 0.95] + } + .into(), + ), + border_radius: 4, + border_width: 1, + border_color: Color::from_rgb(0.6, 0.6, 0.6), + }; ( Primitive::Group { - primitives: vec![rail_top, rail_bottom, handle_border, handle], + primitives: vec![rail_top, rail_bottom, handle], }, if is_dragging { MouseCursor::Grabbing diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs index 929f94db..cf3a31ab 100644 --- a/wgpu/src/renderer/widget/text_input.rs +++ b/wgpu/src/renderer/widget/text_input.rs @@ -64,28 +64,17 @@ impl text_input::Renderer for Renderer { ) -> Self::Output { let is_mouse_over = bounds.contains(cursor_position); - let border = Primitive::Quad { - bounds, - background: Background::Color( - if is_mouse_over || state.is_focused() { - [0.5, 0.5, 0.5] - } else { - [0.7, 0.7, 0.7] - } - .into(), - ), - border_radius: 5, - }; - let input = Primitive::Quad { - bounds: Rectangle { - x: bounds.x + 1.0, - y: bounds.y + 1.0, - width: bounds.width - 2.0, - height: bounds.height - 2.0, - }, + bounds, background: Background::Color(Color::WHITE), - border_radius: 4, + border_radius: 5, + border_width: 1, + border_color: if is_mouse_over || state.is_focused() { + [0.5, 0.5, 0.5] + } else { + [0.7, 0.7, 0.7] + } + .into(), }; let text = value.to_string(); @@ -130,6 +119,8 @@ impl text_input::Renderer for Renderer { }, background: Background::Color(Color::BLACK), border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, }; ( @@ -150,7 +141,7 @@ impl text_input::Renderer for Renderer { ( Primitive::Group { - primitives: vec![border, input, contents], + primitives: vec![input, contents], }, if is_mouse_over { MouseCursor::Text diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag index 2ee77e71..ad1af1ad 100644 --- a/wgpu/src/shader/quad.frag +++ b/wgpu/src/shader/quad.frag @@ -1,14 +1,17 @@ #version 450 layout(location = 0) in vec4 v_Color; -layout(location = 1) in vec2 v_Pos; -layout(location = 2) in vec2 v_Scale; -layout(location = 3) in float v_BorderRadius; +layout(location = 1) in vec4 v_BorderColor; +layout(location = 2) in vec2 v_Pos; +layout(location = 3) in vec2 v_Scale; +layout(location = 4) in float v_BorderRadius; +layout(location = 5) in float v_BorderWidth; layout(location = 0) out vec4 o_Color; -float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius, float s) +float distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius) { + // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN vec2 inner_size = size - vec2(radius, radius) * 2.0; vec2 top_left = position + vec2(radius, radius); vec2 bottom_right = top_left + inner_size; @@ -21,13 +24,43 @@ float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius, max(max(top_left_distance.y, bottom_right_distance.y), 0) ); - float d = sqrt(distance.x * distance.x + distance.y * distance.y); - - return 1.0 - smoothstep(radius - s, radius + s, d); + return sqrt(distance.x * distance.x + distance.y * distance.y); } void main() { - float radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 0.5); + vec4 mixed_color; + + // TODO: Remove branching (?) + if(v_BorderWidth > 0) { + float internal_border = max(v_BorderRadius - v_BorderWidth, 0); + + float internal_distance = distance( + gl_FragCoord.xy, + v_Pos + vec2(v_BorderWidth), + v_Scale - vec2(v_BorderWidth * 2.0), + internal_border + ); + + float border_mix = smoothstep( + max(internal_border - 0.5, 0.0), + internal_border + 0.5, + internal_distance + ); + + mixed_color = mix(v_Color, v_BorderColor, border_mix); + } else { + mixed_color = v_Color; + } + + float d = distance( + gl_FragCoord.xy, + v_Pos, + v_Scale, + v_BorderRadius + ); + + float radius_alpha = + 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0), v_BorderRadius + 0.5, d); - o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha); + o_Color = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); } diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv index 17bd8f46..519f5f01 100644 Binary files a/wgpu/src/shader/quad.frag.spv and b/wgpu/src/shader/quad.frag.spv differ diff --git a/wgpu/src/shader/quad.vert b/wgpu/src/shader/quad.vert index 539755cb..1d9a4fd2 100644 --- a/wgpu/src/shader/quad.vert +++ b/wgpu/src/shader/quad.vert @@ -4,7 +4,9 @@ layout(location = 0) in vec2 v_Pos; layout(location = 1) in vec2 i_Pos; layout(location = 2) in vec2 i_Scale; layout(location = 3) in vec4 i_Color; -layout(location = 4) in float i_BorderRadius; +layout(location = 4) in vec4 i_BorderColor; +layout(location = 5) in float i_BorderRadius; +layout(location = 6) in float i_BorderWidth; layout (set = 0, binding = 0) uniform Globals { mat4 u_Transform; @@ -12,9 +14,11 @@ layout (set = 0, binding = 0) uniform Globals { }; layout(location = 0) out vec4 o_Color; -layout(location = 1) out vec2 o_Pos; -layout(location = 2) out vec2 o_Scale; -layout(location = 3) out float o_BorderRadius; +layout(location = 1) out vec4 o_BorderColor; +layout(location = 2) out vec2 o_Pos; +layout(location = 3) out vec2 o_Scale; +layout(location = 4) out float o_BorderRadius; +layout(location = 5) out float o_BorderWidth; void main() { vec2 p_Pos = i_Pos * u_Scale; @@ -28,9 +32,11 @@ void main() { ); o_Color = i_Color; + o_BorderColor = i_BorderColor; o_Pos = p_Pos; o_Scale = p_Scale; o_BorderRadius = i_BorderRadius * u_Scale; + o_BorderWidth = i_BorderWidth * u_Scale; gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); } diff --git a/wgpu/src/shader/quad.vert.spv b/wgpu/src/shader/quad.vert.spv index 9050adfb..7059b51b 100644 Binary files a/wgpu/src/shader/quad.vert.spv and b/wgpu/src/shader/quad.vert.spv differ -- cgit From e1062a02d17f5748e4809b76ddcc132f1c912886 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Jan 2020 14:16:10 +0100 Subject: Move styling to a brand new `iced_style` crate --- Cargo.toml | 1 + src/native.rs | 14 +++----- style/Cargo.toml | 14 ++++++++ style/src/button.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++ style/src/container.rs | 41 +++++++++++++++++++++++ style/src/lib.rs | 2 ++ wgpu/Cargo.toml | 1 + wgpu/src/widget/button.rs | 77 +----------------------------------------- wgpu/src/widget/container.rs | 43 +++++------------------- winit/Cargo.toml | 3 ++ 10 files changed, 154 insertions(+), 121 deletions(-) create mode 100644 style/Cargo.toml create mode 100644 style/src/button.rs create mode 100644 style/src/container.rs create mode 100644 style/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index ebd6412e..79a9007a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ maintenance = { status = "actively-developed" } members = [ "core", "native", + "style", "web", "wgpu", "winit", diff --git a/src/native.rs b/src/native.rs index d5c9349a..54afee4b 100644 --- a/src/native.rs +++ b/src/native.rs @@ -22,7 +22,7 @@ pub mod widget { //! //! [`TextInput`]: text_input/struct.TextInput.html //! [`text_input::State`]: text_input/struct.State.html - pub use iced_wgpu::button; + pub use iced_wgpu::widget::*; pub mod scrollable { //! Navigate an endless amount of content with a scrollbar. @@ -73,8 +73,9 @@ pub mod widget { #[doc(no_inline)] pub use { - button::Button, image::Image, scrollable::Scrollable, slider::Slider, - svg::Svg, text_input::TextInput, + button::Button, container::Container, image::Image, + scrollable::Scrollable, slider::Slider, svg::Svg, + text_input::TextInput, }; /// A container that distributes its contents vertically. @@ -88,13 +89,6 @@ pub mod widget { /// This is an alias of an `iced_native` row with a default `Renderer`. pub type Row<'a, Message> = iced_winit::Row<'a, Message, iced_wgpu::Renderer>; - - /// An element decorating some content. - /// - /// This is an alias of an `iced_native` container with a default - /// `Renderer`. - pub type Container<'a, Message> = - iced_winit::Container<'a, Message, iced_wgpu::Renderer>; } #[doc(no_inline)] diff --git a/style/Cargo.toml b/style/Cargo.toml new file mode 100644 index 00000000..5928c60d --- /dev/null +++ b/style/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "iced_style" +version = "0.1.0-alpha" +authors = ["Héctor Ramón Jiménez "] +edition = "2018" +description = "The default set of styles of Iced" +license = "MIT" +repository = "https://github.com/hecrj/iced" +documentation = "https://docs.rs/iced_style" +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +categories = ["gui"] + +[dependencies] +iced_core = { version = "0.1.0", path = "../core" } diff --git a/style/src/button.rs b/style/src/button.rs new file mode 100644 index 00000000..42286897 --- /dev/null +++ b/style/src/button.rs @@ -0,0 +1,79 @@ +//! Allow your users to perform actions by pressing a button. +use iced_core::{Background, Color}; + +/// The appearance of a button. +#[derive(Debug)] +pub struct Style { + pub shadow_offset: f32, + pub background: Option, + pub border_radius: u16, + pub text_color: Color, +} + +/// A set of rules that dictate the style of a button. +pub trait StyleSheet { + fn active(&self) -> Style; + + fn hovered(&self) -> Style { + let active = self.active(); + + Style { + shadow_offset: active.shadow_offset + 1.0, + ..active + } + } + + fn pressed(&self) -> Style { + Style { + shadow_offset: 0.0, + ..self.active() + } + } + + fn disabled(&self) -> Style { + let active = self.active(); + + Style { + shadow_offset: 0.0, + background: active.background.map(|background| match background { + Background::Color(color) => Background::Color(Color { + a: color.a * 0.5, + ..color + }), + }), + text_color: Color { + a: active.text_color.a * 0.5, + ..active.text_color + }, + ..active + } + } +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Style { + Style { + shadow_offset: 1.0, + background: Some(Background::Color([0.5, 0.5, 0.5].into())), + border_radius: 5, + text_color: Color::BLACK, + } + } +} + +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/style/src/container.rs b/style/src/container.rs new file mode 100644 index 00000000..756ea0f9 --- /dev/null +++ b/style/src/container.rs @@ -0,0 +1,41 @@ +//! Decorate content and apply alignment. +use iced_core::{Background, Color}; + +/// The appearance of a container. +#[derive(Debug, Clone, Copy)] +pub struct Style { + pub text_color: Option, + pub background: Option, + pub border_radius: u16, +} + +/// A set of rules that dictate the style of a container. +pub trait StyleSheet { + /// Produces the style of a container. + fn style(&self) -> Style { + Style { + text_color: None, + background: None, + border_radius: 0, + } + } +} + +struct Default; + +impl StyleSheet for Default {} + +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/style/src/lib.rs b/style/src/lib.rs new file mode 100644 index 00000000..c6f34301 --- /dev/null +++ b/style/src/lib.rs @@ -0,0 +1,2 @@ +pub mod button; +pub mod container; diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index bb241914..19d41bba 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -12,6 +12,7 @@ svg = ["resvg"] [dependencies] iced_native = { version = "0.1.0", path = "../native" } +iced_style = { version = "0.1.0-alpha", path = "../style" } wgpu = "0.4" glyph_brush = "0.6" wgpu_glyph = { version = "0.7", git = "https://github.com/hecrj/wgpu_glyph", branch = "fix/font-load-panic" } diff --git a/wgpu/src/widget/button.rs b/wgpu/src/widget/button.rs index 2c4e174f..b738c55e 100644 --- a/wgpu/src/widget/button.rs +++ b/wgpu/src/widget/button.rs @@ -5,86 +5,11 @@ //! [`Button`]: type.Button.html //! [`State`]: struct.State.html use crate::Renderer; -use iced_native::{Background, Color}; pub use iced_native::button::State; +pub use iced_style::button::{Style, StyleSheet}; /// A widget that produces a message when clicked. /// /// This is an alias of an `iced_native` button with an `iced_wgpu::Renderer`. pub type Button<'a, Message> = iced_native::Button<'a, Message, Renderer>; - -#[derive(Debug)] -pub struct Style { - pub shadow_offset: f32, - pub background: Option, - pub border_radius: u16, - pub text_color: Color, -} - -pub trait StyleSheet { - fn active(&self) -> Style; - - fn hovered(&self) -> Style { - let active = self.active(); - - Style { - shadow_offset: active.shadow_offset + 1.0, - ..active - } - } - - fn pressed(&self) -> Style { - Style { - shadow_offset: 0.0, - ..self.active() - } - } - - fn disabled(&self) -> Style { - let active = self.active(); - - Style { - shadow_offset: 0.0, - background: active.background.map(|background| match background { - Background::Color(color) => Background::Color(Color { - a: color.a * 0.5, - ..color - }), - }), - text_color: Color { - a: active.text_color.a * 0.5, - ..active.text_color - }, - ..active - } - } -} - -struct Default; - -impl StyleSheet for Default { - fn active(&self) -> Style { - Style { - shadow_offset: 1.0, - background: Some(Background::Color([0.5, 0.5, 0.5].into())), - border_radius: 5, - text_color: Color::BLACK, - } - } -} - -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/widget/container.rs b/wgpu/src/widget/container.rs index 1fc0ec98..9a93a246 100644 --- a/wgpu/src/widget/container.rs +++ b/wgpu/src/widget/container.rs @@ -1,37 +1,10 @@ -use iced_native::{Background, Color}; +//! Decorate content and apply alignment. +use crate::Renderer; -#[derive(Debug, Clone, Copy)] -pub struct Style { - pub text_color: Option, - pub background: Option, - pub border_radius: u16, -} +pub use iced_style::container::{Style, StyleSheet}; -pub trait StyleSheet { - fn style(&self) -> Style { - Style { - text_color: None, - background: None, - border_radius: 0, - } - } -} - -struct Default; - -impl StyleSheet for Default {} - -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) - } -} +/// An element decorating some content. +/// +/// This is an alias of an `iced_native` container with a default +/// `Renderer`. +pub type Container<'a, Message> = iced_native::Container<'a, Message, Renderer>; diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 60e3f2d0..5727f8cf 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -6,6 +6,9 @@ edition = "2018" description = "A winit runtime for Iced" license = "MIT" repository = "https://github.com/hecrj/iced" +documentation = "https://docs.rs/iced_winit" +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +categories = ["gui"] [features] debug = [] -- cgit From d96ced8e2da703117a43399110ef2b8fa21a7546 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Jan 2020 17:49:48 +0100 Subject: Allow configuration of default font --- native/src/renderer/windowed.rs | 4 +++- src/application.rs | 7 ++++++- src/settings.rs | 4 ++++ wgpu/src/lib.rs | 2 ++ wgpu/src/renderer.rs | 13 ++++++++----- wgpu/src/settings.rs | 4 ++++ wgpu/src/text.rs | 11 +++++++---- winit/src/application.rs | 8 +++++--- 8 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 wgpu/src/settings.rs diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs index 89f80bbe..30e08cb8 100644 --- a/native/src/renderer/windowed.rs +++ b/native/src/renderer/windowed.rs @@ -4,13 +4,15 @@ use raw_window_handle::HasRawWindowHandle; /// A renderer that can target windows. pub trait Windowed: super::Renderer + Sized { + type Settings: Default; + /// The type of target. type Target: Target; /// Creates a new [`Windowed`] renderer. /// /// [`Windowed`]: trait.Windowed.html - fn new() -> Self; + fn new(settings: Self::Settings) -> Self; /// Performs the drawing operations described in the output on the given /// target. diff --git a/src/application.rs b/src/application.rs index a7e826fb..7dd76774 100644 --- a/src/application.rs +++ b/src/application.rs @@ -151,7 +151,12 @@ pub trait Application: Sized { Self: 'static, { #[cfg(not(target_arch = "wasm32"))] - as iced_winit::Application>::run(_settings.into()); + as iced_winit::Application>::run( + _settings.into(), + iced_wgpu::Settings { + default_font: _settings.default_font, + }, + ); #[cfg(target_arch = "wasm32")] as iced_web::Application>::run(); diff --git a/src/settings.rs b/src/settings.rs index 4ae18a14..b01e6fc8 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -15,6 +15,9 @@ pub struct Settings { /// /// [`Color`]: ../struct.Color.html pub background: Color, + + // TODO: Add `name` for web compatibility + pub default_font: Option<&'static [u8]>, } impl Default for Settings { @@ -22,6 +25,7 @@ impl Default for Settings { Settings { window: Window::default(), background: Color::WHITE, + default_font: None, } } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 786b6872..80ebc2a7 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -31,12 +31,14 @@ mod image; mod primitive; mod quad; mod renderer; +mod settings; mod text; mod transformation; pub use defaults::Defaults; pub use primitive::Primitive; pub use renderer::{Renderer, Target}; +pub use settings::Settings; #[doc(no_inline)] pub use widget::*; diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index efda046b..7f0f0b89 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,5 +1,6 @@ use crate::{ - image, quad, text, Defaults, Image, Primitive, Quad, Transformation, + image, quad, text, Defaults, Image, Primitive, Quad, Settings, + Transformation, }; use iced_native::{ renderer::{Debugger, Windowed}, @@ -49,7 +50,7 @@ impl<'a> Layer<'a> { } impl Renderer { - fn new() -> Self { + fn new(settings: Settings) -> Self { let adapter = Adapter::request(&RequestAdapterOptions { power_preference: PowerPreference::Default, backends: BackendBit::all(), @@ -63,7 +64,8 @@ impl Renderer { limits: Limits { max_bind_groups: 2 }, }); - let text_pipeline = text::Pipeline::new(&mut device); + let text_pipeline = + text::Pipeline::new(&mut device, settings.default_font); let quad_pipeline = quad::Pipeline::new(&mut device); let image_pipeline = image::Pipeline::new(&mut device); @@ -432,10 +434,11 @@ impl iced_native::Renderer for Renderer { } impl Windowed for Renderer { + type Settings = Settings; type Target = Target; - fn new() -> Self { - Self::new() + fn new(settings: Settings) -> Self { + Self::new(settings) } fn draw>( diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs new file mode 100644 index 00000000..c6d8369b --- /dev/null +++ b/wgpu/src/settings.rs @@ -0,0 +1,4 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct Settings { + pub default_font: Option<&'static [u8]>, +} diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 880ad1a6..ab9a2f71 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -22,13 +22,16 @@ pub struct Pipeline { } impl Pipeline { - pub fn new(device: &mut wgpu::Device) -> Self { + pub fn new(device: &mut wgpu::Device, default_font: Option<&[u8]>) -> Self { // TODO: Font customization let font_source = font::Source::new(); - let default_font = font_source - .load(&[font::Family::SansSerif, font::Family::Serif]) - .unwrap_or_else(|_| FALLBACK_FONT.to_vec()); + let default_font = + default_font.map(|slice| slice.to_vec()).unwrap_or_else(|| { + font_source + .load(&[font::Family::SansSerif, font::Family::Serif]) + .unwrap_or_else(|_| FALLBACK_FONT.to_vec()) + }); let load_glyph_brush = |font: Vec| { let builder = diff --git a/winit/src/application.rs b/winit/src/application.rs index 02fa3780..d16c209c 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -81,8 +81,10 @@ pub trait Application: Sized { /// It should probably be that last thing you call in your `main` function. /// /// [`Application`]: trait.Application.html - fn run(settings: Settings) - where + fn run( + settings: Settings, + renderer_settings: ::Settings, + ) where Self: 'static, { use winit::{ @@ -140,7 +142,7 @@ pub trait Application: Sized { let mut resized = false; let clipboard = Clipboard::new(&window); - let mut renderer = Self::Renderer::new(); + let mut renderer = Self::Renderer::new(renderer_settings); let mut target = { let (width, height) = to_physical(size, dpi); -- cgit From 5af4159848341b14f6ff9ae14a9a222d8d8b0fb8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Jan 2020 18:26:49 +0100 Subject: Draft basic styling for `TextInput` --- native/src/renderer/null.rs | 3 ++ native/src/widget/container.rs | 2 +- native/src/widget/text_input.rs | 33 ++++++++++++---- src/native.rs | 10 ----- style/src/container.rs | 10 +++-- style/src/lib.rs | 1 + style/src/text_input.rs | 72 ++++++++++++++++++++++++++++++++++ wgpu/src/renderer/widget/text_input.rs | 32 +++++++++------ wgpu/src/widget.rs | 1 + wgpu/src/widget/text_input.rs | 15 +++++++ 10 files changed, 143 insertions(+), 36 deletions(-) create mode 100644 style/src/text_input.rs create mode 100644 wgpu/src/widget/text_input.rs diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 56d7e472..96aa132c 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -97,6 +97,8 @@ impl scrollable::Renderer for Null { } impl text_input::Renderer for Null { + type Style = (); + fn default_size(&self) -> u16 { 20 } @@ -124,6 +126,7 @@ impl text_input::Renderer for Null { _placeholder: &str, _value: &text_input::Value, _state: &text_input::State, + _style: &Self::Style, ) -> Self::Output { } } diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 75c2d6b3..abe83264 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -94,7 +94,7 @@ where self } - /// Sets the style the [`Container`]. + /// Sets the style of the [`Container`]. /// /// [`Container`]: struct.Container.html pub fn style(mut self, style: impl Into) -> Self { diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index e2114f00..9952a9bf 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -15,8 +15,9 @@ use unicode_segmentation::UnicodeSegmentation; /// /// # Example /// ``` -/// # use iced_native::{text_input, TextInput}; +/// # use iced_native::{text_input, renderer::Null}; /// # +/// # pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Null>; /// #[derive(Debug, Clone)] /// enum Message { /// TextInputChanged(String), @@ -35,7 +36,7 @@ use unicode_segmentation::UnicodeSegmentation; /// ``` /// ![Text input drawn by `iced_wgpu`](https://github.com/hecrj/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text_input.png?raw=true) #[allow(missing_debug_implementations)] -pub struct TextInput<'a, Message> { +pub struct TextInput<'a, Message, Renderer: self::Renderer> { state: &'a mut State, placeholder: String, value: Value, @@ -46,9 +47,10 @@ pub struct TextInput<'a, Message> { size: Option, on_change: Box Message>, on_submit: Option, + style: Renderer::Style, } -impl<'a, Message> TextInput<'a, Message> { +impl<'a, Message, Renderer: self::Renderer> TextInput<'a, Message, Renderer> { /// Creates a new [`TextInput`]. /// /// It expects: @@ -79,6 +81,7 @@ impl<'a, Message> TextInput<'a, Message> { size: None, on_change: Box::new(on_change), on_submit: None, + style: Renderer::Style::default(), } } @@ -130,11 +133,20 @@ impl<'a, Message> TextInput<'a, Message> { self.on_submit = Some(message); self } + + /// Sets the style of the [`TextInput`]. + /// + /// [`TextInput`]: struct.TextInput.html + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } } -impl<'a, Message, Renderer> Widget for TextInput<'a, Message> +impl<'a, Message, Renderer> Widget + for TextInput<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: 'static + self::Renderer, Message: Clone + std::fmt::Debug, { fn width(&self) -> Length { @@ -359,6 +371,7 @@ where &self.placeholder, &self.value.secure(), &self.state, + &self.style, ) } else { renderer.draw( @@ -369,6 +382,7 @@ where &self.placeholder, &self.value, &self.state, + &self.style, ) } } @@ -376,7 +390,7 @@ where fn hash_layout(&self, state: &mut Hasher) { use std::{any::TypeId, hash::Hash}; - TypeId::of::>().hash(state); + TypeId::of::>().hash(state); self.width.hash(state); self.max_width.hash(state); @@ -393,6 +407,8 @@ where /// [`TextInput`]: struct.TextInput.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { + type Style: Default; + /// Returns the default size of the text of the [`TextInput`]. /// /// [`TextInput`]: struct.TextInput.html @@ -441,17 +457,18 @@ pub trait Renderer: crate::Renderer + Sized { placeholder: &str, value: &Value, state: &State, + style: &Self::Style, ) -> Self::Output; } -impl<'a, Message, Renderer> From> +impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where Renderer: 'static + self::Renderer, Message: 'static + Clone + std::fmt::Debug, { fn from( - text_input: TextInput<'a, Message>, + text_input: TextInput<'a, Message, Renderer>, ) -> Element<'a, Message, Renderer> { Element::new(text_input) } diff --git a/src/native.rs b/src/native.rs index 54afee4b..3535ab6a 100644 --- a/src/native.rs +++ b/src/native.rs @@ -38,16 +38,6 @@ pub mod widget { pub use iced_winit::scrollable::State; } - pub mod text_input { - //! Ask for information using text fields. - //! - //! A [`TextInput`] has some local [`State`]. - //! - //! [`TextInput`]: struct.TextInput.html - //! [`State`]: struct.State.html - pub use iced_winit::text_input::{State, TextInput}; - } - pub mod slider { //! Display an interactive selector of a single value from a range of //! values. diff --git a/style/src/container.rs b/style/src/container.rs index 756ea0f9..a9cd3ccc 100644 --- a/style/src/container.rs +++ b/style/src/container.rs @@ -12,6 +12,12 @@ pub struct Style { /// A set of rules that dictate the style of a container. pub trait StyleSheet { /// Produces the style of a container. + fn style(&self) -> Style; +} + +struct Default; + +impl StyleSheet for Default { fn style(&self) -> Style { Style { text_color: None, @@ -21,10 +27,6 @@ pub trait StyleSheet { } } -struct Default; - -impl StyleSheet for Default {} - impl std::default::Default for Box { fn default() -> Self { Box::new(Default) diff --git a/style/src/lib.rs b/style/src/lib.rs index c6f34301..1d7e57c4 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -1,2 +1,3 @@ pub mod button; pub mod container; +pub mod text_input; diff --git a/style/src/text_input.rs b/style/src/text_input.rs new file mode 100644 index 00000000..75f427a7 --- /dev/null +++ b/style/src/text_input.rs @@ -0,0 +1,72 @@ +//! Display fields that can be filled with text. +use iced_core::{Background, Color}; + +/// The appearance of a text input. +#[derive(Debug, Clone, Copy)] +pub struct Style { + pub background: Background, + pub border_radius: u16, + pub border_width: u16, + pub border_color: Color, +} + +/// A set of rules that dictate the style of a text input. +pub trait StyleSheet { + /// Produces the style of an active text input. + fn active(&self) -> Style; + + /// Produces the style of a focused text input. + fn focused(&self) -> Style; + + /// Produces the style of an hovered text input. + fn hovered(&self) -> Style { + self.focused() + } + + fn placeholder_color(&self) -> Color; + + fn value_color(&self) -> Color; +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Style { + Style { + background: Background::Color(Color::WHITE), + border_radius: 5, + border_width: 1, + border_color: Color::from_rgb(0.7, 0.7, 0.7), + } + } + + fn focused(&self) -> Style { + Style { + border_color: Color::from_rgb(0.5, 0.5, 0.5), + ..self.active() + } + } + + fn placeholder_color(&self) -> Color { + Color::from_rgb(0.7, 0.7, 0.7) + } + + fn value_color(&self) -> Color { + Color::from_rgb(0.3, 0.3, 0.3) + } +} + +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/text_input.rs b/wgpu/src/renderer/widget/text_input.rs index cf3a31ab..8b774a48 100644 --- a/wgpu/src/renderer/widget/text_input.rs +++ b/wgpu/src/renderer/widget/text_input.rs @@ -1,4 +1,4 @@ -use crate::{Primitive, Renderer}; +use crate::{text_input::StyleSheet, Primitive, Renderer}; use iced_native::{ text_input, Background, Color, Font, HorizontalAlignment, MouseCursor, @@ -7,6 +7,8 @@ use iced_native::{ use std::f32; impl text_input::Renderer for Renderer { + type Style = Box; + fn default_size(&self) -> u16 { // TODO: Make this configurable 20 @@ -61,20 +63,24 @@ impl text_input::Renderer for Renderer { placeholder: &str, value: &text_input::Value, state: &text_input::State, + style_sheet: &Self::Style, ) -> Self::Output { let is_mouse_over = bounds.contains(cursor_position); + let style = if state.is_focused() { + style_sheet.focused() + } else if is_mouse_over { + style_sheet.hovered() + } else { + style_sheet.active() + }; + let input = Primitive::Quad { bounds, - background: Background::Color(Color::WHITE), - border_radius: 5, - border_width: 1, - border_color: if is_mouse_over || state.is_focused() { - [0.5, 0.5, 0.5] - } else { - [0.7, 0.7, 0.7] - } - .into(), + background: style.background, + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, }; let text = value.to_string(); @@ -86,9 +92,9 @@ impl text_input::Renderer for Renderer { text.clone() }, color: if text.is_empty() { - [0.7, 0.7, 0.7] + style_sheet.placeholder_color() } else { - [0.3, 0.3, 0.3] + style_sheet.value_color() } .into(), font: Font::Default, @@ -117,7 +123,7 @@ impl text_input::Renderer for Renderer { width: 1.0, height: text_bounds.height, }, - background: Background::Color(Color::BLACK), + background: Background::Color(style_sheet.value_color()), border_radius: 0, border_width: 0, border_color: Color::TRANSPARENT, diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index c6f34301..1d7e57c4 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,2 +1,3 @@ pub mod button; pub mod container; +pub mod text_input; diff --git a/wgpu/src/widget/text_input.rs b/wgpu/src/widget/text_input.rs new file mode 100644 index 00000000..260fe3a6 --- /dev/null +++ b/wgpu/src/widget/text_input.rs @@ -0,0 +1,15 @@ +//! Display fields that can be filled with text. +//! +//! A [`TextInput`] has some local [`State`]. +//! +//! [`TextInput`]: struct.TextInput.html +//! [`State`]: struct.State.html +use crate::Renderer; + +pub use iced_native::text_input::State; +pub use iced_style::text_input::{Style, StyleSheet}; + +/// A field that can be filled with text. +/// +/// This is an alias of an `iced_native` text input with an `iced_wgpu::Renderer`. +pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Renderer>; -- cgit From 8d6f86b317303c06a0daf1ca3ce91c29670dd674 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 5 Jan 2020 18:11:54 +0100 Subject: Remove `background` from `Settings` --- native/src/renderer/windowed.rs | 3 +-- src/settings.rs | 8 -------- wgpu/src/renderer.rs | 18 ++++++------------ winit/src/application.rs | 8 ++------ winit/src/settings/mod.rs | 6 ------ 5 files changed, 9 insertions(+), 34 deletions(-) diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs index 30e08cb8..c3266e6c 100644 --- a/native/src/renderer/windowed.rs +++ b/native/src/renderer/windowed.rs @@ -1,4 +1,4 @@ -use crate::{Color, MouseCursor}; +use crate::MouseCursor; use raw_window_handle::HasRawWindowHandle; @@ -21,7 +21,6 @@ pub trait Windowed: super::Renderer + Sized { /// top of the GUI on most scenarios. fn draw>( &mut self, - clear_color: Color, output: &Self::Output, overlay: &[T], target: &mut Self::Target, diff --git a/src/settings.rs b/src/settings.rs index b01e6fc8..b725ef9f 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,5 +1,4 @@ //! Configure your application. -use crate::Color; /// The settings of an application. #[derive(Debug, Clone, Copy, PartialEq)] @@ -11,11 +10,6 @@ pub struct Settings { /// [`Window`]: struct.Window.html pub window: Window, - /// The default background [`Color`] of the application - /// - /// [`Color`]: ../struct.Color.html - pub background: Color, - // TODO: Add `name` for web compatibility pub default_font: Option<&'static [u8]>, } @@ -24,7 +18,6 @@ impl Default for Settings { fn default() -> Settings { Settings { window: Window::default(), - background: Color::WHITE, default_font: None, } } @@ -63,7 +56,6 @@ impl From for iced_winit::Settings { decorations: settings.window.decorations, platform_specific: Default::default(), }, - background: settings.background, } } } diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 7f0f0b89..8f0b2020 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -80,7 +80,6 @@ impl Renderer { fn draw>( &mut self, - clear_color: Color, (primitive, mouse_cursor): &(Primitive, MouseCursor), overlay: &[T], target: &mut Target, @@ -102,15 +101,11 @@ impl Renderer { resolve_target: None, load_op: wgpu::LoadOp::Clear, store_op: wgpu::StoreOp::Store, - clear_color: { - let [r, g, b, a] = clear_color.into_linear(); - - wgpu::Color { - r: f64::from(r), - g: f64::from(g), - b: f64::from(b), - a: f64::from(a), - } + clear_color: wgpu::Color { + r: 1.0, + g: 1.0, + b: 1.0, + a: 1.0, }, }], depth_stencil_attachment: None, @@ -443,12 +438,11 @@ impl Windowed for Renderer { fn draw>( &mut self, - clear_color: Color, output: &Self::Output, overlay: &[T], target: &mut Target, ) -> MouseCursor { - self.draw(clear_color, output, overlay, target) + self.draw(output, overlay, target) } } diff --git a/winit/src/application.rs b/winit/src/application.rs index d16c209c..da943660 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -281,12 +281,8 @@ pub trait Application: Sized { resized = false; } - let new_mouse_cursor = renderer.draw( - settings.background, - &primitive, - &debug.overlay(), - &mut target, - ); + let new_mouse_cursor = + renderer.draw(&primitive, &debug.overlay(), &mut target); debug.render_finished(); diff --git a/winit/src/settings/mod.rs b/winit/src/settings/mod.rs index 0384df32..b2290b46 100644 --- a/winit/src/settings/mod.rs +++ b/winit/src/settings/mod.rs @@ -1,6 +1,4 @@ //! Configure your application. -use crate::Color; - #[cfg(target_os = "windows")] #[path = "windows.rs"] mod platform; @@ -17,16 +15,12 @@ pub struct Settings { /// /// [`Window`]: struct.Window.html pub window: Window, - - /// The default background color of the application - pub background: Color, } impl Default for Settings { fn default() -> Settings { Settings { window: Window::default(), - background: Color::WHITE, } } } -- cgit From 2116fbb3c2412030a676c60d65784b9dfa467a0a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 5 Jan 2020 18:38:03 +0100 Subject: Add border styling to `Container` --- style/src/container.rs | 4 ++++ wgpu/src/renderer/widget/container.rs | 37 ++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/style/src/container.rs b/style/src/container.rs index a9cd3ccc..484fdfda 100644 --- a/style/src/container.rs +++ b/style/src/container.rs @@ -7,6 +7,8 @@ pub struct Style { pub text_color: Option, pub background: Option, pub border_radius: u16, + pub border_width: u16, + pub border_color: Color, } /// A set of rules that dictate the style of a container. @@ -23,6 +25,8 @@ impl StyleSheet for Default { text_color: None, background: None, border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, } } } diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs index 18908571..2d4d1db8 100644 --- a/wgpu/src/renderer/widget/container.rs +++ b/wgpu/src/renderer/widget/container.rs @@ -1,5 +1,5 @@ use crate::{container, defaults, Defaults, Primitive, Renderer}; -use iced_native::{Color, Element, Layout, Point, Rectangle}; +use iced_native::{Background, Color, Element, Layout, Point, Rectangle}; impl iced_native::container::Renderer for Renderer { type Style = Box; @@ -25,24 +25,25 @@ impl iced_native::container::Renderer for Renderer { let (content, mouse_cursor) = content.draw(self, &defaults, content_layout, cursor_position); - match style.background { - Some(background) => { - let quad = Primitive::Quad { - bounds, - background, - border_radius: style.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, - }; + if style.background.is_some() || style.border_width > 0 { + let quad = Primitive::Quad { + bounds, + background: style + .background + .unwrap_or(Background::Color(Color::TRANSPARENT)), + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, + }; - ( - Primitive::Group { - primitives: vec![quad, content], - }, - mouse_cursor, - ) - } - None => (content, mouse_cursor), + ( + Primitive::Group { + primitives: vec![quad, content], + }, + mouse_cursor, + ) + } else { + (content, mouse_cursor) } } } -- cgit From 1a0effa961344677daf17b4192243423a154f1bf Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 5 Jan 2020 19:29:12 +0100 Subject: Add border and shadow styling to `Button` --- core/src/vector.rs | 12 ++++++++++++ examples/pokedex.rs | 5 +++-- examples/stopwatch.rs | 5 +++-- examples/todos.rs | 20 +++++++------------- examples/tour.rs | 9 +++++---- src/native.rs | 2 +- style/src/button.rs | 29 +++++++++++++++++++++++------ wgpu/src/renderer/widget/button.rs | 8 ++++---- 8 files changed, 58 insertions(+), 32 deletions(-) diff --git a/core/src/vector.rs b/core/src/vector.rs index 7d87343a..1c09ee3e 100644 --- a/core/src/vector.rs +++ b/core/src/vector.rs @@ -31,3 +31,15 @@ where Self::new(self.x + b.x, self.y + b.y) } } + +impl Default for Vector +where + T: Default, +{ + fn default() -> Self { + Self { + x: T::default(), + y: T::default(), + } + } +} diff --git a/examples/pokedex.rs b/examples/pokedex.rs index 35d38251..2a696ffe 100644 --- a/examples/pokedex.rs +++ b/examples/pokedex.rs @@ -225,7 +225,7 @@ fn button<'a>(state: &'a mut button::State, text: &str) -> Button<'a, Message> { } mod style { - use iced::{button, Background, Color}; + use iced::{button, Background, Color, Vector}; pub enum Button { Primary, @@ -238,8 +238,9 @@ mod style { Button::Primary => Color::from_rgb(0.11, 0.42, 0.87), })), border_radius: 12, - shadow_offset: 1.0, + shadow_offset: Vector::new(1.0, 1.0), text_color: Color::WHITE, + ..button::Style::default() } } } diff --git a/examples/stopwatch.rs b/examples/stopwatch.rs index 99746609..9b69f7ca 100644 --- a/examples/stopwatch.rs +++ b/examples/stopwatch.rs @@ -180,7 +180,7 @@ mod time { } mod style { - use iced::{button, Background, Color}; + use iced::{button, Background, Color, Vector}; pub enum Button { Primary, @@ -197,8 +197,9 @@ mod style { Button::Destructive => Color::from_rgb(0.8, 0.2, 0.2), })), border_radius: 12, - shadow_offset: 1.0, + shadow_offset: Vector::new(1.0, 1.0), text_color: Color::WHITE, + ..button::Style::default() } } } diff --git a/examples/todos.rs b/examples/todos.rs index ca20183f..1563aad5 100644 --- a/examples/todos.rs +++ b/examples/todos.rs @@ -551,7 +551,7 @@ impl SavedState { } mod style { - use iced::{button, Background, Color}; + use iced::{button, Background, Color, Vector}; pub enum Button { Filter { selected: bool }, @@ -569,31 +569,25 @@ mod style { Color::from_rgb(0.2, 0.2, 0.7), )), border_radius: 10, - shadow_offset: 0.0, text_color: Color::WHITE, + ..button::Style::default() } } else { - button::Style { - background: None, - border_radius: 0, - shadow_offset: 0.0, - text_color: Color::BLACK, - } + button::Style::default() } } Button::Icon => button::Style { - background: None, - border_radius: 0, - shadow_offset: 0.0, text_color: Color::from_rgb(0.5, 0.5, 0.5), + ..button::Style::default() }, Button::Destructive => button::Style { background: Some(Background::Color(Color::from_rgb( 0.8, 0.2, 0.2, ))), border_radius: 5, - shadow_offset: 1.0, text_color: Color::WHITE, + shadow_offset: Vector::new(1.0, 1.0), + ..button::Style::default() }, } } @@ -609,7 +603,7 @@ mod style { } _ => active.text_color, }, - shadow_offset: active.shadow_offset + 1.0, + shadow_offset: active.shadow_offset + Vector::new(0.0, 1.0), ..active } } diff --git a/examples/tour.rs b/examples/tour.rs index d006d397..84e5d516 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -27,7 +27,7 @@ impl Sandbox for Tour { scroll: scrollable::State::new(), back_button: button::State::new(), next_button: button::State::new(), - debug: true, + debug: false, } } @@ -743,7 +743,7 @@ pub enum Layout { } mod style { - use iced::{button, Background, Color}; + use iced::{button, Background, Color, Vector}; pub enum Button { Primary, @@ -758,15 +758,16 @@ mod style { Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5), })), border_radius: 12, - shadow_offset: 1.0, + shadow_offset: Vector::new(1.0, 1.0), text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE), + ..button::Style::default() } } fn hovered(&self) -> button::Style { button::Style { text_color: Color::WHITE, - shadow_offset: 2.0, + shadow_offset: Vector::new(1.0, 2.0), ..self.active() } } diff --git a/src/native.rs b/src/native.rs index 3535ab6a..b7becdc8 100644 --- a/src/native.rs +++ b/src/native.rs @@ -1,6 +1,6 @@ pub use iced_winit::{ Align, Background, Color, Command, Font, HorizontalAlignment, Length, - Space, Subscription, VerticalAlignment, + Space, Subscription, Vector, VerticalAlignment, }; pub mod widget { diff --git a/style/src/button.rs b/style/src/button.rs index 42286897..4a9dac45 100644 --- a/style/src/button.rs +++ b/style/src/button.rs @@ -1,15 +1,30 @@ //! Allow your users to perform actions by pressing a button. -use iced_core::{Background, Color}; +use iced_core::{Background, Color, Vector}; /// The appearance of a button. #[derive(Debug)] pub struct Style { - pub shadow_offset: f32, + pub shadow_offset: Vector, pub background: Option, pub border_radius: u16, + pub border_width: u16, + pub border_color: Color, pub text_color: Color, } +impl std::default::Default for Style { + fn default() -> Self { + Style { + shadow_offset: Vector::default(), + background: None, + border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, + text_color: Color::BLACK, + } + } +} + /// A set of rules that dictate the style of a button. pub trait StyleSheet { fn active(&self) -> Style; @@ -18,14 +33,14 @@ pub trait StyleSheet { let active = self.active(); Style { - shadow_offset: active.shadow_offset + 1.0, + shadow_offset: active.shadow_offset + Vector::new(0.0, 1.0), ..active } } fn pressed(&self) -> Style { Style { - shadow_offset: 0.0, + shadow_offset: Vector::default(), ..self.active() } } @@ -34,7 +49,7 @@ pub trait StyleSheet { let active = self.active(); Style { - shadow_offset: 0.0, + shadow_offset: Vector::default(), background: active.background.map(|background| match background { Background::Color(color) => Background::Color(Color { a: color.a * 0.5, @@ -55,9 +70,11 @@ struct Default; impl StyleSheet for Default { fn active(&self) -> Style { Style { - shadow_offset: 1.0, + shadow_offset: Vector::new(0.0, 1.0), background: Some(Background::Color([0.5, 0.5, 0.5].into())), border_radius: 5, + border_width: 0, + border_color: Color::TRANSPARENT, text_color: Color::BLACK, } } diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index d00a43a5..63a53473 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -51,8 +51,8 @@ impl iced_native::button::Renderer for Renderer { primitives: vec![ Primitive::Quad { bounds: Rectangle { - x: bounds.x + 1.0, - y: bounds.y + styling.shadow_offset, + x: bounds.x + styling.shadow_offset.x, + y: bounds.y + styling.shadow_offset.y, ..bounds }, background: Background::Color( @@ -66,8 +66,8 @@ impl iced_native::button::Renderer for Renderer { bounds, background, border_radius: styling.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, + border_width: styling.border_width, + border_color: styling.border_color, }, content, ], -- cgit From 07ef59af78107db103b7a9640a660ecae95b1156 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 5 Jan 2020 19:34:38 +0100 Subject: Implement `Default` for `container::Style` --- style/src/button.rs | 2 +- style/src/container.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/style/src/button.rs b/style/src/button.rs index 4a9dac45..03c9ab32 100644 --- a/style/src/button.rs +++ b/style/src/button.rs @@ -14,7 +14,7 @@ pub struct Style { impl std::default::Default for Style { fn default() -> Self { - Style { + Self { shadow_offset: Vector::default(), background: None, border_radius: 0, diff --git a/style/src/container.rs b/style/src/container.rs index 484fdfda..d2247342 100644 --- a/style/src/container.rs +++ b/style/src/container.rs @@ -11,6 +11,18 @@ pub struct Style { pub border_color: Color, } +impl std::default::Default for Style { + fn default() -> Self { + Self { + text_color: None, + background: None, + border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, + } + } +} + /// A set of rules that dictate the style of a container. pub trait StyleSheet { /// Produces the style of a container. -- cgit From 7c4dba29c7614428041bda049924569d751cbb1a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 5 Jan 2020 19:36:44 +0100 Subject: Implement `Default` for `text_input::Style` --- style/src/text_input.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/style/src/text_input.rs b/style/src/text_input.rs index 75f427a7..269b28db 100644 --- a/style/src/text_input.rs +++ b/style/src/text_input.rs @@ -10,6 +10,17 @@ pub struct Style { pub border_color: Color, } +impl std::default::Default for Style { + fn default() -> Self { + Self { + background: Background::Color(Color::WHITE), + border_radius: 0, + border_width: 0, + border_color: Color::TRANSPARENT, + } + } +} + /// A set of rules that dictate the style of a text input. pub trait StyleSheet { /// Produces the style of an active text input. -- cgit From a848306b89053ef4ba2aeb4eb7899bec94d93cb3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 5 Jan 2020 19:48:27 +0100 Subject: Fix styling in `button::Renderer` implementation --- wgpu/src/renderer/widget/button.rs | 64 ++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index 63a53473..eb5d7c09 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -1,6 +1,6 @@ use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer}; use iced_native::{ - Background, Color, Element, Layout, MouseCursor, Point, Rectangle, + Background, Color, Element, Layout, MouseCursor, Point, Rectangle, Vector, }; impl iced_native::button::Renderer for Renderer { @@ -45,33 +45,43 @@ impl iced_native::button::Renderer for Renderer { ); ( - match styling.background { - None => content, - Some(background) => Primitive::Group { - primitives: vec![ - Primitive::Quad { - bounds: Rectangle { - x: bounds.x + styling.shadow_offset.x, - y: bounds.y + styling.shadow_offset.y, - ..bounds - }, - background: Background::Color( - [0.0, 0.0, 0.0, 0.5].into(), - ), - border_radius: styling.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, - }, - Primitive::Quad { - bounds, - background, - border_radius: styling.border_radius, - border_width: styling.border_width, - border_color: styling.border_color, + if styling.background.is_some() || styling.border_width > 0 { + let background = Primitive::Quad { + bounds, + background: styling + .background + .unwrap_or(Background::Color(Color::TRANSPARENT)), + border_radius: styling.border_radius, + border_width: styling.border_width, + border_color: styling.border_color, + }; + + if styling.shadow_offset == Vector::default() { + Primitive::Group { + primitives: vec![background, content], + } + } else { + // TODO: Implement proper shadow support + let shadow = Primitive::Quad { + bounds: Rectangle { + x: bounds.x + styling.shadow_offset.x, + y: bounds.y + styling.shadow_offset.y, + ..bounds }, - content, - ], - }, + background: Background::Color( + [0.0, 0.0, 0.0, 0.5].into(), + ), + border_radius: styling.border_radius, + border_width: 0, + border_color: Color::TRANSPARENT, + }; + + Primitive::Group { + primitives: vec![shadow, background, content], + } + } + } else { + content }, if is_mouse_over { MouseCursor::Pointer -- cgit From 2bbd395d5dcdf9c92ffb354b8b05444478e4b344 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 6 Jan 2020 18:44:45 +0100 Subject: Draft `styling` example --- core/src/vector.rs | 11 ++ examples/styling.rs | 282 +++++++++++++++++++++++++++++++++++++ style/src/button.rs | 2 +- style/src/text_input.rs | 8 +- wgpu/src/renderer/widget/button.rs | 1 - 5 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 examples/styling.rs diff --git a/core/src/vector.rs b/core/src/vector.rs index 1c09ee3e..75c77dbd 100644 --- a/core/src/vector.rs +++ b/core/src/vector.rs @@ -32,6 +32,17 @@ where } } +impl std::ops::Mul for Vector +where + T: std::ops::Mul, +{ + type Output = Self; + + fn mul(self, b: Self) -> Self { + Self::new(self.x * b.x, self.y * b.y) + } +} + impl Default for Vector where T: Default, diff --git a/examples/styling.rs b/examples/styling.rs new file mode 100644 index 00000000..95590f2c --- /dev/null +++ b/examples/styling.rs @@ -0,0 +1,282 @@ +use iced::{ + button, text_input, Button, Column, Container, Element, Length, Radio, Row, + Sandbox, Settings, Text, TextInput, +}; + +pub fn main() { + Styling::run(Settings::default()) +} + +struct Styling { + theme: style::Theme, + input: text_input::State, + input_value: String, + button: button::State, +} + +#[derive(Debug, Clone)] +enum Message { + ThemeChanged(style::Theme), + InputChanged(String), + ButtonPressed, +} + +impl Sandbox for Styling { + type Message = Message; + + fn new() -> Self { + Styling { + theme: style::Theme::Light, + input: text_input::State::default(), + input_value: String::new(), + button: button::State::default(), + } + } + + fn title(&self) -> String { + String::from("Styling - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::ThemeChanged(theme) => self.theme = theme, + Message::InputChanged(value) => self.input_value = value, + Message::ButtonPressed => (), + } + } + + fn view(&mut self) -> Element { + let choose_theme = style::Theme::ALL.iter().fold( + Column::new() + .width(Length::Shrink) + .spacing(10) + .push(Text::new("Choose a theme:").width(Length::Shrink)), + |column, theme| { + column.push(Radio::new( + *theme, + &format!("{:?}", theme), + Some(self.theme), + Message::ThemeChanged, + )) + }, + ); + + let text_input = TextInput::new( + &mut self.input, + "Type something...", + &self.input_value, + Message::InputChanged, + ) + .padding(10) + .size(20) + .style(self.theme); + + let button = Button::new(&mut self.button, Text::new("Submit")) + .padding(10) + .on_press(Message::ButtonPressed) + .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)); + + Container::new(content) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .style(self.theme) + .into() + } +} + +mod style { + use iced::{button, container, text_input}; + + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub enum Theme { + Light, + Dark, + } + + impl Theme { + pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark]; + } + + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => light::Container.into(), + Theme::Dark => dark::Container.into(), + } + } + } + + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => light::TextInput.into(), + Theme::Dark => dark::TextInput.into(), + } + } + } + + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => light::Button.into(), + Theme::Dark => dark::Button.into(), + } + } + } + + mod light { + use iced::{button, container, text_input, Background, Color, Vector}; + + pub struct Container; + + impl container::StyleSheet for Container { + fn style(&self) -> container::Style { + container::Style::default() + } + } + + pub struct TextInput; + + impl text_input::StyleSheet for TextInput { + fn active(&self) -> text_input::Style { + text_input::Style { + background: Background::Color(Color::WHITE), + border_radius: 5, + border_width: 1, + border_color: Color::from_rgb(0.7, 0.7, 0.7), + } + } + + fn focused(&self) -> text_input::Style { + text_input::Style { + border_width: 1, + border_color: Color::from_rgb(0.5, 0.5, 0.5), + ..self.active() + } + } + + fn placeholder_color(&self) -> Color { + Color::from_rgb(0.7, 0.7, 0.7) + } + + fn value_color(&self) -> Color { + Color::from_rgb(0.3, 0.3, 0.3) + } + } + + pub struct Button; + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + button::Style { + background: Some(Background::Color(Color::from_rgb( + 0.11, 0.42, 0.87, + ))), + border_radius: 12, + shadow_offset: Vector::new(1.0, 1.0), + text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE), + ..button::Style::default() + } + } + + fn hovered(&self) -> button::Style { + button::Style { + text_color: Color::WHITE, + shadow_offset: Vector::new(1.0, 2.0), + ..self.active() + } + } + } + } + + mod dark { + use iced::{button, container, text_input, Background, Color}; + + pub struct Container; + + impl container::StyleSheet for Container { + fn style(&self) -> container::Style { + container::Style { + background: Some(Background::Color(Color::from_rgb8( + 0x36, 0x39, 0x3F, + ))), + text_color: Some(Color::WHITE), + ..container::Style::default() + } + } + } + + pub struct TextInput; + + impl text_input::StyleSheet for TextInput { + fn active(&self) -> text_input::Style { + text_input::Style { + background: Background::Color(Color::from_rgb8( + 0x40, 0x44, 0x4B, + )), + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + } + } + + fn focused(&self) -> text_input::Style { + text_input::Style { + border_width: 1, + border_color: Color::from_rgb8(0x6F, 0xFF, 0xE9), + ..self.active() + } + } + + fn hovered(&self) -> text_input::Style { + text_input::Style { + border_width: 1, + border_color: Color::from_rgb8(0x5B, 0xC0, 0xBE), + ..self.focused() + } + } + + fn placeholder_color(&self) -> Color { + Color::from_rgb(0.7, 0.7, 0.7) + } + + fn value_color(&self) -> Color { + Color::WHITE + } + } + + pub struct Button; + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + button::Style { + background: Some(Background::Color(Color::from_rgb8( + 0x72, 0x89, 0xDA, + ))), + border_radius: 3, + text_color: Color::WHITE, + ..button::Style::default() + } + } + + fn hovered(&self) -> button::Style { + button::Style { + background: Some(Background::Color(Color::from_rgb8( + 0x67, 0x7B, 0xC4, + ))), + text_color: Color::WHITE, + ..self.active() + } + } + } + } +} diff --git a/style/src/button.rs b/style/src/button.rs index 03c9ab32..93c27860 100644 --- a/style/src/button.rs +++ b/style/src/button.rs @@ -75,7 +75,7 @@ impl StyleSheet for Default { border_radius: 5, border_width: 0, border_color: Color::TRANSPARENT, - text_color: Color::BLACK, + text_color: Color::WHITE, } } } diff --git a/style/src/text_input.rs b/style/src/text_input.rs index 269b28db..c5123b20 100644 --- a/style/src/text_input.rs +++ b/style/src/text_input.rs @@ -29,14 +29,14 @@ pub trait StyleSheet { /// Produces the style of a focused text input. fn focused(&self) -> Style; + fn placeholder_color(&self) -> Color; + + fn value_color(&self) -> Color; + /// Produces the style of an hovered text input. fn hovered(&self) -> Style { self.focused() } - - fn placeholder_color(&self) -> Color; - - fn value_color(&self) -> Color; } struct Default; diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index eb5d7c09..a9209f64 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -19,7 +19,6 @@ impl iced_native::button::Renderer for Renderer { ) -> Self::Output { let is_mouse_over = bounds.contains(cursor_position); - // TODO: Render proper shadows let styling = if is_disabled { style.disabled() } else if is_mouse_over { -- cgit From fbc25f8d3d94be148663dbbe1de6ceb9c162b308 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 6 Jan 2020 18:46:47 +0100 Subject: Implement `Default` for `Theme` in `styling` example --- examples/styling.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/styling.rs b/examples/styling.rs index 95590f2c..9f8cc53f 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -7,6 +7,7 @@ pub fn main() { Styling::run(Settings::default()) } +#[derive(Default)] struct Styling { theme: style::Theme, input: text_input::State, @@ -25,12 +26,7 @@ impl Sandbox for Styling { type Message = Message; fn new() -> Self { - Styling { - theme: style::Theme::Light, - input: text_input::State::default(), - input_value: String::new(), - button: button::State::default(), - } + Styling::default() } fn title(&self) -> String { @@ -106,6 +102,12 @@ mod style { pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark]; } + impl Default for Theme { + fn default() -> Theme { + Theme::Light + } + } + impl From for Box { fn from(theme: Theme) -> Self { match theme { -- cgit From f7dfd6537429f94af63d75617c27bc998d72d9c8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 6 Jan 2020 19:05:00 +0100 Subject: Use default styles in `styling` example --- examples/styling.rs | 48 ++++-------------------------------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/examples/styling.rs b/examples/styling.rs index 9f8cc53f..c368ea07 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -43,10 +43,7 @@ impl Sandbox for Styling { fn view(&mut self) -> Element { let choose_theme = style::Theme::ALL.iter().fold( - Column::new() - .width(Length::Shrink) - .spacing(10) - .push(Text::new("Choose a theme:").width(Length::Shrink)), + Column::new().spacing(10).push(Text::new("Choose a theme:")), |column, theme| { column.push(Radio::new( *theme, @@ -111,7 +108,7 @@ mod style { impl From for Box { fn from(theme: Theme) -> Self { match theme { - Theme::Light => light::Container.into(), + Theme::Light => Default::default(), Theme::Dark => dark::Container.into(), } } @@ -120,7 +117,7 @@ mod style { impl From for Box { fn from(theme: Theme) -> Self { match theme { - Theme::Light => light::TextInput.into(), + Theme::Light => Default::default(), Theme::Dark => dark::TextInput.into(), } } @@ -136,44 +133,7 @@ mod style { } mod light { - use iced::{button, container, text_input, Background, Color, Vector}; - - pub struct Container; - - impl container::StyleSheet for Container { - fn style(&self) -> container::Style { - container::Style::default() - } - } - - pub struct TextInput; - - impl text_input::StyleSheet for TextInput { - fn active(&self) -> text_input::Style { - text_input::Style { - background: Background::Color(Color::WHITE), - border_radius: 5, - border_width: 1, - border_color: Color::from_rgb(0.7, 0.7, 0.7), - } - } - - fn focused(&self) -> text_input::Style { - text_input::Style { - border_width: 1, - border_color: Color::from_rgb(0.5, 0.5, 0.5), - ..self.active() - } - } - - fn placeholder_color(&self) -> Color { - Color::from_rgb(0.7, 0.7, 0.7) - } - - fn value_color(&self) -> Color { - Color::from_rgb(0.3, 0.3, 0.3) - } - } + use iced::{button, Background, Color, Vector}; pub struct Button; -- cgit From d0dc7cebf9c352f4d14827fe47489788f59e61a1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 6 Jan 2020 21:01:09 +0100 Subject: Implement styling for `Scrollable` --- examples/styling.rs | 63 +++++++++++++++++++++++++--- native/src/renderer/null.rs | 3 ++ native/src/widget/scrollable.rs | 24 ++++++++--- src/native.rs | 14 ------- style/src/lib.rs | 1 + style/src/scrollable.rs | 76 ++++++++++++++++++++++++++++++++++ wgpu/src/renderer/widget/scrollable.rs | 33 +++++++++------ wgpu/src/widget.rs | 1 + wgpu/src/widget/scrollable.rs | 13 ++++++ 9 files changed, 191 insertions(+), 37 deletions(-) create mode 100644 style/src/scrollable.rs create mode 100644 wgpu/src/widget/scrollable.rs diff --git a/examples/styling.rs b/examples/styling.rs index c368ea07..61c8bcba 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -1,6 +1,6 @@ use iced::{ - button, text_input, Button, Column, Container, Element, Length, Radio, Row, - Sandbox, Settings, Text, TextInput, + button, scrollable, text_input, Button, Column, Container, Element, Length, + Radio, Row, Sandbox, Scrollable, Settings, Text, TextInput, }; pub fn main() { @@ -10,6 +10,7 @@ pub fn main() { #[derive(Default)] struct Styling { theme: style::Theme, + scroll: scrollable::State, input: text_input::State, input_value: String, button: button::State, @@ -76,10 +77,13 @@ impl Sandbox for Styling { .push(choose_theme) .push(Row::new().spacing(10).push(text_input).push(button)); - Container::new(content) + let scrollable = Scrollable::new(&mut self.scroll) + .style(self.theme) + .push(Container::new(content).width(Length::Fill).center_x()); + + Container::new(scrollable) .width(Length::Fill) .height(Length::Fill) - .center_x() .center_y() .style(self.theme) .into() @@ -87,7 +91,7 @@ impl Sandbox for Styling { } mod style { - use iced::{button, container, text_input}; + use iced::{button, container, scrollable, text_input}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Theme { @@ -132,6 +136,15 @@ mod style { } } + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Scrollable.into(), + } + } + } + mod light { use iced::{button, Background, Color, Vector}; @@ -161,7 +174,9 @@ mod style { } mod dark { - use iced::{button, container, text_input, Background, Color}; + use iced::{ + button, container, scrollable, text_input, Background, Color, + }; pub struct Container; @@ -239,6 +254,42 @@ mod style { ..self.active() } } + + fn pressed(&self) -> button::Style { + button::Style { + border_width: 1, + border_color: Color::WHITE, + ..self.hovered() + } + } + } + + pub struct Scrollable; + + impl scrollable::StyleSheet for Scrollable { + fn active(&self) -> scrollable::Scrollbar { + scrollable::Scrollbar { + background: None, + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + scroller: scrollable::Scroller { + color: [1.0, 1.0, 1.0, 0.7].into(), + border_radius: 2, + border_width: 1, + border_color: Color::WHITE, + }, + } + } + + fn hovered(&self) -> scrollable::Scrollbar { + scrollable::Scrollbar { + background: Some(Background::Color( + [1.0, 1.0, 1.0, 0.3].into(), + )), + ..self.active() + } + } } } } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 96aa132c..0184ac00 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -73,6 +73,8 @@ impl text::Renderer for Null { } impl scrollable::Renderer for Null { + type Style = (); + fn scrollbar( &self, _bounds: Rectangle, @@ -91,6 +93,7 @@ impl scrollable::Renderer for Null { _is_mouse_over_scrollbar: bool, _scrollbar: Option, _offset: u32, + _style: &Self::Style, _content: Self::Output, ) { } diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 9df09b14..a062abd0 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -11,14 +11,15 @@ use std::{f32, hash::Hash, u32}; /// A widget that can vertically display an infinite amount of content with a /// scrollbar. #[allow(missing_debug_implementations)] -pub struct Scrollable<'a, Message, Renderer> { +pub struct Scrollable<'a, Message, Renderer: self::Renderer> { state: &'a mut State, height: Length, max_height: u32, content: Column<'a, Message, Renderer>, + style: Renderer::Style, } -impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> { +impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> { /// Creates a new [`Scrollable`] with the given [`State`]. /// /// [`Scrollable`]: struct.Scrollable.html @@ -29,6 +30,7 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> { height: Length::Shrink, max_height: u32::MAX, content: Column::new(), + style: Renderer::Style::default(), } } @@ -90,6 +92,14 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> { self } + /// Sets the style of the [`Scrollable`] . + /// + /// [`Scrollable`]: struct.Scrollable.html + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } + /// Adds an element to the [`Scrollable`]. /// /// [`Scrollable`]: struct.Scrollable.html @@ -105,7 +115,7 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> { impl<'a, Message, Renderer> Widget for Scrollable<'a, Message, Renderer> where - Renderer: self::Renderer + column::Renderer, + Renderer: 'static + self::Renderer + column::Renderer, { fn width(&self) -> Length { Length::Fill @@ -295,12 +305,13 @@ where is_mouse_over_scrollbar, scrollbar, offset, + &self.style, content, ) } fn hash_layout(&self, state: &mut Hasher) { - std::any::TypeId::of::>().hash(state); + std::any::TypeId::of::>().hash(state); self.height.hash(state); self.max_height.hash(state); @@ -447,6 +458,8 @@ pub struct Scroller { /// [`Scrollable`]: struct.Scrollable.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { + type Style: Default; + /// Returns the [`Scrollbar`] given the bounds and content bounds of a /// [`Scrollable`]. /// @@ -483,6 +496,7 @@ pub trait Renderer: crate::Renderer + Sized { is_mouse_over_scrollbar: bool, scrollbar: Option, offset: u32, + style: &Self::Style, content: Self::Output, ) -> Self::Output; } @@ -490,7 +504,7 @@ pub trait Renderer: crate::Renderer + Sized { impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: 'a + self::Renderer + column::Renderer, + Renderer: 'static + self::Renderer + column::Renderer, Message: 'static, { fn from( diff --git a/src/native.rs b/src/native.rs index 67f85c20..1061a730 100644 --- a/src/native.rs +++ b/src/native.rs @@ -24,20 +24,6 @@ pub mod widget { //! [`text_input::State`]: text_input/struct.State.html pub use iced_wgpu::widget::*; - pub mod scrollable { - //! Navigate an endless amount of content with a scrollbar. - - /// A widget that can vertically display an infinite amount of content - /// with a scrollbar. - /// - /// This is an alias of an `iced_native` scrollable with a default - /// `Renderer`. - pub type Scrollable<'a, Message> = - iced_winit::Scrollable<'a, Message, iced_wgpu::Renderer>; - - pub use iced_winit::scrollable::State; - } - pub mod slider { //! Display an interactive selector of a single value from a range of //! values. diff --git a/style/src/lib.rs b/style/src/lib.rs index 1d7e57c4..fb90b2b5 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -1,3 +1,4 @@ pub mod button; pub mod container; +pub mod scrollable; pub mod text_input; diff --git a/style/src/scrollable.rs b/style/src/scrollable.rs new file mode 100644 index 00000000..690c14a2 --- /dev/null +++ b/style/src/scrollable.rs @@ -0,0 +1,76 @@ +//! Navigate an endless amount of content with a scrollbar. +use iced_core::{Background, Color}; + +/// The appearance of a scrollable. +#[derive(Debug, Clone, Copy)] +pub struct Scrollbar { + pub background: Option, + pub border_radius: u16, + pub border_width: u16, + pub border_color: Color, + pub scroller: Scroller, +} + +/// The appearance of the scroller of a scrollable. +#[derive(Debug, Clone, Copy)] +pub struct Scroller { + pub color: Color, + pub border_radius: u16, + pub border_width: u16, + pub border_color: Color, +} + +/// A set of rules that dictate the style of a scrollable. +pub trait StyleSheet { + /// Produces the style of an active scrollbar. + fn active(&self) -> Scrollbar; + + /// Produces the style of an hovered scrollbar. + fn hovered(&self) -> Scrollbar; + + /// Produces the style of a scrollbar that is being dragged. + fn dragging(&self) -> Scrollbar { + self.hovered() + } +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Scrollbar { + Scrollbar { + background: None, + border_radius: 5, + border_width: 0, + border_color: Color::TRANSPARENT, + scroller: Scroller { + color: [0.0, 0.0, 0.0, 0.7].into(), + border_radius: 5, + border_width: 0, + border_color: Color::TRANSPARENT, + }, + } + } + + fn hovered(&self) -> Scrollbar { + Scrollbar { + background: Some(Background::Color([0.0, 0.0, 0.0, 0.3].into())), + ..self.active() + } + } +} + +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/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs index 42a4a743..30d7f337 100644 --- a/wgpu/src/renderer/widget/scrollable.rs +++ b/wgpu/src/renderer/widget/scrollable.rs @@ -7,6 +7,8 @@ const SCROLLBAR_WIDTH: u16 = 10; const SCROLLBAR_MARGIN: u16 = 2; impl scrollable::Renderer for Renderer { + type Style = Box; + fn scrollbar( &self, bounds: Rectangle, @@ -53,6 +55,7 @@ impl scrollable::Renderer for Renderer { is_mouse_over_scrollbar: bool, scrollbar: Option, offset: u32, + style_sheet: &Self::Style, (content, mouse_cursor): Self::Output, ) -> Self::Output { let clip = Primitive::Clip { @@ -64,17 +67,23 @@ impl scrollable::Renderer for Renderer { ( if let Some(scrollbar) = scrollbar { if is_mouse_over || state.is_scroller_grabbed() { + let style = if state.is_scroller_grabbed() { + style_sheet.dragging() + } else if is_mouse_over_scrollbar { + style_sheet.hovered() + } else { + style_sheet.active() + }; + let scroller = Primitive::Quad { bounds: scrollbar.scroller.bounds, - background: Background::Color( - [0.0, 0.0, 0.0, 0.7].into(), - ), - border_radius: 5, - border_width: 0, - border_color: Color::TRANSPARENT, + background: Background::Color(style.scroller.color), + border_radius: style.scroller.border_radius, + border_width: style.scroller.border_width, + border_color: style.scroller.border_color, }; - if is_mouse_over_scrollbar || state.is_scroller_grabbed() { + if style.background.is_some() || style.border_width > 0 { let scrollbar = Primitive::Quad { bounds: Rectangle { x: scrollbar.bounds.x @@ -83,12 +92,12 @@ impl scrollable::Renderer for Renderer { - f32::from(2 * SCROLLBAR_MARGIN), ..scrollbar.bounds }, - background: Background::Color( - [0.0, 0.0, 0.0, 0.3].into(), + background: style.background.unwrap_or( + Background::Color(Color::TRANSPARENT), ), - border_radius: 5, - border_width: 0, - border_color: Color::TRANSPARENT, + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, }; Primitive::Group { diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index 1d7e57c4..fb90b2b5 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,3 +1,4 @@ pub mod button; pub mod container; +pub mod scrollable; pub mod text_input; diff --git a/wgpu/src/widget/scrollable.rs b/wgpu/src/widget/scrollable.rs new file mode 100644 index 00000000..1d236105 --- /dev/null +++ b/wgpu/src/widget/scrollable.rs @@ -0,0 +1,13 @@ +//! Navigate an endless amount of content with a scrollbar. +use crate::Renderer; + +pub use iced_native::scrollable::State; +pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; + +/// A widget that can vertically display an infinite amount of content +/// with a scrollbar. +/// +/// This is an alias of an `iced_native` scrollable with a default +/// `Renderer`. +pub type Scrollable<'a, Message> = + iced_native::Scrollable<'a, Message, Renderer>; -- cgit From b329003c8fdcdc3378c8fda93af54be5686fc9ae Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 00:28:08 +0100 Subject: Implement styling for `Slider` --- examples/styling.rs | 75 ++++++++++++++++++++++++++++-- native/src/renderer/null.rs | 25 ++++++++-- native/src/widget/slider.rs | 32 ++++++++++--- src/native.rs | 11 ----- style/src/lib.rs | 1 + style/src/slider.rs | 95 ++++++++++++++++++++++++++++++++++++++ wgpu/src/renderer/widget/slider.rs | 57 ++++++++++++++--------- wgpu/src/widget.rs | 1 + wgpu/src/widget/slider.rs | 16 +++++++ 9 files changed, 266 insertions(+), 47 deletions(-) create mode 100644 style/src/slider.rs create mode 100644 wgpu/src/widget/slider.rs diff --git a/examples/styling.rs b/examples/styling.rs index 61c8bcba..b0cdbcf0 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -1,6 +1,6 @@ use iced::{ - button, scrollable, text_input, Button, Column, Container, Element, Length, - Radio, Row, Sandbox, Scrollable, Settings, Text, TextInput, + button, scrollable, slider, text_input, Button, Column, Container, Element, + Length, Radio, Row, Sandbox, Scrollable, Settings, Slider, Text, TextInput, }; pub fn main() { @@ -14,6 +14,8 @@ struct Styling { input: text_input::State, input_value: String, button: button::State, + slider: slider::State, + slider_value: f32, } #[derive(Debug, Clone)] @@ -21,6 +23,7 @@ enum Message { ThemeChanged(style::Theme), InputChanged(String), ButtonPressed, + SliderChanged(f32), } impl Sandbox for Styling { @@ -39,6 +42,7 @@ impl Sandbox for Styling { Message::ThemeChanged(theme) => self.theme = theme, Message::InputChanged(value) => self.input_value = value, Message::ButtonPressed => (), + Message::SliderChanged(value) => self.slider_value = value, } } @@ -70,12 +74,21 @@ impl Sandbox for Styling { .on_press(Message::ButtonPressed) .style(self.theme); + let slider = Slider::new( + &mut self.slider, + 0.0..=100.0, + self.slider_value, + Message::SliderChanged, + ) + .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(Row::new().spacing(10).push(text_input).push(button)) + .push(slider); let scrollable = Scrollable::new(&mut self.scroll) .style(self.theme) @@ -91,7 +104,7 @@ impl Sandbox for Styling { } mod style { - use iced::{button, container, scrollable, text_input}; + use iced::{button, container, scrollable, slider, text_input}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Theme { @@ -145,6 +158,15 @@ mod style { } } + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Slider.into(), + } + } + } + mod light { use iced::{button, Background, Color, Vector}; @@ -175,7 +197,8 @@ mod style { mod dark { use iced::{ - button, container, scrollable, text_input, Background, Color, + button, container, scrollable, slider, text_input, Background, + Color, }; pub struct Container; @@ -291,5 +314,47 @@ mod style { } } } + + pub struct Slider; + + impl slider::StyleSheet for Slider { + fn active(&self) -> slider::Style { + let blue = Color::from_rgb8(0x72, 0x89, 0xDA); + + slider::Style { + rail_colors: (blue, Color { a: 0.1, ..blue }), + handle: slider::Handle { + shape: slider::HandleShape::Circle { radius: 9 }, + color: blue, + border_width: 0, + border_color: Color::TRANSPARENT, + }, + } + } + + fn hovered(&self) -> slider::Style { + let active = self.active(); + + slider::Style { + handle: slider::Handle { + color: Color::from_rgb(0.90, 0.90, 0.90), + ..active.handle + }, + ..active + } + } + + fn dragging(&self) -> slider::Style { + let active = self.active(); + + slider::Style { + handle: slider::Handle { + color: Color::from_rgb(0.85, 0.85, 0.85), + ..active.handle + }, + ..active + } + } + } } } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 0184ac00..72f06a87 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, text, text_input, Color, - Element, Font, HorizontalAlignment, Layout, Point, Rectangle, Renderer, - Size, VerticalAlignment, + button, checkbox, column, radio, row, scrollable, slider, text, text_input, + Color, Element, Font, HorizontalAlignment, Layout, Point, Rectangle, + Renderer, Size, VerticalAlignment, }; /// A renderer that does nothing. @@ -180,3 +180,22 @@ impl checkbox::Renderer for Null { ) { } } + +impl slider::Renderer for Null { + type Style = (); + + fn height(&self) -> u32 { + 30 + } + + fn draw( + &mut self, + _bounds: Rectangle, + _cursor_position: Point, + _range: std::ops::RangeInclusive, + _value: f32, + _is_dragging: bool, + _style_sheet: &Self::Style, + ) -> Self::Output { + } +} diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index ea66a347..c35a933e 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -21,8 +21,9 @@ use std::{hash::Hash, ops::RangeInclusive}; /// /// # Example /// ``` -/// # use iced_native::{slider, Slider}; +/// # use iced_native::{slider, renderer::Null}; /// # +/// # pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Null>; /// pub enum Message { /// SliderChanged(f32), /// } @@ -35,15 +36,16 @@ use std::{hash::Hash, ops::RangeInclusive}; /// /// ![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, Message> { +pub struct Slider<'a, Message, Renderer: self::Renderer> { state: &'a mut State, range: RangeInclusive, value: f32, on_change: Box Message>, width: Length, + style: Renderer::Style, } -impl<'a, Message> Slider<'a, Message> { +impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> { /// Creates a new [`Slider`]. /// /// It expects: @@ -71,6 +73,7 @@ impl<'a, Message> Slider<'a, Message> { range, on_change: Box::new(on_change), width: Length::Fill, + style: Renderer::Style::default(), } } @@ -81,6 +84,14 @@ impl<'a, Message> Slider<'a, Message> { self.width = width; self } + + /// Sets the style of the [`Slider`]. + /// + /// [`Slider`]: struct.Slider.html + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); + self + } } /// The local state of a [`Slider`]. @@ -100,7 +111,8 @@ impl State { } } -impl<'a, Message, Renderer> Widget for Slider<'a, Message> +impl<'a, Message, Renderer> Widget + for Slider<'a, Message, Renderer> where Renderer: self::Renderer, { @@ -188,6 +200,7 @@ where self.range.clone(), self.value, self.state.is_dragging, + &self.style, ) } @@ -204,6 +217,8 @@ where /// [`Slider`]: struct.Slider.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + type Style: Default; + /// Returns the height of the [`Slider`]. /// /// [`Slider`]: struct.Slider.html @@ -228,16 +243,19 @@ pub trait Renderer: crate::Renderer { range: RangeInclusive, value: f32, is_dragging: bool, + style: &Self::Style, ) -> Self::Output; } -impl<'a, Message, Renderer> From> +impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: 'static + self::Renderer, Message: 'static, { - fn from(slider: Slider<'a, Message>) -> Element<'a, Message, Renderer> { + fn from( + slider: Slider<'a, Message, Renderer>, + ) -> Element<'a, Message, Renderer> { Element::new(slider) } } diff --git a/src/native.rs b/src/native.rs index 1061a730..c2584fdd 100644 --- a/src/native.rs +++ b/src/native.rs @@ -24,17 +24,6 @@ pub mod widget { //! [`text_input::State`]: text_input/struct.State.html pub use iced_wgpu::widget::*; - pub mod slider { - //! 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 - pub use iced_winit::slider::{Slider, State}; - } - pub mod image { //! Display images in your user interface. pub use iced_winit::image::{Handle, Image}; diff --git a/style/src/lib.rs b/style/src/lib.rs index fb90b2b5..4b8d339e 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -1,4 +1,5 @@ pub mod button; pub mod container; pub mod scrollable; +pub mod slider; pub mod text_input; diff --git a/style/src/slider.rs b/style/src/slider.rs new file mode 100644 index 00000000..776e180c --- /dev/null +++ b/style/src/slider.rs @@ -0,0 +1,95 @@ +//! Display an interactive selector of a single value from a range of values. +use iced_core::Color; + +/// The appearance of a slider. +#[derive(Debug, Clone, Copy)] +pub struct Style { + pub rail_colors: (Color, Color), + pub handle: Handle, +} + +/// The appearance of the handle of a slider. +#[derive(Debug, Clone, Copy)] +pub struct Handle { + pub shape: HandleShape, + pub color: Color, + pub border_width: u16, + pub border_color: Color, +} + +/// The shape of the handle of a slider. +#[derive(Debug, Clone, Copy)] +pub enum HandleShape { + Circle { radius: u16 }, + Rectangle { width: u16, border_radius: u16 }, +} + +/// A set of rules that dictate the style of a slider. +pub trait StyleSheet { + /// Produces the style of an active slider. + fn active(&self) -> Style; + + /// Produces the style of an hovered slider. + fn hovered(&self) -> Style; + + /// Produces the style of a slider that is being dragged. + fn dragging(&self) -> Style; +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Style { + Style { + rail_colors: ([0.6, 0.6, 0.6, 0.5].into(), Color::WHITE), + handle: Handle { + shape: HandleShape::Rectangle { + width: 8, + border_radius: 4, + }, + color: Color::from_rgb(0.95, 0.95, 0.95), + border_color: Color::from_rgb(0.6, 0.6, 0.6), + border_width: 1, + }, + } + } + + fn hovered(&self) -> Style { + let active = self.active(); + + Style { + handle: Handle { + color: Color::from_rgb(0.90, 0.90, 0.90), + ..active.handle + }, + ..active + } + } + + fn dragging(&self) -> Style { + let active = self.active(); + + Style { + handle: Handle { + color: Color::from_rgb(0.85, 0.85, 0.85), + ..active.handle + }, + ..active + } + } +} + +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/slider.rs b/wgpu/src/renderer/widget/slider.rs index 386decb5..c8ebd0da 100644 --- a/wgpu/src/renderer/widget/slider.rs +++ b/wgpu/src/renderer/widget/slider.rs @@ -1,10 +1,14 @@ -use crate::{Primitive, Renderer}; +use crate::{ + slider::{HandleShape, StyleSheet}, + Primitive, Renderer, +}; use iced_native::{slider, Background, Color, MouseCursor, Point, Rectangle}; -const HANDLE_WIDTH: f32 = 8.0; const HANDLE_HEIGHT: f32 = 22.0; impl slider::Renderer for Renderer { + type Style = Box; + fn height(&self) -> u32 { 30 } @@ -16,9 +20,18 @@ impl slider::Renderer for Renderer { range: std::ops::RangeInclusive, value: f32, is_dragging: bool, + style_sheet: &Self::Style, ) -> Self::Output { let is_mouse_over = bounds.contains(cursor_position); + let style = if is_dragging { + style_sheet.dragging() + } else if is_mouse_over { + style_sheet.hovered() + } else { + style_sheet.active() + }; + let rail_y = bounds.y + (bounds.height / 2.0).round(); let (rail_top, rail_bottom) = ( @@ -29,7 +42,7 @@ impl slider::Renderer for Renderer { width: bounds.width, height: 2.0, }, - background: Background::Color([0.6, 0.6, 0.6, 0.5].into()), + background: Background::Color(style.rail_colors.0), border_radius: 0, border_width: 0, border_color: Color::TRANSPARENT, @@ -41,7 +54,7 @@ impl slider::Renderer for Renderer { width: bounds.width, height: 2.0, }, - background: Background::Color(Color::WHITE), + background: Background::Color(style.rail_colors.1), border_radius: 0, border_width: 0, border_color: Color::TRANSPARENT, @@ -50,29 +63,31 @@ impl slider::Renderer for Renderer { let (range_start, range_end) = range.into_inner(); - let handle_offset = (bounds.width - HANDLE_WIDTH) + let (handle_width, handle_height, handle_border_radius) = + match style.handle.shape { + HandleShape::Circle { radius } => { + (f32::from(radius * 2), f32::from(radius * 2), radius) + } + HandleShape::Rectangle { + width, + border_radius, + } => (f32::from(width), HANDLE_HEIGHT, border_radius), + }; + + let handle_offset = (bounds.width - handle_width) * ((value - range_start) / (range_end - range_start).max(1.0)); let handle = Primitive::Quad { bounds: Rectangle { x: bounds.x + handle_offset.round(), - y: rail_y - HANDLE_HEIGHT / 2.0, - width: HANDLE_WIDTH, - height: HANDLE_HEIGHT, + y: rail_y - handle_height / 2.0, + width: handle_width, + height: handle_height, }, - background: Background::Color( - if is_dragging { - [0.85, 0.85, 0.85] - } else if is_mouse_over { - [0.90, 0.90, 0.90] - } else { - [0.95, 0.95, 0.95] - } - .into(), - ), - border_radius: 4, - border_width: 1, - border_color: Color::from_rgb(0.6, 0.6, 0.6), + background: Background::Color(style.handle.color), + border_radius: handle_border_radius, + border_width: style.handle.border_width, + border_color: style.handle.border_color, }; ( diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index fb90b2b5..4b8d339e 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,4 +1,5 @@ pub mod button; pub mod container; pub mod scrollable; +pub mod slider; pub mod text_input; diff --git a/wgpu/src/widget/slider.rs b/wgpu/src/widget/slider.rs new file mode 100644 index 00000000..4e47978f --- /dev/null +++ b/wgpu/src/widget/slider.rs @@ -0,0 +1,16 @@ +//! 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 crate::Renderer; + +pub use iced_native::slider::State; +pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; + +/// An horizontal bar and a handle that selects a single value from a range of +/// values. +/// +/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. +pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Renderer>; -- cgit From fce89d0ffe36111cdbf42480c28e67811afb42e6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 01:17:32 +0100 Subject: Use constants for colors in `styling` example --- core/src/color.rs | 14 +++++++------- examples/styling.rs | 48 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/core/src/color.rs b/core/src/color.rs index d72651d9..d6bdd365 100644 --- a/core/src/color.rs +++ b/core/src/color.rs @@ -33,6 +33,13 @@ impl Color { a: 0.0, }; + /// Creates a [`Color`] from its RGB components. + /// + /// [`Color`]: struct.Color.html + pub const fn from_rgb(r: f32, g: f32, b: f32) -> Color { + Color { r, g, b, a: 1.0 } + } + /// Creates a [`Color`] from its RGB8 components. /// /// [`Color`]: struct.Color.html @@ -45,13 +52,6 @@ impl Color { } } - /// Creates a [`Color`] from its RGB components. - /// - /// [`Color`]: struct.Color.html - pub fn from_rgb(r: f32, g: f32, b: f32) -> Color { - Color { r, g, b, a: 1.0 } - } - /// Converts the [`Color`] into its linear values. /// /// [`Color`]: struct.Color.html diff --git a/examples/styling.rs b/examples/styling.rs index b0cdbcf0..215185e3 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -201,6 +201,30 @@ mod style { Color, }; + const SURFACE: Color = Color::from_rgb( + 0x40 as f32 / 255.0, + 0x44 as f32 / 255.0, + 0x4B as f32 / 255.0, + ); + + const ACCENT: Color = Color::from_rgb( + 0x6F as f32 / 255.0, + 0xFF as f32 / 255.0, + 0xE9 as f32 / 255.0, + ); + + const ACTIVE: Color = Color::from_rgb( + 0x72 as f32 / 255.0, + 0x89 as f32 / 255.0, + 0xDA as f32 / 255.0, + ); + + const HOVERED: Color = Color::from_rgb( + 0x67 as f32 / 255.0, + 0x7B as f32 / 255.0, + 0xC4 as f32 / 255.0, + ); + pub struct Container; impl container::StyleSheet for Container { @@ -220,9 +244,7 @@ mod style { impl text_input::StyleSheet for TextInput { fn active(&self) -> text_input::Style { text_input::Style { - background: Background::Color(Color::from_rgb8( - 0x40, 0x44, 0x4B, - )), + background: Background::Color(SURFACE), border_radius: 2, border_width: 0, border_color: Color::TRANSPARENT, @@ -232,7 +254,7 @@ mod style { fn focused(&self) -> text_input::Style { text_input::Style { border_width: 1, - border_color: Color::from_rgb8(0x6F, 0xFF, 0xE9), + border_color: ACCENT, ..self.active() } } @@ -240,7 +262,7 @@ mod style { fn hovered(&self) -> text_input::Style { text_input::Style { border_width: 1, - border_color: Color::from_rgb8(0x5B, 0xC0, 0xBE), + border_color: Color { a: 0.3, ..ACCENT }, ..self.focused() } } @@ -259,9 +281,7 @@ mod style { impl button::StyleSheet for Button { fn active(&self) -> button::Style { button::Style { - background: Some(Background::Color(Color::from_rgb8( - 0x72, 0x89, 0xDA, - ))), + background: Some(Background::Color(ACTIVE)), border_radius: 3, text_color: Color::WHITE, ..button::Style::default() @@ -270,9 +290,7 @@ mod style { fn hovered(&self) -> button::Style { button::Style { - background: Some(Background::Color(Color::from_rgb8( - 0x67, 0x7B, 0xC4, - ))), + background: Some(Background::Color(HOVERED)), text_color: Color::WHITE, ..self.active() } @@ -319,13 +337,11 @@ mod style { impl slider::StyleSheet for Slider { fn active(&self) -> slider::Style { - let blue = Color::from_rgb8(0x72, 0x89, 0xDA); - slider::Style { - rail_colors: (blue, Color { a: 0.1, ..blue }), + rail_colors: (ACTIVE, Color { a: 0.1, ..ACTIVE }), handle: slider::Handle { shape: slider::HandleShape::Circle { radius: 9 }, - color: blue, + color: ACTIVE, border_width: 0, border_color: Color::TRANSPARENT, }, @@ -337,7 +353,7 @@ mod style { slider::Style { handle: slider::Handle { - color: Color::from_rgb(0.90, 0.90, 0.90), + color: HOVERED, ..active.handle }, ..active -- cgit From 48b3b78a3840778eef1035f4585d5ba9dd3d6291 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 01:53:26 +0100 Subject: 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; -- cgit From 387fc0be26ccd1adc66c1dc80420f9b08d0c023a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 02:25:57 +0100 Subject: Implement styling for `Radio` --- examples/styling.rs | 50 +++++++++++++++++++++++++++++------- native/src/renderer/null.rs | 3 +++ native/src/widget/radio.rs | 33 +++++++++++++----------- src/native.rs | 6 ++--- style/src/lib.rs | 1 + style/src/radio.rs | 53 +++++++++++++++++++++++++++++++++++++++ wgpu/src/renderer/widget/radio.rs | 26 ++++++++++--------- wgpu/src/widget.rs | 1 + wgpu/src/widget/radio.rs | 10 ++++++++ 9 files changed, 145 insertions(+), 38 deletions(-) create mode 100644 style/src/radio.rs create mode 100644 wgpu/src/widget/radio.rs diff --git a/examples/styling.rs b/examples/styling.rs index 426e0638..b5600e85 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -51,12 +51,15 @@ impl Sandbox for Styling { let choose_theme = style::Theme::ALL.iter().fold( Column::new().spacing(10).push(Text::new("Choose a theme:")), |column, theme| { - column.push(Radio::new( - *theme, - &format!("{:?}", theme), - Some(self.theme), - Message::ThemeChanged, - )) + column.push( + Radio::new( + *theme, + &format!("{:?}", theme), + Some(self.theme), + Message::ThemeChanged, + ) + .style(self.theme), + ) }, ); @@ -110,7 +113,7 @@ impl Sandbox for Styling { mod style { use iced::{ - button, container, progress_bar, scrollable, slider, text_input, + button, container, progress_bar, radio, scrollable, slider, text_input, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -138,6 +141,15 @@ mod style { } } + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Radio.into(), + } + } + } + impl From for Box { fn from(theme: Theme) -> Self { match theme { @@ -213,8 +225,8 @@ mod style { mod dark { use iced::{ - button, container, progress_bar, scrollable, slider, text_input, - Background, Color, + button, container, progress_bar, radio, scrollable, slider, + text_input, Background, Color, }; const SURFACE: Color = Color::from_rgb( @@ -255,6 +267,26 @@ mod style { } } + pub struct Radio; + + impl radio::StyleSheet for Radio { + fn active(&self) -> radio::Style { + radio::Style { + background: Background::Color(SURFACE), + dot_color: Color::WHITE, + border_width: 0, + border_color: Color::TRANSPARENT, + } + } + + fn hovered(&self) -> radio::Style { + radio::Style { + background: Background::Color(Color { a: 0.5, ..SURFACE }), + ..self.active() + } + } + } + pub struct TextInput; impl text_input::StyleSheet for TextInput { diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index b721e29e..4fb4f2d5 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -152,6 +152,8 @@ impl button::Renderer for Null { } impl radio::Renderer for Null { + type Style = (); + fn default_size(&self) -> u32 { 20 } @@ -162,6 +164,7 @@ impl radio::Renderer for Null { _is_selected: bool, _is_mouse_over: bool, _label: Self::Output, + _style: &Self::Style, ) { } } diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 6ac00770..faf2736c 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -1,7 +1,7 @@ //! Create choices using radio buttons. use crate::{ input::{mouse, ButtonState}, - layout, row, text, Align, Clipboard, Color, Element, Event, Font, Hasher, + layout, row, text, Align, Clipboard, Element, Event, Font, Hasher, HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text, VerticalAlignment, Widget, }; @@ -12,7 +12,8 @@ use std::hash::Hash; /// /// # Example /// ``` -/// # use iced_native::Radio; +/// # type Radio = +/// # iced_native::Radio; /// # /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// pub enum Choice { @@ -34,14 +35,14 @@ use std::hash::Hash; /// /// ![Radio buttons drawn by `iced_wgpu`](https://github.com/hecrj/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/radio.png?raw=true) #[allow(missing_debug_implementations)] -pub struct Radio { +pub struct Radio { is_selected: bool, on_click: Message, label: String, - label_color: Option, + style: Renderer::Style, } -impl Radio { +impl Radio { /// Creates a new [`Radio`] button. /// /// It expects: @@ -61,20 +62,20 @@ impl Radio { is_selected: Some(value) == selected, on_click: f(value), label: String::from(label), - label_color: None, + style: Renderer::Style::default(), } } - /// Sets the `Color` of the label of the [`Radio`]. + /// Sets the style of the [`Radio`] button. /// /// [`Radio`]: struct.Radio.html - pub fn label_color>(mut self, color: C) -> Self { - self.label_color = Some(color.into()); + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); self } } -impl Widget for Radio +impl Widget for Radio where Renderer: self::Renderer + text::Renderer + row::Renderer, Message: Clone, @@ -149,7 +150,7 @@ where &self.label, text::Renderer::default_size(renderer), Font::Default, - self.label_color, + None, HorizontalAlignment::Left, VerticalAlignment::Center, ); @@ -162,6 +163,7 @@ where self.is_selected, is_mouse_over, label, + &self.style, ) } @@ -178,6 +180,8 @@ where /// [`Radio`]: struct.Radio.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + type Style: Default; + /// Returns the default size of a [`Radio`] button. /// /// [`Radio`]: struct.Radio.html @@ -198,16 +202,17 @@ pub trait Renderer: crate::Renderer { is_selected: bool, is_mouse_over: bool, label: Self::Output, + style: &Self::Style, ) -> Self::Output; } -impl<'a, Message, Renderer> From> +impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: self::Renderer + row::Renderer + text::Renderer, + Renderer: 'static + self::Renderer + row::Renderer + text::Renderer, Message: 'static + Clone, { - fn from(radio: Radio) -> Element<'a, Message, Renderer> { + fn from(radio: Radio) -> Element<'a, Message, Renderer> { Element::new(radio) } } diff --git a/src/native.rs b/src/native.rs index 5a4db8f6..2f2182ff 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, Radio, Text}; + pub use iced_winit::{Checkbox, Text}; #[doc(no_inline)] pub use { button::Button, container::Container, image::Image, - progress_bar::ProgressBar, scrollable::Scrollable, slider::Slider, - svg::Svg, text_input::TextInput, + progress_bar::ProgressBar, radio::Radio, 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 3f3dc0b0..991e0644 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -1,6 +1,7 @@ pub mod button; pub mod container; pub mod progress_bar; +pub mod radio; pub mod scrollable; pub mod slider; pub mod text_input; diff --git a/style/src/radio.rs b/style/src/radio.rs new file mode 100644 index 00000000..1f0689b9 --- /dev/null +++ b/style/src/radio.rs @@ -0,0 +1,53 @@ +//! Create choices using radio buttons. +use iced_core::{Background, Color}; + +/// The appearance of a radio button. +#[derive(Debug)] +pub struct Style { + pub background: Background, + pub dot_color: Color, + pub border_width: u16, + pub border_color: Color, +} + +/// A set of rules that dictate the style of a radio button. +pub trait StyleSheet { + fn active(&self) -> Style; + + fn hovered(&self) -> Style; +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Style { + Style { + background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)), + dot_color: Color::from_rgb(0.3, 0.3, 0.3), + border_width: 1, + border_color: Color::from_rgb(0.6, 0.6, 0.6), + } + } + + fn hovered(&self) -> Style { + Style { + background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)), + ..self.active() + } + } +} + +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/radio.rs b/wgpu/src/renderer/widget/radio.rs index aa1dbadc..564f066b 100644 --- a/wgpu/src/renderer/widget/radio.rs +++ b/wgpu/src/renderer/widget/radio.rs @@ -1,10 +1,12 @@ -use crate::{Primitive, Renderer}; +use crate::{radio::StyleSheet, Primitive, Renderer}; use iced_native::{radio, Background, Color, MouseCursor, Rectangle}; const SIZE: f32 = 28.0; const DOT_SIZE: f32 = SIZE / 2.0; impl radio::Renderer for Renderer { + type Style = Box; + fn default_size(&self) -> u32 { SIZE as u32 } @@ -15,20 +17,20 @@ impl radio::Renderer for Renderer { is_selected: bool, is_mouse_over: bool, (label, _): Self::Output, + style_sheet: &Self::Style, ) -> Self::Output { + let style = if is_mouse_over { + style_sheet.hovered() + } else { + style_sheet.active() + }; + let radio = Primitive::Quad { bounds, - background: Background::Color( - if is_mouse_over { - [0.90, 0.90, 0.90] - } else { - [0.95, 0.95, 0.95] - } - .into(), - ), + background: style.background, border_radius: (SIZE / 2.0) as u16, - border_width: 1, - border_color: Color::from_rgb(0.6, 0.6, 0.6), + border_width: style.border_width, + border_color: style.border_color, }; ( @@ -41,7 +43,7 @@ impl radio::Renderer for Renderer { width: bounds.width - DOT_SIZE, height: bounds.height - DOT_SIZE, }, - background: Background::Color([0.3, 0.3, 0.3].into()), + background: Background::Color(style.dot_color), border_radius: (DOT_SIZE / 2.0) as u16, border_width: 0, border_color: Color::TRANSPARENT, diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index 3f3dc0b0..991e0644 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,6 +1,7 @@ pub mod button; pub mod container; pub mod progress_bar; +pub mod radio; pub mod scrollable; pub mod slider; pub mod text_input; diff --git a/wgpu/src/widget/radio.rs b/wgpu/src/widget/radio.rs new file mode 100644 index 00000000..6e5cf042 --- /dev/null +++ b/wgpu/src/widget/radio.rs @@ -0,0 +1,10 @@ +//! Create choices using radio buttons. +use crate::Renderer; + +pub use iced_style::radio::{Style, StyleSheet}; + +/// A circular button representing a choice. +/// +/// This is an alias of an `iced_native` radio button with an +/// `iced_wgpu::Renderer`. +pub type Radio = iced_native::Radio; -- cgit From ed30b487d649ffa0967ab8bfd66f4820ee2150fd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 02:54:54 +0100 Subject: Implement styling for `Checkbox` --- examples/styling.rs | 81 ++++++++++++++++++++++++++++++------ native/src/renderer/null.rs | 3 ++ native/src/widget/checkbox.rs | 41 ++++++++++-------- src/native.rs | 4 +- style/src/checkbox.rs | 55 ++++++++++++++++++++++++ style/src/lib.rs | 1 + wgpu/src/renderer/widget/checkbox.rs | 31 +++++++------- wgpu/src/widget.rs | 1 + wgpu/src/widget/checkbox.rs | 9 ++++ 9 files changed, 180 insertions(+), 46 deletions(-) create mode 100644 style/src/checkbox.rs create mode 100644 wgpu/src/widget/checkbox.rs diff --git a/examples/styling.rs b/examples/styling.rs index b5600e85..97095cff 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -1,7 +1,7 @@ use iced::{ - button, scrollable, slider, text_input, Button, Column, Container, Element, - Length, ProgressBar, Radio, Row, Sandbox, Scrollable, Settings, Slider, - Text, TextInput, + button, scrollable, slider, text_input, Button, Checkbox, Column, + Container, Element, Length, ProgressBar, Radio, Row, Sandbox, Scrollable, + Settings, Slider, Text, TextInput, }; pub fn main() { @@ -17,6 +17,7 @@ struct Styling { button: button::State, slider: slider::State, slider_value: f32, + debug: bool, } #[derive(Debug, Clone)] @@ -25,6 +26,7 @@ enum Message { InputChanged(String), ButtonPressed, SliderChanged(f32), + DebugToggled(bool), } impl Sandbox for Styling { @@ -44,6 +46,7 @@ impl Sandbox for Styling { Message::InputChanged(value) => self.input_value = value, Message::ButtonPressed => (), Message::SliderChanged(value) => self.slider_value = value, + Message::DebugToggled(debug) => self.debug = debug, } } @@ -89,18 +92,34 @@ impl Sandbox for Styling { let progress_bar = ProgressBar::new(0.0..=100.0, self.slider_value).style(self.theme); - let content = Column::new() + let checkbox = Checkbox::new( + self.debug, + "Enable layout debugger", + Message::DebugToggled, + ) + .style(self.theme); + + let content: Element<_> = 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(progress_bar); - - let scrollable = Scrollable::new(&mut self.scroll) - .style(self.theme) - .push(Container::new(content).width(Length::Fill).center_x()); + .push(progress_bar) + .push(checkbox) + .into(); + + let scrollable = + Scrollable::new(&mut self.scroll).style(self.theme).push( + Container::new(if self.debug { + content.explain(self.theme.debug_color()) + } else { + content + }) + .width(Length::Fill) + .center_x(), + ); Container::new(scrollable) .width(Length::Fill) @@ -113,7 +132,8 @@ impl Sandbox for Styling { mod style { use iced::{ - button, container, progress_bar, radio, scrollable, slider, text_input, + button, checkbox, container, progress_bar, radio, scrollable, slider, + text_input, Color, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -124,6 +144,13 @@ mod style { impl Theme { pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark]; + + pub fn debug_color(&self) -> Color { + match self { + Theme::Light => Color::BLACK, + Theme::Dark => Color::WHITE, + } + } } impl Default for Theme { @@ -195,6 +222,15 @@ mod style { } } + impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Checkbox.into(), + } + } + } + mod light { use iced::{button, Background, Color, Vector}; @@ -225,8 +261,8 @@ mod style { mod dark { use iced::{ - button, container, progress_bar, radio, scrollable, slider, - text_input, Background, Color, + button, checkbox, container, progress_bar, radio, scrollable, + slider, text_input, Background, Color, }; const SURFACE: Color = Color::from_rgb( @@ -432,5 +468,26 @@ mod style { } } } + + pub struct Checkbox; + + impl checkbox::StyleSheet for Checkbox { + fn active(&self) -> checkbox::Style { + checkbox::Style { + background: Background::Color(SURFACE), + checkmark_color: Color::WHITE, + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + } + } + + fn hovered(&self) -> checkbox::Style { + checkbox::Style { + background: Background::Color(Color { a: 0.5, ..SURFACE }), + ..self.active() + } + } + } } } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 4fb4f2d5..bd5bba23 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -170,6 +170,8 @@ impl radio::Renderer for Null { } impl checkbox::Renderer for Null { + type Style = (); + fn default_size(&self) -> u32 { 20 } @@ -180,6 +182,7 @@ impl checkbox::Renderer for Null { _is_checked: bool, _is_mouse_over: bool, _label: Self::Output, + _style: &Self::Style, ) { } } diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 87a7f629..13a59410 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -3,7 +3,7 @@ use std::hash::Hash; use crate::{ input::{mouse, ButtonState}, - layout, row, text, Align, Clipboard, Color, Element, Event, Font, Hasher, + layout, row, text, Align, Clipboard, Element, Event, Font, Hasher, HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text, VerticalAlignment, Widget, }; @@ -13,7 +13,7 @@ use crate::{ /// # Example /// /// ``` -/// # use iced_native::Checkbox; +/// # type Checkbox = iced_native::Checkbox; /// # /// pub enum Message { /// CheckboxToggled(bool), @@ -26,15 +26,15 @@ use crate::{ /// /// ![Checkbox drawn by `iced_wgpu`](https://github.com/hecrj/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true) #[allow(missing_debug_implementations)] -pub struct Checkbox { +pub struct Checkbox { is_checked: bool, on_toggle: Box Message>, label: String, - label_color: Option, width: Length, + style: Renderer::Style, } -impl Checkbox { +impl Checkbox { /// Creates a new [`Checkbox`]. /// /// It expects: @@ -53,29 +53,30 @@ impl Checkbox { is_checked, on_toggle: Box::new(f), label: String::from(label), - label_color: None, width: Length::Fill, + style: Renderer::Style::default(), } } - /// Sets the color of the label of the [`Checkbox`]. + /// Sets the width of the [`Checkbox`]. /// /// [`Checkbox`]: struct.Checkbox.html - pub fn label_color>(mut self, color: C) -> Self { - self.label_color = Some(color.into()); + pub fn width(mut self, width: Length) -> Self { + self.width = width; self } - /// Sets the width of the [`Checkbox`]. + /// Sets the style of the [`Checkbox`]. /// /// [`Checkbox`]: struct.Checkbox.html - pub fn width(mut self, width: Length) -> Self { - self.width = width; + pub fn style(mut self, style: impl Into) -> Self { + self.style = style.into(); self } } -impl Widget for Checkbox +impl Widget + for Checkbox where Renderer: self::Renderer + text::Renderer + row::Renderer, { @@ -152,7 +153,7 @@ where &self.label, text::Renderer::default_size(renderer), Font::Default, - self.label_color, + None, HorizontalAlignment::Left, VerticalAlignment::Center, ); @@ -165,6 +166,7 @@ where self.is_checked, is_mouse_over, label, + &self.style, ) } @@ -181,6 +183,8 @@ where /// [`Checkbox`]: struct.Checkbox.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + type Style: Default; + /// Returns the default size of a [`Checkbox`]. /// /// [`Checkbox`]: struct.Checkbox.html @@ -201,16 +205,19 @@ pub trait Renderer: crate::Renderer { is_checked: bool, is_mouse_over: bool, label: Self::Output, + style: &Self::Style, ) -> Self::Output; } -impl<'a, Message, Renderer> From> +impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: self::Renderer + text::Renderer + row::Renderer, + Renderer: 'static + self::Renderer + text::Renderer + row::Renderer, Message: 'static, { - fn from(checkbox: Checkbox) -> Element<'a, Message, Renderer> { + fn from( + checkbox: Checkbox, + ) -> Element<'a, Message, Renderer> { Element::new(checkbox) } } diff --git a/src/native.rs b/src/native.rs index 2f2182ff..35441a3e 100644 --- a/src/native.rs +++ b/src/native.rs @@ -34,11 +34,11 @@ pub mod widget { pub use iced_winit::svg::{Handle, Svg}; } - pub use iced_winit::{Checkbox, Text}; + pub use iced_winit::Text; #[doc(no_inline)] pub use { - button::Button, container::Container, image::Image, + button::Button, checkbox::Checkbox, container::Container, image::Image, progress_bar::ProgressBar, radio::Radio, scrollable::Scrollable, slider::Slider, svg::Svg, text_input::TextInput, }; diff --git a/style/src/checkbox.rs b/style/src/checkbox.rs new file mode 100644 index 00000000..e84dfd18 --- /dev/null +++ b/style/src/checkbox.rs @@ -0,0 +1,55 @@ +//! Show toggle controls using checkboxes. +use iced_core::{Background, Color}; + +/// The appearance of a checkbox. +#[derive(Debug)] +pub struct Style { + pub background: Background, + pub checkmark_color: Color, + pub border_radius: u16, + pub border_width: u16, + pub border_color: Color, +} + +/// A set of rules that dictate the style of a checkbox. +pub trait StyleSheet { + fn active(&self) -> Style; + + fn hovered(&self) -> Style; +} + +struct Default; + +impl StyleSheet for Default { + fn active(&self) -> Style { + Style { + background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)), + checkmark_color: Color::from_rgb(0.3, 0.3, 0.3), + border_radius: 5, + border_width: 1, + border_color: Color::from_rgb(0.6, 0.6, 0.6), + } + } + + fn hovered(&self) -> Style { + Style { + background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)), + ..self.active() + } + } +} + +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/style/src/lib.rs b/style/src/lib.rs index 991e0644..e0f56594 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -1,4 +1,5 @@ pub mod button; +pub mod checkbox; pub mod container; pub mod progress_bar; pub mod radio; diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs index 1ed27ff7..cd90be5e 100644 --- a/wgpu/src/renderer/widget/checkbox.rs +++ b/wgpu/src/renderer/widget/checkbox.rs @@ -1,12 +1,13 @@ -use crate::{Primitive, Renderer}; +use crate::{checkbox::StyleSheet, Primitive, Renderer}; use iced_native::{ - checkbox, Background, Color, HorizontalAlignment, MouseCursor, Rectangle, - VerticalAlignment, + checkbox, HorizontalAlignment, MouseCursor, Rectangle, VerticalAlignment, }; const SIZE: f32 = 28.0; impl checkbox::Renderer for Renderer { + type Style = Box; + fn default_size(&self) -> u32 { SIZE as u32 } @@ -17,20 +18,20 @@ impl checkbox::Renderer for Renderer { is_checked: bool, is_mouse_over: bool, (label, _): Self::Output, + style_sheet: &Self::Style, ) -> Self::Output { + let style = if is_mouse_over { + style_sheet.hovered() + } else { + style_sheet.active() + }; + let checkbox = Primitive::Quad { bounds, - background: Background::Color( - if is_mouse_over { - [0.90, 0.90, 0.90] - } else { - [0.95, 0.95, 0.95] - } - .into(), - ), - border_radius: 5, - border_width: 1, - border_color: Color::from_rgb(0.6, 0.6, 0.6), + background: style.background, + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, }; ( @@ -41,7 +42,7 @@ impl checkbox::Renderer for Renderer { font: crate::text::BUILTIN_ICONS, size: bounds.height * 0.7, bounds: bounds, - color: [0.3, 0.3, 0.3].into(), + color: style.checkmark_color, horizontal_alignment: HorizontalAlignment::Center, vertical_alignment: VerticalAlignment::Center, }; diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index 991e0644..e0f56594 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,4 +1,5 @@ pub mod button; +pub mod checkbox; pub mod container; pub mod progress_bar; pub mod radio; diff --git a/wgpu/src/widget/checkbox.rs b/wgpu/src/widget/checkbox.rs new file mode 100644 index 00000000..da0d7a84 --- /dev/null +++ b/wgpu/src/widget/checkbox.rs @@ -0,0 +1,9 @@ +//! Show toggle controls using checkboxes. +use crate::Renderer; + +pub use iced_style::checkbox::{Style, StyleSheet}; + +/// A box that can be checked. +/// +/// This is an alias of an `iced_native` checkbox with an `iced_wgpu::Renderer`. +pub type Checkbox = iced_native::Checkbox; -- cgit From 3d26eb79c2b6a4ed4d186552b052c31235bd0b83 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 03:18:39 +0100 Subject: Always show scroller if scrollbar is visible --- wgpu/src/renderer/widget/scrollable.rs | 73 ++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs index 30d7f337..bfee7411 100644 --- a/wgpu/src/renderer/widget/scrollable.rs +++ b/wgpu/src/renderer/widget/scrollable.rs @@ -66,50 +66,53 @@ impl scrollable::Renderer for Renderer { ( if let Some(scrollbar) = scrollbar { - if is_mouse_over || state.is_scroller_grabbed() { - let style = if state.is_scroller_grabbed() { - style_sheet.dragging() - } else if is_mouse_over_scrollbar { - style_sheet.hovered() - } else { - style_sheet.active() - }; + let style = if state.is_scroller_grabbed() { + style_sheet.dragging() + } else if is_mouse_over_scrollbar { + style_sheet.hovered() + } else { + style_sheet.active() + }; + + let is_scrollbar_visible = + style.background.is_some() || style.border_width > 0; - let scroller = Primitive::Quad { + let scroller = if is_mouse_over + || state.is_scroller_grabbed() + || is_scrollbar_visible + { + Primitive::Quad { bounds: scrollbar.scroller.bounds, background: Background::Color(style.scroller.color), border_radius: style.scroller.border_radius, border_width: style.scroller.border_width, border_color: style.scroller.border_color, - }; - - if style.background.is_some() || style.border_width > 0 { - let scrollbar = Primitive::Quad { - bounds: Rectangle { - x: scrollbar.bounds.x - + f32::from(SCROLLBAR_MARGIN), - width: scrollbar.bounds.width - - f32::from(2 * SCROLLBAR_MARGIN), - ..scrollbar.bounds - }, - background: style.background.unwrap_or( - Background::Color(Color::TRANSPARENT), - ), - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, - }; + } + } else { + Primitive::None + }; - Primitive::Group { - primitives: vec![clip, scrollbar, scroller], - } - } else { - Primitive::Group { - primitives: vec![clip, scroller], - } + let scrollbar = if is_scrollbar_visible { + Primitive::Quad { + bounds: Rectangle { + x: scrollbar.bounds.x + f32::from(SCROLLBAR_MARGIN), + width: scrollbar.bounds.width + - f32::from(2 * SCROLLBAR_MARGIN), + ..scrollbar.bounds + }, + background: style + .background + .unwrap_or(Background::Color(Color::TRANSPARENT)), + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, } } else { - clip + Primitive::None + }; + + Primitive::Group { + primitives: vec![clip, scrollbar, scroller], } } else { clip -- cgit From 3e3f426af882d9b19815cb3a8cf7ac6fe65c88ea Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 03:19:00 +0100 Subject: Add `Scrollable` to `styling` example --- examples/styling.rs | 81 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/examples/styling.rs b/examples/styling.rs index 97095cff..a11bf155 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -1,7 +1,7 @@ use iced::{ - button, scrollable, slider, text_input, Button, Checkbox, Column, + button, scrollable, slider, text_input, Align, Button, Checkbox, Column, Container, Element, Length, ProgressBar, Radio, Row, Sandbox, Scrollable, - Settings, Slider, Text, TextInput, + Settings, Slider, Space, Text, TextInput, }; pub fn main() { @@ -17,7 +17,7 @@ struct Styling { button: button::State, slider: slider::State, slider_value: f32, - debug: bool, + toggle_value: bool, } #[derive(Debug, Clone)] @@ -26,7 +26,7 @@ enum Message { InputChanged(String), ButtonPressed, SliderChanged(f32), - DebugToggled(bool), + CheckboxToggled(bool), } impl Sandbox for Styling { @@ -46,7 +46,7 @@ impl Sandbox for Styling { Message::InputChanged(value) => self.input_value = value, Message::ButtonPressed => (), Message::SliderChanged(value) => self.slider_value = value, - Message::DebugToggled(debug) => self.debug = debug, + Message::CheckboxToggled(value) => self.toggle_value = value, } } @@ -92,14 +92,21 @@ impl Sandbox for Styling { let progress_bar = ProgressBar::new(0.0..=100.0, self.slider_value).style(self.theme); + let scrollable = Scrollable::new(&mut self.scroll) + .height(Length::Units(100)) + .style(self.theme) + .push(Text::new("Scroll me!")) + .push(Space::with_height(Length::Units(800))) + .push(Text::new("You did it!")); + let checkbox = Checkbox::new( - self.debug, - "Enable layout debugger", - Message::DebugToggled, + self.toggle_value, + "Toggle me!", + Message::CheckboxToggled, ) .style(self.theme); - let content: Element<_> = Column::new() + let content = Column::new() .spacing(20) .padding(20) .max_width(600) @@ -107,23 +114,18 @@ impl Sandbox for Styling { .push(Row::new().spacing(10).push(text_input).push(button)) .push(slider) .push(progress_bar) - .push(checkbox) - .into(); - - let scrollable = - Scrollable::new(&mut self.scroll).style(self.theme).push( - Container::new(if self.debug { - content.explain(self.theme.debug_color()) - } else { - content - }) - .width(Length::Fill) - .center_x(), + .push( + Row::new() + .spacing(10) + .align_items(Align::Center) + .push(scrollable) + .push(checkbox), ); - Container::new(scrollable) + Container::new(content) .width(Length::Fill) .height(Length::Fill) + .center_x() .center_y() .style(self.theme) .into() @@ -394,25 +396,44 @@ mod style { impl scrollable::StyleSheet for Scrollable { fn active(&self) -> scrollable::Scrollbar { scrollable::Scrollbar { - background: None, + background: Some(Background::Color(SURFACE)), border_radius: 2, border_width: 0, border_color: Color::TRANSPARENT, scroller: scrollable::Scroller { - color: [1.0, 1.0, 1.0, 0.7].into(), + color: ACTIVE, border_radius: 2, - border_width: 1, - border_color: Color::WHITE, + border_width: 0, + border_color: Color::TRANSPARENT, }, } } fn hovered(&self) -> scrollable::Scrollbar { + let active = self.active(); + scrollable::Scrollbar { - background: Some(Background::Color( - [1.0, 1.0, 1.0, 0.3].into(), - )), - ..self.active() + background: Some(Background::Color(Color { + a: 0.5, + ..SURFACE + })), + scroller: scrollable::Scroller { + color: HOVERED, + ..active.scroller + }, + ..active + } + } + + fn dragging(&self) -> scrollable::Scrollbar { + let hovered = self.hovered(); + + scrollable::Scrollbar { + scroller: scrollable::Scroller { + color: Color::from_rgb(0.85, 0.85, 0.85), + ..hovered.scroller + }, + ..hovered } } } -- cgit From f7a8b6983c2af491803bf84f341d8069045ffb5e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 04:56:32 +0100 Subject: Remove `Mul` implementation for `Vector` --- core/src/vector.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/src/vector.rs b/core/src/vector.rs index 75c77dbd..1c09ee3e 100644 --- a/core/src/vector.rs +++ b/core/src/vector.rs @@ -32,17 +32,6 @@ where } } -impl std::ops::Mul for Vector -where - T: std::ops::Mul, -{ - type Output = Self; - - fn mul(self, b: Self) -> Self { - Self::new(self.x * b.x, self.y * b.y) - } -} - impl Default for Vector where T: Default, -- cgit From 08faaaf6234e93acb3b0dc8e10bf9c4cb266f21c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Jan 2020 05:19:01 +0100 Subject: Color borders of `Checkbox` and `Radio` in `styling` example --- examples/styling.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/styling.rs b/examples/styling.rs index a11bf155..f0edfd82 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -311,9 +311,9 @@ mod style { fn active(&self) -> radio::Style { radio::Style { background: Background::Color(SURFACE), - dot_color: Color::WHITE, - border_width: 0, - border_color: Color::TRANSPARENT, + dot_color: ACTIVE, + border_width: 1, + border_color: ACTIVE, } } @@ -496,10 +496,10 @@ mod style { fn active(&self) -> checkbox::Style { checkbox::Style { background: Background::Color(SURFACE), - checkmark_color: Color::WHITE, + checkmark_color: ACTIVE, border_radius: 2, - border_width: 0, - border_color: Color::TRANSPARENT, + border_width: 1, + border_color: ACTIVE, } } -- cgit From cae4463e8379cddefbd8322a40ad8957bce07215 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 8 Jan 2020 03:30:15 +0100 Subject: Allow `Checkbox` style to change based on its state --- examples/styling.rs | 19 +++++++++++++------ style/src/checkbox.rs | 10 +++++----- wgpu/src/renderer/widget/checkbox.rs | 4 ++-- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/examples/styling.rs b/examples/styling.rs index f0edfd82..59c9c734 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -493,20 +493,27 @@ mod style { pub struct Checkbox; impl checkbox::StyleSheet for Checkbox { - fn active(&self) -> checkbox::Style { + fn active(&self, is_checked: bool) -> checkbox::Style { checkbox::Style { - background: Background::Color(SURFACE), - checkmark_color: ACTIVE, + background: Background::Color(if is_checked { + ACTIVE + } else { + SURFACE + }), + checkmark_color: Color::WHITE, border_radius: 2, border_width: 1, border_color: ACTIVE, } } - fn hovered(&self) -> checkbox::Style { + fn hovered(&self, is_checked: bool) -> checkbox::Style { checkbox::Style { - background: Background::Color(Color { a: 0.5, ..SURFACE }), - ..self.active() + background: Background::Color(Color { + a: 0.8, + ..if is_checked { ACTIVE } else { SURFACE } + }), + ..self.active(is_checked) } } } diff --git a/style/src/checkbox.rs b/style/src/checkbox.rs index e84dfd18..3c645f15 100644 --- a/style/src/checkbox.rs +++ b/style/src/checkbox.rs @@ -13,15 +13,15 @@ pub struct Style { /// A set of rules that dictate the style of a checkbox. pub trait StyleSheet { - fn active(&self) -> Style; + fn active(&self, is_checked: bool) -> Style; - fn hovered(&self) -> Style; + fn hovered(&self, is_checked: bool) -> Style; } struct Default; impl StyleSheet for Default { - fn active(&self) -> Style { + fn active(&self, _is_checked: bool) -> Style { Style { background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)), checkmark_color: Color::from_rgb(0.3, 0.3, 0.3), @@ -31,10 +31,10 @@ impl StyleSheet for Default { } } - fn hovered(&self) -> Style { + fn hovered(&self, is_checked: bool) -> Style { Style { background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)), - ..self.active() + ..self.active(is_checked) } } } diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs index cd90be5e..17121eea 100644 --- a/wgpu/src/renderer/widget/checkbox.rs +++ b/wgpu/src/renderer/widget/checkbox.rs @@ -21,9 +21,9 @@ impl checkbox::Renderer for Renderer { style_sheet: &Self::Style, ) -> Self::Output { let style = if is_mouse_over { - style_sheet.hovered() + style_sheet.hovered(is_checked) } else { - style_sheet.active() + style_sheet.active(is_checked) }; let checkbox = Primitive::Quad { -- cgit From 89b1ac6eac03bec9e2acb9b4d59da86e59d26153 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 8 Jan 2020 03:32:38 +0100 Subject: Fix drawing empty `Quad` on empty `ProgressBar` --- wgpu/src/renderer/widget/progress_bar.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs index 8bb9db03..34e33276 100644 --- a/wgpu/src/renderer/widget/progress_bar.rs +++ b/wgpu/src/renderer/widget/progress_bar.rs @@ -29,20 +29,24 @@ impl progress_bar::Renderer for Renderer { }], }; - let bar = Primitive::Quad { - bounds: Rectangle { - width: active_progress_width, - ..bounds - }, - background: style.bar, - border_radius: style.border_radius, - border_width: 0, - border_color: Color::TRANSPARENT, - }; - ( - Primitive::Group { - primitives: vec![background, bar], + if active_progress_width > 0.0 { + let bar = Primitive::Quad { + bounds: Rectangle { + width: active_progress_width, + ..bounds + }, + background: style.bar, + border_radius: style.border_radius, + border_width: 0, + border_color: Color::TRANSPARENT, + }; + + Primitive::Group { + primitives: vec![background, bar], + } + } else { + background }, MouseCursor::OutOfBounds, ) -- cgit From 775500cf1f5a14afacdc0bb6875136a4fd3369a4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 9 Jan 2020 06:05:26 +0100 Subject: Remove leftover `debug_color` in `styling` example --- examples/styling.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/examples/styling.rs b/examples/styling.rs index 59c9c734..50095ec7 100644 --- a/examples/styling.rs +++ b/examples/styling.rs @@ -135,7 +135,7 @@ impl Sandbox for Styling { mod style { use iced::{ button, checkbox, container, progress_bar, radio, scrollable, slider, - text_input, Color, + text_input, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -146,13 +146,6 @@ mod style { impl Theme { pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark]; - - pub fn debug_color(&self) -> Color { - match self { - Theme::Light => Color::BLACK, - Theme::Dark => Color::WHITE, - } - } } impl Default for Theme { -- cgit From 7b278755fc7929633b5771824beac4d39b16e82e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 9 Jan 2020 18:31:07 +0100 Subject: Write missing docs and reenable deny statements --- native/src/lib.rs | 2 +- native/src/renderer.rs | 5 +++++ native/src/renderer/null.rs | 3 +++ native/src/renderer/windowed.rs | 1 + native/src/widget/button.rs | 4 ++++ native/src/widget/checkbox.rs | 1 + native/src/widget/container.rs | 8 ++++++++ native/src/widget/progress_bar.rs | 1 + native/src/widget/radio.rs | 1 + native/src/widget/scrollable.rs | 1 + native/src/widget/slider.rs | 1 + native/src/widget/text_input.rs | 1 + src/lib.rs | 2 +- src/settings.rs | 14 ++++---------- wgpu/src/defaults.rs | 5 +++++ wgpu/src/lib.rs | 2 +- wgpu/src/settings.rs | 6 ++++++ wgpu/src/widget.rs | 26 ++++++++++++++++++++++++++ 18 files changed, 71 insertions(+), 13 deletions(-) diff --git a/native/src/lib.rs b/native/src/lib.rs index 9d237196..8dcacb2b 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -34,7 +34,7 @@ //! [`Windowed`]: renderer/trait.Windowed.html //! [`UserInterface`]: struct.UserInterface.html //! [renderer]: renderer/index.html -//#![deny(missing_docs)] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![deny(unsafe_code)] diff --git a/native/src/renderer.rs b/native/src/renderer.rs index 90cec6c8..284c95f6 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -44,6 +44,11 @@ pub trait Renderer: Sized { /// [`Renderer`]: trait.Renderer.html type Output; + /// The default styling attributes of the [`Renderer`]. + /// + /// This type can be leveraged to implement style inheritance. + /// + /// [`Renderer`]: trait.Renderer.html type Defaults: Default; /// Lays out the elements of a user interface. diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index bd5bba23..df261cdc 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -11,6 +11,9 @@ use crate::{ pub struct Null; impl Null { + /// Creates a new [`Null`] renderer. + /// + /// [`Null`]: struct.Null.html pub fn new() -> Null { Null } diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs index c3266e6c..ee020ab1 100644 --- a/native/src/renderer/windowed.rs +++ b/native/src/renderer/windowed.rs @@ -4,6 +4,7 @@ use raw_window_handle::HasRawWindowHandle; /// A renderer that can target windows. pub trait Windowed: super::Renderer + Sized { + /// The settings of the renderer. type Settings: Default; /// The type of target. diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index 75ef2693..51b02172 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -114,6 +114,9 @@ where self } + /// Sets the style of the [`Button`]. + /// + /// [`Button`]: struct.Button.html pub fn style(mut self, style: impl Into) -> Self { self.style = style.into(); self @@ -246,6 +249,7 @@ where /// [`Button`]: struct.Button.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { + /// The style supported by this renderer. type Style: Default; /// Draws a [`Button`]. diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index d88a59f4..95165997 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -183,6 +183,7 @@ where /// [`Checkbox`]: struct.Checkbox.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + /// The style supported by this renderer. type Style: Default; /// Returns the default size of a [`Checkbox`]. diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index abe83264..5682fc87 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -183,7 +183,15 @@ where } } +/// The renderer of a [`Container`]. +/// +/// Your [renderer] will need to implement this trait before being +/// able to use a [`Container`] in your user interface. +/// +/// [`Container`]: struct.Container.html +/// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + /// The style supported by this renderer. type Style: Default; /// Draws a [`Container`]. diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index 0bc860dd..67d1ab83 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -127,6 +127,7 @@ where /// [`ProgressBar`]: struct.ProgressBar.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + /// The style supported by this renderer. type Style: Default; /// The default height of a [`ProgressBar`]. diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index b0a6080b..99743ec3 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -181,6 +181,7 @@ where /// [`Radio`]: struct.Radio.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + /// The style supported by this renderer. type Style: Default; /// Returns the default size of a [`Radio`] button. diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index a062abd0..e83f25af 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -458,6 +458,7 @@ pub struct Scroller { /// [`Scrollable`]: struct.Scrollable.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { + /// The style supported by this renderer. type Style: Default; /// Returns the [`Scrollbar`] given the bounds and content bounds of a diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index c35a933e..008203fe 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -217,6 +217,7 @@ where /// [`Slider`]: struct.Slider.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + /// The style supported by this renderer. type Style: Default; /// Returns the height of the [`Slider`]. diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index efbd65c8..25032559 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -407,6 +407,7 @@ where /// [`TextInput`]: struct.TextInput.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { + /// The style supported by this renderer. type Style: Default; /// Returns the default size of the text of the [`TextInput`]. diff --git a/src/lib.rs b/src/lib.rs index 579ff43d..1ef11378 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,7 +174,7 @@ //! [documentation]: https://docs.rs/iced //! [examples]: https://github.com/hecrj/iced/tree/master/examples //! [`Application`]: trait.Application.html -//#![deny(missing_docs)] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![deny(unsafe_code)] diff --git a/src/settings.rs b/src/settings.rs index b725ef9f..e20edc97 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,7 +1,7 @@ //! Configure your application. /// The settings of an application. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct Settings { /// The [`Window`] settings. /// @@ -10,19 +10,13 @@ pub struct Settings { /// [`Window`]: struct.Window.html pub window: Window, + /// The bytes of the font that will be used by default. + /// + /// If `None` is provided, a default system font will be chosen. // TODO: Add `name` for web compatibility pub default_font: Option<&'static [u8]>, } -impl Default for Settings { - fn default() -> Settings { - Settings { - window: Window::default(), - default_font: None, - } - } -} - /// The window settings of an application. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Window { diff --git a/wgpu/src/defaults.rs b/wgpu/src/defaults.rs index 8de8258b..11718a87 100644 --- a/wgpu/src/defaults.rs +++ b/wgpu/src/defaults.rs @@ -1,7 +1,10 @@ +//! Use default styling attributes to inherit styles. use iced_native::Color; +/// Some default styling attributes. #[derive(Debug, Clone, Copy)] pub struct Defaults { + /// Text styling pub text: Text, } @@ -13,8 +16,10 @@ impl Default for Defaults { } } +/// Some default text styling attributes. #[derive(Debug, Clone, Copy)] pub struct Text { + /// The default color of text pub color: Color, } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index dda4f322..ab14987c 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -19,7 +19,7 @@ //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph -//#![deny(missing_docs)] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![deny(unsafe_code)] diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs index c6d8369b..dbe81830 100644 --- a/wgpu/src/settings.rs +++ b/wgpu/src/settings.rs @@ -1,4 +1,10 @@ +/// The settings of a [`Renderer`]. +/// +/// [`Renderer`]: struct.Renderer.html #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct Settings { + /// The bytes of the font that will be used by default. + /// + /// If `None` is provided, a default system font will be chosen. pub default_font: Option<&'static [u8]>, } diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index e0f56594..e3edda0b 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -1,3 +1,12 @@ +//! Use the widgets supported out-of-the-box. +//! +//! # Re-exports +//! For convenience, the contents of this module are available at the root +//! module. Therefore, you can directly type: +//! +//! ``` +//! use iced_wgpu::{button, Button}; +//! ``` pub mod button; pub mod checkbox; pub mod container; @@ -6,3 +15,20 @@ pub mod radio; pub mod scrollable; pub mod slider; pub mod text_input; + +#[doc(no_inline)] +pub use button::Button; +#[doc(no_inline)] +pub use checkbox::Checkbox; +#[doc(no_inline)] +pub use container::Container; +#[doc(no_inline)] +pub use progress_bar::ProgressBar; +#[doc(no_inline)] +pub use radio::Radio; +#[doc(no_inline)] +pub use scrollable::Scrollable; +#[doc(no_inline)] +pub use slider::Slider; +#[doc(no_inline)] +pub use text_input::TextInput; -- cgit