diff options
| author | 2019-09-24 15:39:33 +0200 | |
|---|---|---|
| committer | 2019-09-24 15:39:33 +0200 | |
| commit | 68c4752e998dca1d618380ce4e7d8ac52b710056 (patch) | |
| tree | 35e386030b072c189509bb2ed3adeaec5b0fd4d1 /core | |
| parent | bb5cac49d028eb53c259ae58e3a007ebfb736fd4 (diff) | |
| parent | 05c7c39ecb8910c75b82dc4052a7720fb2d42b4a (diff) | |
| download | iced-68c4752e998dca1d618380ce4e7d8ac52b710056.tar.gz iced-68c4752e998dca1d618380ce4e7d8ac52b710056.tar.bz2 iced-68c4752e998dca1d618380ce4e7d8ac52b710056.zip | |
Merge pull request #17 from hecrj/web
Basic web support (core, native, and web crates)
Diffstat (limited to '')
| -rw-r--r-- | core/Cargo.toml | 8 | ||||
| -rw-r--r-- | core/src/align.rs | 21 | ||||
| -rw-r--r-- | core/src/color.rs | 19 | ||||
| -rw-r--r-- | core/src/justify.rs | 27 | ||||
| -rw-r--r-- | core/src/length.rs | 7 | ||||
| -rw-r--r-- | core/src/lib.rs | 18 | ||||
| -rw-r--r-- | core/src/point.rs (renamed from src/point.rs) | 0 | ||||
| -rw-r--r-- | core/src/rectangle.rs (renamed from src/rectangle.rs) | 0 | ||||
| -rw-r--r-- | core/src/vector.rs (renamed from src/vector.rs) | 0 | ||||
| -rw-r--r-- | core/src/widget.rs | 33 | ||||
| -rw-r--r-- | core/src/widget/button.rs | 158 | ||||
| -rw-r--r-- | core/src/widget/checkbox.rs | 78 | ||||
| -rw-r--r-- | core/src/widget/column.rs | 147 | ||||
| -rw-r--r-- | core/src/widget/image.rs | 89 | ||||
| -rw-r--r-- | core/src/widget/radio.rs | 88 | ||||
| -rw-r--r-- | core/src/widget/row.rs | 142 | ||||
| -rw-r--r-- | core/src/widget/slider.rs | 123 | ||||
| -rw-r--r-- | core/src/widget/text.rs | 119 | 
18 files changed, 1077 insertions, 0 deletions
| diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 00000000..a244bcba --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "iced_core" +version = "0.1.0-alpha" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2018" +description = "The essential concepts of Iced" +license = "MIT" +repository = "https://github.com/hecrj/iced" diff --git a/core/src/align.rs b/core/src/align.rs new file mode 100644 index 00000000..5dbd658d --- /dev/null +++ b/core/src/align.rs @@ -0,0 +1,21 @@ +/// Alignment on the cross axis of a container. +/// +///   * On a [`Column`], it describes __horizontal__ alignment. +///   * On a [`Row`], it describes __vertical__ alignment. +/// +/// [`Column`]: widget/struct.Column.html +/// [`Row`]: widget/struct.Row.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Align { +    /// Align at the start of the cross axis. +    Start, + +    /// Align at the center of the cross axis. +    Center, + +    /// Align at the end of the cross axis. +    End, + +    /// Stretch over the cross axis. +    Stretch, +} diff --git a/core/src/color.rs b/core/src/color.rs new file mode 100644 index 00000000..5cc3a084 --- /dev/null +++ b/core/src/color.rs @@ -0,0 +1,19 @@ +/// A color in the sRGB color space. +#[derive(Debug, Clone, Copy, PartialEq)] +#[allow(missing_docs)] +pub struct Color { +    pub r: f32, +    pub g: f32, +    pub b: f32, +    pub a: f32, +} + +impl Color { +    /// The black color. +    pub const BLACK: Color = Color { +        r: 0.0, +        g: 0.0, +        b: 0.0, +        a: 1.0, +    }; +} diff --git a/core/src/justify.rs b/core/src/justify.rs new file mode 100644 index 00000000..53aa7319 --- /dev/null +++ b/core/src/justify.rs @@ -0,0 +1,27 @@ +/// Distribution on the main axis of a container. +/// +///   * On a [`Column`], it describes __vertical__ distribution. +///   * On a [`Row`], it describes __horizontal__ distribution. +/// +/// [`Column`]: widget/struct.Column.html +/// [`Row`]: widget/struct.Row.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Justify { +    /// Place items at the start of the main axis. +    Start, + +    /// Place items at the center of the main axis. +    Center, + +    /// Place items at the end of the main axis. +    End, + +    /// Place items with space between. +    SpaceBetween, + +    /// Place items with space around. +    SpaceAround, + +    /// Place items with evenly distributed space. +    SpaceEvenly, +} diff --git a/core/src/length.rs b/core/src/length.rs new file mode 100644 index 00000000..0e670038 --- /dev/null +++ b/core/src/length.rs @@ -0,0 +1,7 @@ +/// The strategy used to fill space in a specific dimension. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum Length { +    Fill, +    Shrink, +    Units(u16), +} diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 00000000..1f43b2b7 --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,18 @@ +pub mod widget; + +mod align; +mod color; +mod justify; +mod length; +mod point; +mod rectangle; +mod vector; + +pub use align::Align; +pub use color::Color; +pub use justify::Justify; +pub use length::Length; +pub use point::Point; +pub use rectangle::Rectangle; +pub use vector::Vector; +pub use widget::*; diff --git a/src/point.rs b/core/src/point.rs index 183998dd..183998dd 100644 --- a/src/point.rs +++ b/core/src/point.rs diff --git a/src/rectangle.rs b/core/src/rectangle.rs index 95c2570c..95c2570c 100644 --- a/src/rectangle.rs +++ b/core/src/rectangle.rs diff --git a/src/vector.rs b/core/src/vector.rs index f45daab9..f45daab9 100644 --- a/src/vector.rs +++ b/core/src/vector.rs diff --git a/core/src/widget.rs b/core/src/widget.rs new file mode 100644 index 00000000..f9d4bf2a --- /dev/null +++ b/core/src/widget.rs @@ -0,0 +1,33 @@ +//! Use the essential widgets. +//! +//! # Re-exports +//! For convenience, the contents of this module are available at the root +//! module. Therefore, you can directly type: +//! +//! ``` +//! use iced_core::{button, Button}; +//! ``` +mod checkbox; +mod column; +mod image; +mod radio; +mod row; + +pub mod button; +pub mod slider; +pub mod text; + +#[doc(no_inline)] +pub use button::Button; + +#[doc(no_inline)] +pub use slider::Slider; + +#[doc(no_inline)] +pub use text::Text; + +pub use checkbox::Checkbox; +pub use column::Column; +pub use image::Image; +pub use radio::Radio; +pub use row::Row; diff --git a/core/src/widget/button.rs b/core/src/widget/button.rs new file mode 100644 index 00000000..b98bb443 --- /dev/null +++ b/core/src/widget/button.rs @@ -0,0 +1,158 @@ +//! 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::{Align, Length}; + +/// A generic widget that produces a message when clicked. +/// +/// # Example +/// +/// ``` +/// use iced_core::{button, Button}; +/// +/// pub enum Message { +///     ButtonClicked, +/// } +/// +/// let state = &mut button::State::new(); +/// +/// Button::new(state, "Click me!") +///     .on_press(Message::ButtonClicked); +/// ``` +/// +///  +pub struct Button<'a, Message> { +    /// The current state of the button +    pub state: &'a mut State, + +    /// The label of the button +    pub label: String, + +    /// The message to produce when the button is pressed +    pub on_press: Option<Message>, + +    pub class: Class, + +    pub width: Length, + +    pub align_self: Option<Align>, +} + +impl<'a, Message> std::fmt::Debug for Button<'a, Message> +where +    Message: std::fmt::Debug, +{ +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        f.debug_struct("Button") +            .field("state", &self.state) +            .field("label", &self.label) +            .field("on_press", &self.on_press) +            .finish() +    } +} + +impl<'a, Message> Button<'a, Message> { +    /// Creates a new [`Button`] with some local [`State`] and the given label. +    /// +    /// [`Button`]: struct.Button.html +    /// [`State`]: struct.State.html +    pub fn new(state: &'a mut State, label: &str) -> Self { +        Button { +            state, +            label: String::from(label), +            on_press: None, +            class: Class::Primary, +            width: Length::Shrink, +            align_self: None, +        } +    } + +    /// Sets the width of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the alignment of the [`Button`] itself. +    /// +    /// This is useful if you want to override the default alignment given by +    /// the parent container. +    /// +    /// [`Button`]: struct.Button.html +    pub fn align_self(mut self, align: Align) -> Self { +        self.align_self = Some(align); +        self +    } + +    /// Sets the [`Class`] of the [`Button`]. +    /// +    /// +    /// [`Button`]: struct.Button.html +    /// [`Class`]: enum.Class.html +    pub fn class(mut self, class: Class) -> Self { +        self.class = class; +        self +    } + +    /// Sets the message that will be produced when the [`Button`] is pressed. +    /// +    /// [`Button`]: struct.Button.html +    pub fn on_press(mut self, msg: Message) -> Self { +        self.on_press = Some(msg); +        self +    } +} + +/// The local state of a [`Button`]. +/// +/// [`Button`]: struct.Button.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct State { +    pub is_pressed: bool, +} + +impl State { +    /// Creates a new [`State`]. +    /// +    /// [`State`]: struct.State.html +    pub fn new() -> State { +        State::default() +    } + +    /// Returns whether the associated [`Button`] is currently being pressed or +    /// not. +    /// +    /// [`Button`]: struct.Button.html +    pub fn is_pressed(&self) -> bool { +        self.is_pressed +    } +} + +/// The type of a [`Button`]. +/// +///  +/// +/// [`Button`]: struct.Button.html +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Class { +    /// The [`Button`] performs the main action. +    /// +    /// [`Button`]: struct.Button.html +    Primary, + +    /// The [`Button`] performs an alternative action. +    /// +    /// [`Button`]: struct.Button.html +    Secondary, + +    /// The [`Button`] performs a productive action. +    /// +    /// [`Button`]: struct.Button.html +    Positive, +} diff --git a/core/src/widget/checkbox.rs b/core/src/widget/checkbox.rs new file mode 100644 index 00000000..1f0a0c04 --- /dev/null +++ b/core/src/widget/checkbox.rs @@ -0,0 +1,78 @@ +//! Show toggle controls using checkboxes. +use crate::Color; + +/// A box that can be checked. +/// +/// # Example +/// +/// ``` +/// use iced_core::Checkbox; +/// +/// pub enum Message { +///     CheckboxToggled(bool), +/// } +/// +/// let is_checked = true; +/// +/// Checkbox::new(is_checked, "Toggle me!", Message::CheckboxToggled); +/// ``` +/// +///  +pub struct Checkbox<Message> { +    /// Whether the checkbox is checked or not +    pub is_checked: bool, + +    /// Function to call when checkbox is toggled to produce a __message__. +    /// +    /// The function should be provided `true` when the checkbox is checked +    /// and `false` otherwise. +    pub on_toggle: Box<dyn Fn(bool) -> Message>, + +    /// The label of the checkbox +    pub label: String, + +    /// The color of the label +    pub label_color: Option<Color>, +} + +impl<Message> std::fmt::Debug for Checkbox<Message> { +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        f.debug_struct("Checkbox") +            .field("is_checked", &self.is_checked) +            .field("label", &self.label) +            .field("label_color", &self.label_color) +            .finish() +    } +} + +impl<Message> Checkbox<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`. +    /// +    /// [`Checkbox`]: struct.Checkbox.html +    pub fn new<F>(is_checked: bool, label: &str, f: F) -> Self +    where +        F: 'static + Fn(bool) -> Message, +    { +        Checkbox { +            is_checked, +            on_toggle: Box::new(f), +            label: String::from(label), +            label_color: None, +        } +    } + +    /// Sets the color of the label of the [`Checkbox`]. +    /// +    /// [`Checkbox`]: struct.Checkbox.html +    pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self { +        self.label_color = Some(color.into()); +        self +    } +} diff --git a/core/src/widget/column.rs b/core/src/widget/column.rs new file mode 100644 index 00000000..2df327a0 --- /dev/null +++ b/core/src/widget/column.rs @@ -0,0 +1,147 @@ +use crate::{Align, Justify, Length}; + +/// A container that distributes its contents vertically. +/// +/// A [`Column`] will try to fill the horizontal space of its container. +/// +/// [`Column`]: struct.Column.html +pub struct Column<Element> { +    pub spacing: u16, +    pub padding: u16, +    pub width: Length, +    pub height: Length, +    pub max_width: Length, +    pub max_height: Length, +    pub align_self: Option<Align>, +    pub align_items: Align, +    pub justify_content: Justify, +    pub children: Vec<Element>, +} + +impl<Element> Column<Element> { +    /// Creates an empty [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn new() -> Self { +        Column { +            spacing: 0, +            padding: 0, +            width: Length::Fill, +            height: Length::Shrink, +            max_width: Length::Shrink, +            max_height: Length::Shrink, +            align_self: None, +            align_items: Align::Start, +            justify_content: Justify::Start, +            children: Vec::new(), +        } +    } + +    /// 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`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn padding(mut self, units: u16) -> Self { +        self.padding = units; +        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: Length) -> 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: Length) -> Self { +        self.max_height = max_height; +        self +    } + +    /// Sets the alignment of the [`Column`] itself. +    /// +    /// This is useful if you want to override the default alignment given by +    /// the parent container. +    /// +    /// [`Column`]: struct.Column.html +    pub fn align_self(mut self, align: Align) -> Self { +        self.align_self = Some(align); +        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 +    } + +    /// Sets the vertical distribution strategy for the contents of the +    /// [`Column`] . +    /// +    /// [`Column`]: struct.Column.html +    pub fn justify_content(mut self, justify: Justify) -> Self { +        self.justify_content = justify; +        self +    } + +    /// Adds an element to the [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn push<E>(mut self, child: E) -> Column<Element> +    where +        E: Into<Element>, +    { +        self.children.push(child.into()); +        self +    } +} + +impl<Element> Default for Column<Element> { +    fn default() -> Self { +        Self::new() +    } +} + +impl<Element> std::fmt::Debug for Column<Element> +where +    Element: std::fmt::Debug, +{ +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        // TODO: Complete once stabilized +        f.debug_struct("Column") +            .field("spacing", &self.spacing) +            .field("children", &self.children) +            .finish() +    } +} diff --git a/core/src/widget/image.rs b/core/src/widget/image.rs new file mode 100644 index 00000000..110ba99a --- /dev/null +++ b/core/src/widget/image.rs @@ -0,0 +1,89 @@ +//! Display images in your user interface. + +use crate::{Align, Length, Rectangle}; + +/// A frame that displays an image while keeping aspect ratio. +/// +/// # Example +/// +/// ``` +/// use iced_core::Image; +/// +/// # let my_handle = String::from("some_handle"); +/// let image = Image::new(my_handle); +/// ``` +pub struct Image<I> { +    /// The image handle +    pub handle: I, + +    /// The part of the image to show +    pub clip: Option<Rectangle<u16>>, + +    /// The width of the image +    pub width: Length, + +    /// The height of the image +    pub height: Length, + +    pub align_self: Option<Align>, +} + +impl<I> std::fmt::Debug for Image<I> { +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        f.debug_struct("Image") +            .field("clip", &self.clip) +            .field("width", &self.width) +            .field("height", &self.height) +            .finish() +    } +} + +impl<I> Image<I> { +    /// Creates a new [`Image`] with given image handle. +    /// +    /// [`Image`]: struct.Image.html +    pub fn new(handle: I) -> Self { +        Image { +            handle, +            clip: None, +            width: Length::Shrink, +            height: Length::Shrink, +            align_self: None, +        } +    } + +    /// Sets the portion of the [`Image`] to draw. +    /// +    /// [`Image`]: struct.Image.html +    pub fn clip(mut self, clip: Rectangle<u16>) -> Self { +        self.clip = Some(clip); +        self +    } + +    /// 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 alignment of the [`Image`] itself. +    /// +    /// This is useful if you want to override the default alignment given by +    /// the parent container. +    /// +    /// [`Image`]: struct.Image.html +    pub fn align_self(mut self, align: Align) -> Self { +        self.align_self = Some(align); +        self +    } +} diff --git a/core/src/widget/radio.rs b/core/src/widget/radio.rs new file mode 100644 index 00000000..9765e928 --- /dev/null +++ b/core/src/widget/radio.rs @@ -0,0 +1,88 @@ +//! Create choices using radio buttons. +use crate::Color; + +/// A circular button representing a choice. +/// +/// # Example +/// ``` +/// use iced_core::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); +/// ``` +/// +///  +pub struct Radio<Message> { +    /// Whether the radio button is selected or not +    pub is_selected: bool, + +    /// The message to produce when the radio button is clicked +    pub on_click: Message, + +    /// The label of the radio button +    pub label: String, + +    /// The color of the label +    pub label_color: Option<Color>, +} + +impl<Message> std::fmt::Debug for Radio<Message> +where +    Message: std::fmt::Debug, +{ +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        f.debug_struct("Radio") +            .field("is_selected", &self.is_selected) +            .field("on_click", &self.on_click) +            .field("label", &self.label) +            .field("label_color", &self.label_color) +            .finish() +    } +} + +impl<Message> Radio<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`. +    /// +    /// [`Radio`]: struct.Radio.html +    pub fn new<F, V>(value: V, label: &str, 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: String::from(label), +            label_color: None, +        } +    } + +    /// Sets the `Color` of the label of the [`Radio`]. +    /// +    /// [`Radio`]: struct.Radio.html +    pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self { +        self.label_color = Some(color.into()); +        self +    } +} diff --git a/core/src/widget/row.rs b/core/src/widget/row.rs new file mode 100644 index 00000000..6bdb4ed2 --- /dev/null +++ b/core/src/widget/row.rs @@ -0,0 +1,142 @@ +use crate::{Align, Justify, Length}; + +/// A container that distributes its contents horizontally. +/// +/// A [`Row`] will try to fill the horizontal space of its container. +/// +/// [`Row`]: struct.Row.html +pub struct Row<Element> { +    pub spacing: u16, +    pub padding: u16, +    pub width: Length, +    pub height: Length, +    pub max_width: Length, +    pub max_height: Length, +    pub align_self: Option<Align>, +    pub align_items: Align, +    pub justify_content: Justify, +    pub children: Vec<Element>, +} + +impl<Element> Row<Element> { +    /// Creates an empty [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn new() -> Self { +        Row { +            spacing: 0, +            padding: 0, +            width: Length::Fill, +            height: Length::Shrink, +            max_width: Length::Shrink, +            max_height: Length::Shrink, +            align_self: None, +            align_items: Align::Start, +            justify_content: Justify::Start, +            children: Vec::new(), +        } +    } + +    /// 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`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn padding(mut self, units: u16) -> Self { +        self.padding = units; +        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: Length) -> 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: Length) -> Self { +        self.max_height = max_height; +        self +    } + +    /// Sets the alignment of the [`Row`] itself. +    /// +    /// This is useful if you want to override the default alignment given by +    /// the parent container. +    /// +    /// [`Row`]: struct.Row.html +    pub fn align_self(mut self, align: Align) -> Self { +        self.align_self = Some(align); +        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 +    } + +    /// Sets the horizontal distribution strategy for the contents of the +    /// [`Row`] . +    /// +    /// [`Row`]: struct.Row.html +    pub fn justify_content(mut self, justify: Justify) -> Self { +        self.justify_content = justify; +        self +    } + +    /// Adds an [`Element`] to the [`Row`]. +    /// +    /// [`Element`]: ../struct.Element.html +    /// [`Row`]: struct.Row.html +    pub fn push<E>(mut self, child: E) -> Row<Element> +    where +        E: Into<Element>, +    { +        self.children.push(child.into()); +        self +    } +} + +impl<Element> std::fmt::Debug for Row<Element> +where +    Element: std::fmt::Debug, +{ +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        // TODO: Complete once stabilized +        f.debug_struct("Row") +            .field("spacing", &self.spacing) +            .field("children", &self.children) +            .finish() +    } +} diff --git a/core/src/widget/slider.rs b/core/src/widget/slider.rs new file mode 100644 index 00000000..b65e3991 --- /dev/null +++ b/core/src/widget/slider.rs @@ -0,0 +1,123 @@ +//! 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::Length; + +use std::ops::RangeInclusive; +use std::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. +/// +/// [`Slider`]: struct.Slider.html +/// +/// # Example +/// ``` +/// use iced_core::{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); +/// ``` +/// +///  +pub struct Slider<'a, Message> { +    /// The state of the slider +    pub state: &'a mut State, + +    /// The range of the slider +    pub range: RangeInclusive<f32>, + +    /// The current value of the slider +    pub value: f32, + +    /// The function to produce messages on change +    pub on_change: Rc<Box<dyn Fn(f32) -> Message>>, + +    pub width: Length, +} + +impl<'a, Message> std::fmt::Debug for Slider<'a, Message> { +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +        f.debug_struct("Slider") +            .field("state", &self.state) +            .field("range", &self.range) +            .field("value", &self.value) +            .finish() +    } +} + +impl<'a, Message> Slider<'a, Message> { +    /// 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`. +    /// +    /// [`Slider`]: struct.Slider.html +    /// [`State`]: struct.State.html +    pub fn new<F>( +        state: &'a mut State, +        range: RangeInclusive<f32>, +        value: f32, +        on_change: F, +    ) -> Self +    where +        F: 'static + Fn(f32) -> Message, +    { +        Slider { +            state, +            value: value.max(*range.start()).min(*range.end()), +            range, +            on_change: Rc::new(Box::new(on_change)), +            width: Length::Fill, +        } +    } + +    /// Sets the width of the [`Slider`]. +    /// +    /// [`Slider`]: struct.Slider.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } +} + +/// The local state of a [`Slider`]. +/// +/// [`Slider`]: struct.Slider.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct State { +    pub is_dragging: bool, +} + +impl State { +    /// Creates a new [`State`]. +    /// +    /// [`State`]: struct.State.html +    pub fn new() -> State { +        State::default() +    } + +    /// Returns whether the associated [`Slider`] is currently being dragged or +    /// not. +    /// +    /// [`Slider`]: struct.Slider.html +    pub fn is_dragging(&self) -> bool { +        self.is_dragging +    } +} diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs new file mode 100644 index 00000000..427d9471 --- /dev/null +++ b/core/src/widget/text.rs @@ -0,0 +1,119 @@ +//! Write some text for your users to read. +use crate::{Color, Length}; + +/// A paragraph of text. +/// +/// # Example +/// +/// ``` +/// use iced_core::Text; +/// +/// Text::new("I <3 iced!") +///     .size(40); +/// ``` +#[derive(Debug, Clone)] +pub struct Text { +    pub content: String, +    pub size: Option<u16>, +    pub color: Option<Color>, +    pub width: Length, +    pub height: Length, +    pub horizontal_alignment: HorizontalAlignment, +    pub vertical_alignment: VerticalAlignment, +} + +impl Text { +    /// Create a new fragment of [`Text`] with the given contents. +    /// +    /// [`Text`]: struct.Text.html +    pub fn new(label: &str) -> Self { +        Text { +            content: String::from(label), +            size: None, +            color: None, +            width: Length::Fill, +            height: Length::Shrink, +            horizontal_alignment: HorizontalAlignment::Left, +            vertical_alignment: VerticalAlignment::Top, +        } +    } + +    /// 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 +    pub fn color<C: Into<Color>>(mut self, color: C) -> Self { +        self.color = Some(color.into()); +        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, +    ) -> Self { +        self.horizontal_alignment = alignment; +        self +    } + +    /// 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 +    } +} + +/// The horizontal alignment of some resource. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HorizontalAlignment { +    /// Align left +    Left, + +    /// Horizontally centered +    Center, + +    /// Align right +    Right, +} + +/// The vertical alignment of some resource. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VerticalAlignment { +    /// Align top +    Top, + +    /// Vertically centered +    Center, + +    /// Align bottom +    Bottom, +} | 
