diff options
Diffstat (limited to 'web/src')
-rw-r--r-- | web/src/bus.rs | 6 | ||||
-rw-r--r-- | web/src/clipboard.rs | 21 | ||||
-rw-r--r-- | web/src/css.rs | 96 | ||||
-rw-r--r-- | web/src/element.rs | 9 | ||||
-rw-r--r-- | web/src/lib.rs | 50 | ||||
-rw-r--r-- | web/src/subscription.rs | 3 | ||||
-rw-r--r-- | web/src/widget.rs | 9 | ||||
-rw-r--r-- | web/src/widget/button.rs | 76 | ||||
-rw-r--r-- | web/src/widget/checkbox.rs | 9 | ||||
-rw-r--r-- | web/src/widget/column.rs | 40 | ||||
-rw-r--r-- | web/src/widget/container.rs | 39 | ||||
-rw-r--r-- | web/src/widget/image.rs | 18 | ||||
-rw-r--r-- | web/src/widget/progress_bar.rs | 8 | ||||
-rw-r--r-- | web/src/widget/radio.rs | 9 | ||||
-rw-r--r-- | web/src/widget/row.rs | 41 | ||||
-rw-r--r-- | web/src/widget/scrollable.rs | 34 | ||||
-rw-r--r-- | web/src/widget/slider.rs | 20 | ||||
-rw-r--r-- | web/src/widget/space.rs | 6 | ||||
-rw-r--r-- | web/src/widget/text.rs | 20 | ||||
-rw-r--r-- | web/src/widget/text_input.rs | 58 | ||||
-rw-r--r-- | web/src/widget/toggler.rs | 171 |
21 files changed, 363 insertions, 380 deletions
diff --git a/web/src/bus.rs b/web/src/bus.rs index c66e9659..5ce8e810 100644 --- a/web/src/bus.rs +++ b/web/src/bus.rs @@ -5,7 +5,7 @@ use std::rc::Rc; /// /// It can be used to route messages back to the [`Application`]. /// -/// [`Application`]: trait.Application.html +/// [`Application`]: crate::Application #[allow(missing_debug_implementations)] pub struct Bus<Message> { publish: Rc<Box<dyn Fn(Message) -> ()>>, @@ -33,15 +33,13 @@ where /// Publishes a new message for the [`Application`]. /// - /// [`Application`]: trait.Application.html + /// [`Application`]: crate::Application pub fn publish(&self, message: Message) { (self.publish)(message) } /// Creates a new [`Bus`] that applies the given function to the messages /// before publishing. - /// - /// [`Bus`]: struct.Bus.html pub fn map<B>(&self, mapper: Rc<Box<dyn Fn(B) -> Message>>) -> Bus<B> where B: 'static, diff --git a/web/src/clipboard.rs b/web/src/clipboard.rs new file mode 100644 index 00000000..167a1e53 --- /dev/null +++ b/web/src/clipboard.rs @@ -0,0 +1,21 @@ +/// A buffer for short-term storage and transfer within and between +/// applications. +#[derive(Debug, Clone, Copy)] +pub struct Clipboard; + +impl Clipboard { + /// Creates a new [`Clipboard`]. + pub fn new() -> Self { + Self + } + + /// Reads the current content of the [`Clipboard`] as text. + pub fn read(&self) -> Option<String> { + unimplemented! {} + } + + /// Writes the given text contents to the [`Clipboard`]. + pub fn write(&mut self, _contents: String) { + unimplemented! {} + } +} diff --git a/web/src/css.rs b/web/src/css.rs index 6a307770..21f51f85 100644 --- a/web/src/css.rs +++ b/web/src/css.rs @@ -1,5 +1,5 @@ //! Style your widgets. -use crate::{bumpalo, Align, Background, Color, Length}; +use crate::{bumpalo, Align, Background, Color, Length, Padding}; use std::collections::BTreeMap; @@ -12,29 +12,25 @@ pub enum Rule { /// Container with horizonal distribution Row, - /// Padding of the container - Padding(u16), - /// Spacing between elements Spacing(u16), + + /// Toggler input for a specific size + Toggler(u16), } impl Rule { - /// Returns the class name of the [`Style`]. - /// - /// [`Style`]: enum.Style.html + /// Returns the class name of the [`Rule`]. pub fn class<'a>(&self) -> String { match self { Rule::Column => String::from("c"), Rule::Row => String::from("r"), - Rule::Padding(padding) => format!("p-{}", padding), Rule::Spacing(spacing) => format!("s-{}", spacing), + Rule::Toggler(size) => format!("toggler-{}", size), } } - /// Returns the declaration of the [`Style`]. - /// - /// [`Style`]: enum.Style.html + /// Returns the declaration of the [`Rule`]. pub fn declaration<'a>(&self, bump: &'a bumpalo::Bump) -> &'a str { let class = self.class(); @@ -49,13 +45,6 @@ impl Rule { bumpalo::format!(in bump, ".{} {}", class, body).into_bump_str() } - Rule::Padding(padding) => bumpalo::format!( - in bump, - ".{} {{ box-sizing: border-box; padding: {}px }}", - class, - padding - ) - .into_bump_str(), Rule::Spacing(spacing) => bumpalo::format!( in bump, ".c.{} > * {{ margin-bottom: {}px }} \ @@ -70,6 +59,46 @@ impl Rule { class ) .into_bump_str(), + Rule::Toggler(size) => bumpalo::format!( + in bump, + ".toggler-{} {{ display: flex; cursor: pointer; justify-content: space-between; }} \ + .toggler-{} input {{ display:none; }} \ + .toggler-{} span {{ background-color: #b1b1b1; position: relative; display: inline-flex; width:{}px; height: {}px; border-radius: {}px;}} \ + .toggler-{} span > span {{ background-color: #FFFFFF; width: {}px; height: {}px; border-radius: 50%; top: 1px; left: 1px;}} \ + .toggler-{}:hover span > span {{ background-color: #f1f1f1 !important; }} \ + .toggler-{} input:checked + span {{ background-color: #00FF00; }} \ + .toggler-{} input:checked + span > span {{ -webkit-transform: translateX({}px); -ms-transform:translateX({}px); transform: translateX({}px); }} + ", + // toggler + size, + + // toggler input + size, + + // toggler span + size, + size*2, + size, + size, + + // toggler span > span + size, + size-2, + size-2, + + // toggler: hover + span > span + size, + + // toggler input:checked + span + size, + + // toggler input:checked + span > span + size, + size, + size, + size + ) + .into_bump_str(), } } } @@ -81,22 +110,17 @@ pub struct Css<'a> { } impl<'a> Css<'a> { - /// Creates an empty style [`Sheet`]. - /// - /// [`Sheet`]: struct.Sheet.html + /// Creates an empty [`Css`]. pub fn new() -> Self { Css { rules: BTreeMap::new(), } } - /// Inserts the [`rule`] in the [`Sheet`], if it was not previously + /// Inserts the [`Rule`] in the [`Css`], if it was not previously /// inserted. /// /// It returns the class name of the provided [`Rule`]. - /// - /// [`Sheet`]: struct.Sheet.html - /// [`Rule`]: enum.Rule.html pub fn insert(&mut self, bump: &'a bumpalo::Bump, rule: Rule) -> String { let class = rule.class(); @@ -107,9 +131,7 @@ impl<'a> Css<'a> { class } - /// Produces the VDOM node of the style [`Sheet`]. - /// - /// [`Sheet`]: struct.Sheet.html + /// Produces the VDOM node of the [`Css`]. pub fn node(self, bump: &'a bumpalo::Bump) -> dodrio::Node<'a> { use dodrio::builder::*; @@ -133,8 +155,6 @@ impl<'a> Css<'a> { } /// Returns the style value for the given [`Length`]. -/// -/// [`Length`]: ../enum.Length.html pub fn length(length: Length) -> String { match length { Length::Shrink => String::from("auto"), @@ -164,15 +184,11 @@ pub fn min_length(units: u32) -> String { } /// Returns the style value for the given [`Color`]. -/// -/// [`Color`]: ../struct.Color.html pub fn color(Color { r, g, b, a }: Color) -> String { format!("rgba({}, {}, {}, {})", 255.0 * r, 255.0 * g, 255.0 * b, a) } /// Returns the style value for the given [`Background`]. -/// -/// [`Background`]: ../struct.Background.html pub fn background(background: Background) -> String { match background { Background::Color(c) => color(c), @@ -180,8 +196,6 @@ pub fn background(background: Background) -> String { } /// Returns the style value for the given [`Align`]. -/// -/// [`Align`]: ../enum.Align.html pub fn align(align: Align) -> &'static str { match align { Align::Start => "flex-start", @@ -189,3 +203,13 @@ pub fn align(align: Align) -> &'static str { Align::End => "flex-end", } } + +/// Returns the style value for the given [`Padding`]. +/// +/// [`Padding`]: struct.Padding.html +pub fn padding(padding: Padding) -> String { + format!( + "{}px {}px {}px {}px", + padding.top, padding.right, padding.bottom, padding.left + ) +} diff --git a/web/src/element.rs b/web/src/element.rs index 93e73713..6bb90177 100644 --- a/web/src/element.rs +++ b/web/src/element.rs @@ -11,9 +11,7 @@ use std::rc::Rc; /// If you have a [built-in widget], you should be able to use `Into<Element>` /// to turn it into an [`Element`]. /// -/// [built-in widget]: widget/index.html -/// [`Widget`]: widget/trait.Widget.html -/// [`Element`]: struct.Element.html +/// [built-in widget]: mod@crate::widget #[allow(missing_debug_implementations)] pub struct Element<'a, Message> { pub(crate) widget: Box<dyn Widget<Message> + 'a>, @@ -21,9 +19,6 @@ pub struct Element<'a, Message> { impl<'a, Message> Element<'a, Message> { /// Create a new [`Element`] containing the given [`Widget`]. - /// - /// [`Element`]: struct.Element.html - /// [`Widget`]: widget/trait.Widget.html pub fn new(widget: impl Widget<Message> + 'a) -> Self { Self { widget: Box::new(widget), @@ -34,8 +29,6 @@ impl<'a, Message> Element<'a, Message> { /// /// This method is useful when you want to decouple different parts of your /// UI and make them __composable__. - /// - /// [`Element`]: struct.Element.html pub fn map<F, B>(self, f: F) -> Element<'a, B> where Message: 'static, diff --git a/web/src/lib.rs b/web/src/lib.rs index 0776e9d5..bb09bb0d 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -1,7 +1,5 @@ //! A web runtime for Iced, targetting the DOM. //! -//!  -//! //! `iced_web` takes [`iced_core`] and builds a WebAssembly runtime on top. It //! achieves this by introducing a `Widget` trait that can be used to produce //! VDOM nodes. @@ -51,7 +49,7 @@ //! //! [`wasm-pack`]: https://github.com/rustwasm/wasm-pack //! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen -//! [`tour` example]: https://github.com/hecrj/iced/tree/0.1/examples/tour +//! [`tour` example]: https://github.com/hecrj/iced/tree/0.3/examples/tour #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] @@ -61,6 +59,7 @@ use dodrio::bumpalo; use std::{cell::RefCell, rc::Rc}; mod bus; +mod clipboard; mod element; mod hasher; @@ -69,13 +68,14 @@ pub mod subscription; pub mod widget; pub use bus::Bus; +pub use clipboard::Clipboard; pub use css::Css; pub use dodrio; pub use element::Element; pub use hasher::Hasher; pub use iced_core::{ - keyboard, mouse, Align, Background, Color, Font, HorizontalAlignment, - Length, Point, Rectangle, Size, Vector, VerticalAlignment, + keyboard, menu, mouse, Align, Background, Color, Font, HorizontalAlignment, + Length, Menu, Padding, Point, Rectangle, Size, Vector, VerticalAlignment, }; pub use iced_futures::{executor, futures, Command}; pub use subscription::Subscription; @@ -96,33 +96,21 @@ pub use executor::Executor; /// by returning a [`Command`](struct.Command.html) in some of its methods. pub trait Application { /// The [`Executor`] that will run commands and subscriptions. - /// - /// The [`executor::WasmBindgen`] can be a good choice for the Web. - /// - /// [`Executor`]: trait.Executor.html - /// [`executor::Default`]: executor/struct.Default.html type Executor: Executor; /// The type of __messages__ your [`Application`] will produce. - /// - /// [`Application`]: trait.Application.html type Message: Send; /// The data needed to initialize your [`Application`]. - /// - /// [`Application`]: trait.Application.html type Flags; /// Initializes the [`Application`]. /// /// Here is where you should return the initial state of your app. /// - /// Additionally, you can return a [`Command`](struct.Command.html) if you - /// need to perform some async action in the background on startup. This is - /// useful if you want to load state from a file, perform an initial HTTP - /// request, etc. - /// - /// [`Application`]: trait.Application.html + /// Additionally, you can return a [`Command`] if you need to perform some + /// async action in the background on startup. This is useful if you want to + /// load state from a file, perform an initial HTTP request, etc. fn new(flags: Self::Flags) -> (Self, Command<Self::Message>) where Self: Sized; @@ -131,8 +119,6 @@ pub trait Application { /// /// This title can be dynamic! The runtime will automatically update the /// title of your application when necessary. - /// - /// [`Application`]: trait.Application.html fn title(&self) -> String; /// Handles a __message__ and updates the state of the [`Application`]. @@ -142,16 +128,15 @@ pub trait Application { /// this method. /// /// Any [`Command`] returned will be executed immediately in the background. - /// - /// [`Application`]: trait.Application.html - /// [`Command`]: struct.Command.html - fn update(&mut self, message: Self::Message) -> Command<Self::Message>; + fn update( + &mut self, + message: Self::Message, + clipboard: &mut Clipboard, + ) -> Command<Self::Message>; /// Returns the widgets to display in the [`Application`]. /// /// These widgets can produce __messages__ based on user interaction. - /// - /// [`Application`]: trait.Application.html fn view(&mut self) -> Element<'_, Self::Message>; /// Returns the event [`Subscription`] for the current state of the @@ -162,15 +147,11 @@ pub trait Application { /// [`update`](#tymethod.update). /// /// By default, this method returns an empty [`Subscription`]. - /// - /// [`Subscription`]: struct.Subscription.html fn subscription(&self) -> Subscription<Self::Message> { Subscription::none() } /// Runs the [`Application`]. - /// - /// [`Application`]: trait.Application.html fn run(flags: Self::Flags) where Self: 'static + Sized, @@ -181,6 +162,8 @@ pub trait Application { let document = window.document().unwrap(); let body = document.body().unwrap(); + let mut clipboard = Clipboard::new(); + let (sender, receiver) = iced_futures::futures::channel::mpsc::unbounded(); @@ -207,7 +190,8 @@ pub trait Application { let event_loop = receiver.for_each(move |message| { let (command, subscription) = runtime.enter(|| { - let command = application.borrow_mut().update(message); + let command = + application.borrow_mut().update(message, &mut clipboard); let subscription = application.borrow().subscription(); (command, subscription) diff --git a/web/src/subscription.rs b/web/src/subscription.rs index 6b8415c0..fb54f7e3 100644 --- a/web/src/subscription.rs +++ b/web/src/subscription.rs @@ -12,8 +12,7 @@ use crate::Hasher; /// For instance, you can use a [`Subscription`] to listen to a WebSocket /// connection, keyboard presses, mouse events, time ticks, etc. /// -/// [`Command`]: ../struct.Command.html -/// [`Subscription`]: struct.Subscription.html +/// [`Command`]: crate::Command pub type Subscription<T> = iced_futures::Subscription<Hasher, (), T>; pub use iced_futures::subscription::Recipe; diff --git a/web/src/widget.rs b/web/src/widget.rs index 025cf22f..4cb0a9cc 100644 --- a/web/src/widget.rs +++ b/web/src/widget.rs @@ -12,8 +12,6 @@ //! ``` //! use iced_web::{button, Button, Widget}; //! ``` -//! -//! [`Widget`]: trait.Widget.html use crate::{Bus, Css}; use dodrio::bumpalo; @@ -26,6 +24,7 @@ pub mod radio; pub mod scrollable; pub mod slider; pub mod text_input; +pub mod toggler; mod column; mod row; @@ -42,6 +41,8 @@ pub use slider::Slider; pub use text::Text; #[doc(no_inline)] pub use text_input::TextInput; +#[doc(no_inline)] +pub use toggler::Toggler; pub use checkbox::Checkbox; pub use column::Column; @@ -56,12 +57,8 @@ pub use space::Space; /// /// If you want to build your own widgets, you will need to implement this /// trait. -/// -/// [`Widget`]: trait.Widget.html pub trait Widget<Message> { /// Produces a VDOM node for the [`Widget`]. - /// - /// [`Widget`]: trait.Widget.html fn node<'b>( &self, bump: &'b bumpalo::Bump, diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index a4bcc33d..cd450b55 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -1,10 +1,7 @@ //! Allow your users to perform actions by pressing a button. //! //! A [`Button`] has some local [`State`]. -//! -//! [`Button`]: struct.Button.html -//! [`State`]: struct.State.html -use crate::{css, Background, Bus, Css, Element, Length, Widget}; +use crate::{css, Background, Bus, Css, Element, Length, Padding, Widget}; pub use iced_style::button::{Style, StyleSheet}; @@ -23,24 +20,43 @@ use dodrio::bumpalo; /// 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: u16, + padding: Padding, style: Box<dyn StyleSheet>, } impl<'a, Message> Button<'a, Message> { /// Creates a new [`Button`] with some local [`State`] and the given /// content. - /// - /// [`Button`]: struct.Button.html - /// [`State`]: struct.State.html pub fn new<E>(_state: &'a mut State, content: E) -> Self where E: Into<Element<'a, Message>>, @@ -52,62 +68,49 @@ impl<'a, Message> Button<'a, Message> { height: Length::Shrink, min_width: 0, min_height: 0, - padding: 5, + padding: Padding::new(5), style: Default::default(), } } /// Sets the width of the [`Button`]. - /// - /// [`Button`]: struct.Button.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Button`]. - /// - /// [`Button`]: struct.Button.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the minimum width of the [`Button`]. - /// - /// [`Button`]: struct.Button.html pub fn min_width(mut self, min_width: u32) -> Self { self.min_width = min_width; self } /// Sets the minimum height of the [`Button`]. - /// - /// [`Button`]: struct.Button.html pub fn min_height(mut self, min_height: u32) -> Self { self.min_height = min_height; self } - /// Sets the padding of the [`Button`]. - /// - /// [`Button`]: struct.Button.html - pub fn padding(mut self, padding: u16) -> Self { - self.padding = padding; + /// 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`]. - /// - /// [`Button`]: struct.Button.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style = style.into(); self } /// Sets the message that will be produced when the [`Button`] is pressed. - /// - /// [`Button`]: struct.Button.html + /// 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 @@ -115,15 +118,11 @@ impl<'a, Message> Button<'a, Message> { } /// The local state of a [`Button`]. -/// -/// [`Button`]: struct.Button.html #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct State; impl State { /// Creates a new [`State`]. - /// - /// [`State`]: struct.State.html pub fn new() -> State { State::default() } @@ -144,9 +143,6 @@ where // TODO: State-based styling let style = self.style.active(); - let padding_class = - style_sheet.insert(bump, css::Rule::Padding(self.padding)); - let background = match style.background { None => String::from("none"), Some(background) => match background { @@ -154,25 +150,19 @@ where }, }; - let class = { - use dodrio::bumpalo::collections::String; - - String::from_str_in(&padding_class, bump).into_bump_str() - }; - let mut node = button(bump) - .attr("class", class) .attr( "style", bumpalo::format!( in bump, "background: {}; border-radius: {}px; width:{}; \ - min-width: {}; color: {}", + min-width: {}; color: {}; padding: {}", background, style.border_radius, css::length(self.width), css::min_length(self.min_width), - css::color(style.text_color) + css::color(style.text_color), + css::padding(self.padding) ) .into_bump_str(), ) @@ -184,6 +174,8 @@ where node = node.on("click", move |_root, _vdom, _event| { event_bus.publish(on_press.clone()); }); + } else { + node = node.attr("disabled", ""); } node.finish() diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index 21801e39..43110aa7 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -30,6 +30,7 @@ pub struct Checkbox<Message> { label: String, id: Option<String>, width: Length, + #[allow(dead_code)] style: Box<dyn StyleSheet>, } @@ -42,8 +43,6 @@ impl<Message> Checkbox<Message> { /// * a function that will be called when the [`Checkbox`] is toggled. It /// will receive the new state of the [`Checkbox`] and must produce a /// `Message`. - /// - /// [`Checkbox`]: struct.Checkbox.html pub fn new<F>(is_checked: bool, label: impl Into<String>, f: F) -> Self where F: 'static + Fn(bool) -> Message, @@ -59,24 +58,18 @@ impl<Message> Checkbox<Message> { } /// Sets the width of the [`Checkbox`]. - /// - /// [`Checkbox`]: struct.Checkbox.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the style of the [`Checkbox`]. - /// - /// [`Checkbox`]: struct.Checkbox.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style = style.into(); self } /// Sets the id of the [`Checkbox`]. - /// - /// [`Checkbox`]: struct.Checkbox.html pub fn id(mut self, id: impl Into<String>) -> Self { self.id = Some(id.into()); self diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index 25b88b0e..8738c2af 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -1,4 +1,4 @@ -use crate::{css, Align, Bus, Css, Element, Length, Widget}; +use crate::{css, Align, Bus, Css, Element, Length, Padding, Widget}; use dodrio::bumpalo; use std::u32; @@ -6,12 +6,10 @@ use std::u32; /// A container that distributes its contents vertically. /// /// A [`Column`] will try to fill the horizontal space of its container. -/// -/// [`Column`]: struct.Column.html #[allow(missing_debug_implementations)] pub struct Column<'a, Message> { spacing: u16, - padding: u16, + padding: Padding, width: Length, height: Length, max_width: u32, @@ -22,19 +20,15 @@ pub struct Column<'a, Message> { impl<'a, Message> Column<'a, Message> { /// Creates an empty [`Column`]. - /// - /// [`Column`]: struct.Column.html pub fn new() -> Self { Self::with_children(Vec::new()) } /// Creates a [`Column`] with the given elements. - /// - /// [`Column`]: struct.Column.html pub fn with_children(children: Vec<Element<'a, Message>>) -> Self { Column { spacing: 0, - padding: 0, + padding: Padding::ZERO, width: Length::Fill, height: Length::Shrink, max_width: u32::MAX, @@ -54,57 +48,43 @@ impl<'a, Message> Column<'a, Message> { self } - /// Sets the padding of the [`Column`]. - /// - /// [`Column`]: struct.Column.html - pub fn padding(mut self, units: u16) -> Self { - self.padding = units; + /// 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`]. - /// - /// [`Column`]: struct.Column.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Column`]. - /// - /// [`Column`]: struct.Column.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the maximum width of the [`Column`]. - /// - /// [`Column`]: struct.Column.html pub fn max_width(mut self, max_width: u32) -> Self { self.max_width = max_width; self } /// Sets the maximum height of the [`Column`] in pixels. - /// - /// [`Column`]: struct.Column.html pub fn max_height(mut self, max_height: u32) -> Self { self.max_height = max_height; self } /// Sets the horizontal alignment of the contents of the [`Column`] . - /// - /// [`Column`]: struct.Column.html pub fn align_items(mut self, align: Align) -> Self { self.align_items = align; self } /// Adds an element to the [`Column`]. - /// - /// [`Column`]: struct.Column.html pub fn push<E>(mut self, child: E) -> Self where E: Into<Element<'a, Message>>, @@ -134,23 +114,21 @@ impl<'a, Message> Widget<Message> for Column<'a, Message> { let spacing_class = style_sheet.insert(bump, css::Rule::Spacing(self.spacing)); - let padding_class = - style_sheet.insert(bump, css::Rule::Padding(self.padding)); - // TODO: Complete styling div(bump) .attr( "class", - bumpalo::format!(in bump, "{} {} {}", column_class, spacing_class, padding_class) + bumpalo::format!(in bump, "{} {}", column_class, spacing_class) .into_bump_str(), ) .attr("style", bumpalo::format!( in bump, - "width: {}; height: {}; max-width: {}; max-height: {}; align-items: {}", + "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::align(self.align_items) ).into_bump_str() ) diff --git a/web/src/widget/container.rs b/web/src/widget/container.rs index 78be3543..c006e011 100644 --- a/web/src/widget/container.rs +++ b/web/src/widget/container.rs @@ -1,5 +1,5 @@ //! Decorate content and apply alignment. -use crate::{bumpalo, css, Align, Bus, Css, Element, Length, Widget}; +use crate::{bumpalo, css, Align, Bus, Css, Element, Length, Padding, Widget}; pub use iced_style::container::{Style, StyleSheet}; @@ -8,10 +8,11 @@ pub use iced_style::container::{Style, StyleSheet}; /// It is normally used for alignment purposes. #[allow(missing_debug_implementations)] pub struct Container<'a, Message> { - padding: u16, + padding: Padding, width: Length, height: Length, max_width: u32, + #[allow(dead_code)] max_height: u32, horizontal_alignment: Align, vertical_alignment: Align, @@ -21,8 +22,6 @@ pub struct Container<'a, Message> { impl<'a, Message> Container<'a, Message> { /// Creates an empty [`Container`]. - /// - /// [`Container`]: struct.Container.html pub fn new<T>(content: T) -> Self where T: Into<Element<'a, Message>>, @@ -30,7 +29,7 @@ impl<'a, Message> Container<'a, Message> { use std::u32; Container { - padding: 0, + padding: Padding::ZERO, width: Length::Shrink, height: Length::Shrink, max_width: u32::MAX, @@ -42,49 +41,37 @@ impl<'a, Message> Container<'a, Message> { } } - /// Sets the padding of the [`Container`]. - /// - /// [`Container`]: struct.Column.html - pub fn padding(mut self, units: u16) -> Self { - self.padding = units; + /// 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`]. - /// - /// [`Container`]: struct.Container.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Container`]. - /// - /// [`Container`]: struct.Container.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the maximum width of the [`Container`]. - /// - /// [`Container`]: struct.Container.html 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. - /// - /// [`Container`]: struct.Container.html 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`]. - /// - /// [`Container`]: struct.Container.html pub fn center_x(mut self) -> Self { self.horizontal_alignment = Align::Center; @@ -92,8 +79,6 @@ impl<'a, Message> Container<'a, Message> { } /// Centers the contents in the vertical axis of the [`Container`]. - /// - /// [`Container`]: struct.Container.html pub fn center_y(mut self) -> Self { self.vertical_alignment = Align::Center; @@ -101,8 +86,6 @@ impl<'a, Message> Container<'a, Message> { } /// Sets the style of the [`Container`]. - /// - /// [`Container`]: struct.Container.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style_sheet = style.into(); self @@ -123,24 +106,22 @@ where let column_class = style_sheet.insert(bump, css::Rule::Column); - let padding_class = - style_sheet.insert(bump, css::Rule::Padding(self.padding)); - let style = self.style_sheet.style(); let node = div(bump) .attr( "class", - bumpalo::format!(in bump, "{} {}", column_class, padding_class).into_bump_str(), + bumpalo::format!(in bump, "{}", column_class).into_bump_str(), ) .attr( "style", bumpalo::format!( in bump, - "width: {}; height: {}; max-width: {}; align-items: {}; justify-content: {}; background: {}; color: {}; border-width: {}px; border-color: {}; border-radius: {}px", + "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::align(self.horizontal_alignment), css::align(self.vertical_alignment), style.background.map(css::background).unwrap_or(String::from("initial")), diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index a595c29a..05c89ea5 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -34,8 +34,6 @@ pub struct Image { impl Image { /// Creates a new [`Image`] with the given path. - /// - /// [`Image`]: struct.Image.html pub fn new<T: Into<Handle>>(handle: T) -> Self { Image { handle: handle.into(), @@ -46,24 +44,18 @@ impl Image { } /// Sets the width of the [`Image`] boundaries. - /// - /// [`Image`]: struct.Image.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Image`] boundaries. - /// - /// [`Image`]: struct.Image.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the alt text of the [`Image`]. - /// - /// [`Image`]: struct.Image.html pub fn alt(mut self, alt: impl Into<String>) -> Self { self.alt = alt.into(); self @@ -118,8 +110,6 @@ impl<'a, Message> From<Image> for Element<'a, Message> { } /// An [`Image`] handle. -/// -/// [`Image`]: struct.Image.html #[derive(Debug, Clone)] pub struct Handle { id: u64, @@ -128,8 +118,6 @@ pub struct Handle { impl Handle { /// Creates an image [`Handle`] pointing to the image of the given path. - /// - /// [`Handle`]: struct.Handle.html pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle { Self::from_data(Data::Path(path.into())) } @@ -145,15 +133,11 @@ impl Handle { } /// Returns the unique identifier of the [`Handle`]. - /// - /// [`Handle`]: struct.Handle.html pub fn id(&self) -> u64 { self.id } /// Returns a reference to the image [`Data`]. - /// - /// [`Data`]: enum.Data.html pub fn data(&self) -> &Data { &self.data } @@ -172,8 +156,6 @@ impl From<&str> for Handle { } /// The data of an [`Image`]. -/// -/// [`Image`]: struct.Image.html #[derive(Clone, Hash)] pub enum Data { /// A remote image diff --git a/web/src/widget/progress_bar.rs b/web/src/widget/progress_bar.rs index 856203c0..7d77616e 100644 --- a/web/src/widget/progress_bar.rs +++ b/web/src/widget/progress_bar.rs @@ -32,8 +32,6 @@ impl ProgressBar { /// It expects: /// * an inclusive range of possible values /// * the current value of the [`ProgressBar`] - /// - /// [`ProgressBar`]: struct.ProgressBar.html pub fn new(range: RangeInclusive<f32>, value: f32) -> Self { ProgressBar { value: value.max(*range.start()).min(*range.end()), @@ -45,24 +43,18 @@ impl ProgressBar { } /// Sets the width of the [`ProgressBar`]. - /// - /// [`ProgressBar`]: struct.ProgressBar.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`ProgressBar`]. - /// - /// [`ProgressBar`]: struct.ProgressBar.html pub fn height(mut self, height: Length) -> Self { self.height = Some(height); self } /// Sets the style of the [`ProgressBar`]. - /// - /// [`ProgressBar`]: struct.ProgressBar.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style = style.into(); self diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index c9d0a00e..fbc88d29 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -37,6 +37,7 @@ pub struct Radio<Message> { label: String, id: Option<String>, name: Option<String>, + #[allow(dead_code)] style: Box<dyn StyleSheet>, } @@ -49,8 +50,6 @@ impl<Message> Radio<Message> { /// * the current selected value /// * a function that will be called when the [`Radio`] is selected. It /// receives the value of the radio and must produce a `Message`. - /// - /// [`Radio`]: struct.Radio.html pub fn new<F, V>( value: V, label: impl Into<String>, @@ -72,24 +71,18 @@ impl<Message> Radio<Message> { } /// Sets the style of the [`Radio`] button. - /// - /// [`Radio`]: struct.Radio.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style = style.into(); self } /// Sets the name attribute of the [`Radio`] button. - /// - /// [`Radio`]: struct.Radio.html pub fn name(mut self, name: impl Into<String>) -> Self { self.name = Some(name.into()); self } /// Sets the id of the [`Radio`] button. - /// - /// [`Radio`]: struct.Radio.html pub fn id(mut self, id: impl Into<String>) -> Self { self.id = Some(id.into()); self diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index cfa10fdf..ffb515cf 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -1,4 +1,4 @@ -use crate::{css, Align, Bus, Css, Element, Length, Widget}; +use crate::{css, Align, Bus, Css, Element, Length, Padding, Widget}; use dodrio::bumpalo; use std::u32; @@ -6,12 +6,10 @@ use std::u32; /// A container that distributes its contents horizontally. /// /// A [`Row`] will try to fill the horizontal space of its container. -/// -/// [`Row`]: struct.Row.html #[allow(missing_debug_implementations)] pub struct Row<'a, Message> { spacing: u16, - padding: u16, + padding: Padding, width: Length, height: Length, max_width: u32, @@ -22,19 +20,15 @@ pub struct Row<'a, Message> { impl<'a, Message> Row<'a, Message> { /// Creates an empty [`Row`]. - /// - /// [`Row`]: struct.Row.html pub fn new() -> Self { Self::with_children(Vec::new()) } /// Creates a [`Row`] with the given elements. - /// - /// [`Row`]: struct.Row.html pub fn with_children(children: Vec<Element<'a, Message>>) -> Self { Row { spacing: 0, - padding: 0, + padding: Padding::ZERO, width: Length::Fill, height: Length::Shrink, max_width: u32::MAX, @@ -54,58 +48,43 @@ impl<'a, Message> Row<'a, Message> { self } - /// Sets the padding of the [`Row`]. - /// - /// [`Row`]: struct.Row.html - pub fn padding(mut self, units: u16) -> Self { - self.padding = units; + /// 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`]. - /// - /// [`Row`]: struct.Row.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Row`]. - /// - /// [`Row`]: struct.Row.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the maximum width of the [`Row`]. - /// - /// [`Row`]: struct.Row.html pub fn max_width(mut self, max_width: u32) -> Self { self.max_width = max_width; self } /// Sets the maximum height of the [`Row`]. - /// - /// [`Row`]: struct.Row.html pub fn max_height(mut self, max_height: u32) -> Self { self.max_height = max_height; self } /// Sets the vertical alignment of the contents of the [`Row`] . - /// - /// [`Row`]: struct.Row.html pub fn align_items(mut self, align: Align) -> Self { self.align_items = align; self } /// Adds an [`Element`] to the [`Row`]. - /// - /// [`Element`]: ../struct.Element.html - /// [`Row`]: struct.Row.html pub fn push<E>(mut self, child: E) -> Self where E: Into<Element<'a, Message>>, @@ -135,23 +114,21 @@ impl<'a, Message> Widget<Message> for Row<'a, Message> { let spacing_class = style_sheet.insert(bump, css::Rule::Spacing(self.spacing)); - let padding_class = - style_sheet.insert(bump, css::Rule::Padding(self.padding)); - // TODO: Complete styling div(bump) .attr( "class", - bumpalo::format!(in bump, "{} {} {}", row_class, spacing_class, padding_class) + bumpalo::format!(in bump, "{} {}", row_class, spacing_class) .into_bump_str(), ) .attr("style", bumpalo::format!( in bump, - "width: {}; height: {}; max-width: {}; max-height: {}; align-items: {}", + "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::align(self.align_items) ).into_bump_str() ) diff --git a/web/src/widget/scrollable.rs b/web/src/widget/scrollable.rs index 07b38aad..ce0a10d4 100644 --- a/web/src/widget/scrollable.rs +++ b/web/src/widget/scrollable.rs @@ -1,5 +1,7 @@ //! Navigate an endless amount of content with a scrollbar. -use crate::{bumpalo, css, Align, Bus, Column, Css, Element, Length, Widget}; +use crate::{ + bumpalo, css, Align, Bus, Column, Css, Element, Length, Padding, Widget, +}; pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; @@ -11,14 +13,12 @@ pub struct Scrollable<'a, Message> { height: Length, max_height: u32, content: Column<'a, Message>, + #[allow(dead_code)] style: Box<dyn StyleSheet>, } impl<'a, Message> Scrollable<'a, Message> { /// Creates a new [`Scrollable`] with the given [`State`]. - /// - /// [`Scrollable`]: struct.Scrollable.html - /// [`State`]: struct.State.html pub fn new(_state: &'a mut State) -> Self { use std::u32; @@ -41,65 +41,49 @@ impl<'a, Message> Scrollable<'a, Message> { self } - /// Sets the padding of the [`Scrollable`]. - /// - /// [`Scrollable`]: struct.Scrollable.html - pub fn padding(mut self, units: u16) -> Self { - self.content = self.content.padding(units); + /// 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`]. - /// - /// [`Scrollable`]: struct.Scrollable.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Scrollable`]. - /// - /// [`Scrollable`]: struct.Scrollable.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the maximum width of the [`Scrollable`]. - /// - /// [`Scrollable`]: struct.Scrollable.html 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. - /// - /// [`Scrollable`]: struct.Scrollable.html pub fn max_height(mut self, max_height: u32) -> Self { self.max_height = max_height; self } /// Sets the horizontal alignment of the contents of the [`Scrollable`] . - /// - /// [`Scrollable`]: struct.Scrollable.html pub fn align_items(mut self, align_items: Align) -> Self { self.content = self.content.align_items(align_items); self } /// Sets the style of the [`Scrollable`] . - /// - /// [`Scrollable`]: struct.Scrollable.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style = style.into(); self } /// Adds an element to the [`Scrollable`]. - /// - /// [`Scrollable`]: struct.Scrollable.html pub fn push<E>(mut self, child: E) -> Self where E: Into<Element<'a, Message>>, @@ -154,15 +138,11 @@ where } /// The local state of a [`Scrollable`]. -/// -/// [`Scrollable`]: struct.Scrollable.html #[derive(Debug, Clone, Copy, Default)] pub struct State; impl State { /// Creates a new [`State`] with the scrollbar located at the top. - /// - /// [`State`]: struct.State.html pub fn new() -> Self { State::default() } diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index a0d9df00..f457aa4c 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -1,9 +1,6 @@ //! Display an interactive selector of a single value from a range of values. //! //! A [`Slider`] has some local [`State`]. -//! -//! [`Slider`]: struct.Slider.html -//! [`State`]: struct.State.html use crate::{Bus, Css, Element, Length, Widget}; pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; @@ -19,8 +16,6 @@ use std::{ops::RangeInclusive, rc::Rc}; /// The [`Slider`] range of numeric values is generic and its step size defaults /// to 1 unit. /// -/// [`Slider`]: struct.Slider.html -/// /// # Example /// ``` /// # use iced_web::{slider, Slider}; @@ -43,7 +38,9 @@ pub struct Slider<'a, T, Message> { step: T, value: T, on_change: Rc<Box<dyn Fn(T) -> Message>>, + #[allow(dead_code)] width: Length, + #[allow(dead_code)] style: Box<dyn StyleSheet>, } @@ -60,9 +57,6 @@ where /// * a function that will be called when the [`Slider`] is dragged. /// It receives the new value of the [`Slider`] and must produce a /// `Message`. - /// - /// [`Slider`]: struct.Slider.html - /// [`State`]: struct.State.html pub fn new<F>( state: &'a mut State, range: RangeInclusive<T>, @@ -96,24 +90,18 @@ where } /// Sets the width of the [`Slider`]. - /// - /// [`Slider`]: struct.Slider.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the style of the [`Slider`]. - /// - /// [`Slider`]: struct.Slider.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style = style.into(); self } /// Sets the step size of the [`Slider`]. - /// - /// [`Slider`]: struct.Slider.html pub fn step(mut self, step: T) -> Self { self.step = step; self @@ -181,15 +169,11 @@ where } /// The local state of a [`Slider`]. -/// -/// [`Slider`]: struct.Slider.html #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct State; impl State { /// Creates a new [`State`]. - /// - /// [`State`]: struct.State.html pub fn new() -> Self { Self } diff --git a/web/src/widget/space.rs b/web/src/widget/space.rs index 4ce52595..a8571fdb 100644 --- a/web/src/widget/space.rs +++ b/web/src/widget/space.rs @@ -12,15 +12,11 @@ pub struct Space { impl Space { /// Creates an amount of empty [`Space`] with the given width and height. - /// - /// [`Space`]: struct.Space.html pub fn new(width: Length, height: Length) -> Self { Space { width, height } } /// Creates an amount of horizontal [`Space`]. - /// - /// [`Space`]: struct.Space.html pub fn with_width(width: Length) -> Self { Space { width, @@ -29,8 +25,6 @@ impl Space { } /// Creates an amount of vertical [`Space`]. - /// - /// [`Space`]: struct.Space.html pub fn with_height(height: Length) -> Self { Space { width: Length::Shrink, diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index 2f7308ee..72232dc0 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -28,8 +28,6 @@ pub struct Text { impl Text { /// Create a new fragment of [`Text`] with the given contents. - /// - /// [`Text`]: struct.Text.html pub fn new<T: Into<String>>(label: T) -> Self { Text { content: label.into(), @@ -44,51 +42,36 @@ impl Text { } /// Sets the size of the [`Text`]. - /// - /// [`Text`]: struct.Text.html pub fn size(mut self, size: u16) -> Self { self.size = Some(size); self } /// Sets the [`Color`] of the [`Text`]. - /// - /// [`Text`]: struct.Text.html - /// [`Color`]: ../../struct.Color.html pub fn color<C: Into<Color>>(mut self, color: C) -> Self { self.color = Some(color.into()); self } /// Sets the [`Font`] of the [`Text`]. - /// - /// [`Text`]: struct.Text.html - /// [`Font`]: ../../struct.Font.html pub fn font(mut self, font: Font) -> Self { self.font = font; self } /// Sets the width of the [`Text`] boundaries. - /// - /// [`Text`]: struct.Text.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Text`] boundaries. - /// - /// [`Text`]: struct.Text.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the [`HorizontalAlignment`] of the [`Text`]. - /// - /// [`Text`]: struct.Text.html - /// [`HorizontalAlignment`]: enum.HorizontalAlignment.html pub fn horizontal_alignment( mut self, alignment: HorizontalAlignment, @@ -98,9 +81,6 @@ impl Text { } /// Sets the [`VerticalAlignment`] of the [`Text`]. - /// - /// [`Text`]: struct.Text.html - /// [`VerticalAlignment`]: enum.VerticalAlignment.html pub fn vertical_alignment(mut self, alignment: VerticalAlignment) -> Self { self.vertical_alignment = alignment; self diff --git a/web/src/widget/text_input.rs b/web/src/widget/text_input.rs index 0049a553..e4877f2a 100644 --- a/web/src/widget/text_input.rs +++ b/web/src/widget/text_input.rs @@ -1,10 +1,7 @@ //! Display fields that can be filled with text. //! //! A [`TextInput`] has some local [`State`]. -//! -//! [`TextInput`]: struct.TextInput.html -//! [`State`]: struct.State.html -use crate::{bumpalo, css, Bus, Css, Element, Length, Widget}; +use crate::{bumpalo, css, Bus, Css, Element, Length, Padding, Widget}; pub use iced_style::text_input::{Style, StyleSheet}; @@ -38,7 +35,7 @@ pub struct TextInput<'a, Message> { is_secure: bool, width: Length, max_width: u32, - padding: u16, + padding: Padding, size: Option<u16>, on_change: Rc<Box<dyn Fn(String) -> Message>>, on_submit: Option<Message>, @@ -53,9 +50,6 @@ impl<'a, Message> TextInput<'a, Message> { /// - a placeholder /// - the current value /// - a function that produces a message when the [`TextInput`] changes - /// - /// [`TextInput`]: struct.TextInput.html - /// [`State`]: struct.State.html pub fn new<F>( state: &'a mut State, placeholder: &str, @@ -72,7 +66,7 @@ impl<'a, Message> TextInput<'a, Message> { is_secure: false, width: Length::Fill, max_width: u32::MAX, - padding: 0, + padding: Padding::ZERO, size: None, on_change: Rc::new(Box::new(on_change)), on_submit: None, @@ -81,40 +75,30 @@ impl<'a, Message> TextInput<'a, Message> { } /// Converts the [`TextInput`] into a secure password input. - /// - /// [`TextInput`]: struct.TextInput.html pub fn password(mut self) -> Self { self.is_secure = true; self } /// Sets the width of the [`TextInput`]. - /// - /// [`TextInput`]: struct.TextInput.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the maximum width of the [`TextInput`]. - /// - /// [`TextInput`]: struct.TextInput.html pub fn max_width(mut self, max_width: u32) -> Self { self.max_width = max_width; self } - /// Sets the padding of the [`TextInput`]. - /// - /// [`TextInput`]: struct.TextInput.html - pub fn padding(mut self, units: u16) -> Self { - self.padding = units; + /// 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`]. - /// - /// [`TextInput`]: struct.TextInput.html pub fn size(mut self, size: u16) -> Self { self.size = Some(size); self @@ -122,16 +106,12 @@ impl<'a, Message> TextInput<'a, Message> { /// Sets the message that should be produced when the [`TextInput`] is /// focused and the enter key is pressed. - /// - /// [`TextInput`]: struct.TextInput.html pub fn on_submit(mut self, message: Message) -> Self { self.on_submit = Some(message); self } /// Sets the style of the [`TextInput`]. - /// - /// [`TextInput`]: struct.TextInput.html pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self { self.style_sheet = style.into(); self @@ -146,20 +126,11 @@ where &self, bump: &'b bumpalo::Bump, bus: &Bus<Message>, - style_sheet: &mut Css<'b>, + _style_sheet: &mut Css<'b>, ) -> dodrio::Node<'b> { use dodrio::builder::*; use wasm_bindgen::JsCast; - let class = { - use dodrio::bumpalo::collections::String; - - let padding_class = - style_sheet.insert(bump, css::Rule::Padding(self.padding)); - - String::from_str_in(&padding_class, bump).into_bump_str() - }; - let placeholder = { use dodrio::bumpalo::collections::String; @@ -179,16 +150,16 @@ where let style = self.style_sheet.active(); input(bump) - .attr("class", class) .attr( "style", bumpalo::format!( in bump, - "width: {}; max-width: {}; font-size: {}px; \ + "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, @@ -238,24 +209,23 @@ where } /// The state of a [`TextInput`]. -/// -/// [`TextInput`]: struct.TextInput.html #[derive(Debug, Clone, Copy, Default)] pub struct State; impl State { /// Creates a new [`State`], representing an unfocused [`TextInput`]. - /// - /// [`State`]: struct.State.html pub fn new() -> Self { Self::default() } /// Creates a new [`State`], representing a focused [`TextInput`]. - /// - /// [`State`]: struct.State.html pub fn focused() -> Self { // TODO Self::default() } + + /// 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 new file mode 100644 index 00000000..0a198079 --- /dev/null +++ b/web/src/widget/toggler.rs @@ -0,0 +1,171 @@ +//! 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) + } +} |