summaryrefslogtreecommitdiffstats
path: root/web/src/widget
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2020-02-06 10:21:52 -0600
committerLibravatar GitHub <noreply@github.com>2020-02-06 10:21:52 -0600
commit97c308076ff93d09eb874f8e954aae4c7c5deaf7 (patch)
treec3a4ec76931c8153c932c364fa393e25d39d74f0 /web/src/widget
parent7b892eb3e11596925a2993bcc4175ac09ff3768a (diff)
parent36e617ae70cc7a86ce998cbd61f6aa702bb42933 (diff)
downloadiced-97c308076ff93d09eb874f8e954aae4c7c5deaf7.tar.gz
iced-97c308076ff93d09eb874f8e954aae4c7c5deaf7.tar.bz2
iced-97c308076ff93d09eb874f8e954aae4c7c5deaf7.zip
Merge pull request #180 from hecrj/feature/web-styling
Custom styling for `iced_web`
Diffstat (limited to 'web/src/widget')
-rw-r--r--web/src/widget/button.rs66
-rw-r--r--web/src/widget/checkbox.rs46
-rw-r--r--web/src/widget/column.rs29
-rw-r--r--web/src/widget/container.rs42
-rw-r--r--web/src/widget/image.rs91
-rw-r--r--web/src/widget/progress_bar.rs124
-rw-r--r--web/src/widget/radio.rs17
-rw-r--r--web/src/widget/row.rs29
-rw-r--r--web/src/widget/scrollable.rs24
-rw-r--r--web/src/widget/slider.rs18
-rw-r--r--web/src/widget/space.rs8
-rw-r--r--web/src/widget/text.rs21
-rw-r--r--web/src/widget/text_input.rs67
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);
+/// ```
+///
+/// ![Progress bar](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png)
+#[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()
+ }
}