diff options
Diffstat (limited to 'web/src/widget')
| -rw-r--r-- | web/src/widget/button.rs | 66 | ||||
| -rw-r--r-- | web/src/widget/checkbox.rs | 46 | ||||
| -rw-r--r-- | web/src/widget/column.rs | 29 | ||||
| -rw-r--r-- | web/src/widget/container.rs | 42 | ||||
| -rw-r--r-- | web/src/widget/image.rs | 91 | ||||
| -rw-r--r-- | web/src/widget/progress_bar.rs | 124 | ||||
| -rw-r--r-- | web/src/widget/radio.rs | 17 | ||||
| -rw-r--r-- | web/src/widget/row.rs | 29 | ||||
| -rw-r--r-- | web/src/widget/scrollable.rs | 24 | ||||
| -rw-r--r-- | web/src/widget/slider.rs | 18 | ||||
| -rw-r--r-- | web/src/widget/space.rs | 8 | ||||
| -rw-r--r-- | web/src/widget/text.rs | 21 | ||||
| -rw-r--r-- | web/src/widget/text_input.rs | 67 | 
13 files changed, 450 insertions, 132 deletions
| diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 6fef48ce..3a5afe60 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -4,7 +4,9 @@  //!  //! [`Button`]: struct.Button.html  //! [`State`]: struct.State.html -use crate::{style, Background, Bus, Element, Length, Style, Widget}; +use crate::{css, Background, Bus, Css, Element, Length, Widget}; + +pub use iced_style::button::{Style, StyleSheet};  use dodrio::bumpalo; @@ -26,10 +28,11 @@ pub struct Button<'a, Message> {      content: Element<'a, Message>,      on_press: Option<Message>,      width: Length, +    height: Length,      min_width: u32, +    min_height: u32,      padding: u16, -    background: Option<Background>, -    border_radius: u16, +    style: Box<dyn StyleSheet>,  }  impl<'a, Message> Button<'a, Message> { @@ -46,10 +49,11 @@ impl<'a, Message> Button<'a, Message> {              content: content.into(),              on_press: None,              width: Length::Shrink, +            height: Length::Shrink,              min_width: 0, -            padding: 0, -            background: None, -            border_radius: 0, +            min_height: 0, +            padding: 5, +            style: Default::default(),          }      } @@ -61,6 +65,14 @@ impl<'a, Message> Button<'a, Message> {          self      } +    /// Sets the height of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    pub fn height(mut self, height: Length) -> Self { +        self.height = height; +        self +    } +      /// Sets the minimum width of the [`Button`].      ///      /// [`Button`]: struct.Button.html @@ -69,28 +81,27 @@ impl<'a, Message> Button<'a, Message> {          self      } -    /// Sets the padding of the [`Button`]. +    /// Sets the minimum height of the [`Button`].      ///      /// [`Button`]: struct.Button.html -    pub fn padding(mut self, padding: u16) -> Self { -        self.padding = padding; +    pub fn min_height(mut self, min_height: u32) -> Self { +        self.min_height = min_height;          self      } -    /// Sets the [`Background`] of the [`Button`]. +    /// Sets the padding 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()); +    pub fn padding(mut self, padding: u16) -> Self { +        self.padding = padding;          self      } -    /// Sets the border radius of the [`Button`]. +    /// Sets the style of the [`Button`].      ///      /// [`Button`]: struct.Button.html -    pub fn border_radius(mut self, border_radius: u16) -> Self { -        self.border_radius = border_radius; +    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { +        self.style = style.into();          self      } @@ -126,18 +137,20 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; -        let width = style::length(self.width); +        // TODO: State-based styling +        let style = self.style.active(); +          let padding_class = -            style_sheet.insert(bump, Style::Padding(self.padding)); +            style_sheet.insert(bump, css::Rule::Padding(self.padding)); -        let background = match self.background { +        let background = match style.background {              None => String::from("none"),              Some(background) => match background { -                Background::Color(color) => style::color(color), +                Background::Color(color) => css::color(color),              },          }; @@ -150,11 +163,12 @@ where                  "style",                  bumpalo::format!(                      in bump, -                    "background: {}; border-radius: {}px; width:{}; min-width: {}px", +                    "background: {}; border-radius: {}px; width:{}; min-width: {}; color: {}",                      background, -                    self.border_radius, -                    width, -                    self.min_width +                    style.border_radius, +                    css::length(self.width), +                    css::min_length(self.min_width), +                    css::color(style.text_color)                  )                  .into_bump_str(),              ) @@ -168,8 +182,6 @@ where              });          } -        // TODO: Complete styling -          node.finish()      }  } diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index 1e864875..0657ccfb 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -1,4 +1,7 @@ -use crate::{style, Bus, Color, Element, Widget}; +//! Show toggle controls using checkboxes. +use crate::{css, Bus, Css, Element, Length, Widget}; + +pub use iced_style::checkbox::{Style, StyleSheet};  use dodrio::bumpalo;  use std::rc::Rc; @@ -25,7 +28,8 @@ pub struct Checkbox<Message> {      is_checked: bool,      on_toggle: Rc<dyn Fn(bool) -> Message>,      label: String, -    label_color: Option<Color>, +    width: Length, +    style: Box<dyn StyleSheet>,  }  impl<Message> Checkbox<Message> { @@ -47,15 +51,24 @@ impl<Message> Checkbox<Message> {              is_checked,              on_toggle: Rc::new(f),              label: String::from(label), -            label_color: None, +            width: Length::Shrink, +            style: Default::default(),          }      } -    /// Sets the color of the label of the [`Checkbox`]. +    /// Sets the width of the [`Checkbox`]. +    /// +    /// [`Checkbox`]: struct.Checkbox.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the style 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()); +    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { +        self.style = style.into();          self      }  } @@ -68,7 +81,7 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        _style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; @@ -78,9 +91,23 @@ where          let on_toggle = self.on_toggle.clone();          let is_checked = self.is_checked; -        // TODO: Complete styling +        let row_class = style_sheet.insert(bump, css::Rule::Row); + +        let spacing_class = style_sheet.insert(bump, css::Rule::Spacing(5)); +          label(bump) +            .attr( +                "class", +                bumpalo::format!(in bump, "{} {}", row_class, spacing_class) +                    .into_bump_str(), +            ) +            .attr( +                "style", +                bumpalo::format!(in bump, "width: {}; align-items: center", css::length(self.width)) +                    .into_bump_str(), +            )              .children(vec![ +                // TODO: Checkbox styling                  input(bump)                      .attr("type", "checkbox")                      .bool_attr("checked", self.is_checked) @@ -91,7 +118,8 @@ where                          vdom.schedule_render();                      })                      .finish(), -                text(checkbox_label.into_bump_str()), +                span(bump).children(vec![ +                text(checkbox_label.into_bump_str())]).finish(),              ])              .finish()      } diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index 9aa988ff..6454ffba 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -1,4 +1,4 @@ -use crate::{style, Align, Bus, Element, Length, Style, Widget}; +use crate::{css, Align, Bus, Css, Element, Length, Widget};  use dodrio::bumpalo;  use std::u32; @@ -28,7 +28,7 @@ impl<'a, Message> Column<'a, Message> {          Column {              spacing: 0,              padding: 0, -            width: Length::Shrink, +            width: Length::Fill,              height: Length::Shrink,              max_width: u32::MAX,              max_height: u32::MAX, @@ -112,7 +112,7 @@ impl<'a, Message> Widget<Message> for Column<'a, Message> {          &self,          bump: &'b bumpalo::Bump,          publish: &Bus<Message>, -        style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; @@ -122,18 +122,13 @@ impl<'a, Message> Widget<Message> for Column<'a, Message> {              .map(|element| element.widget.node(bump, publish, style_sheet))              .collect(); -        let column_class = style_sheet.insert(bump, Style::Column); +        let column_class = style_sheet.insert(bump, css::Rule::Column);          let spacing_class = -            style_sheet.insert(bump, Style::Spacing(self.spacing)); +            style_sheet.insert(bump, css::Rule::Spacing(self.spacing));          let padding_class = -            style_sheet.insert(bump, Style::Padding(self.padding)); - -        let width = style::length(self.width); -        let height = style::length(self.height); - -        let align_items = style::align(self.align_items); +            style_sheet.insert(bump, css::Rule::Padding(self.padding));          // TODO: Complete styling          div(bump) @@ -144,12 +139,12 @@ impl<'a, Message> Widget<Message> for Column<'a, Message> {              )              .attr("style", bumpalo::format!(                      in bump, -                    "width: {}; height: {}; max-width: {}px; max-height: {}px; align-items: {}", -                    width, -                    height, -                    self.max_width, -                    self.max_height, -                    align_items +                    "width: {}; height: {}; max-width: {}; max-height: {}; align-items: {}", +                    css::length(self.width), +                    css::length(self.height), +                    css::max_length(self.max_width), +                    css::max_length(self.max_height), +                    css::align(self.align_items)                  ).into_bump_str()              )              .children(children) diff --git a/web/src/widget/container.rs b/web/src/widget/container.rs index bdc88979..8e4318f9 100644 --- a/web/src/widget/container.rs +++ b/web/src/widget/container.rs @@ -1,4 +1,7 @@ -use crate::{bumpalo, style, Align, Bus, Element, Length, Style, Widget}; +//! Decorate content and apply alignment. +use crate::{bumpalo, css, Align, Bus, Css, Element, Length, Widget}; + +pub use iced_style::container::{Style, StyleSheet};  /// An element decorating some content.  /// @@ -11,6 +14,7 @@ pub struct Container<'a, Message> {      max_height: u32,      horizontal_alignment: Align,      vertical_alignment: Align, +    style_sheet: Box<dyn StyleSheet>,      content: Element<'a, Message>,  } @@ -31,6 +35,7 @@ impl<'a, Message> Container<'a, Message> {              max_height: u32::MAX,              horizontal_alignment: Align::Start,              vertical_alignment: Align::Start, +            style_sheet: Default::default(),              content: content.into(),          }      } @@ -84,6 +89,14 @@ impl<'a, Message> Container<'a, Message> {          self      } + +    /// Sets the style of the [`Container`]. +    /// +    /// [`Container`]: struct.Container.html +    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { +        self.style_sheet = style.into(); +        self +    }  }  impl<'a, Message> Widget<Message> for Container<'a, Message> @@ -94,17 +107,13 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; -        let column_class = style_sheet.insert(bump, Style::Column); - -        let width = style::length(self.width); -        let height = style::length(self.height); +        let column_class = style_sheet.insert(bump, css::Rule::Column); -        let align_items = style::align(self.horizontal_alignment); -        let justify_content = style::align(self.vertical_alignment); +        let style = self.style_sheet.style();          let node = div(bump)              .attr( @@ -115,12 +124,17 @@ where                  "style",                  bumpalo::format!(                      in bump, -                    "width: {}; height: {}; max-width: {}px; align-items: {}; justify-content: {}", -                    width, -                    height, -                    self.max_width, -                    align_items, -                    justify_content +                    "width: {}; height: {}; max-width: {}; align-items: {}; justify-content: {}; background: {}; color: {}; border-width: {}px; border-color: {}; border-radius: {}px", +                    css::length(self.width), +                    css::length(self.height), +                    css::max_length(self.max_width), +                    css::align(self.horizontal_alignment), +                    css::align(self.vertical_alignment), +                    style.background.map(css::background).unwrap_or(String::from("initial")), +                    style.text_color.map(css::color).unwrap_or(String::from("inherit")), +                    style.border_width, +                    css::color(style.border_color), +                    style.border_radius                  )                  .into_bump_str(),              ) diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index 413b663e..029ab352 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -1,6 +1,12 @@ -use crate::{style, Bus, Element, Length, Widget}; +//! Display images in your user interface. +use crate::{Bus, Css, Element, Hasher, Length, Widget};  use dodrio::bumpalo; +use std::{ +    hash::{Hash, Hasher as _}, +    path::PathBuf, +    sync::Arc, +};  /// A frame that displays an image while keeping aspect ratio.  /// @@ -14,7 +20,7 @@ use dodrio::bumpalo;  #[derive(Debug)]  pub struct Image {      /// The image path -    pub path: String, +    pub handle: Handle,      /// The width of the image      pub width: Length, @@ -27,9 +33,9 @@ impl Image {      /// Creates a new [`Image`] with the given path.      ///      /// [`Image`]: struct.Image.html -    pub fn new<T: Into<String>>(path: T) -> Self { +    pub fn new<T: Into<Handle>>(handle: T) -> Self {          Image { -            path: path.into(), +            handle: handle.into(),              width: Length::Shrink,              height: Length::Shrink,          } @@ -57,11 +63,13 @@ impl<Message> Widget<Message> for Image {          &self,          bump: &'b bumpalo::Bump,          _bus: &Bus<Message>, -        _style_sheet: &mut style::Sheet<'b>, +        _style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; -        let src = bumpalo::format!(in bump, "{}", self.path); +        let src = bumpalo::format!(in bump, "{}", match self.handle.data.as_ref() { +            Data::Path(path) => path.to_str().unwrap_or("") +        });          let mut image = img(bump).attr("src", src.into_bump_str()); @@ -89,3 +97,74 @@ impl<'a, Message> From<Image> for Element<'a, Message> {          Element::new(image)      }  } + +/// An [`Image`] handle. +/// +/// [`Image`]: struct.Image.html +#[derive(Debug, Clone)] +pub struct Handle { +    id: u64, +    data: Arc<Data>, +} + +impl Handle { +    /// Creates an image [`Handle`] pointing to the image of the given path. +    /// +    /// [`Handle`]: struct.Handle.html +    pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle { +        Self::from_data(Data::Path(path.into())) +    } + +    fn from_data(data: Data) -> Handle { +        let mut hasher = Hasher::default(); +        data.hash(&mut hasher); + +        Handle { +            id: hasher.finish(), +            data: Arc::new(data), +        } +    } + +    /// Returns the unique identifier of the [`Handle`]. +    /// +    /// [`Handle`]: struct.Handle.html +    pub fn id(&self) -> u64 { +        self.id +    } + +    /// Returns a reference to the image [`Data`]. +    /// +    /// [`Data`]: enum.Data.html +    pub fn data(&self) -> &Data { +        &self.data +    } +} + +impl From<String> for Handle { +    fn from(path: String) -> Handle { +        Handle::from_path(path) +    } +} + +impl From<&str> for Handle { +    fn from(path: &str) -> Handle { +        Handle::from_path(path) +    } +} + +/// The data of an [`Image`]. +/// +/// [`Image`]: struct.Image.html +#[derive(Clone, Hash)] +pub enum Data { +    /// A remote image +    Path(PathBuf), +} + +impl std::fmt::Debug for Data { +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        match self { +            Data::Path(path) => write!(f, "Path({:?})", path), +        } +    } +} diff --git a/web/src/widget/progress_bar.rs b/web/src/widget/progress_bar.rs new file mode 100644 index 00000000..856203c0 --- /dev/null +++ b/web/src/widget/progress_bar.rs @@ -0,0 +1,124 @@ +//! Provide progress feedback to your users. +use crate::{bumpalo, css, Bus, Css, Element, Length, Widget}; + +pub use iced_style::progress_bar::{Style, StyleSheet}; + +use std::ops::RangeInclusive; + +/// A bar that displays progress. +/// +/// # Example +/// ``` +/// use iced_web::ProgressBar; +/// +/// let value = 50.0; +/// +/// ProgressBar::new(0.0..=100.0, value); +/// ``` +/// +///  +#[allow(missing_debug_implementations)] +pub struct ProgressBar { +    range: RangeInclusive<f32>, +    value: f32, +    width: Length, +    height: Option<Length>, +    style: Box<dyn StyleSheet>, +} + +impl ProgressBar { +    /// Creates a new [`ProgressBar`]. +    /// +    /// It expects: +    ///   * an inclusive range of possible values +    ///   * the current value of the [`ProgressBar`] +    /// +    /// [`ProgressBar`]: struct.ProgressBar.html +    pub fn new(range: RangeInclusive<f32>, value: f32) -> Self { +        ProgressBar { +            value: value.max(*range.start()).min(*range.end()), +            range, +            width: Length::Fill, +            height: None, +            style: Default::default(), +        } +    } + +    /// Sets the width of the [`ProgressBar`]. +    /// +    /// [`ProgressBar`]: struct.ProgressBar.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the height of the [`ProgressBar`]. +    /// +    /// [`ProgressBar`]: struct.ProgressBar.html +    pub fn height(mut self, height: Length) -> Self { +        self.height = Some(height); +        self +    } + +    /// Sets the style of the [`ProgressBar`]. +    /// +    /// [`ProgressBar`]: struct.ProgressBar.html +    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { +        self.style = style.into(); +        self +    } +} + +impl<Message> Widget<Message> for ProgressBar { +    fn node<'b>( +        &self, +        bump: &'b bumpalo::Bump, +        _bus: &Bus<Message>, +        _style_sheet: &mut Css<'b>, +    ) -> dodrio::Node<'b> { +        use dodrio::builder::*; + +        let (range_start, range_end) = self.range.clone().into_inner(); +        let amount_filled = +            (self.value - range_start) / (range_end - range_start).max(1.0); + +        let style = self.style.style(); + +        let bar = div(bump) +            .attr( +                "style", +                bumpalo::format!( +                    in bump, +                    "width: {}%; height: 100%; background: {}", +                    amount_filled * 100.0, +                    css::background(style.bar) +                ) +                .into_bump_str(), +            ) +            .finish(); + +        let node = div(bump).attr( +            "style", +            bumpalo::format!( +                in bump, +                "width: {}; height: {}; background: {}; border-radius: {}px; overflow: hidden;", +                css::length(self.width), +                css::length(self.height.unwrap_or(Length::Units(30))), +                css::background(style.background), +                style.border_radius +            ) +            .into_bump_str(), +        ).children(vec![bar]); + +        node.finish() +    } +} + +impl<'a, Message> From<ProgressBar> for Element<'a, Message> +where +    Message: 'static, +{ +    fn from(container: ProgressBar) -> Element<'a, Message> { +        Element::new(container) +    } +} diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index 6dd0ad45..e00e26db 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -1,4 +1,7 @@ -use crate::{style, Bus, Color, Element, Widget}; +//! Create choices using radio buttons. +use crate::{Bus, Css, Element, Widget}; + +pub use iced_style::radio::{Style, StyleSheet};  use dodrio::bumpalo; @@ -32,7 +35,7 @@ pub struct Radio<Message> {      is_selected: bool,      on_click: Message,      label: String, -    label_color: Option<Color>, +    style: Box<dyn StyleSheet>,  }  impl<Message> Radio<Message> { @@ -55,15 +58,15 @@ impl<Message> Radio<Message> {              is_selected: Some(value) == selected,              on_click: f(value),              label: String::from(label), -            label_color: None, +            style: Default::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<C: Into<Color>>(mut self, color: C) -> Self { -        self.label_color = Some(color.into()); +    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { +        self.style = style.into();          self      }  } @@ -76,7 +79,7 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        _style_sheet: &mut style::Sheet<'b>, +        _style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index c26cb91b..02035113 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -1,4 +1,4 @@ -use crate::{style, Align, Bus, Element, Length, Style, Widget}; +use crate::{css, Align, Bus, Css, Element, Length, Widget};  use dodrio::bumpalo;  use std::u32; @@ -28,7 +28,7 @@ impl<'a, Message> Row<'a, Message> {          Row {              spacing: 0,              padding: 0, -            width: Length::Shrink, +            width: Length::Fill,              height: Length::Shrink,              max_width: u32::MAX,              max_height: u32::MAX, @@ -113,7 +113,7 @@ impl<'a, Message> Widget<Message> for Row<'a, Message> {          &self,          bump: &'b bumpalo::Bump,          publish: &Bus<Message>, -        style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; @@ -123,18 +123,13 @@ impl<'a, Message> Widget<Message> for Row<'a, Message> {              .map(|element| element.widget.node(bump, publish, style_sheet))              .collect(); -        let row_class = style_sheet.insert(bump, Style::Row); +        let row_class = style_sheet.insert(bump, css::Rule::Row);          let spacing_class = -            style_sheet.insert(bump, Style::Spacing(self.spacing)); +            style_sheet.insert(bump, css::Rule::Spacing(self.spacing));          let padding_class = -            style_sheet.insert(bump, Style::Padding(self.padding)); - -        let width = style::length(self.width); -        let height = style::length(self.height); - -        let justify_content = style::align(self.align_items); +            style_sheet.insert(bump, css::Rule::Padding(self.padding));          // TODO: Complete styling          div(bump) @@ -145,12 +140,12 @@ impl<'a, Message> Widget<Message> for Row<'a, Message> {              )              .attr("style", bumpalo::format!(                      in bump, -                    "width: {}; height: {}; max-width: {}px; max-height: {}px; justify-content: {}", -                    width, -                    height, -                    self.max_width, -                    self.max_height, -                    justify_content +                    "width: {}; height: {}; max-width: {}; max-height: {}; align-items: {}", +                    css::length(self.width), +                    css::length(self.height), +                    css::max_length(self.max_width), +                    css::max_length(self.max_height), +                    css::align(self.align_items)                  ).into_bump_str()              )              .children(children) diff --git a/web/src/widget/scrollable.rs b/web/src/widget/scrollable.rs index f146e007..07b38aad 100644 --- a/web/src/widget/scrollable.rs +++ b/web/src/widget/scrollable.rs @@ -1,5 +1,7 @@  //! Navigate an endless amount of content with a scrollbar. -use crate::{bumpalo, style, Align, Bus, Column, Element, Length, Widget}; +use crate::{bumpalo, css, Align, Bus, Column, Css, Element, Length, Widget}; + +pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet};  /// A widget that can vertically display an infinite amount of content with a  /// scrollbar. @@ -9,6 +11,7 @@ pub struct Scrollable<'a, Message> {      height: Length,      max_height: u32,      content: Column<'a, Message>, +    style: Box<dyn StyleSheet>,  }  impl<'a, Message> Scrollable<'a, Message> { @@ -24,6 +27,7 @@ impl<'a, Message> Scrollable<'a, Message> {              height: Length::Shrink,              max_height: u32::MAX,              content: Column::new(), +            style: Default::default(),          }      } @@ -85,6 +89,14 @@ impl<'a, Message> Scrollable<'a, Message> {          self      } +    /// Sets the style of the [`Scrollable`] . +    /// +    /// [`Scrollable`]: struct.Scrollable.html +    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { +        self.style = style.into(); +        self +    } +      /// Adds an element to the [`Scrollable`].      ///      /// [`Scrollable`]: struct.Scrollable.html @@ -105,12 +117,14 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; -        let width = style::length(self.width); -        let height = style::length(self.height); +        let width = css::length(self.width); +        let height = css::length(self.height); + +        // TODO: Scrollbar styling          let node = div(bump)              .attr( @@ -126,8 +140,6 @@ where              )              .children(vec![self.content.node(bump, bus, style_sheet)]); -        // TODO: Complete styling -          node.finish()      }  } diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 25c57933..5aa6439e 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -4,7 +4,9 @@  //!  //! [`Slider`]: struct.Slider.html  //! [`State`]: struct.State.html -use crate::{style, Bus, Element, Length, Widget}; +use crate::{Bus, Css, Element, Length, Widget}; + +pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};  use dodrio::bumpalo;  use std::{ops::RangeInclusive, rc::Rc}; @@ -38,6 +40,7 @@ pub struct Slider<'a, Message> {      value: f32,      on_change: Rc<Box<dyn Fn(f32) -> Message>>,      width: Length, +    style: Box<dyn StyleSheet>,  }  impl<'a, Message> Slider<'a, Message> { @@ -68,6 +71,7 @@ impl<'a, Message> Slider<'a, Message> {              range,              on_change: Rc::new(Box::new(on_change)),              width: Length::Fill, +            style: Default::default(),          }      } @@ -78,6 +82,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<Box<dyn StyleSheet>>) -> Self { +        self.style = style.into(); +        self +    }  }  impl<'a, Message> Widget<Message> for Slider<'a, Message> @@ -88,7 +100,7 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        _style_sheet: &mut style::Sheet<'b>, +        _style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*;          use wasm_bindgen::JsCast; @@ -103,7 +115,7 @@ where          let event_bus = bus.clone();          // TODO: Make `step` configurable -        // TODO: Complete styling +        // TODO: Styling          input(bump)              .attr("type", "range")              .attr("step", "0.01") diff --git a/web/src/widget/space.rs b/web/src/widget/space.rs index baf4c80b..4ce52595 100644 --- a/web/src/widget/space.rs +++ b/web/src/widget/space.rs @@ -1,4 +1,4 @@ -use crate::{style, Bus, Element, Length, Widget}; +use crate::{css, Bus, Css, Element, Length, Widget};  use dodrio::bumpalo;  /// An amount of empty space. @@ -44,12 +44,12 @@ impl<'a, Message> Widget<Message> for Space {          &self,          bump: &'b bumpalo::Bump,          _publish: &Bus<Message>, -        _style_sheet: &mut style::Sheet<'b>, +        _css: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*; -        let width = style::length(self.width); -        let height = style::length(self.height); +        let width = css::length(self.width); +        let height = css::length(self.height);          let style = bumpalo::format!(              in bump, diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index 5b0bee55..3ec565a8 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -1,5 +1,5 @@  use crate::{ -    style, Bus, Color, Element, Font, HorizontalAlignment, Length, +    css, Bus, Color, Css, Element, Font, HorizontalAlignment, Length,      VerticalAlignment, Widget,  };  use dodrio::bumpalo; @@ -112,15 +112,18 @@ impl<'a, Message> Widget<Message> for Text {          &self,          bump: &'b bumpalo::Bump,          _publish: &Bus<Message>, -        _style_sheet: &mut style::Sheet<'b>, +        _style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*;          let content = bumpalo::format!(in bump, "{}", self.content); -        let color = style::color(self.color.unwrap_or(Color::BLACK)); +        let color = self +            .color +            .map(css::color) +            .unwrap_or(String::from("inherit")); -        let width = style::length(self.width); -        let height = style::length(self.height); +        let width = css::length(self.width); +        let height = css::length(self.height);          let text_align = match self.horizontal_alignment {              HorizontalAlignment::Left => "left", @@ -130,12 +133,16 @@ impl<'a, Message> Widget<Message> for Text {          let style = bumpalo::format!(              in bump, -            "width: {}; height: {}; font-size: {}px; color: {}; text-align: {}", +            "width: {}; height: {}; font-size: {}px; color: {}; text-align: {}; font-family: {}",              width,              height,              self.size.unwrap_or(20),              color, -            text_align +            text_align, +            match self.font { +                Font::Default => "inherit", +                Font::External { name, .. } => name, +            }          );          // TODO: Complete styling diff --git a/web/src/widget/text_input.rs b/web/src/widget/text_input.rs index 078e05b2..3fa458bd 100644 --- a/web/src/widget/text_input.rs +++ b/web/src/widget/text_input.rs @@ -4,8 +4,11 @@  //!  //! [`TextInput`]: struct.TextInput.html  //! [`State`]: struct.State.html -use crate::{bumpalo, style, Bus, Element, Length, Style, Widget}; -use std::rc::Rc; +use crate::{bumpalo, css, Bus, Css, Element, Length, Widget}; + +pub use iced_style::text_input::{Style, StyleSheet}; + +use std::{rc::Rc, u32};  /// A field that can be filled with text.  /// @@ -34,11 +37,12 @@ pub struct TextInput<'a, Message> {      value: String,      is_secure: bool,      width: Length, -    max_width: Length, +    max_width: u32,      padding: u16,      size: Option<u16>,      on_change: Rc<Box<dyn Fn(String) -> Message>>,      on_submit: Option<Message>, +    style_sheet: Box<dyn StyleSheet>,  }  impl<'a, Message> TextInput<'a, Message> { @@ -67,11 +71,12 @@ impl<'a, Message> TextInput<'a, Message> {              value: String::from(value),              is_secure: false,              width: Length::Fill, -            max_width: Length::Shrink, +            max_width: u32::MAX,              padding: 0,              size: None,              on_change: Rc::new(Box::new(on_change)),              on_submit: None, +            style_sheet: Default::default(),          }      } @@ -94,7 +99,7 @@ impl<'a, Message> TextInput<'a, Message> {      /// Sets the maximum width of the [`TextInput`].      ///      /// [`TextInput`]: struct.TextInput.html -    pub fn max_width(mut self, max_width: Length) -> Self { +    pub fn max_width(mut self, max_width: u32) -> Self {          self.max_width = max_width;          self      } @@ -123,6 +128,14 @@ 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<Box<dyn StyleSheet>>) -> Self { +        self.style_sheet = style.into(); +        self +    }  }  impl<'a, Message> Widget<Message> for TextInput<'a, Message> @@ -133,18 +146,19 @@ where          &self,          bump: &'b bumpalo::Bump,          bus: &Bus<Message>, -        style_sheet: &mut style::Sheet<'b>, +        style_sheet: &mut Css<'b>,      ) -> dodrio::Node<'b> {          use dodrio::builder::*;          use wasm_bindgen::JsCast; -        let width = style::length(self.width); -        let max_width = style::length(self.max_width);          let padding_class = -            style_sheet.insert(bump, Style::Padding(self.padding)); +            style_sheet.insert(bump, css::Rule::Padding(self.padding));          let on_change = self.on_change.clone(); -        let event_bus = bus.clone(); +        let on_submit = self.on_submit.clone(); +        let input_event_bus = bus.clone(); +        let submit_event_bus = bus.clone(); +        let style = self.style_sheet.active();          input(bump)              .attr( @@ -155,10 +169,15 @@ where                  "style",                  bumpalo::format!(                      in bump, -                    "width: {}; max-width: {}; font-size: {}px", -                    width, -                    max_width, -                    self.size.unwrap_or(20) +                    "width: {}; max-width: {}; font-size: {}px; background: {}; border-width: {}px; border-color: {}; border-radius: {}px; color: {}", +                    css::length(self.width), +                    css::max_length(self.max_width), +                    self.size.unwrap_or(20), +                    css::background(style.background), +                    style.border_width, +                    css::color(style.border_color), +                    style.border_radius, +                    css::color(self.style_sheet.value_color())                  )                  .into_bump_str(),              ) @@ -183,7 +202,17 @@ where                      Some(text_input) => text_input,                  }; -                event_bus.publish(on_change(text_input.value())); +                input_event_bus.publish(on_change(text_input.value())); +            }) +            .on("keypress", move |_root, _vdom, event| { +                if let Some(on_submit) = on_submit.clone() { +                    let event = event.unchecked_into::<web_sys::KeyboardEvent>(); + +                    match event.key_code() { +                        13 => { submit_event_bus.publish(on_submit); } +                        _ => {} +                    } +                }              })              .finish()      } @@ -211,4 +240,12 @@ impl State {      pub fn new() -> Self {          Self::default()      } + +    /// Creates a new [`State`], representing a focused [`TextInput`]. +    /// +    /// [`State`]: struct.State.html +    pub fn focused() -> Self { +        // TODO +        Self::default() +    }  } | 
