summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-12-29 10:57:01 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-12-29 10:57:01 +0100
commitc7b170da6d180f80e539910cccb543720fa3713c (patch)
tree6ef48d17104173f0ac7182d3647bd461e5581bd2
parent4b86c2ff987e334c3454540828c6f8d16d27c670 (diff)
downloadiced-c7b170da6d180f80e539910cccb543720fa3713c.tar.gz
iced-c7b170da6d180f80e539910cccb543720fa3713c.tar.bz2
iced-c7b170da6d180f80e539910cccb543720fa3713c.zip
Draft `Style` and `StyleSheet` for `Button`
-rw-r--r--examples/pokedex.rs23
-rw-r--r--examples/stopwatch.rs43
-rw-r--r--examples/todos.rs51
-rw-r--r--examples/tour.rs47
-rw-r--r--native/src/lib.rs2
-rw-r--r--native/src/renderer/null.rs11
-rw-r--r--native/src/widget/button.rs47
-rw-r--r--src/lib.rs2
-rw-r--r--src/native.rs18
-rw-r--r--wgpu/src/lib.rs14
-rw-r--r--wgpu/src/renderer.rs4
-rw-r--r--wgpu/src/renderer/widget/button.rs28
-rw-r--r--wgpu/src/renderer/widget/button/style.rs1
-rw-r--r--wgpu/src/widget.rs1
-rw-r--r--wgpu/src/widget/button.rs97
15 files changed, 275 insertions, 114 deletions
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<surf::Exception> 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<Background>,
- _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<Message>,
@@ -37,11 +37,13 @@ pub struct Button<'a, Message, Renderer> {
min_width: u32,
min_height: u32,
padding: u16,
- background: Option<Background>,
- 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<T: Into<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<Renderer::Style>) -> 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<Background>,
- 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<dyn StyleSheet>;
-impl button::Renderer for Renderer {
fn draw(
&mut self,
bounds: Rectangle,
cursor_position: Point,
is_pressed: bool,
- background: Option<Background>,
- border_radius: u16,
+ style: &Box<dyn StyleSheet>,
(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<Background>,
+ 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<dyn StyleSheet> {
+ fn default() -> Self {
+ Box::new(Default)
+ }
+}
+
+impl<T> From<T> for Box<dyn StyleSheet>
+where
+ T: 'static + StyleSheet,
+{
+ fn from(style: T) -> Self {
+ Box::new(style)
+ }
+}