diff options
author | 2019-11-21 13:47:20 +0100 | |
---|---|---|
committer | 2019-11-21 13:47:20 +0100 | |
commit | 65eb218d3d7ba52b2869a586a1480eeb3c8f84e4 (patch) | |
tree | 644f27f40f2f4b8ee1abe7743aac426297503eea /web/src/widget | |
parent | d3553adf278e5b616fbd885f321faa83a4d24b56 (diff) | |
download | iced-65eb218d3d7ba52b2869a586a1480eeb3c8f84e4.tar.gz iced-65eb218d3d7ba52b2869a586a1480eeb3c8f84e4.tar.bz2 iced-65eb218d3d7ba52b2869a586a1480eeb3c8f84e4.zip |
Move widgets from `core` to `native` and `web`
Also made fields private and improved `Renderer` traits.
Diffstat (limited to 'web/src/widget')
-rw-r--r-- | web/src/widget/button.rs | 100 | ||||
-rw-r--r-- | web/src/widget/checkbox.rs | 58 | ||||
-rw-r--r-- | web/src/widget/column.rs | 106 | ||||
-rw-r--r-- | web/src/widget/image.rs | 50 | ||||
-rw-r--r-- | web/src/widget/radio.rs | 67 | ||||
-rw-r--r-- | web/src/widget/row.rs | 108 | ||||
-rw-r--r-- | web/src/widget/slider.rs | 59 | ||||
-rw-r--r-- | web/src/widget/text.rs | 108 |
8 files changed, 639 insertions, 17 deletions
diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 257034a7..ddf67743 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -1,11 +1,103 @@ -use crate::{Bus, Element, Widget}; +use crate::{Background, Bus, Element, Length, Widget}; use dodrio::bumpalo; -pub use iced_core::button::State; +/// A generic widget that produces a message when clicked. +pub struct Button<'a, Message> { + content: Element<'a, Message>, + on_press: Option<Message>, + width: Length, + min_width: u32, + padding: u16, + background: Option<Background>, + border_radius: u16, +} + +impl<'a, Message> Button<'a, Message> { + /// Creates a new [`Button`] with some local [`State`] and the given + /// content. + /// + /// [`Button`]: struct.Button.html + /// [`State`]: struct.State.html + pub fn new<E>(_state: &'a mut State, content: E) -> Self + where + E: Into<Element<'a, Message>>, + { + Button { + content: content.into(), + on_press: None, + width: Length::Shrink, + min_width: 0, + padding: 0, + background: None, + border_radius: 0, + } + } + + /// Sets the width of the [`Button`]. + /// + /// [`Button`]: struct.Button.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the minimum width of the [`Button`]. + /// + /// [`Button`]: struct.Button.html + pub fn min_width(mut self, min_width: u32) -> Self { + self.min_width = min_width; + self + } + + /// Sets the padding of the [`Button`]. + /// + /// [`Button`]: struct.Button.html + pub fn padding(mut self, padding: u16) -> Self { + self.padding = padding; + self + } -pub type Button<'a, Message> = - iced_core::Button<'a, Message, Element<'a, Message>>; + /// Sets the [`Background`] of the [`Button`]. + /// + /// [`Button`]: struct.Button.html + /// [`Background`]: ../../struct.Background.html + pub fn background(mut self, background: Background) -> Self { + self.background = Some(background); + 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 + pub fn on_press(mut self, msg: Message) -> Self { + self.on_press = Some(msg); + self + } +} + +/// The local state of a [`Button`]. +/// +/// [`Button`]: struct.Button.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct State; + +impl State { + /// Creates a new [`State`]. + /// + /// [`State`]: struct.State.html + pub fn new() -> State { + State::default() + } +} impl<'a, Message> Widget<Message> for Button<'a, Message> where diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index 72f0a2aa..8bcef816 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -1,8 +1,62 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Color, Element, Widget}; use dodrio::bumpalo; -pub use iced_core::Checkbox; +/// A box that can be checked. +/// +/// # Example +/// +/// ``` +/// # use iced_web::Checkbox; +/// +/// pub enum Message { +/// CheckboxToggled(bool), +/// } +/// +/// let is_checked = true; +/// +/// Checkbox::new(is_checked, "Toggle me!", Message::CheckboxToggled); +/// ``` +/// +///  +pub struct Checkbox<Message> { + is_checked: bool, + on_toggle: Box<dyn Fn(bool) -> Message>, + label: String, + label_color: Option<Color>, +} + +impl<Message> Checkbox<Message> { + /// Creates a new [`Checkbox`]. + /// + /// It expects: + /// * a boolean describing whether the [`Checkbox`] is checked or not + /// * the label of the [`Checkbox`] + /// * a function that will be called when the [`Checkbox`] is toggled. It + /// will receive the new state of the [`Checkbox`] and must produce a + /// `Message`. + /// + /// [`Checkbox`]: struct.Checkbox.html + pub fn new<F>(is_checked: bool, label: &str, f: F) -> Self + where + F: 'static + Fn(bool) -> Message, + { + Checkbox { + is_checked, + on_toggle: Box::new(f), + label: String::from(label), + label_color: None, + } + } + + /// Sets the color of the label of the [`Checkbox`]. + /// + /// [`Checkbox`]: struct.Checkbox.html + pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self { + self.label_color = Some(color.into()); + self + } +} impl<Message> Widget<Message> for Checkbox<Message> where diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index becd6bc6..cea50f6d 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -1,8 +1,110 @@ -use crate::{Bus, Element, Widget}; +use crate::{Align, Bus, Element, Length, Widget}; use dodrio::bumpalo; +use std::u32; -pub type Column<'a, Message> = iced_core::Column<Element<'a, Message>>; +/// A container that distributes its contents vertically. +/// +/// A [`Column`] will try to fill the horizontal space of its container. +/// +/// [`Column`]: struct.Column.html +pub struct Column<'a, Message> { + spacing: u16, + padding: u16, + width: Length, + height: Length, + max_width: u32, + max_height: u32, + align_items: Align, + children: Vec<Element<'a, Message>>, +} + +impl<'a, Message> Column<'a, Message> { + /// Creates an empty [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn new() -> Self { + Column { + spacing: 0, + padding: 0, + width: Length::Fill, + height: Length::Shrink, + max_width: u32::MAX, + max_height: u32::MAX, + align_items: Align::Start, + children: Vec::new(), + } + } + + /// Sets the vertical spacing _between_ elements. + /// + /// Custom margins per element do not exist in Iced. You should use this + /// method instead! While less flexible, it helps you keep spacing between + /// elements consistent. + pub fn spacing(mut self, units: u16) -> Self { + self.spacing = units; + self + } + + /// Sets the padding of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn padding(mut self, units: u16) -> Self { + self.padding = units; + self + } + + /// Sets the width of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + /// Sets the maximum width of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn max_width(mut self, max_width: u32) -> Self { + self.max_width = max_width; + self + } + + /// Sets the maximum height of the [`Column`] in pixels. + /// + /// [`Column`]: struct.Column.html + pub fn max_height(mut self, max_height: u32) -> Self { + self.max_height = max_height; + self + } + + /// Sets the horizontal alignment of the contents of the [`Column`] . + /// + /// [`Column`]: struct.Column.html + pub fn align_items(mut self, align: Align) -> Self { + self.align_items = align; + self + } + + /// Adds an element to the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn push<E>(mut self, child: E) -> Self + where + E: Into<Element<'a, Message>>, + { + self.children.push(child.into()); + self + } +} impl<'a, Message> Widget<Message> for Column<'a, Message> { fn node<'b>( diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index bd3e5daf..ab510bdb 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -2,7 +2,55 @@ use crate::{Bus, Element, Length, Widget}; use dodrio::bumpalo; -pub use iced_core::Image; +/// A frame that displays an image while keeping aspect ratio. +/// +/// # Example +/// +/// ``` +/// # use iced_web::Image; +/// +/// let image = Image::new("resources/ferris.png"); +/// ``` +#[derive(Debug)] +pub struct Image { + /// The image path + pub path: String, + + /// The width of the image + pub width: Length, + + /// The height of the image + pub height: Length, +} + +impl Image { + /// Creates a new [`Image`] with the given path. + /// + /// [`Image`]: struct.Image.html + pub fn new<T: Into<String>>(path: T) -> Self { + Image { + path: path.into(), + width: Length::Shrink, + height: Length::Shrink, + } + } + + /// Sets the width of the [`Image`] boundaries. + /// + /// [`Image`]: struct.Image.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Image`] boundaries. + /// + /// [`Image`]: struct.Image.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } +} impl<Message> Widget<Message> for Image { fn node<'b>( diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index d249ad26..a0b8fc43 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -1,8 +1,71 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Color, Element, Widget}; use dodrio::bumpalo; -pub use iced_core::Radio; +/// A circular button representing a choice. +/// +/// # Example +/// ``` +/// # use iced_web::Radio; +/// +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// pub enum Choice { +/// A, +/// B, +/// } +/// +/// #[derive(Debug, Clone, Copy)] +/// pub enum Message { +/// RadioSelected(Choice), +/// } +/// +/// let selected_choice = Some(Choice::A); +/// +/// Radio::new(Choice::A, "This is A", selected_choice, Message::RadioSelected); +/// +/// Radio::new(Choice::B, "This is B", selected_choice, Message::RadioSelected); +/// ``` +/// +///  +pub struct Radio<Message> { + is_selected: bool, + on_click: Message, + label: String, + label_color: Option<Color>, +} + +impl<Message> Radio<Message> { + /// Creates a new [`Radio`] button. + /// + /// It expects: + /// * the value related to the [`Radio`] button + /// * the label of the [`Radio`] button + /// * the current selected value + /// * a function that will be called when the [`Radio`] is selected. It + /// receives the value of the radio and must produce a `Message`. + /// + /// [`Radio`]: struct.Radio.html + pub fn new<F, V>(value: V, label: &str, selected: Option<V>, f: F) -> Self + where + V: Eq + Copy, + F: 'static + Fn(V) -> Message, + { + Radio { + is_selected: Some(value) == selected, + on_click: f(value), + label: String::from(label), + label_color: None, + } + } + + /// Sets the `Color` of the label of the [`Radio`]. + /// + /// [`Radio`]: struct.Radio.html + pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self { + self.label_color = Some(color.into()); + self + } +} impl<Message> Widget<Message> for Radio<Message> where diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index cf6ae594..44cacd50 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -1,8 +1,112 @@ -use crate::{Bus, Element, Widget}; +use crate::{Align, Bus, Element, Length, Widget}; use dodrio::bumpalo; +use std::u32; -pub type Row<'a, Message> = iced_core::Row<Element<'a, Message>>; +/// A container that distributes its contents horizontally. +/// +/// A [`Row`] will try to fill the horizontal space of its container. +/// +/// [`Row`]: struct.Row.html +#[allow(missing_docs)] +pub struct Row<'a, Message> { + spacing: u16, + padding: u16, + width: Length, + height: Length, + max_width: u32, + max_height: u32, + align_items: Align, + children: Vec<Element<'a, Message>>, +} + +impl<'a, Message> Row<'a, Message> { + /// Creates an empty [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn new() -> Self { + Row { + spacing: 0, + padding: 0, + width: Length::Fill, + height: Length::Shrink, + max_width: u32::MAX, + max_height: u32::MAX, + align_items: Align::Start, + children: Vec::new(), + } + } + + /// Sets the horizontal spacing _between_ elements. + /// + /// Custom margins per element do not exist in Iced. You should use this + /// method instead! While less flexible, it helps you keep spacing between + /// elements consistent. + pub fn spacing(mut self, units: u16) -> Self { + self.spacing = units; + self + } + + /// Sets the padding of the [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn padding(mut self, units: u16) -> Self { + self.padding = units; + self + } + + /// Sets the width of the [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + /// Sets the maximum width of the [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn max_width(mut self, max_width: u32) -> Self { + self.max_width = max_width; + self + } + + /// Sets the maximum height of the [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn max_height(mut self, max_height: u32) -> Self { + self.max_height = max_height; + self + } + + /// Sets the vertical alignment of the contents of the [`Row`] . + /// + /// [`Row`]: struct.Row.html + pub fn align_items(mut self, align: Align) -> Self { + self.align_items = align; + self + } + + /// Adds an [`Element`] to the [`Row`]. + /// + /// [`Element`]: ../struct.Element.html + /// [`Row`]: struct.Row.html + pub fn push<E>(mut self, child: E) -> Self + where + E: Into<Element<'a, Message>>, + { + self.children.push(child.into()); + self + } +} impl<'a, Message> Widget<Message> for Row<'a, Message> { fn node<'b>( diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 54b2fdf6..acdef0a1 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -1,8 +1,55 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Element, Length, Widget}; use dodrio::bumpalo; +use std::{ops::RangeInclusive, rc::Rc}; -pub use iced_core::slider::*; +pub struct Slider<'a, Message> { + _state: &'a mut State, + range: RangeInclusive<f32>, + value: f32, + on_change: Rc<Box<dyn Fn(f32) -> Message>>, + width: Length, +} + +impl<'a, Message> Slider<'a, Message> { + /// Creates a new [`Slider`]. + /// + /// It expects: + /// * the local [`State`] of the [`Slider`] + /// * an inclusive range of possible values + /// * the current value of the [`Slider`] + /// * a function that will be called when the [`Slider`] is dragged. + /// It receives the new value of the [`Slider`] and must produce a + /// `Message`. + /// + /// [`Slider`]: struct.Slider.html + /// [`State`]: struct.State.html + pub fn new<F>( + state: &'a mut State, + range: RangeInclusive<f32>, + value: f32, + on_change: F, + ) -> Self + where + F: 'static + Fn(f32) -> Message, + { + Slider { + _state: state, + value: value.max(*range.start()).min(*range.end()), + range, + on_change: Rc::new(Box::new(on_change)), + width: Length::Fill, + } + } + + /// Sets the width of the [`Slider`]. + /// + /// [`Slider`]: struct.Slider.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } +} impl<'a, Message> Widget<Message> for Slider<'a, Message> where @@ -60,3 +107,11 @@ where Element::new(slider) } } + +pub struct State; + +impl State { + pub fn new() -> Self { + Self + } +} diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index 41ccd6fc..3740af13 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -1,7 +1,111 @@ -use crate::{Bus, Element, Widget}; +use crate::{ + Bus, Color, Element, Font, HorizontalAlignment, Length, VerticalAlignment, + Widget, +}; use dodrio::bumpalo; -pub use iced_core::text::*; +/// A paragraph of text. +/// +/// # Example +/// +/// ``` +/// # use iced_web::Text; +/// +/// Text::new("I <3 iced!") +/// .size(40); +/// ``` +#[derive(Debug, Clone)] +pub struct Text { + content: String, + size: Option<u16>, + color: Option<Color>, + font: Font, + width: Length, + height: Length, + horizontal_alignment: HorizontalAlignment, + vertical_alignment: VerticalAlignment, +} + +impl Text { + /// Create a new fragment of [`Text`] with the given contents. + /// + /// [`Text`]: struct.Text.html + pub fn new(label: &str) -> Self { + Text { + content: String::from(label), + size: None, + color: None, + font: Font::Default, + width: Length::Fill, + height: Length::Shrink, + horizontal_alignment: HorizontalAlignment::Left, + vertical_alignment: VerticalAlignment::Top, + } + } + + /// Sets the size of the [`Text`]. + /// + /// [`Text`]: struct.Text.html + pub fn size(mut self, size: u16) -> Self { + self.size = Some(size); + self + } + + /// Sets the [`Color`] of the [`Text`]. + /// + /// [`Text`]: struct.Text.html + /// [`Color`]: ../../struct.Color.html + pub fn color<C: Into<Color>>(mut self, color: C) -> Self { + self.color = Some(color.into()); + self + } + + /// Sets the [`Font`] of the [`Text`]. + /// + /// [`Text`]: struct.Text.html + /// [`Font`]: ../../struct.Font.html + pub fn font(mut self, font: Font) -> Self { + self.font = font; + self + } + + /// Sets the width of the [`Text`] boundaries. + /// + /// [`Text`]: struct.Text.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Text`] boundaries. + /// + /// [`Text`]: struct.Text.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + /// Sets the [`HorizontalAlignment`] of the [`Text`]. + /// + /// [`Text`]: struct.Text.html + /// [`HorizontalAlignment`]: enum.HorizontalAlignment.html + pub fn horizontal_alignment( + mut self, + alignment: HorizontalAlignment, + ) -> Self { + self.horizontal_alignment = alignment; + self + } + + /// Sets the [`VerticalAlignment`] of the [`Text`]. + /// + /// [`Text`]: struct.Text.html + /// [`VerticalAlignment`]: enum.VerticalAlignment.html + pub fn vertical_alignment(mut self, alignment: VerticalAlignment) -> Self { + self.vertical_alignment = alignment; + self + } +} impl<'a, Message> Widget<Message> for Text { fn node<'b>( |