diff options
| author | 2022-01-28 16:47:50 +0700 | |
|---|---|---|
| committer | 2022-01-28 21:37:16 +0700 | |
| commit | 825c7749ff364cf1f7ae5cab0c25f27ed85c7d82 (patch) | |
| tree | fdd7e499c343a7e3cf690d4b5aa40ba568674a3c /web/src/widget | |
| parent | 1e3feee3a36f25d7e2eda231c3e6b895858952c5 (diff) | |
| download | iced-825c7749ff364cf1f7ae5cab0c25f27ed85c7d82.tar.gz iced-825c7749ff364cf1f7ae5cab0c25f27ed85c7d82.tar.bz2 iced-825c7749ff364cf1f7ae5cab0c25f27ed85c7d82.zip | |
Replace `iced_web` with WebGL support in `wgpu` :tada:
Diffstat (limited to 'web/src/widget')
| -rw-r--r-- | web/src/widget/button.rs | 192 | ||||
| -rw-r--r-- | web/src/widget/checkbox.rs | 150 | ||||
| -rw-r--r-- | web/src/widget/column.rs | 148 | ||||
| -rw-r--r-- | web/src/widget/container.rs | 153 | ||||
| -rw-r--r-- | web/src/widget/image.rs | 186 | ||||
| -rw-r--r-- | web/src/widget/progress_bar.rs | 116 | ||||
| -rw-r--r-- | web/src/widget/radio.rs | 155 | ||||
| -rw-r--r-- | web/src/widget/row.rs | 148 | ||||
| -rw-r--r-- | web/src/widget/scrollable.rs | 152 | ||||
| -rw-r--r-- | web/src/widget/slider.rs | 183 | ||||
| -rw-r--r-- | web/src/widget/space.rs | 63 | ||||
| -rw-r--r-- | web/src/widget/text.rs | 148 | ||||
| -rw-r--r-- | web/src/widget/text_input.rs | 234 | ||||
| -rw-r--r-- | web/src/widget/toggler.rs | 171 | 
14 files changed, 0 insertions, 2199 deletions
| diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs deleted file mode 100644 index 88137607..00000000 --- a/web/src/widget/button.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Allow your users to perform actions by pressing a button. -//! -//! A [`Button`] has some local [`State`]. -use crate::{css, Background, Bus, Css, Element, Length, Padding, Widget}; - -pub use iced_style::button::{Style, StyleSheet}; - -use dodrio::bumpalo; - -/// A generic widget that produces a message when pressed. -/// -/// ``` -/// # use iced_web::{button, Button, Text}; -/// # -/// enum Message { -///     ButtonPressed, -/// } -/// -/// let mut state = button::State::new(); -/// let button = Button::new(&mut state, Text::new("Press me!")) -///     .on_press(Message::ButtonPressed); -/// ``` -/// -/// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will -/// be disabled: -/// -/// ``` -/// # use iced_web::{button, Button, Text}; -/// # -/// #[derive(Clone)] -/// enum Message { -///     ButtonPressed, -/// } -/// -/// fn disabled_button(state: &mut button::State) -> Button<'_, Message> { -///     Button::new(state, Text::new("I'm disabled!")) -/// } -/// -/// fn enabled_button(state: &mut button::State) -> Button<'_, Message> { -///     disabled_button(state).on_press(Message::ButtonPressed) -/// } -/// ``` -#[allow(missing_debug_implementations)] -pub struct Button<'a, Message> { -    content: Element<'a, Message>, -    on_press: Option<Message>, -    width: Length, -    #[allow(dead_code)] -    height: Length, -    min_width: u32, -    #[allow(dead_code)] -    min_height: u32, -    padding: Padding, -    style: Box<dyn StyleSheet + 'a>, -} - -impl<'a, Message> Button<'a, Message> { -    /// Creates a new [`Button`] with some local [`State`] and the given -    /// content. -    pub fn new<E>(_state: &'a mut State, content: E) -> Self -    where -        E: Into<Element<'a, Message>>, -    { -        Button { -            content: content.into(), -            on_press: None, -            width: Length::Shrink, -            height: Length::Shrink, -            min_width: 0, -            min_height: 0, -            padding: Padding::new(5), -            style: Default::default(), -        } -    } - -    /// Sets the width of the [`Button`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Button`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the minimum width of the [`Button`]. -    pub fn min_width(mut self, min_width: u32) -> Self { -        self.min_width = min_width; -        self -    } - -    /// Sets the minimum height of the [`Button`]. -    pub fn min_height(mut self, min_height: u32) -> Self { -        self.min_height = min_height; -        self -    } - -    /// Sets the [`Padding`] of the [`Button`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the style of the [`Button`]. -    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet + 'a>>) -> Self { -        self.style = style.into(); -        self -    } - -    /// Sets the message that will be produced when the [`Button`] is pressed. -    /// If on_press isn't set, button will be disabled. -    pub fn on_press(mut self, msg: Message) -> Self { -        self.on_press = Some(msg); -        self -    } -} - -/// The local state of a [`Button`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct State; - -impl State { -    /// Creates a new [`State`]. -    pub fn new() -> State { -        State::default() -    } -} - -impl<'a, Message> Widget<Message> for Button<'a, Message> -where -    Message: 'static + Clone, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        // TODO: State-based styling -        let style = self.style.active(); - -        let background = match style.background { -            None => String::from("none"), -            Some(background) => match background { -                Background::Color(color) => css::color(color), -            }, -        }; - -        let mut node = button(bump) -            .attr( -                "style", -                bumpalo::format!( -                    in bump, -                    "background: {}; border-radius: {}px; width:{}; \ -                    min-width: {}; color: {}; padding: {}", -                    background, -                    style.border_radius, -                    css::length(self.width), -                    css::min_length(self.min_width), -                    css::color(style.text_color), -                    css::padding(self.padding) -                ) -                .into_bump_str(), -            ) -            .children(vec![self.content.node(bump, bus, style_sheet)]); - -        if let Some(on_press) = self.on_press.clone() { -            let event_bus = bus.clone(); - -            node = node.on("click", move |_root, _vdom, _event| { -                event_bus.publish(on_press.clone()); -            }); -        } else { -            node = node.attr("disabled", ""); -        } - -        node.finish() -    } -} - -impl<'a, Message> From<Button<'a, Message>> for Element<'a, Message> -where -    Message: 'static + Clone, -{ -    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 deleted file mode 100644 index 844bf862..00000000 --- a/web/src/widget/checkbox.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! 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; - -/// A box that can be checked. -/// -/// # Example -/// -/// ``` -/// # use iced_web::Checkbox; -/// -/// pub enum Message { -///     CheckboxToggled(bool), -/// } -/// -/// let is_checked = true; -/// -/// Checkbox::new(is_checked, "Toggle me!", Message::CheckboxToggled); -/// ``` -/// -///  -#[allow(missing_debug_implementations)] -pub struct Checkbox<'a, Message> { -    is_checked: bool, -    on_toggle: Rc<dyn Fn(bool) -> Message>, -    label: String, -    id: Option<String>, -    width: Length, -    #[allow(dead_code)] -    style_sheet: Box<dyn StyleSheet + 'a>, -} - -impl<'a, Message> Checkbox<'a, Message> { -    /// Creates a new [`Checkbox`]. -    /// -    /// It expects: -    ///   * a boolean describing whether the [`Checkbox`] is checked or not -    ///   * the label of the [`Checkbox`] -    ///   * a function that will be called when the [`Checkbox`] is toggled. It -    ///     will receive the new state of the [`Checkbox`] and must produce a -    ///     `Message`. -    pub fn new<F>(is_checked: bool, label: impl Into<String>, f: F) -> Self -    where -        F: 'static + Fn(bool) -> Message, -    { -        Checkbox { -            is_checked, -            on_toggle: Rc::new(f), -            label: label.into(), -            id: None, -            width: Length::Shrink, -            style_sheet: Default::default(), -        } -    } - -    /// Sets the width of the [`Checkbox`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the style of the [`Checkbox`]. -    pub fn style( -        mut self, -        style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, -    ) -> Self { -        self.style_sheet = style_sheet.into(); -        self -    } - -    /// Sets the id of the [`Checkbox`]. -    pub fn id(mut self, id: impl Into<String>) -> Self { -        self.id = Some(id.into()); -        self -    } -} - -impl<'a, Message> Widget<Message> for Checkbox<'a, Message> -where -    Message: 'static, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; -        use dodrio::bumpalo::collections::String; - -        let checkbox_label = -            String::from_str_in(&self.label, bump).into_bump_str(); - -        let event_bus = bus.clone(); -        let on_toggle = self.on_toggle.clone(); -        let is_checked = self.is_checked; - -        let row_class = style_sheet.insert(bump, css::Rule::Row); - -        let spacing_class = style_sheet.insert(bump, css::Rule::Spacing(5)); - -        let (label, input) = if let Some(id) = &self.id { -            let id = String::from_str_in(id, bump).into_bump_str(); - -            (label(bump).attr("for", id), input(bump).attr("id", id)) -        } else { -            (label(bump), input(bump)) -        }; - -        label -            .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 -                    .attr("type", "checkbox") -                    .bool_attr("checked", self.is_checked) -                    .on("click", move |_root, vdom, _event| { -                        let msg = on_toggle(!is_checked); -                        event_bus.publish(msg); - -                        vdom.schedule_render(); -                    }) -                    .finish(), -                text(checkbox_label), -            ]) -            .finish() -    } -} - -impl<'a, Message> From<Checkbox<'a, Message>> for Element<'a, Message> -where -    Message: 'static, -{ -    fn from(checkbox: Checkbox<'a, Message>) -> Element<'a, Message> { -        Element::new(checkbox) -    } -} diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs deleted file mode 100644 index 30a57c41..00000000 --- a/web/src/widget/column.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::css; -use crate::{Alignment, Bus, Css, Element, Length, Padding, Widget}; - -use dodrio::bumpalo; -use std::u32; - -/// A container that distributes its contents vertically. -/// -/// A [`Column`] will try to fill the horizontal space of its container. -#[allow(missing_debug_implementations)] -pub struct Column<'a, Message> { -    spacing: u16, -    padding: Padding, -    width: Length, -    height: Length, -    max_width: u32, -    max_height: u32, -    align_items: Alignment, -    children: Vec<Element<'a, Message>>, -} - -impl<'a, Message> Column<'a, Message> { -    /// Creates an empty [`Column`]. -    pub fn new() -> Self { -        Self::with_children(Vec::new()) -    } - -    /// Creates a [`Column`] with the given elements. -    pub fn with_children(children: Vec<Element<'a, Message>>) -> Self { -        Column { -            spacing: 0, -            padding: Padding::ZERO, -            width: Length::Fill, -            height: Length::Shrink, -            max_width: u32::MAX, -            max_height: u32::MAX, -            align_items: Alignment::Start, -            children, -        } -    } - -    /// Sets the vertical spacing _between_ elements. -    /// -    /// Custom margins per element do not exist in Iced. You should use this -    /// method instead! While less flexible, it helps you keep spacing between -    /// elements consistent. -    pub fn spacing(mut self, units: u16) -> Self { -        self.spacing = units; -        self -    } - -    /// Sets the [`Padding`] of the [`Column`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the width of the [`Column`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Column`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the maximum width of the [`Column`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.max_width = max_width; -        self -    } - -    /// Sets the maximum height of the [`Column`] in pixels. -    pub fn max_height(mut self, max_height: u32) -> Self { -        self.max_height = max_height; -        self -    } - -    /// Sets the horizontal alignment of the contents of the [`Column`] . -    pub fn align_items(mut self, align: Alignment) -> Self { -        self.align_items = align; -        self -    } - -    /// Adds an element to the [`Column`]. -    pub fn push<E>(mut self, child: E) -> Self -    where -        E: Into<Element<'a, Message>>, -    { -        self.children.push(child.into()); -        self -    } -} - -impl<'a, Message> Widget<Message> for Column<'a, Message> { -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        publish: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        let children: Vec<_> = self -            .children -            .iter() -            .map(|element| element.widget.node(bump, publish, style_sheet)) -            .collect(); - -        let column_class = style_sheet.insert(bump, css::Rule::Column); - -        let spacing_class = -            style_sheet.insert(bump, css::Rule::Spacing(self.spacing)); - -        // TODO: Complete styling -        div(bump) -            .attr( -                "class", -                bumpalo::format!(in bump, "{} {}", column_class, spacing_class) -                    .into_bump_str(), -            ) -            .attr("style", bumpalo::format!( -                    in bump, -                    "width: {}; height: {}; max-width: {}; max-height: {}; padding: {}; align-items: {}", -                    css::length(self.width), -                    css::length(self.height), -                    css::max_length(self.max_width), -                    css::max_length(self.max_height), -                    css::padding(self.padding), -                    css::alignment(self.align_items) -                ).into_bump_str() -            ) -            .children(children) -            .finish() -    } -} - -impl<'a, Message> From<Column<'a, Message>> 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/container.rs b/web/src/widget/container.rs deleted file mode 100644 index 8e345b9a..00000000 --- a/web/src/widget/container.rs +++ /dev/null @@ -1,153 +0,0 @@ -//! Decorate content and apply alignment. -use crate::alignment::{self, Alignment}; -use crate::bumpalo; -use crate::css; -use crate::{Bus, Css, Element, Length, Padding, Widget}; - -pub use iced_style::container::{Style, StyleSheet}; - -/// An element decorating some content. -/// -/// It is normally used for alignment purposes. -#[allow(missing_debug_implementations)] -pub struct Container<'a, Message> { -    padding: Padding, -    width: Length, -    height: Length, -    max_width: u32, -    #[allow(dead_code)] -    max_height: u32, -    horizontal_alignment: alignment::Horizontal, -    vertical_alignment: alignment::Vertical, -    style_sheet: Box<dyn StyleSheet + 'a>, -    content: Element<'a, Message>, -} - -impl<'a, Message> Container<'a, Message> { -    /// Creates an empty [`Container`]. -    pub fn new<T>(content: T) -> Self -    where -        T: Into<Element<'a, Message>>, -    { -        use std::u32; - -        Container { -            padding: Padding::ZERO, -            width: Length::Shrink, -            height: Length::Shrink, -            max_width: u32::MAX, -            max_height: u32::MAX, -            horizontal_alignment: alignment::Horizontal::Left, -            vertical_alignment: alignment::Vertical::Top, -            style_sheet: Default::default(), -            content: content.into(), -        } -    } - -    /// Sets the [`Padding`] of the [`Container`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the width of the [`Container`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Container`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the maximum width of the [`Container`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.max_width = max_width; -        self -    } - -    /// Sets the maximum height of the [`Container`] in pixels. -    pub fn max_height(mut self, max_height: u32) -> Self { -        self.max_height = max_height; -        self -    } - -    /// Centers the contents in the horizontal axis of the [`Container`]. -    pub fn center_x(mut self) -> Self { -        self.horizontal_alignment = alignment::Horizontal::Center; - -        self -    } - -    /// Centers the contents in the vertical axis of the [`Container`]. -    pub fn center_y(mut self) -> Self { -        self.vertical_alignment = alignment::Vertical::Center; - -        self -    } - -    /// Sets the style of the [`Container`]. -    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet + 'a>>) -> Self { -        self.style_sheet = style.into(); -        self -    } -} - -impl<'a, Message> Widget<Message> for Container<'a, Message> -where -    Message: 'static, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        let column_class = style_sheet.insert(bump, css::Rule::Column); - -        let style = self.style_sheet.style(); - -        let node = div(bump) -            .attr( -                "class", -                bumpalo::format!(in bump, "{}", column_class).into_bump_str(), -            ) -            .attr( -                "style", -                bumpalo::format!( -                    in bump, -                    "width: {}; height: {}; max-width: {}; padding: {}; 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::padding(self.padding), -                    css::alignment(Alignment::from(self.horizontal_alignment)), -                    css::alignment(Alignment::from(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(), -            ) -            .children(vec![self.content.node(bump, bus, style_sheet)]); - -        // TODO: Complete styling - -        node.finish() -    } -} - -impl<'a, Message> From<Container<'a, Message>> for Element<'a, Message> -where -    Message: 'static, -{ -    fn from(container: Container<'a, Message>) -> Element<'a, Message> { -        Element::new(container) -    } -} diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs deleted file mode 100644 index 28435f4f..00000000 --- a/web/src/widget/image.rs +++ /dev/null @@ -1,186 +0,0 @@ -//! 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. -/// -/// # Example -/// -/// ``` -/// # use iced_web::Image; -/// -/// let image = Image::new("resources/ferris.png"); -/// ``` -#[derive(Debug)] -pub struct Image { -    /// The image path -    pub handle: Handle, - -    /// The alt text of the image -    pub alt: String, - -    /// The width of the image -    pub width: Length, - -    /// The height of the image -    pub height: Length, -} - -impl Image { -    /// Creates a new [`Image`] with the given path. -    pub fn new<T: Into<Handle>>(handle: T) -> Self { -        Image { -            handle: handle.into(), -            alt: Default::default(), -            width: Length::Shrink, -            height: Length::Shrink, -        } -    } - -    /// Sets the width of the [`Image`] boundaries. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Image`] boundaries. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the alt text of the [`Image`]. -    pub fn alt(mut self, alt: impl Into<String>) -> Self { -        self.alt = alt.into(); -        self -    } -} - -impl<Message> Widget<Message> for Image { -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        _bus: &Bus<Message>, -        _style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; -        use dodrio::bumpalo::collections::String; - -        let src = match self.handle.data.as_ref() { -            Data::Path(path) => { -                String::from_str_in(path.to_str().unwrap_or(""), bump) -            } -            Data::Bytes(bytes) => { -                // The web is able to infer the kind of image, so we don't have to add a dependency on image-rs to guess the mime type. -                bumpalo::format!(in bump, "data:;base64,{}", base64::encode(bytes)) -            }, -        } -        .into_bump_str(); - -        let alt = String::from_str_in(&self.alt, bump).into_bump_str(); - -        let mut image = img(bump).attr("src", src).attr("alt", alt); - -        match self.width { -            Length::Shrink => {} -            Length::Fill | Length::FillPortion(_) => { -                image = image.attr("width", "100%"); -            } -            Length::Units(px) => { -                image = image.attr( -                    "width", -                    bumpalo::format!(in bump, "{}px", px).into_bump_str(), -                ); -            } -        } - -        // TODO: Complete styling - -        image.finish() -    } -} - -impl<'a, Message> From<Image> for Element<'a, Message> { -    fn from(image: Image) -> Element<'a, Message> { -        Element::new(image) -    } -} - -/// An [`Image`] handle. -#[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. -    pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle { -        Self::from_data(Data::Path(path.into())) -    } - -    /// Creates an image [`Handle`] containing the image data directly. -    /// -    /// This is useful if you already have your image loaded in-memory, maybe -    /// because you downloaded or generated it procedurally. -    pub fn from_memory(bytes: Vec<u8>) -> Handle { -        Self::from_data(Data::Bytes(bytes)) -    } - -    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`]. -    pub fn id(&self) -> u64 { -        self.id -    } - -    /// Returns a reference to the image [`Data`]. -    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`]. -#[derive(Clone, Hash)] -pub enum Data { -    /// A remote image -    Path(PathBuf), - -    /// In-memory data -    Bytes(Vec<u8>), -} - -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), -            Data::Bytes(_) => write!(f, "Bytes(...)"), -        } -    } -} diff --git a/web/src/widget/progress_bar.rs b/web/src/widget/progress_bar.rs deleted file mode 100644 index 01f412f8..00000000 --- a/web/src/widget/progress_bar.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! 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<'a> { -    range: RangeInclusive<f32>, -    value: f32, -    width: Length, -    height: Option<Length>, -    style: Box<dyn StyleSheet + 'a>, -} - -impl<'a> ProgressBar<'a> { -    /// Creates a new [`ProgressBar`]. -    /// -    /// It expects: -    ///   * an inclusive range of possible values -    ///   * the current value of the [`ProgressBar`] -    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`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`ProgressBar`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = Some(height); -        self -    } - -    /// Sets the style of the [`ProgressBar`]. -    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { -        self.style = style.into(); -        self -    } -} - -impl<'a, Message> Widget<Message> for ProgressBar<'a> { -    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<'a>> for Element<'a, Message> -where -    Message: 'static, -{ -    fn from(container: ProgressBar<'a>) -> Element<'a, Message> { -        Element::new(container) -    } -} diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs deleted file mode 100644 index 03b2922b..00000000 --- a/web/src/widget/radio.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Create choices using radio buttons. -use crate::{Bus, Css, Element, Widget}; - -pub use iced_style::radio::{Style, StyleSheet}; - -use dodrio::bumpalo; - -/// A circular button representing a choice. -/// -/// # Example -/// ``` -/// # use iced_web::Radio; -/// -/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] -/// pub enum Choice { -///     A, -///     B, -/// } -/// -/// #[derive(Debug, Clone, Copy)] -/// pub enum Message { -///     RadioSelected(Choice), -/// } -/// -/// let selected_choice = Some(Choice::A); -/// -/// Radio::new(Choice::A, "This is A", selected_choice, Message::RadioSelected); -/// -/// Radio::new(Choice::B, "This is B", selected_choice, Message::RadioSelected); -/// ``` -/// -///  -#[allow(missing_debug_implementations)] -pub struct Radio<'a, Message> { -    is_selected: bool, -    on_click: Message, -    label: String, -    id: Option<String>, -    name: Option<String>, -    #[allow(dead_code)] -    style_sheet: Box<dyn StyleSheet + 'a>, -} - -impl<'a, Message> Radio<'a, Message> { -    /// Creates a new [`Radio`] button. -    /// -    /// It expects: -    ///   * the value related to the [`Radio`] button -    ///   * the label of the [`Radio`] button -    ///   * the current selected value -    ///   * a function that will be called when the [`Radio`] is selected. It -    ///   receives the value of the radio and must produce a `Message`. -    pub fn new<F, V>( -        value: V, -        label: impl Into<String>, -        selected: Option<V>, -        f: F, -    ) -> Self -    where -        V: Eq + Copy, -        F: 'static + Fn(V) -> Message, -    { -        Radio { -            is_selected: Some(value) == selected, -            on_click: f(value), -            label: label.into(), -            id: None, -            name: None, -            style_sheet: Default::default(), -        } -    } - -    /// Sets the style of the [`Radio`] button. -    pub fn style( -        mut self, -        style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, -    ) -> Self { -        self.style_sheet = style_sheet.into(); -        self -    } - -    /// Sets the name attribute of the [`Radio`] button. -    pub fn name(mut self, name: impl Into<String>) -> Self { -        self.name = Some(name.into()); -        self -    } - -    /// Sets the id of the [`Radio`] button. -    pub fn id(mut self, id: impl Into<String>) -> Self { -        self.id = Some(id.into()); -        self -    } -} - -impl<'a, Message> Widget<Message> for Radio<'a, Message> -where -    Message: 'static + Clone, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        _style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; -        use dodrio::bumpalo::collections::String; - -        let radio_label = -            String::from_str_in(&self.label, bump).into_bump_str(); - -        let event_bus = bus.clone(); -        let on_click = self.on_click.clone(); - -        let (label, input) = if let Some(id) = &self.id { -            let id = String::from_str_in(id, bump).into_bump_str(); - -            (label(bump).attr("for", id), input(bump).attr("id", id)) -        } else { -            (label(bump), input(bump)) -        }; - -        let input = if let Some(name) = &self.name { -            let name = String::from_str_in(name, bump).into_bump_str(); - -            dodrio::builder::input(bump).attr("name", name) -        } else { -            input -        }; - -        // TODO: Complete styling -        label -            .attr("style", "display: block; font-size: 20px") -            .children(vec![ -                input -                    .attr("type", "radio") -                    .attr("style", "margin-right: 10px") -                    .bool_attr("checked", self.is_selected) -                    .on("click", move |_root, _vdom, _event| { -                        event_bus.publish(on_click.clone()); -                    }) -                    .finish(), -                text(radio_label), -            ]) -            .finish() -    } -} - -impl<'a, Message> From<Radio<'a, Message>> for Element<'a, Message> -where -    Message: 'static + Clone, -{ -    fn from(radio: Radio<'a, Message>) -> Element<'a, Message> { -        Element::new(radio) -    } -} diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs deleted file mode 100644 index 13eab27d..00000000 --- a/web/src/widget/row.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::css; -use crate::{Alignment, Bus, Css, Element, Length, Padding, Widget}; - -use dodrio::bumpalo; -use std::u32; - -/// A container that distributes its contents horizontally. -/// -/// A [`Row`] will try to fill the horizontal space of its container. -#[allow(missing_debug_implementations)] -pub struct Row<'a, Message> { -    spacing: u16, -    padding: Padding, -    width: Length, -    height: Length, -    max_width: u32, -    max_height: u32, -    align_items: Alignment, -    children: Vec<Element<'a, Message>>, -} - -impl<'a, Message> Row<'a, Message> { -    /// Creates an empty [`Row`]. -    pub fn new() -> Self { -        Self::with_children(Vec::new()) -    } - -    /// Creates a [`Row`] with the given elements. -    pub fn with_children(children: Vec<Element<'a, Message>>) -> Self { -        Row { -            spacing: 0, -            padding: Padding::ZERO, -            width: Length::Fill, -            height: Length::Shrink, -            max_width: u32::MAX, -            max_height: u32::MAX, -            align_items: Alignment::Start, -            children, -        } -    } - -    /// Sets the horizontal spacing _between_ elements. -    /// -    /// Custom margins per element do not exist in Iced. You should use this -    /// method instead! While less flexible, it helps you keep spacing between -    /// elements consistent. -    pub fn spacing(mut self, units: u16) -> Self { -        self.spacing = units; -        self -    } - -    /// Sets the [`Padding`] of the [`Row`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the width of the [`Row`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Row`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the maximum width of the [`Row`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.max_width = max_width; -        self -    } - -    /// Sets the maximum height of the [`Row`]. -    pub fn max_height(mut self, max_height: u32) -> Self { -        self.max_height = max_height; -        self -    } - -    /// Sets the vertical alignment of the contents of the [`Row`] . -    pub fn align_items(mut self, align: Alignment) -> Self { -        self.align_items = align; -        self -    } - -    /// Adds an [`Element`] to the [`Row`]. -    pub fn push<E>(mut self, child: E) -> Self -    where -        E: Into<Element<'a, Message>>, -    { -        self.children.push(child.into()); -        self -    } -} - -impl<'a, Message> Widget<Message> for Row<'a, Message> { -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        publish: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        let children: Vec<_> = self -            .children -            .iter() -            .map(|element| element.widget.node(bump, publish, style_sheet)) -            .collect(); - -        let row_class = style_sheet.insert(bump, css::Rule::Row); - -        let spacing_class = -            style_sheet.insert(bump, css::Rule::Spacing(self.spacing)); - -        // TODO: Complete styling -        div(bump) -            .attr( -                "class", -                bumpalo::format!(in bump, "{} {}", row_class, spacing_class) -                    .into_bump_str(), -            ) -            .attr("style", bumpalo::format!( -                    in bump, -                    "width: {}; height: {}; max-width: {}; max-height: {}; padding: {}; align-items: {}", -                    css::length(self.width), -                    css::length(self.height), -                    css::max_length(self.max_width), -                    css::max_length(self.max_height), -                    css::padding(self.padding), -                    css::alignment(self.align_items) -                ).into_bump_str() -            ) -            .children(children) -            .finish() -    } -} - -impl<'a, Message> From<Row<'a, Message>> 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/scrollable.rs b/web/src/widget/scrollable.rs deleted file mode 100644 index 22cb61be..00000000 --- a/web/src/widget/scrollable.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Navigate an endless amount of content with a scrollbar. -use crate::bumpalo; -use crate::css; -use crate::{Alignment, Bus, Column, Css, Element, Length, Padding, Widget}; - -pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; - -/// A widget that can vertically display an infinite amount of content with a -/// scrollbar. -#[allow(missing_debug_implementations)] -pub struct Scrollable<'a, Message> { -    width: Length, -    height: Length, -    max_height: u32, -    content: Column<'a, Message>, -    #[allow(dead_code)] -    style_sheet: Box<dyn StyleSheet + 'a>, -} - -impl<'a, Message> Scrollable<'a, Message> { -    /// Creates a new [`Scrollable`] with the given [`State`]. -    pub fn new(_state: &'a mut State) -> Self { -        use std::u32; - -        Scrollable { -            width: Length::Fill, -            height: Length::Shrink, -            max_height: u32::MAX, -            content: Column::new(), -            style_sheet: Default::default(), -        } -    } - -    /// Sets the vertical spacing _between_ elements. -    /// -    /// Custom margins per element do not exist in Iced. You should use this -    /// method instead! While less flexible, it helps you keep spacing between -    /// elements consistent. -    pub fn spacing(mut self, units: u16) -> Self { -        self.content = self.content.spacing(units); -        self -    } - -    /// Sets the [`Padding`] of the [`Scrollable`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.content = self.content.padding(padding); -        self -    } - -    /// Sets the width of the [`Scrollable`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Scrollable`]. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the maximum width of the [`Scrollable`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.content = self.content.max_width(max_width); -        self -    } - -    /// Sets the maximum height of the [`Scrollable`] in pixels. -    pub fn max_height(mut self, max_height: u32) -> Self { -        self.max_height = max_height; -        self -    } - -    /// Sets the horizontal alignment of the contents of the [`Scrollable`] . -    pub fn align_items(mut self, align_items: Alignment) -> Self { -        self.content = self.content.align_items(align_items); -        self -    } - -    /// Sets the style of the [`Scrollable`] . -    pub fn style( -        mut self, -        style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, -    ) -> Self { -        self.style_sheet = style_sheet.into(); -        self -    } - -    /// Adds an element to the [`Scrollable`]. -    pub fn push<E>(mut self, child: E) -> Self -    where -        E: Into<Element<'a, Message>>, -    { -        self.content = self.content.push(child); -        self -    } -} - -impl<'a, Message> Widget<Message> for Scrollable<'a, Message> -where -    Message: 'static, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        let width = css::length(self.width); -        let height = css::length(self.height); - -        // TODO: Scrollbar styling - -        let node = div(bump) -            .attr( -                "style", -                bumpalo::format!( -                    in bump, -                    "width: {}; height: {}; max-height: {}px; overflow: auto", -                    width, -                    height, -                    self.max_height -                ) -                .into_bump_str(), -            ) -            .children(vec![self.content.node(bump, bus, style_sheet)]); - -        node.finish() -    } -} - -impl<'a, Message> From<Scrollable<'a, Message>> for Element<'a, Message> -where -    Message: 'static, -{ -    fn from(scrollable: Scrollable<'a, Message>) -> Element<'a, Message> { -        Element::new(scrollable) -    } -} - -/// The local state of a [`Scrollable`]. -#[derive(Debug, Clone, Copy, Default)] -pub struct State; - -impl State { -    /// Creates a new [`State`] with the scrollbar located at the top. -    pub fn new() -> Self { -        State::default() -    } -} diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs deleted file mode 100644 index 8cbf5bd0..00000000 --- a/web/src/widget/slider.rs +++ /dev/null @@ -1,183 +0,0 @@ -//! Display an interactive selector of a single value from a range of values. -//! -//! A [`Slider`] has some local [`State`]. -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}; - -/// An horizontal bar and a handle that selects a single value from a range of -/// values. -/// -/// A [`Slider`] will try to fill the horizontal space of its container. -/// -/// The [`Slider`] range of numeric values is generic and its step size defaults -/// to 1 unit. -/// -/// # Example -/// ``` -/// # use iced_web::{slider, Slider}; -/// # -/// pub enum Message { -///     SliderChanged(f32), -/// } -/// -/// let state = &mut slider::State::new(); -/// let value = 50.0; -/// -/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged); -/// ``` -/// -///  -#[allow(missing_debug_implementations)] -pub struct Slider<'a, T, Message> { -    _state: &'a mut State, -    range: RangeInclusive<T>, -    step: T, -    value: T, -    on_change: Rc<Box<dyn Fn(T) -> Message>>, -    #[allow(dead_code)] -    width: Length, -    #[allow(dead_code)] -    style_sheet: Box<dyn StyleSheet + 'a>, -} - -impl<'a, T, Message> Slider<'a, T, Message> -where -    T: Copy + From<u8> + std::cmp::PartialOrd, -{ -    /// Creates a new [`Slider`]. -    /// -    /// It expects: -    ///   * the local [`State`] of the [`Slider`] -    ///   * an inclusive range of possible values -    ///   * the current value of the [`Slider`] -    ///   * a function that will be called when the [`Slider`] is dragged. -    ///   It receives the new value of the [`Slider`] and must produce a -    ///   `Message`. -    pub fn new<F>( -        state: &'a mut State, -        range: RangeInclusive<T>, -        value: T, -        on_change: F, -    ) -> Self -    where -        F: 'static + Fn(T) -> Message, -    { -        let value = if value >= *range.start() { -            value -        } else { -            *range.start() -        }; - -        let value = if value <= *range.end() { -            value -        } else { -            *range.end() -        }; - -        Slider { -            _state: state, -            value, -            range, -            step: T::from(1), -            on_change: Rc::new(Box::new(on_change)), -            width: Length::Fill, -            style_sheet: Default::default(), -        } -    } - -    /// Sets the width of the [`Slider`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the style of the [`Slider`]. -    pub fn style( -        mut self, -        style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, -    ) -> Self { -        self.style_sheet = style_sheet.into(); -        self -    } - -    /// Sets the step size of the [`Slider`]. -    pub fn step(mut self, step: T) -> Self { -        self.step = step; -        self -    } -} - -impl<'a, T, Message> Widget<Message> for Slider<'a, T, Message> -where -    T: 'static + Copy + Into<f64> + num_traits::FromPrimitive, -    Message: 'static, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        _style_sheet: &mut Css<'b>, -    ) -> 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.into()); -        let max = bumpalo::format!(in bump, "{}", end.into()); -        let value = bumpalo::format!(in bump, "{}", self.value.into()); -        let step = bumpalo::format!(in bump, "{}", self.step.into()); - -        let on_change = self.on_change.clone(); -        let event_bus = bus.clone(); - -        // TODO: Styling -        input(bump) -            .attr("type", "range") -            .attr("step", step.into_bump_str()) -            .attr("min", min.into_bump_str()) -            .attr("max", max.into_bump_str()) -            .attr("value", value.into_bump_str()) -            .attr("style", "width: 100%") -            .on("input", move |_root, _vdom, event| { -                let slider = match event.target().and_then(|t| { -                    t.dyn_into::<web_sys::HtmlInputElement>().ok() -                }) { -                    None => return, -                    Some(slider) => slider, -                }; - -                if let Ok(value) = slider.value().parse::<f64>() { -                    if let Some(value) = T::from_f64(value) { -                        event_bus.publish(on_change(value)); -                    } -                } -            }) -            .finish() -    } -} - -impl<'a, T, Message> From<Slider<'a, T, Message>> for Element<'a, Message> -where -    T: 'static + Copy + Into<f64> + num_traits::FromPrimitive, -    Message: 'static, -{ -    fn from(slider: Slider<'a, T, Message>) -> Element<'a, Message> { -        Element::new(slider) -    } -} - -/// The local state of a [`Slider`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct State; - -impl State { -    /// Creates a new [`State`]. -    pub fn new() -> Self { -        Self -    } -} diff --git a/web/src/widget/space.rs b/web/src/widget/space.rs deleted file mode 100644 index a8571fdb..00000000 --- a/web/src/widget/space.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::{css, Bus, Css, Element, Length, Widget}; -use dodrio::bumpalo; - -/// An amount of empty space. -/// -/// It can be useful if you want to fill some space with nothing. -#[derive(Debug)] -pub struct Space { -    width: Length, -    height: Length, -} - -impl Space { -    /// Creates an amount of empty [`Space`] with the given width and height. -    pub fn new(width: Length, height: Length) -> Self { -        Space { width, height } -    } - -    /// Creates an amount of horizontal [`Space`]. -    pub fn with_width(width: Length) -> Self { -        Space { -            width, -            height: Length::Shrink, -        } -    } - -    /// Creates an amount of vertical [`Space`]. -    pub fn with_height(height: Length) -> Self { -        Space { -            width: Length::Shrink, -            height, -        } -    } -} - -impl<'a, Message> Widget<Message> for Space { -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        _publish: &Bus<Message>, -        _css: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        let width = css::length(self.width); -        let height = css::length(self.height); - -        let style = bumpalo::format!( -            in bump, -            "width: {}; height: {};", -            width, -            height -        ); - -        div(bump).attr("style", style.into_bump_str()).finish() -    } -} - -impl<'a, Message> From<Space> for Element<'a, Message> { -    fn from(space: Space) -> Element<'a, Message> { -        Element::new(space) -    } -} diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs deleted file mode 100644 index 53d57bfd..00000000 --- a/web/src/widget/text.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::alignment; -use crate::css; -use crate::{Bus, Color, Css, Element, Font, Length, Widget}; -use dodrio::bumpalo; - -/// A paragraph of text. -/// -/// # Example -/// -/// ``` -/// # use iced_web::Text; -/// -/// Text::new("I <3 iced!") -///     .size(40); -/// ``` -#[derive(Debug, Clone)] -pub struct Text { -    content: String, -    size: Option<u16>, -    color: Option<Color>, -    font: Font, -    width: Length, -    height: Length, -    horizontal_alignment: alignment::Horizontal, -    vertical_alignment: alignment::Vertical, -} - -impl Text { -    /// Create a new fragment of [`Text`] with the given contents. -    pub fn new<T: Into<String>>(label: T) -> Self { -        Text { -            content: label.into(), -            size: None, -            color: None, -            font: Font::Default, -            width: Length::Shrink, -            height: Length::Shrink, -            horizontal_alignment: alignment::Horizontal::Left, -            vertical_alignment: alignment::Vertical::Top, -        } -    } - -    /// Sets the size of the [`Text`]. -    pub fn size(mut self, size: u16) -> Self { -        self.size = Some(size); -        self -    } - -    /// Sets the [`Color`] of the [`Text`]. -    pub fn color<C: Into<Color>>(mut self, color: C) -> Self { -        self.color = Some(color.into()); -        self -    } - -    /// Sets the [`Font`] of the [`Text`]. -    pub fn font(mut self, font: Font) -> Self { -        self.font = font; -        self -    } - -    /// Sets the width of the [`Text`] boundaries. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the height of the [`Text`] boundaries. -    pub fn height(mut self, height: Length) -> Self { -        self.height = height; -        self -    } - -    /// Sets the [`HorizontalAlignment`] of the [`Text`]. -    pub fn horizontal_alignment( -        mut self, -        alignment: alignment::Horizontal, -    ) -> Self { -        self.horizontal_alignment = alignment; -        self -    } - -    /// Sets the [`VerticalAlignment`] of the [`Text`]. -    pub fn vertical_alignment( -        mut self, -        alignment: alignment::Vertical, -    ) -> Self { -        self.vertical_alignment = alignment; -        self -    } -} - -impl<'a, Message> Widget<Message> for Text { -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        _publish: &Bus<Message>, -        _style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; - -        let content = { -            use dodrio::bumpalo::collections::String; - -            String::from_str_in(&self.content, bump) -        }; - -        let color = self -            .color -            .map(css::color) -            .unwrap_or(String::from("inherit")); - -        let width = css::length(self.width); -        let height = css::length(self.height); - -        let text_align = match self.horizontal_alignment { -            alignment::Horizontal::Left => "left", -            alignment::Horizontal::Center => "center", -            alignment::Horizontal::Right => "right", -        }; - -        let style = bumpalo::format!( -            in bump, -            "width: {}; height: {}; font-size: {}px; color: {}; \ -            text-align: {}; font-family: {}", -            width, -            height, -            self.size.unwrap_or(20), -            color, -            text_align, -            match self.font { -                Font::Default => "inherit", -                Font::External { name, .. } => name, -            } -        ); - -        // TODO: Complete styling -        p(bump) -            .attr("style", style.into_bump_str()) -            .children(vec![text(content.into_bump_str())]) -            .finish() -    } -} - -impl<'a, Message> From<Text> for Element<'a, Message> { -    fn from(text: Text) -> Element<'a, Message> { -        Element::new(text) -    } -} diff --git a/web/src/widget/text_input.rs b/web/src/widget/text_input.rs deleted file mode 100644 index c5874485..00000000 --- a/web/src/widget/text_input.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! Display fields that can be filled with text. -//! -//! A [`TextInput`] has some local [`State`]. -use crate::{bumpalo, css, Bus, Css, Element, Length, Padding, Widget}; - -pub use iced_style::text_input::{Style, StyleSheet}; - -use std::{rc::Rc, u32}; - -/// A field that can be filled with text. -/// -/// # Example -/// ``` -/// # use iced_web::{text_input, TextInput}; -/// # -/// enum Message { -///     TextInputChanged(String), -/// } -/// -/// let mut state = text_input::State::new(); -/// let value = "Some text"; -/// -/// let input = TextInput::new( -///     &mut state, -///     "This is the placeholder...", -///     value, -///     Message::TextInputChanged, -/// ); -/// ``` -#[allow(missing_debug_implementations)] -pub struct TextInput<'a, Message> { -    _state: &'a mut State, -    placeholder: String, -    value: String, -    is_secure: bool, -    width: Length, -    max_width: u32, -    padding: Padding, -    size: Option<u16>, -    on_change: Rc<Box<dyn Fn(String) -> Message>>, -    on_submit: Option<Message>, -    style_sheet: Box<dyn StyleSheet + 'a>, -} - -impl<'a, Message> TextInput<'a, Message> { -    /// Creates a new [`TextInput`]. -    /// -    /// It expects: -    /// - some [`State`] -    /// - a placeholder -    /// - the current value -    /// - a function that produces a message when the [`TextInput`] changes -    pub fn new<F>( -        state: &'a mut State, -        placeholder: &str, -        value: &str, -        on_change: F, -    ) -> Self -    where -        F: 'static + Fn(String) -> Message, -    { -        Self { -            _state: state, -            placeholder: String::from(placeholder), -            value: String::from(value), -            is_secure: false, -            width: Length::Fill, -            max_width: u32::MAX, -            padding: Padding::ZERO, -            size: None, -            on_change: Rc::new(Box::new(on_change)), -            on_submit: None, -            style_sheet: Default::default(), -        } -    } - -    /// Converts the [`TextInput`] into a secure password input. -    pub fn password(mut self) -> Self { -        self.is_secure = true; -        self -    } - -    /// Sets the width of the [`TextInput`]. -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the maximum width of the [`TextInput`]. -    pub fn max_width(mut self, max_width: u32) -> Self { -        self.max_width = max_width; -        self -    } - -    /// Sets the [`Padding`] of the [`TextInput`]. -    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { -        self.padding = padding.into(); -        self -    } - -    /// Sets the text size of the [`TextInput`]. -    pub fn size(mut self, size: u16) -> Self { -        self.size = Some(size); -        self -    } - -    /// Sets the message that should be produced when the [`TextInput`] is -    /// focused and the enter key is pressed. -    pub fn on_submit(mut self, message: Message) -> Self { -        self.on_submit = Some(message); -        self -    } - -    /// Sets the style of the [`TextInput`]. -    pub fn style( -        mut self, -        style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, -    ) -> Self { -        self.style_sheet = style_sheet.into(); -        self -    } -} - -impl<'a, Message> Widget<Message> for TextInput<'a, Message> -where -    Message: 'static + Clone, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        _style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; -        use wasm_bindgen::JsCast; - -        let placeholder = { -            use dodrio::bumpalo::collections::String; - -            String::from_str_in(&self.placeholder, bump).into_bump_str() -        }; - -        let value = { -            use dodrio::bumpalo::collections::String; - -            String::from_str_in(&self.value, bump).into_bump_str() -        }; - -        let on_change = self.on_change.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( -                "style", -                bumpalo::format!( -                    in bump, -                    "width: {}; max-width: {}; padding: {}; font-size: {}px; \ -                    background: {}; border-width: {}px; border-color: {}; \ -                    border-radius: {}px; color: {}", -                    css::length(self.width), -                    css::max_length(self.max_width), -                    css::padding(self.padding), -                    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(), -            ) -            .attr("placeholder", placeholder) -            .attr("value", value) -            .attr("type", if self.is_secure { "password" } else { "text" }) -            .on("input", move |_root, _vdom, event| { -                let text_input = match event.target().and_then(|t| { -                    t.dyn_into::<web_sys::HtmlInputElement>().ok() -                }) { -                    None => return, -                    Some(text_input) => text_input, -                }; - -                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() -    } -} - -impl<'a, Message> From<TextInput<'a, Message>> for Element<'a, Message> -where -    Message: 'static + Clone, -{ -    fn from(text_input: TextInput<'a, Message>) -> Element<'a, Message> { -        Element::new(text_input) -    } -} - -/// The state of a [`TextInput`]. -#[derive(Debug, Clone, Copy, Default)] -pub struct State; - -impl State { -    /// Creates a new [`State`], representing an unfocused [`TextInput`]. -    pub fn new() -> Self { -        Self::default() -    } - -    /// Creates a new [`State`], representing a focused [`TextInput`]. -    pub fn focused() -> Self { -        // TODO -        Self::default() -    } - -    /// Selects all the content of the [`TextInput`]. -    pub fn select_all(&mut self) { -        // TODO -    } -} diff --git a/web/src/widget/toggler.rs b/web/src/widget/toggler.rs deleted file mode 100644 index 0a198079..00000000 --- a/web/src/widget/toggler.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! Show toggle controls using togglers. -use crate::{css, Bus, Css, Element, Length, Widget}; - -pub use iced_style::toggler::{Style, StyleSheet}; - -use dodrio::bumpalo; -use std::rc::Rc; - -/// A toggler that can be toggled. -/// -/// # Example -/// -/// ``` -/// # use iced_web::Toggler; -/// -/// pub enum Message { -///     TogglerToggled(bool), -/// } -/// -/// let is_active = true; -/// -/// Toggler::new(is_active, String::from("Toggle me!"), Message::TogglerToggled); -/// ``` -/// -#[allow(missing_debug_implementations)] -pub struct Toggler<Message> { -    is_active: bool, -    on_toggle: Rc<dyn Fn(bool) -> Message>, -    label: Option<String>, -    id: Option<String>, -    width: Length, -    style: Box<dyn StyleSheet>, -} - -impl<Message> Toggler<Message> { -    /// Creates a new [`Toggler`]. -    /// -    /// It expects: -    ///   * a boolean describing whether the [`Toggler`] is active or not -    ///   * An optional label for the [`Toggler`] -    ///   * a function that will be called when the [`Toggler`] is toggled. It -    ///     will receive the new state of the [`Toggler`] and must produce a -    ///     `Message`. -    /// -    /// [`Toggler`]: struct.Toggler.html -    pub fn new<F>( -        is_active: bool, -        label: impl Into<Option<String>>, -        f: F, -    ) -> Self -    where -        F: 'static + Fn(bool) -> Message, -    { -        Toggler { -            is_active, -            on_toggle: Rc::new(f), -            label: label.into(), -            id: None, -            width: Length::Shrink, -            style: Default::default(), -        } -    } - -    /// Sets the width of the [`Toggler`]. -    /// -    /// [`Toggler`]: struct.Toggler.html -    pub fn width(mut self, width: Length) -> Self { -        self.width = width; -        self -    } - -    /// Sets the style of the [`Toggler`]. -    /// -    /// [`Toggler`]: struct.Toggler.html -    pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { -        self.style = style.into(); -        self -    } - -    /// Sets the id of the [`Toggler`]. -    /// -    /// [`Toggler`]: struct.Toggler.html -    pub fn id(mut self, id: impl Into<String>) -> Self { -        self.id = Some(id.into()); -        self -    } -} - -impl<Message> Widget<Message> for Toggler<Message> -where -    Message: 'static, -{ -    fn node<'b>( -        &self, -        bump: &'b bumpalo::Bump, -        bus: &Bus<Message>, -        style_sheet: &mut Css<'b>, -    ) -> dodrio::Node<'b> { -        use dodrio::builder::*; -        use dodrio::bumpalo::collections::String; - -        let toggler_label = &self -            .label -            .as_ref() -            .map(|label| String::from_str_in(&label, bump).into_bump_str()); - -        let event_bus = bus.clone(); -        let on_toggle = self.on_toggle.clone(); -        let is_active = self.is_active; - -        let row_class = style_sheet.insert(bump, css::Rule::Row); -        let toggler_class = style_sheet.insert(bump, css::Rule::Toggler(16)); - -        let (label, input) = if let Some(id) = &self.id { -            let id = String::from_str_in(id, bump).into_bump_str(); - -            (label(bump).attr("for", id), input(bump).attr("id", id)) -        } else { -            (label(bump), input(bump)) -        }; - -        let checkbox = input -            .attr("type", "checkbox") -            .bool_attr("checked", self.is_active) -            .on("click", move |_root, vdom, _event| { -                let msg = on_toggle(!is_active); -                event_bus.publish(msg); - -                vdom.schedule_render(); -            }) -            .finish(); - -        let toggler = span(bump).children(vec![span(bump).finish()]).finish(); - -        label -            .attr( -                "class", -                bumpalo::format!(in bump, "{} {}", row_class, toggler_class) -                    .into_bump_str(), -            ) -            .attr( -                "style", -                bumpalo::format!(in bump, "width: {}; align-items: center", css::length(self.width)) -                .into_bump_str() -            ) -            .children( -                if let Some(label) = toggler_label { -                    vec![ -                        text(label), -                        checkbox, -                        toggler, -                    ] -                } else { -                    vec![ -                        checkbox, -                        toggler, -                    ] -                } -            ) -            .finish() -    } -} - -impl<'a, Message> From<Toggler<Message>> for Element<'a, Message> -where -    Message: 'static, -{ -    fn from(toggler: Toggler<Message>) -> Element<'a, Message> { -        Element::new(toggler) -    } -} | 
