From a97401aed2a173260a4abfdb65a77975ce6c0f01 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 14 Sep 2019 19:16:06 +0200 Subject: Rethink workspace structure --- web/src/lib.rs | 1 + 1 file changed, 1 insertion(+) create mode 100644 web/src/lib.rs (limited to 'web/src') diff --git a/web/src/lib.rs b/web/src/lib.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/web/src/lib.rs @@ -0,0 +1 @@ + -- cgit From 27ac85a9d98474904c422a891e54888376dec00a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 14 Sep 2019 20:54:50 +0200 Subject: Draft web runtime and widgets --- web/src/color.rs | 16 ++++++++++++++++ web/src/element.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++ web/src/lib.rs | 27 ++++++++++++++++++++++++++ web/src/widget.rs | 20 +++++++++++++++++++ web/src/widget/button.rs | 16 ++++++++++++++++ web/src/widget/checkbox.rs | 14 ++++++++++++++ web/src/widget/column.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++ web/src/widget/image.rs | 11 +++++++++++ web/src/widget/radio.rs | 14 ++++++++++++++ web/src/widget/row.rs | 36 ++++++++++++++++++++++++++++++++++ web/src/widget/slider.rs | 16 ++++++++++++++++ web/src/widget/text.rs | 13 +++++++++++++ 12 files changed, 278 insertions(+) create mode 100644 web/src/color.rs create mode 100644 web/src/element.rs create mode 100644 web/src/widget.rs create mode 100644 web/src/widget/button.rs create mode 100644 web/src/widget/checkbox.rs create mode 100644 web/src/widget/column.rs create mode 100644 web/src/widget/image.rs create mode 100644 web/src/widget/radio.rs create mode 100644 web/src/widget/row.rs create mode 100644 web/src/widget/slider.rs create mode 100644 web/src/widget/text.rs (limited to 'web/src') diff --git a/web/src/color.rs b/web/src/color.rs new file mode 100644 index 00000000..2624c3c9 --- /dev/null +++ b/web/src/color.rs @@ -0,0 +1,16 @@ +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Color { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +impl Color { + pub const BLACK: Color = Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }; +} diff --git a/web/src/element.rs b/web/src/element.rs new file mode 100644 index 00000000..c0c9ce5d --- /dev/null +++ b/web/src/element.rs @@ -0,0 +1,47 @@ +use crate::{Color, Widget}; + +pub struct Element<'a, Message> { + pub(crate) widget: Box + 'a>, +} + +impl<'a, Message> Element<'a, Message> { + pub fn new(widget: impl Widget + 'a) -> Self { + Self { + widget: Box::new(widget), + } + } + + pub fn explain(self, color: Color) -> Element<'a, Message> { + self + } + + pub fn map(self, f: F) -> Element<'a, B> + where + Message: 'static, + B: 'static, + F: 'static + Fn(Message) -> B, + { + Element { + widget: Box::new(Map::new(self.widget, f)), + } + } +} + +struct Map<'a, A, B> { + widget: Box + 'a>, + mapper: Box B>, +} + +impl<'a, A, B> Map<'a, A, B> { + pub fn new(widget: Box + 'a>, mapper: F) -> Map<'a, A, B> + where + F: 'static + Fn(A) -> B, + { + Map { + widget, + mapper: Box::new(mapper), + } + } +} + +impl<'a, A, B> Widget for Map<'a, A, B> {} diff --git a/web/src/lib.rs b/web/src/lib.rs index 8b137891..187e8ad9 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -1 +1,28 @@ +use futures::Future; +mod color; +mod element; +mod widget; + +pub use color::Color; +pub use element::Element; +pub use iced::Align; +pub use widget::*; + +pub trait UserInterface { + type Message; + + fn update( + &mut self, + message: Self::Message, + ) -> Box>; + + fn view(&mut self) -> Element; + + fn run(mut self) + where + Self: Sized, + { + let element = self.view(); + } +} diff --git a/web/src/widget.rs b/web/src/widget.rs new file mode 100644 index 00000000..5cb89a60 --- /dev/null +++ b/web/src/widget.rs @@ -0,0 +1,20 @@ +pub mod button; +pub mod slider; +pub mod text; + +mod checkbox; +mod column; +mod image; +mod radio; +mod row; + +pub use button::Button; +pub use checkbox::Checkbox; +pub use column::Column; +pub use image::Image; +pub use radio::Radio; +pub use row::Row; +pub use slider::Slider; +pub use text::Text; + +pub trait Widget {} diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs new file mode 100644 index 00000000..1f117d82 --- /dev/null +++ b/web/src/widget/button.rs @@ -0,0 +1,16 @@ +use crate::{Element, Widget}; + +pub use iced::button::{Class, State}; + +pub type Button<'a, Message> = iced::Button<'a, Message>; + +impl<'a, Message> Widget for Button<'a, Message> {} + +impl<'a, Message> From> for Element<'a, Message> +where + Message: 'static, +{ + fn from(button: Button<'a, Message>) -> Element<'a, Message> { + Element::new(button) + } +} diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs new file mode 100644 index 00000000..a231d801 --- /dev/null +++ b/web/src/widget/checkbox.rs @@ -0,0 +1,14 @@ +use crate::{Color, Element, Widget}; + +pub type Checkbox = iced::Checkbox; + +impl Widget for Checkbox {} + +impl<'a, Message> From> for Element<'a, Message> +where + Message: 'static, +{ + fn from(checkbox: Checkbox) -> Element<'a, Message> { + Element::new(checkbox) + } +} diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs new file mode 100644 index 00000000..84068ce6 --- /dev/null +++ b/web/src/widget/column.rs @@ -0,0 +1,48 @@ +use crate::{Align, Element, Widget}; + +pub struct Column<'a, Message> { + children: Vec>, +} + +impl<'a, Message> Column<'a, Message> { + pub fn new() -> Self { + Self { + children: Vec::new(), + } + } + + pub fn spacing(self, _spacing: u16) -> Self { + self + } + + pub fn padding(self, _padding: u16) -> Self { + self + } + + pub fn max_width(self, _max_width: u16) -> Self { + self + } + + pub fn align_items(self, _align: Align) -> Self { + self + } + + pub fn push(mut self, element: E) -> Self + where + E: Into>, + { + self.children.push(element.into()); + self + } +} + +impl<'a, Message> Widget for Column<'a, Message> {} + +impl<'a, Message> From> for Element<'a, Message> +where + Message: 'static, +{ + fn from(column: Column<'a, Message>) -> Element<'a, Message> { + Element::new(column) + } +} diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs new file mode 100644 index 00000000..ac144fd8 --- /dev/null +++ b/web/src/widget/image.rs @@ -0,0 +1,11 @@ +use crate::{Element, Widget}; + +pub type Image<'a> = iced::Image<&'a str>; + +impl<'a, Message> Widget for Image<'a> {} + +impl<'a, Message> From> for Element<'a, Message> { + fn from(image: Image<'a>) -> Element<'a, Message> { + Element::new(image) + } +} diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs new file mode 100644 index 00000000..0c28b46f --- /dev/null +++ b/web/src/widget/radio.rs @@ -0,0 +1,14 @@ +use crate::{Color, Element, Widget}; + +pub type Radio = iced::Radio; + +impl Widget for Radio {} + +impl<'a, Message> From> for Element<'a, Message> +where + Message: 'static, +{ + fn from(radio: Radio) -> Element<'a, Message> { + Element::new(radio) + } +} diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs new file mode 100644 index 00000000..fc474ec3 --- /dev/null +++ b/web/src/widget/row.rs @@ -0,0 +1,36 @@ +use crate::{Element, Widget}; + +pub struct Row<'a, Message> { + children: Vec>, +} + +impl<'a, Message> Row<'a, Message> { + pub fn new() -> Self { + Self { + children: Vec::new(), + } + } + + pub fn spacing(self, _spacing: u16) -> Self { + self + } + + pub fn push(mut self, element: E) -> Self + where + E: Into>, + { + self.children.push(element.into()); + self + } +} + +impl<'a, Message> Widget for Row<'a, Message> {} + +impl<'a, Message> From> for Element<'a, Message> +where + Message: 'static, +{ + fn from(column: Row<'a, Message>) -> Element<'a, Message> { + Element::new(column) + } +} diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs new file mode 100644 index 00000000..9c83befb --- /dev/null +++ b/web/src/widget/slider.rs @@ -0,0 +1,16 @@ +use crate::{Element, Widget}; + +pub use iced::slider::State; + +pub type Slider<'a, Message> = iced::Slider<'a, Message>; + +impl<'a, Message> Widget for Slider<'a, Message> {} + +impl<'a, Message> From> for Element<'a, Message> +where + Message: 'static, +{ + fn from(slider: Slider<'a, Message>) -> Element<'a, Message> { + Element::new(slider) + } +} diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs new file mode 100644 index 00000000..0c1f75b6 --- /dev/null +++ b/web/src/widget/text.rs @@ -0,0 +1,13 @@ +use crate::{Color, Element, Widget}; + +pub use iced::text::HorizontalAlignment; + +pub type Text = iced::Text; + +impl<'a, Message> Widget for Text {} + +impl<'a, Message> From for Element<'a, Message> { + fn from(text: Text) -> Element<'a, Message> { + Element::new(text) + } +} -- cgit From 8834772fa70850559f7bd82cc8432394e3fd9db7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 15 Sep 2019 17:43:15 +0200 Subject: Draft widget nodes and wire interaction --- web/src/bus.rs | 40 +++++++++++++++++++++++++++++++++++ web/src/element.rs | 25 +++++++++++++++++----- web/src/lib.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++--- web/src/widget.rs | 15 +++++++++++++- web/src/widget/button.rs | 34 +++++++++++++++++++++++++++--- web/src/widget/column.rs | 22 ++++++++++++++++++-- web/src/widget/row.rs | 22 ++++++++++++++++++-- web/src/widget/text.rs | 21 +++++++++++++++++-- 8 files changed, 215 insertions(+), 18 deletions(-) create mode 100644 web/src/bus.rs (limited to 'web/src') diff --git a/web/src/bus.rs b/web/src/bus.rs new file mode 100644 index 00000000..d76466f5 --- /dev/null +++ b/web/src/bus.rs @@ -0,0 +1,40 @@ +use crate::Application; + +use std::rc::Rc; + +#[derive(Clone)] +pub struct Bus { + publish: Rc>, +} + +impl Bus +where + Message: 'static, +{ + pub fn new() -> Self { + Self { + publish: Rc::new(Box::new(|message, root| { + let app = root.unwrap_mut::>(); + + app.update(message) + })), + } + } + + pub fn publish(&self, message: Message, root: &mut dyn dodrio::RootRender) { + (self.publish)(message, root); + } + + pub fn map(&self, mapper: Rc Message>>) -> Bus + where + B: 'static, + { + let publish = self.publish.clone(); + + Bus { + publish: Rc::new(Box::new(move |message, root| { + publish(mapper(message), root) + })), + } + } +} diff --git a/web/src/element.rs b/web/src/element.rs index c0c9ce5d..8270d8db 100644 --- a/web/src/element.rs +++ b/web/src/element.rs @@ -1,4 +1,7 @@ -use crate::{Color, Widget}; +use crate::{Bus, Color, Widget}; + +use dodrio::bumpalo; +use std::rc::Rc; pub struct Element<'a, Message> { pub(crate) widget: Box + 'a>, @@ -11,7 +14,7 @@ impl<'a, Message> Element<'a, Message> { } } - pub fn explain(self, color: Color) -> Element<'a, Message> { + pub fn explain(self, _color: Color) -> Element<'a, Message> { self } @@ -29,7 +32,7 @@ impl<'a, Message> Element<'a, Message> { struct Map<'a, A, B> { widget: Box + 'a>, - mapper: Box B>, + mapper: Rc B>>, } impl<'a, A, B> Map<'a, A, B> { @@ -39,9 +42,21 @@ impl<'a, A, B> Map<'a, A, B> { { Map { widget, - mapper: Box::new(mapper), + mapper: Rc::new(Box::new(mapper)), } } } -impl<'a, A, B> Widget for Map<'a, A, B> {} +impl<'a, A, B> Widget for Map<'a, A, B> +where + A: 'static, + B: 'static, +{ + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + bus: &Bus, + ) -> dodrio::Node<'b> { + self.widget.node(bump, &bus.map(self.mapper.clone())) + } +} diff --git a/web/src/lib.rs b/web/src/lib.rs index 187e8ad9..3173e736 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -1,9 +1,13 @@ +use dodrio::bumpalo; use futures::Future; +use std::cell::RefCell; +mod bus; mod color; mod element; mod widget; +pub use bus::Bus; pub use color::Color; pub use element::Element; pub use iced::Align; @@ -19,10 +23,54 @@ pub trait UserInterface { fn view(&mut self) -> Element; - fn run(mut self) + fn run(self) where - Self: Sized, + Self: 'static + Sized, { - let element = self.view(); + let window = web_sys::window().unwrap(); + let document = window.document().unwrap(); + let body = document.body().unwrap(); + + let app = Application::new(self); + + let vdom = dodrio::Vdom::new(&body, app); + vdom.forget(); + } +} + +struct Application { + ui: RefCell>>, +} + +impl Application { + fn new(ui: impl UserInterface + 'static) -> Self { + Self { + ui: RefCell::new(Box::new(ui)), + } + } + + fn update(&mut self, message: Message) { + let mut ui = self.ui.borrow_mut(); + + // TODO: Resolve futures and publish resulting messages + let _ = ui.update(message); + } +} + +impl dodrio::Render for Application +where + Message: 'static, +{ + fn render<'a, 'bump>( + &'a self, + bump: &'bump bumpalo::Bump, + ) -> dodrio::Node<'bump> + where + 'a: 'bump, + { + let mut ui = self.ui.borrow_mut(); + let element = ui.view(); + + element.widget.node(bump, &Bus::new()) } } diff --git a/web/src/widget.rs b/web/src/widget.rs index 5cb89a60..7af592e1 100644 --- a/web/src/widget.rs +++ b/web/src/widget.rs @@ -1,3 +1,6 @@ +use crate::Bus; +use dodrio::bumpalo; + pub mod button; pub mod slider; pub mod text; @@ -17,4 +20,14 @@ pub use row::Row; pub use slider::Slider; pub use text::Text; -pub trait Widget {} +pub trait Widget { + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + _bus: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + div(bump).children(vec![text("WIP")]).finish() + } +} diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 1f117d82..8ccda107 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -1,14 +1,42 @@ -use crate::{Element, Widget}; +use crate::{Bus, Element, Widget}; +use dodrio::bumpalo; pub use iced::button::{Class, State}; pub type Button<'a, Message> = iced::Button<'a, Message>; -impl<'a, Message> Widget for Button<'a, Message> {} +impl<'a, Message> Widget for Button<'a, Message> +where + Message: 'static + Copy, +{ + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + bus: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let label = bumpalo::format!(in bump, "{}", self.label); + + let mut node = button(bump).children(vec![text(label.into_bump_str())]); + + if let Some(on_press) = self.on_press { + let event_bus = bus.clone(); + + node = node.on("click", move |root, vdom, _event| { + event_bus.publish(on_press, root); + + vdom.schedule_render(); + }); + } + + node.finish() + } +} impl<'a, Message> From> for Element<'a, Message> where - Message: 'static, + Message: 'static + Copy, { fn from(button: Button<'a, Message>) -> Element<'a, Message> { Element::new(button) diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index 84068ce6..b3131f5e 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -1,4 +1,6 @@ -use crate::{Align, Element, Widget}; +use crate::{Align, Bus, Element, Widget}; + +use dodrio::bumpalo; pub struct Column<'a, Message> { children: Vec>, @@ -36,7 +38,23 @@ impl<'a, Message> Column<'a, Message> { } } -impl<'a, Message> Widget for Column<'a, Message> {} +impl<'a, Message> Widget for Column<'a, Message> { + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + publish: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let children: Vec<_> = self + .children + .iter() + .map(|element| element.widget.node(bump, publish)) + .collect(); + + div(bump).children(children).finish() + } +} impl<'a, Message> From> for Element<'a, Message> where diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index fc474ec3..40fc68e3 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -1,4 +1,6 @@ -use crate::{Element, Widget}; +use crate::{Bus, Element, Widget}; + +use dodrio::bumpalo; pub struct Row<'a, Message> { children: Vec>, @@ -24,7 +26,23 @@ impl<'a, Message> Row<'a, Message> { } } -impl<'a, Message> Widget for Row<'a, Message> {} +impl<'a, Message> Widget for Row<'a, Message> { + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + publish: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let children: Vec<_> = self + .children + .iter() + .map(|element| element.widget.node(bump, publish)) + .collect(); + + div(bump).children(children).finish() + } +} impl<'a, Message> From> for Element<'a, Message> where diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index 0c1f75b6..b8fe9565 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -1,10 +1,27 @@ -use crate::{Color, Element, Widget}; +use crate::{Bus, Color, Element, Widget}; +use dodrio::bumpalo; pub use iced::text::HorizontalAlignment; pub type Text = iced::Text; -impl<'a, Message> Widget for Text {} +impl<'a, Message> Widget for Text { + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + _publish: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let content = bumpalo::format!(in bump, "{}", self.content); + let size = bumpalo::format!(in bump, "font-size: {}px", self.size.unwrap_or(20)); + + p(bump) + .attr("style", size.into_bump_str()) + .children(vec![text(content.into_bump_str())]) + .finish() + } +} impl<'a, Message> From for Element<'a, Message> { fn from(text: Text) -> Element<'a, Message> { -- cgit From 655978f480c32bc696f0d5fe2fff834bfbf238ea Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 15 Sep 2019 18:53:13 +0200 Subject: Draft nodes for missing widgets --- web/src/widget.rs | 6 +---- web/src/widget/button.rs | 4 ++-- web/src/widget/checkbox.rs | 39 +++++++++++++++++++++++++++++--- web/src/widget/column.rs | 5 ++++- web/src/widget/image.rs | 25 +++++++++++++++++++-- web/src/widget/radio.rs | 40 ++++++++++++++++++++++++++++++--- web/src/widget/row.rs | 5 ++++- web/src/widget/slider.rs | 55 ++++++++++++++++++++++++++++++++++++++++++---- 8 files changed, 158 insertions(+), 21 deletions(-) (limited to 'web/src') diff --git a/web/src/widget.rs b/web/src/widget.rs index 7af592e1..67ca8e81 100644 --- a/web/src/widget.rs +++ b/web/src/widget.rs @@ -25,9 +25,5 @@ pub trait Widget { &self, bump: &'b bumpalo::Bump, _bus: &Bus, - ) -> dodrio::Node<'b> { - use dodrio::builder::*; - - div(bump).children(vec![text("WIP")]).finish() - } + ) -> dodrio::Node<'b>; } diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 8ccda107..63c0262a 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -1,8 +1,8 @@ use crate::{Bus, Element, Widget}; -use dodrio::bumpalo; - pub use iced::button::{Class, State}; +use dodrio::bumpalo; + pub type Button<'a, Message> = iced::Button<'a, Message>; impl<'a, Message> Widget for Button<'a, Message> diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index a231d801..e3c61ca7 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -1,12 +1,45 @@ -use crate::{Color, Element, Widget}; +use crate::{Bus, Color, Element, Widget}; + +use dodrio::bumpalo; pub type Checkbox = iced::Checkbox; -impl Widget for Checkbox {} +impl Widget for Checkbox +where + Message: 'static + Copy, +{ + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + bus: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let checkbox_label = bumpalo::format!(in bump, "{}", self.label); + + let event_bus = bus.clone(); + let msg = (self.on_toggle)(!self.is_checked); + + label(bump) + .children(vec![ + input(bump) + .attr("type", "checkbox") + .bool_attr("checked", self.is_checked) + .on("click", move |root, vdom, _event| { + event_bus.publish(msg, root); + + vdom.schedule_render(); + }) + .finish(), + text(checkbox_label.into_bump_str()), + ]) + .finish() + } +} impl<'a, Message> From> for Element<'a, Message> where - Message: 'static, + Message: 'static + Copy, { fn from(checkbox: Checkbox) -> Element<'a, Message> { Element::new(checkbox) diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index b3131f5e..a2b8232e 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -52,7 +52,10 @@ impl<'a, Message> Widget for Column<'a, Message> { .map(|element| element.widget.node(bump, publish)) .collect(); - div(bump).children(children).finish() + div(bump) + .attr("style", "display: flex; flex-direction: column") + .children(children) + .finish() } } diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index ac144fd8..a882faff 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -1,8 +1,29 @@ -use crate::{Element, Widget}; +use crate::{Bus, Element, Widget}; + +use dodrio::bumpalo; pub type Image<'a> = iced::Image<&'a str>; -impl<'a, Message> Widget for Image<'a> {} +impl<'a, Message> Widget for Image<'a> { + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + _bus: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let src = bumpalo::format!(in bump, "{}", self.image); + + let mut image = img(bump).attr("src", src.into_bump_str()); + + if let Some(width) = self.width { + let width = bumpalo::format!(in bump, "{}", width); + image = image.attr("width", width.into_bump_str()); + } + + image.finish() + } +} impl<'a, Message> From> for Element<'a, Message> { fn from(image: Image<'a>) -> Element<'a, Message> { diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index 0c28b46f..df08a977 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -1,12 +1,46 @@ -use crate::{Color, Element, Widget}; +use crate::{Bus, Color, Element, Widget}; + +use dodrio::bumpalo; pub type Radio = iced::Radio; -impl Widget for Radio {} +impl Widget for Radio +where + Message: 'static + Copy, +{ + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + bus: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let radio_label = bumpalo::format!(in bump, "{}", self.label); + + let event_bus = bus.clone(); + let on_click = self.on_click; + + label(bump) + .attr("style", "display: block") + .children(vec![ + input(bump) + .attr("type", "radio") + .bool_attr("checked", self.is_selected) + .on("click", move |root, vdom, _event| { + event_bus.publish(on_click, root); + + vdom.schedule_render(); + }) + .finish(), + text(radio_label.into_bump_str()), + ]) + .finish() + } +} impl<'a, Message> From> for Element<'a, Message> where - Message: 'static, + Message: 'static + Copy, { fn from(radio: Radio) -> Element<'a, Message> { Element::new(radio) diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index 40fc68e3..71532245 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -40,7 +40,10 @@ impl<'a, Message> Widget for Row<'a, Message> { .map(|element| element.widget.node(bump, publish)) .collect(); - div(bump).children(children).finish() + div(bump) + .attr("style", "display: flex; flex-direction: row") + .children(children) + .finish() } } diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 9c83befb..31bfcbf3 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -1,14 +1,61 @@ -use crate::{Element, Widget}; +use crate::{Bus, Element, Widget}; -pub use iced::slider::State; +use dodrio::bumpalo; pub type Slider<'a, Message> = iced::Slider<'a, Message>; -impl<'a, Message> Widget for Slider<'a, Message> {} +pub use iced::slider::State; + +impl<'a, Message> Widget for Slider<'a, Message> +where + Message: 'static + Copy, +{ + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + bus: &Bus, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + use wasm_bindgen::JsCast; + + let (start, end) = self.range.clone().into_inner(); + + let min = bumpalo::format!(in bump, "{}", start); + let max = bumpalo::format!(in bump, "{}", end); + let value = bumpalo::format!(in bump, "{}", self.value); + + let on_change = self.on_change.clone(); + let event_bus = bus.clone(); + + // TODO: Make `step` configurable + label(bump) + .children(vec![input(bump) + .attr("type", "range") + .attr("step", "0.01") + .attr("min", min.into_bump_str()) + .attr("max", max.into_bump_str()) + .attr("value", value.into_bump_str()) + .on("input", move |root, vdom, event| { + let slider = match event.target().and_then(|t| { + t.dyn_into::().ok() + }) { + None => return, + Some(slider) => slider, + }; + + if let Ok(value) = slider.value().parse::() { + event_bus.publish(on_change(value), root); + vdom.schedule_render(); + } + }) + .finish()]) + .finish() + } +} impl<'a, Message> From> for Element<'a, Message> where - Message: 'static, + Message: 'static + Copy, { fn from(slider: Slider<'a, Message>) -> Element<'a, Message> { Element::new(slider) -- cgit From dd093c79d7da84675be648c7df2ebfc85b5039f2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 16 Sep 2019 18:03:57 +0200 Subject: Use `futures-preview` instead of `futures` --- web/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/src') diff --git a/web/src/lib.rs b/web/src/lib.rs index 3173e736..5a0dd6f2 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -19,7 +19,7 @@ pub trait UserInterface { fn update( &mut self, message: Self::Message, - ) -> Box>; + ) -> Option>>; fn view(&mut self) -> Element; -- cgit From f9de39ddaa3020a9585b1648afb0ead45dfd7aa9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 19 Sep 2019 15:01:12 +0200 Subject: Unify `web` and `ggez` tour examples :tada: --- web/src/color.rs | 16 ---------------- web/src/lib.rs | 4 +--- 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 web/src/color.rs (limited to 'web/src') diff --git a/web/src/color.rs b/web/src/color.rs deleted file mode 100644 index 2624c3c9..00000000 --- a/web/src/color.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Color { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} - -impl Color { - pub const BLACK: Color = Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 1.0, - }; -} diff --git a/web/src/lib.rs b/web/src/lib.rs index 5a0dd6f2..a6dc2b79 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -3,14 +3,12 @@ use futures::Future; use std::cell::RefCell; mod bus; -mod color; mod element; mod widget; pub use bus::Bus; -pub use color::Color; pub use element::Element; -pub use iced::Align; +pub use iced::{Align, Color}; pub use widget::*; pub trait UserInterface { -- cgit From b83a4b42dd912b5f59d40e7d4f7f7ccdabc43019 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 19 Sep 2019 18:47:01 +0200 Subject: Remove generic `Color` in widgets --- web/src/widget/checkbox.rs | 4 ++-- web/src/widget/radio.rs | 4 ++-- web/src/widget/text.rs | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'web/src') diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index e3c61ca7..5aadd65d 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -1,8 +1,8 @@ -use crate::{Bus, Color, Element, Widget}; +use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub type Checkbox = iced::Checkbox; +pub use iced::Checkbox; impl Widget for Checkbox where diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index df08a977..e762ae28 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -1,8 +1,8 @@ -use crate::{Bus, Color, Element, Widget}; +use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub type Radio = iced::Radio; +pub use iced::Radio; impl Widget for Radio where diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index b8fe9565..a5709775 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -1,9 +1,7 @@ -use crate::{Bus, Color, Element, Widget}; +use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub use iced::text::HorizontalAlignment; - -pub type Text = iced::Text; +pub use iced::text::*; impl<'a, Message> Widget for Text { fn node<'b>( -- cgit From b9e0f7494881ad7cdfbcbc16878ecc6ef717753f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 20 Sep 2019 19:15:31 +0200 Subject: Create `iced_core` and `iced_native` --- web/src/lib.rs | 2 +- web/src/widget/button.rs | 3 +-- web/src/widget/checkbox.rs | 2 +- web/src/widget/column.rs | 38 ++------------------------------------ web/src/widget/image.rs | 20 ++++++++++++++------ web/src/widget/radio.rs | 2 +- web/src/widget/row.rs | 24 +----------------------- web/src/widget/slider.rs | 4 ++-- web/src/widget/text.rs | 2 +- 9 files changed, 24 insertions(+), 73 deletions(-) (limited to 'web/src') diff --git a/web/src/lib.rs b/web/src/lib.rs index a6dc2b79..09ca3460 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -8,7 +8,7 @@ mod widget; pub use bus::Bus; pub use element::Element; -pub use iced::{Align, Color}; +pub use iced_core::{Align, Color, Length}; pub use widget::*; pub trait UserInterface { diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 63c0262a..36b35901 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -1,9 +1,8 @@ use crate::{Bus, Element, Widget}; -pub use iced::button::{Class, State}; use dodrio::bumpalo; -pub type Button<'a, Message> = iced::Button<'a, Message>; +pub type Button<'a, Message> = iced_core::Button<'a, Message>; impl<'a, Message> Widget for Button<'a, Message> where diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index 5aadd65d..34995781 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -2,7 +2,7 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub use iced::Checkbox; +pub use iced_core::Checkbox; impl Widget for Checkbox where diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index a2b8232e..99491647 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -1,42 +1,8 @@ -use crate::{Align, Bus, Element, Widget}; +use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub struct Column<'a, Message> { - children: Vec>, -} - -impl<'a, Message> Column<'a, Message> { - pub fn new() -> Self { - Self { - children: Vec::new(), - } - } - - pub fn spacing(self, _spacing: u16) -> Self { - self - } - - pub fn padding(self, _padding: u16) -> Self { - self - } - - pub fn max_width(self, _max_width: u16) -> Self { - self - } - - pub fn align_items(self, _align: Align) -> Self { - self - } - - pub fn push(mut self, element: E) -> Self - where - E: Into>, - { - self.children.push(element.into()); - self - } -} +pub type Column<'a, Message> = iced_core::Column>; impl<'a, Message> Widget for Column<'a, Message> { fn node<'b>( diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index a882faff..48ff539f 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -1,8 +1,8 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Element, Length, Widget}; use dodrio::bumpalo; -pub type Image<'a> = iced::Image<&'a str>; +pub type Image<'a> = iced_core::Image<&'a str>; impl<'a, Message> Widget for Image<'a> { fn node<'b>( @@ -12,13 +12,21 @@ impl<'a, Message> Widget for Image<'a> { ) -> dodrio::Node<'b> { use dodrio::builder::*; - let src = bumpalo::format!(in bump, "{}", self.image); + let src = bumpalo::format!(in bump, "{}", self.handle); let mut image = img(bump).attr("src", src.into_bump_str()); - if let Some(width) = self.width { - let width = bumpalo::format!(in bump, "{}", width); - image = image.attr("width", width.into_bump_str()); + match self.width { + Length::Shrink => {} + Length::Fill => { + image = image.attr("width", "100%"); + } + Length::Units(px) => { + image = image.attr( + "width", + bumpalo::format!(in bump, "{}px", px).into_bump_str(), + ); + } } image.finish() diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index e762ae28..9063770a 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -2,7 +2,7 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub use iced::Radio; +pub use iced_core::Radio; impl Widget for Radio where diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index 71532245..d4f4c4a0 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -2,29 +2,7 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub struct Row<'a, Message> { - children: Vec>, -} - -impl<'a, Message> Row<'a, Message> { - pub fn new() -> Self { - Self { - children: Vec::new(), - } - } - - pub fn spacing(self, _spacing: u16) -> Self { - self - } - - pub fn push(mut self, element: E) -> Self - where - E: Into>, - { - self.children.push(element.into()); - self - } -} +pub type Row<'a, Message> = iced_core::Row>; impl<'a, Message> Widget for Row<'a, Message> { fn node<'b>( diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 31bfcbf3..19668025 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -2,9 +2,9 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub type Slider<'a, Message> = iced::Slider<'a, Message>; +pub type Slider<'a, Message> = iced_core::Slider<'a, Message>; -pub use iced::slider::State; +pub use iced_core::slider::State; impl<'a, Message> Widget for Slider<'a, Message> where diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index a5709775..ef9170ef 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -1,7 +1,7 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub use iced::text::*; +pub use iced_core::text::*; impl<'a, Message> Widget for Text { fn node<'b>( -- cgit From 86dede4c4cc2bca9be7d2e6bd831daa98bd7043d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 21 Sep 2019 13:38:14 +0200 Subject: Make example work on web and update READMEs --- web/src/widget/button.rs | 4 +++- web/src/widget/checkbox.rs | 1 + web/src/widget/column.rs | 1 + web/src/widget/image.rs | 2 ++ web/src/widget/radio.rs | 1 + web/src/widget/row.rs | 1 + web/src/widget/slider.rs | 5 ++--- web/src/widget/text.rs | 1 + 8 files changed, 12 insertions(+), 4 deletions(-) (limited to 'web/src') diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 36b35901..23a4165a 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -2,7 +2,7 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub type Button<'a, Message> = iced_core::Button<'a, Message>; +pub use iced_core::button::*; impl<'a, Message> Widget for Button<'a, Message> where @@ -29,6 +29,8 @@ where }); } + // TODO: Complete styling + node.finish() } } diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index 34995781..72f0a2aa 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -20,6 +20,7 @@ where let event_bus = bus.clone(); let msg = (self.on_toggle)(!self.is_checked); + // TODO: Complete styling label(bump) .children(vec![ input(bump) diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index 99491647..becd6bc6 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -18,6 +18,7 @@ impl<'a, Message> Widget for Column<'a, Message> { .map(|element| element.widget.node(bump, publish)) .collect(); + // TODO: Complete styling div(bump) .attr("style", "display: flex; flex-direction: column") .children(children) diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index 48ff539f..fd4ff0df 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -29,6 +29,8 @@ impl<'a, Message> Widget for Image<'a> { } } + // TODO: Complete styling + image.finish() } } diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index 9063770a..d249ad26 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -20,6 +20,7 @@ where let event_bus = bus.clone(); let on_click = self.on_click; + // TODO: Complete styling label(bump) .attr("style", "display: block") .children(vec![ diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index d4f4c4a0..cf6ae594 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -18,6 +18,7 @@ impl<'a, Message> Widget for Row<'a, Message> { .map(|element| element.widget.node(bump, publish)) .collect(); + // TODO: Complete styling div(bump) .attr("style", "display: flex; flex-direction: row") .children(children) diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 19668025..54b2fdf6 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -2,9 +2,7 @@ use crate::{Bus, Element, Widget}; use dodrio::bumpalo; -pub type Slider<'a, Message> = iced_core::Slider<'a, Message>; - -pub use iced_core::slider::State; +pub use iced_core::slider::*; impl<'a, Message> Widget for Slider<'a, Message> where @@ -28,6 +26,7 @@ where let event_bus = bus.clone(); // TODO: Make `step` configurable + // TODO: Complete styling label(bump) .children(vec![input(bump) .attr("type", "range") diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index ef9170ef..41ccd6fc 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -14,6 +14,7 @@ impl<'a, Message> Widget for Text { let content = bumpalo::format!(in bump, "{}", self.content); let size = bumpalo::format!(in bump, "font-size: {}px", self.size.unwrap_or(20)); + // TODO: Complete styling p(bump) .attr("style", size.into_bump_str()) .children(vec![text(content.into_bump_str())]) -- cgit From 5e28f80af8349be2638eb80d2a06c81fd14d631c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 24 Sep 2019 15:15:34 +0200 Subject: Improve documentation --- web/src/lib.rs | 4 ++-- web/src/widget.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'web/src') diff --git a/web/src/lib.rs b/web/src/lib.rs index 09ca3460..caf17df5 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -4,11 +4,11 @@ use std::cell::RefCell; mod bus; mod element; -mod widget; +pub mod widget; pub use bus::Bus; pub use element::Element; -pub use iced_core::{Align, Color, Length}; +pub use iced_core::{Align, Color, Justify, Length}; pub use widget::*; pub trait UserInterface { diff --git a/web/src/widget.rs b/web/src/widget.rs index 67ca8e81..88b2efc9 100644 --- a/web/src/widget.rs +++ b/web/src/widget.rs @@ -11,14 +11,20 @@ mod image; mod radio; mod row; +#[doc(no_inline)] pub use button::Button; + +#[doc(no_inline)] +pub use slider::Slider; + +#[doc(no_inline)] +pub use text::Text; + pub use checkbox::Checkbox; pub use column::Column; pub use image::Image; pub use radio::Radio; pub use row::Row; -pub use slider::Slider; -pub use text::Text; pub trait Widget { fn node<'b>( -- cgit