From bf74e6e7d47a012a9c592a9da044f8d3bf9efbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 30 Dec 2019 19:16:46 +0100 Subject: [PATCH 01/16] Implement `Default` for `MouseCursor` --- native/src/mouse_cursor.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/native/src/mouse_cursor.rs b/native/src/mouse_cursor.rs index a4740a27..c7297e0e 100644 --- a/native/src/mouse_cursor.rs +++ b/native/src/mouse_cursor.rs @@ -22,3 +22,9 @@ pub enum MouseCursor { /// The cursor is over a text widget. Text, } + +impl Default for MouseCursor { + fn default() -> MouseCursor { + MouseCursor::OutOfBounds + } +} From 7163e1d8b669b61d6fba6528c2a28fde3bfb72a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 30 Dec 2019 19:17:00 +0100 Subject: [PATCH 02/16] Implement `Default` for `iced_wgpu::Primitive` --- wgpu/src/primitive.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 958cc17f..6c61f800 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -64,3 +64,9 @@ pub enum Primitive { content: Box, }, } + +impl Default for Primitive { + fn default() -> Primitive { + Primitive::None + } +} From 8426bf953cb50f3b7fcb1e0ec8c2fdf22d2b01af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 30 Dec 2019 19:20:59 +0100 Subject: [PATCH 03/16] Implement `Empty` widget It can be useful if you want to fill some space with nothing. --- examples/tour.rs | 4 +- native/src/widget.rs | 3 + native/src/widget/empty.rs | 103 ++++++++++++++++++++++++++++++ src/native.rs | 4 +- web/src/widget.rs | 2 + web/src/widget/empty.rs | 70 ++++++++++++++++++++ wgpu/src/renderer/widget.rs | 1 + wgpu/src/renderer/widget/empty.rs | 8 +++ 8 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 native/src/widget/empty.rs create mode 100644 web/src/widget/empty.rs create mode 100644 wgpu/src/renderer/widget/empty.rs diff --git a/examples/tour.rs b/examples/tour.rs index da05b396..fcace9c3 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -1,6 +1,6 @@ use iced::{ button, scrollable, slider, text_input, Button, Checkbox, Color, Column, - Container, Element, HorizontalAlignment, Image, Length, Radio, Row, + Container, Element, Empty, HorizontalAlignment, Image, Length, Radio, Row, Sandbox, Scrollable, Settings, Slider, Text, TextInput, }; @@ -67,7 +67,7 @@ impl Sandbox for Tour { ); } - controls = controls.push(Column::new()); + controls = controls.push(Empty::new().width(Length::Fill)); if steps.can_continue() { controls = controls.push( diff --git a/native/src/widget.rs b/native/src/widget.rs index 26889280..b73f229e 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -24,6 +24,7 @@ pub mod button; pub mod checkbox; pub mod column; pub mod container; +pub mod empty; pub mod image; pub mod radio; pub mod row; @@ -42,6 +43,8 @@ pub use column::Column; #[doc(no_inline)] pub use container::Container; #[doc(no_inline)] +pub use empty::Empty; +#[doc(no_inline)] pub use image::Image; #[doc(no_inline)] pub use radio::Radio; diff --git a/native/src/widget/empty.rs b/native/src/widget/empty.rs new file mode 100644 index 00000000..f670048f --- /dev/null +++ b/native/src/widget/empty.rs @@ -0,0 +1,103 @@ +//! Distribute content vertically. +use std::hash::Hash; + +use crate::{ + layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, +}; + +/// An amount of empty space. +/// +/// It can be useful if you want to fill some space with nothing. +/// +/// [`Empty`]: struct.Empty.html +#[derive(Debug)] +pub struct Empty { + width: Length, + height: Length, +} + +impl Empty { + /// Creates an amount of [`Empty`] space. + /// + /// [`Empty`]: struct.Empty.html + pub fn new() -> Self { + Empty { + width: Length::Shrink, + height: Length::Shrink, + } + } + + /// Sets the width of the [`Empty`] space. + /// + /// [`Empty`]: struct..html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Empty`] space. + /// + /// [`Empty`]: struct.Column.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } +} + +impl<'a, Message, Renderer> Widget for Empty +where + Renderer: self::Renderer, +{ + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + self.height + } + + fn layout( + &self, + _renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let limits = limits.width(self.width).height(self.height); + + layout::Node::new(limits.resolve(Size::ZERO)) + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + _cursor_position: Point, + ) -> Renderer::Output { + renderer.draw(layout.bounds()) + } + + fn hash_layout(&self, state: &mut Hasher) { + std::any::TypeId::of::().hash(state); + self.width.hash(state); + self.height.hash(state); + } +} + +/// The renderer of an amount of [`Empty`] space. +/// +/// [`Empty`]: struct.Empty.html +pub trait Renderer: crate::Renderer { + /// Draws an amount of [`Empty`] space. + /// + /// You should most likely return an empty primitive here. + fn draw(&mut self, bounds: Rectangle) -> Self::Output; +} + +impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +where + Renderer: self::Renderer, + Message: 'static, +{ + fn from(empty: Empty) -> Element<'a, Message, Renderer> { + Element::new(empty) + } +} diff --git a/src/native.rs b/src/native.rs index f06f1c99..8a04b7c3 100644 --- a/src/native.rs +++ b/src/native.rs @@ -1,6 +1,6 @@ pub use iced_winit::{ - Align, Background, Color, Command, Font, HorizontalAlignment, Length, - Subscription, VerticalAlignment, + Align, Background, Color, Command, Empty, Font, HorizontalAlignment, + Length, Subscription, VerticalAlignment, }; pub mod widget { diff --git a/web/src/widget.rs b/web/src/widget.rs index b0e16692..5cf0238a 100644 --- a/web/src/widget.rs +++ b/web/src/widget.rs @@ -25,6 +25,7 @@ pub mod text_input; mod checkbox; mod column; mod container; +mod empty; mod image; mod radio; mod row; @@ -44,6 +45,7 @@ pub use text_input::TextInput; pub use checkbox::Checkbox; pub use column::Column; pub use container::Container; +pub use empty::Empty; pub use image::Image; pub use radio::Radio; pub use row::Row; diff --git a/web/src/widget/empty.rs b/web/src/widget/empty.rs new file mode 100644 index 00000000..dda17efe --- /dev/null +++ b/web/src/widget/empty.rs @@ -0,0 +1,70 @@ +use crate::{style, Bus, Element, Length, Widget}; +use dodrio::bumpalo; + +/// An amount of empty space. +/// +/// It can be useful if you want to fill some space with nothing. +/// +/// [`Empty`]: struct.Empty.html +#[derive(Debug)] +pub struct Empty { + width: Length, + height: Length, +} + +impl Empty { + /// Creates an amount of [`Empty`] space. + /// + /// [`Empty`]: struct.Empty.html + pub fn new() -> Self { + Empty { + width: Length::Shrink, + height: Length::Shrink, + } + } + + /// Sets the width of the [`Empty`] space. + /// + /// [`Empty`]: struct..html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Empty`] space. + /// + /// [`Empty`]: struct.Column.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } +} + +impl<'a, Message> Widget for Empty { + fn node<'b>( + &self, + bump: &'b bumpalo::Bump, + _publish: &Bus, + _style_sheet: &mut style::Sheet<'b>, + ) -> dodrio::Node<'b> { + use dodrio::builder::*; + + let width = style::length(self.width); + let height = style::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 for Element<'a, Message> { + fn from(empty: Empty) -> Element<'a, Message> { + Element::new(empty) + } +} diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs index 91f107e8..f2d443fb 100644 --- a/wgpu/src/renderer/widget.rs +++ b/wgpu/src/renderer/widget.rs @@ -1,6 +1,7 @@ mod button; mod checkbox; mod column; +mod empty; mod image; mod radio; mod row; diff --git a/wgpu/src/renderer/widget/empty.rs b/wgpu/src/renderer/widget/empty.rs new file mode 100644 index 00000000..26ee74b4 --- /dev/null +++ b/wgpu/src/renderer/widget/empty.rs @@ -0,0 +1,8 @@ +use crate::{Primitive, Renderer}; +use iced_native::{empty, MouseCursor, Rectangle}; + +impl empty::Renderer for Renderer { + fn draw(&mut self, _bounds: Rectangle) -> Self::Output { + (Primitive::None, MouseCursor::OutOfBounds) + } +} From aecc3ad1955b8433d1634ab1b975d2af20e772a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 30 Dec 2019 18:37:13 +0100 Subject: [PATCH 04/16] Add `Length::FillPortion` variant It allows to specify the amount of available space an element should take relative to other elements. --- core/src/length.rs | 10 ++++++++++ native/src/layout/limits.rs | 4 ++-- web/src/style.rs | 2 +- web/src/widget/image.rs | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/core/src/length.rs b/core/src/length.rs index 10873e89..06d8cf0a 100644 --- a/core/src/length.rs +++ b/core/src/length.rs @@ -4,6 +4,15 @@ pub enum Length { /// Fill all the remaining space Fill, + /// Fill a portion of the remaining space relative to other elements. + /// + /// Let's say we have two elements: one with `FillPortion(2)` and one with + /// `FillPortion(3)`. The first will get 2 portions of the available space, + /// while the second one would get 3. + /// + /// `Length::Fill` is equivalent to `Length::FillPortion(1)`. + FillPortion(u16), + /// Fill the least amount of space Shrink, @@ -22,6 +31,7 @@ impl Length { pub fn fill_factor(&self) -> u16 { match self { Length::Fill => 1, + Length::FillPortion(factor) => *factor, Length::Shrink => 0, Length::Units(_) => 0, } diff --git a/native/src/layout/limits.rs b/native/src/layout/limits.rs index 2705a47d..a35f7ff7 100644 --- a/native/src/layout/limits.rs +++ b/native/src/layout/limits.rs @@ -52,7 +52,7 @@ impl Limits { Length::Shrink => { self.fill.width = self.min.width; } - Length::Fill => { + Length::Fill | Length::FillPortion(_) => { self.fill.width = self.fill.width.min(self.max.width); } Length::Units(units) => { @@ -76,7 +76,7 @@ impl Limits { Length::Shrink => { self.fill.height = self.min.height; } - Length::Fill => { + Length::Fill | Length::FillPortion(_) => { self.fill.height = self.fill.height.min(self.max.height); } Length::Units(units) => { diff --git a/web/src/style.rs b/web/src/style.rs index 2fb8602a..4f72b22c 100644 --- a/web/src/style.rs +++ b/web/src/style.rs @@ -139,7 +139,7 @@ pub fn length(length: Length) -> String { match length { Length::Shrink => String::from("auto"), Length::Units(px) => format!("{}px", px), - Length::Fill => String::from("100%"), + Length::Fill | Length::FillPortion(_) => String::from("100%"), } } diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index ed8b7ecf..413b663e 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -67,7 +67,7 @@ impl Widget for Image { match self.width { Length::Shrink => {} - Length::Fill => { + Length::Fill | Length::FillPortion(_) => { image = image.attr("width", "100%"); } Length::Units(px) => { From 3a327e08e96d9588d145c32afe4f04f37a8f0f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 30 Dec 2019 21:32:21 +0100 Subject: [PATCH 05/16] Rename `Empty` widget to `Space` --- examples/tour.rs | 6 +- native/src/widget.rs | 6 +- native/src/widget/{empty.rs => space.rs} | 61 ++++++++++--------- src/native.rs | 4 +- web/src/widget.rs | 4 +- web/src/widget/{empty.rs => space.rs} | 51 ++++++++-------- wgpu/src/renderer/widget.rs | 2 +- .../renderer/widget/{empty.rs => space.rs} | 4 +- 8 files changed, 69 insertions(+), 69 deletions(-) rename native/src/widget/{empty.rs => space.rs} (57%) rename web/src/widget/{empty.rs => space.rs} (53%) rename wgpu/src/renderer/widget/{empty.rs => space.rs} (64%) diff --git a/examples/tour.rs b/examples/tour.rs index fcace9c3..91b75296 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -1,7 +1,7 @@ use iced::{ button, scrollable, slider, text_input, Button, Checkbox, Color, Column, - Container, Element, Empty, HorizontalAlignment, Image, Length, Radio, Row, - Sandbox, Scrollable, Settings, Slider, Text, TextInput, + Container, Element, HorizontalAlignment, Image, Length, Radio, Row, + Sandbox, Scrollable, Settings, Slider, Space, Text, TextInput, }; pub fn main() { @@ -67,7 +67,7 @@ impl Sandbox for Tour { ); } - controls = controls.push(Empty::new().width(Length::Fill)); + controls = controls.push(Space::with_width(Length::Fill)); if steps.can_continue() { controls = controls.push( diff --git a/native/src/widget.rs b/native/src/widget.rs index b73f229e..dcc99645 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -24,12 +24,12 @@ pub mod button; pub mod checkbox; pub mod column; pub mod container; -pub mod empty; pub mod image; pub mod radio; pub mod row; pub mod scrollable; pub mod slider; +pub mod space; pub mod svg; pub mod text; pub mod text_input; @@ -43,8 +43,6 @@ pub use column::Column; #[doc(no_inline)] pub use container::Container; #[doc(no_inline)] -pub use empty::Empty; -#[doc(no_inline)] pub use image::Image; #[doc(no_inline)] pub use radio::Radio; @@ -55,6 +53,8 @@ pub use scrollable::Scrollable; #[doc(no_inline)] pub use slider::Slider; #[doc(no_inline)] +pub use space::Space; +#[doc(no_inline)] pub use svg::Svg; #[doc(no_inline)] pub use text::Text; diff --git a/native/src/widget/empty.rs b/native/src/widget/space.rs similarity index 57% rename from native/src/widget/empty.rs rename to native/src/widget/space.rs index f670048f..2029c52f 100644 --- a/native/src/widget/empty.rs +++ b/native/src/widget/space.rs @@ -8,43 +8,42 @@ use crate::{ /// An amount of empty space. /// /// It can be useful if you want to fill some space with nothing. -/// -/// [`Empty`]: struct.Empty.html #[derive(Debug)] -pub struct Empty { +pub struct Space { width: Length, height: Length, } -impl Empty { - /// Creates an amount of [`Empty`] space. +impl Space { + /// Creates an amount of empty [`Space`] with the given width and height. /// - /// [`Empty`]: struct.Empty.html - pub fn new() -> Self { - Empty { - width: Length::Shrink, + /// [`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, height: Length::Shrink, } } - /// Sets the width of the [`Empty`] space. + /// Creates an amount of vertical [`Space`]. /// - /// [`Empty`]: struct..html - pub fn width(mut self, width: Length) -> Self { - self.width = width; - self - } - - /// Sets the height of the [`Empty`] space. - /// - /// [`Empty`]: struct.Column.html - pub fn height(mut self, height: Length) -> Self { - self.height = height; - self + /// [`Space`]: struct.Space.html + pub fn with_height(height: Length) -> Self { + Space { + width: Length::Shrink, + height, + } } } -impl<'a, Message, Renderer> Widget for Empty +impl<'a, Message, Renderer> Widget for Space where Renderer: self::Renderer, { @@ -76,28 +75,30 @@ where } fn hash_layout(&self, state: &mut Hasher) { - std::any::TypeId::of::().hash(state); + std::any::TypeId::of::().hash(state); self.width.hash(state); self.height.hash(state); } } -/// The renderer of an amount of [`Empty`] space. +/// The renderer of an amount of [`Space`]. /// -/// [`Empty`]: struct.Empty.html +/// [`Space`]: struct.Space.html pub trait Renderer: crate::Renderer { - /// Draws an amount of [`Empty`] space. + /// Draws an amount of empty [`Space`]. /// /// You should most likely return an empty primitive here. + /// + /// [`Space`]: struct.Space.html fn draw(&mut self, bounds: Rectangle) -> Self::Output; } -impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> where Renderer: self::Renderer, Message: 'static, { - fn from(empty: Empty) -> Element<'a, Message, Renderer> { - Element::new(empty) + fn from(space: Space) -> Element<'a, Message, Renderer> { + Element::new(space) } } diff --git a/src/native.rs b/src/native.rs index 8a04b7c3..cf48a391 100644 --- a/src/native.rs +++ b/src/native.rs @@ -1,6 +1,6 @@ pub use iced_winit::{ - Align, Background, Color, Command, Empty, Font, HorizontalAlignment, - Length, Subscription, VerticalAlignment, + Align, Background, Color, Command, Font, HorizontalAlignment, Length, + Space, Subscription, VerticalAlignment, }; pub mod widget { diff --git a/web/src/widget.rs b/web/src/widget.rs index 5cf0238a..0ac536bd 100644 --- a/web/src/widget.rs +++ b/web/src/widget.rs @@ -25,10 +25,10 @@ pub mod text_input; mod checkbox; mod column; mod container; -mod empty; mod image; mod radio; mod row; +mod space; mod text; #[doc(no_inline)] @@ -45,10 +45,10 @@ pub use text_input::TextInput; pub use checkbox::Checkbox; pub use column::Column; pub use container::Container; -pub use empty::Empty; pub use image::Image; pub use radio::Radio; pub use row::Row; +pub use space::Space; /// A component that displays information and allows interaction. /// diff --git a/web/src/widget/empty.rs b/web/src/widget/space.rs similarity index 53% rename from web/src/widget/empty.rs rename to web/src/widget/space.rs index dda17efe..baf4c80b 100644 --- a/web/src/widget/empty.rs +++ b/web/src/widget/space.rs @@ -4,43 +4,42 @@ use dodrio::bumpalo; /// An amount of empty space. /// /// It can be useful if you want to fill some space with nothing. -/// -/// [`Empty`]: struct.Empty.html #[derive(Debug)] -pub struct Empty { +pub struct Space { width: Length, height: Length, } -impl Empty { - /// Creates an amount of [`Empty`] space. +impl Space { + /// Creates an amount of empty [`Space`] with the given width and height. /// - /// [`Empty`]: struct.Empty.html - pub fn new() -> Self { - Empty { - width: Length::Shrink, + /// [`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, height: Length::Shrink, } } - /// Sets the width of the [`Empty`] space. + /// Creates an amount of vertical [`Space`]. /// - /// [`Empty`]: struct..html - pub fn width(mut self, width: Length) -> Self { - self.width = width; - self - } - - /// Sets the height of the [`Empty`] space. - /// - /// [`Empty`]: struct.Column.html - pub fn height(mut self, height: Length) -> Self { - self.height = height; - self + /// [`Space`]: struct.Space.html + pub fn with_height(height: Length) -> Self { + Space { + width: Length::Shrink, + height, + } } } -impl<'a, Message> Widget for Empty { +impl<'a, Message> Widget for Space { fn node<'b>( &self, bump: &'b bumpalo::Bump, @@ -63,8 +62,8 @@ impl<'a, Message> Widget for Empty { } } -impl<'a, Message> From for Element<'a, Message> { - fn from(empty: Empty) -> Element<'a, Message> { - Element::new(empty) +impl<'a, Message> From for Element<'a, Message> { + fn from(space: Space) -> Element<'a, Message> { + Element::new(space) } } diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs index f2d443fb..f82631d5 100644 --- a/wgpu/src/renderer/widget.rs +++ b/wgpu/src/renderer/widget.rs @@ -1,12 +1,12 @@ mod button; mod checkbox; mod column; -mod empty; mod image; mod radio; mod row; mod scrollable; mod slider; +mod space; mod text; mod text_input; diff --git a/wgpu/src/renderer/widget/empty.rs b/wgpu/src/renderer/widget/space.rs similarity index 64% rename from wgpu/src/renderer/widget/empty.rs rename to wgpu/src/renderer/widget/space.rs index 26ee74b4..28e05437 100644 --- a/wgpu/src/renderer/widget/empty.rs +++ b/wgpu/src/renderer/widget/space.rs @@ -1,7 +1,7 @@ use crate::{Primitive, Renderer}; -use iced_native::{empty, MouseCursor, Rectangle}; +use iced_native::{space, MouseCursor, Rectangle}; -impl empty::Renderer for Renderer { +impl space::Renderer for Renderer { fn draw(&mut self, _bounds: Rectangle) -> Self::Output { (Primitive::None, MouseCursor::OutOfBounds) } From 0d620b7701f427ed0091f3640ab9ca0e116eb412 Mon Sep 17 00:00:00 2001 From: Artur Sapek Date: Wed, 1 Jan 2020 15:44:32 -0700 Subject: [PATCH 06/16] Implement Geometry2D primitive --- core/src/geometry.rs | 20 +++ core/src/lib.rs | 2 + examples/geometry.rs | 227 ++++++++++++++++++++++++++++++++ native/src/lib.rs | 2 +- native/src/widget/geometry.rs | 0 wgpu/src/geometry.rs | 215 ++++++++++++++++++++++++++++++ wgpu/src/lib.rs | 1 + wgpu/src/primitive.rs | 7 +- wgpu/src/renderer.rs | 33 ++++- wgpu/src/shader/geom2d.frag | 8 ++ wgpu/src/shader/geom2d.frag.spv | Bin 0 -> 372 bytes wgpu/src/shader/geom2d.vert | 17 +++ wgpu/src/shader/geom2d.vert.spv | Bin 0 -> 1468 bytes 13 files changed, 528 insertions(+), 4 deletions(-) create mode 100644 core/src/geometry.rs create mode 100644 examples/geometry.rs create mode 100644 native/src/widget/geometry.rs create mode 100644 wgpu/src/geometry.rs create mode 100644 wgpu/src/shader/geom2d.frag create mode 100644 wgpu/src/shader/geom2d.frag.spv create mode 100644 wgpu/src/shader/geom2d.vert create mode 100644 wgpu/src/shader/geom2d.vert.spv diff --git a/core/src/geometry.rs b/core/src/geometry.rs new file mode 100644 index 00000000..f04ce42e --- /dev/null +++ b/core/src/geometry.rs @@ -0,0 +1,20 @@ +/// A two-dimensional vertex which has a color +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Vertex2D { + /// The vertex position + pub position: [f32; 2], + /// The vertex color in rgba + pub color: [f32; 4], +} + +/// A set of [`Vertex2D`] and indices for drawing some 2D geometry on the GPU. +/// +/// [`Vertex2D`]: struct.Vertex2D.html +#[derive(Clone, Debug)] +pub struct Geometry2D { + /// The vertices for this geometry + pub vertices: Vec, + /// The indices for this geometry + pub indices: Vec, +} diff --git a/core/src/lib.rs b/core/src/lib.rs index 821b09c1..881f56c9 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -23,6 +23,7 @@ mod length; mod point; mod rectangle; mod vector; +mod geometry; pub use align::{Align, HorizontalAlignment, VerticalAlignment}; pub use background::Background; @@ -32,6 +33,7 @@ pub use length::Length; pub use point::Point; pub use rectangle::Rectangle; pub use vector::Vector; +pub use geometry::{Vertex2D, Geometry2D}; #[cfg(feature = "command")] mod command; diff --git a/examples/geometry.rs b/examples/geometry.rs new file mode 100644 index 00000000..feb7684e --- /dev/null +++ b/examples/geometry.rs @@ -0,0 +1,227 @@ +//! This example showcases a simple native custom widget that renders using +//! arbitrary low-level geometry. +mod rainbow { + // For now, to implement a custom native widget you will need to add + // `iced_native` and `iced_wgpu` to your dependencies. + // + // Then, you simply need to define your widget type and implement the + // `iced_native::Widget` trait with the `iced_wgpu::Renderer`. + // + // Of course, you can choose to make the implementation renderer-agnostic, + // if you wish to, by creating your own `Renderer` trait, which could be + // implemented by `iced_wgpu` and other renderers. + use iced_native::{ + layout, Element, Geometry2D, Hasher, Layout, Length, + MouseCursor, Point, Size, Vertex2D, Widget, + }; + use iced_wgpu::{Primitive, Renderer}; + + pub struct Rainbow { + dimen: u16, + } + + impl Rainbow { + pub fn new(dimen: u16) -> Self { + Self { dimen } + } + } + + impl Widget for Rainbow { + fn width(&self) -> Length { + Length::Shrink + } + + fn height(&self) -> Length { + Length::Shrink + } + + fn layout( + &self, + _renderer: &Renderer, + _limits: &layout::Limits, + ) -> layout::Node { + layout::Node::new(Size::new( + f32::from(self.dimen), + f32::from(self.dimen), + )) + } + + fn hash_layout(&self, state: &mut Hasher) { + use std::hash::Hash; + + self.dimen.hash(state); + } + + fn draw( + &self, + _renderer: &mut Renderer, + layout: Layout<'_>, + cursor_position: Point, + ) -> (Primitive, MouseCursor) { + let b = layout.bounds(); + + // R O Y G B I V + let color_r = [1.0, 0.0, 0.0, 1.0]; + let color_o = [1.0, 0.5, 0.0, 1.0]; + let color_y = [1.0, 1.0, 0.0, 1.0]; + let color_g = [0.0, 1.0, 0.0, 1.0]; + let color_gb = [0.0, 1.0, 0.5, 1.0]; + let color_b = [0.0, 0.2, 1.0, 1.0]; + let color_i = [0.5, 0.0, 1.0, 1.0]; + let color_v = [0.75, 0.0, 0.5, 1.0]; + + let posn_center = { + if b.contains(cursor_position) { + [cursor_position.x, cursor_position.y] + } else { + [b.x + (b.width / 2.0), b.y + (b.height / 2.0)] + } + }; + + let posn_tl = [b.x, b.y]; + let posn_t = [b.x + (b.width / 2.0), b.y]; + let posn_tr = [b.x + b.width, b.y]; + let posn_r = [b.x + b.width, b.y + (b.height / 2.0)]; + let posn_br = [b.x + b.width, b.y + b.height]; + let posn_b = [b.x + (b.width / 2.0), b.y + b.height]; + let posn_bl = [b.x, b.y + b.height]; + let posn_l = [b.x, b.y + (b.height / 2.0)]; + + ( + Primitive::Geometry2D { + geometry: Geometry2D { + vertices: vec![ + Vertex2D { + position: posn_center, + color: [1.0, 1.0, 1.0, 1.0], + }, + Vertex2D { + position: posn_tl, + color: color_r, + }, + Vertex2D { + position: posn_t, + color: color_o, + }, + Vertex2D { + position: posn_tr, + color: color_y, + }, + Vertex2D { + position: posn_r, + color: color_g, + }, + Vertex2D { + position: posn_br, + color: color_gb, + }, + Vertex2D { + position: posn_b, + color: color_b, + }, + Vertex2D { + position: posn_bl, + color: color_i, + }, + Vertex2D { + position: posn_l, + color: color_v, + }, + ], + indices: vec![ + 0, 1, 2, // TL + 0, 2, 3, // T + 0, 3, 4, // TR + 0, 4, 5, // R + 0, 5, 6, // BR + 0, 6, 7, // B + 0, 7, 8, // BL + 0, 8, 1, // L + ], + }, + }, + MouseCursor::OutOfBounds, + ) + } + } + + impl<'a, Message> Into> for Rainbow { + fn into(self) -> Element<'a, Message, Renderer> { + Element::new(self) + } + } +} + +use iced::{ + scrollable, settings::Window, Align, Column, Container, Element, + Length, Sandbox, Scrollable, Settings, Text, +}; +use rainbow::Rainbow; + +pub fn main() { + Example::run(Settings { + window: Window { + size: (660, 660), + resizable: true, + decorations: true, + }, + }) +} + +struct Example { + dimen: u16, + scroll: scrollable::State, +} + +#[derive(Debug, Clone, Copy)] +enum Message {} + +impl Sandbox for Example { + type Message = Message; + + fn new() -> Self { + Example { + dimen: 500, + scroll: scrollable::State::new(), + } + } + + fn title(&self) -> String { + String::from("Custom 2D geometry - Iced") + } + + fn update(&mut self, _: Message) {} + + fn view(&mut self) -> Element { + let content = Column::new() + .padding(20) + .spacing(20) + .max_width(500) + .align_items(Align::Start) + .push(Rainbow::new(self.dimen)) + .push( + Text::new(String::from("In this example we draw a custom widget Rainbow, using the \ + Geometry2D primitive. This primitive supplies a list of triangles, expressed as vertices and indices.")) + .width(Length::Shrink), + ) + .push( + Text::new(String::from("Move your cursor over it, and see the center vertex follow you!")) + .width(Length::Shrink), + ) + .push( + Text::new(String::from("Every Vertex2D defines its own color. You could use the \ + Geometry2D primitive to render virtually any two-dimensional geometry for your widget.")) + .width(Length::Shrink), + ); + + let scrollable = + Scrollable::new(&mut self.scroll).push(Container::new(content)); + + Container::new(scrollable) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } +} diff --git a/native/src/lib.rs b/native/src/lib.rs index 8dcacb2b..6f6af159 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -55,7 +55,7 @@ mod user_interface; pub use iced_core::{ Align, Background, Color, Command, Font, HorizontalAlignment, Length, - Point, Rectangle, Vector, VerticalAlignment, + Point, Rectangle, Vector, VerticalAlignment, Geometry2D, Vertex2D, }; pub use clipboard::Clipboard; diff --git a/native/src/widget/geometry.rs b/native/src/widget/geometry.rs new file mode 100644 index 00000000..e69de29b diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs new file mode 100644 index 00000000..f79e9c43 --- /dev/null +++ b/wgpu/src/geometry.rs @@ -0,0 +1,215 @@ +use crate::Transformation; +use iced_native::{Geometry2D, Rectangle, Vertex2D}; +use std::mem; + +#[derive(Debug)] +pub struct Pipeline { + pipeline: wgpu::RenderPipeline, + constants: wgpu::BindGroup, + constants_buffer: wgpu::Buffer, +} + +impl Pipeline { + pub fn new(device: &mut wgpu::Device) -> Pipeline { + let constant_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }); + + let constants_buffer = device + .create_buffer_mapped( + 1, + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ) + .fill_from_slice(&[Uniforms::default()]); + + let constant_bind_group = + device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &constant_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &constants_buffer, + range: 0..std::mem::size_of::() as u64, + }, + }], + }); + + let layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&constant_layout], + }); + + let vs = include_bytes!("shader/geom2d.vert.spv"); + let vs_module = device.create_shader_module( + &wgpu::read_spirv(std::io::Cursor::new(&vs[..])) + .expect("Read quad vertex shader as SPIR-V"), + ); + + let fs = include_bytes!("shader/geom2d.frag.spv"); + let fs_module = device.create_shader_module( + &wgpu::read_spirv(std::io::Cursor::new(&fs[..])) + .expect("Read quad fragment shader as SPIR-V"), + ); + + let pipeline = + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Cw, + cull_mode: wgpu::CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[wgpu::ColorStateDescriptor { + format: wgpu::TextureFormat::Bgra8UnormSrgb, + color_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + write_mask: wgpu::ColorWrite::ALL, + }], + depth_stencil_state: None, + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[wgpu::VertexBufferDescriptor { + stride: mem::size_of::() as u64, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &[ + // Position + wgpu::VertexAttributeDescriptor { + shader_location: 0, + format: wgpu::VertexFormat::Float2, + offset: 0, + }, + // Color + wgpu::VertexAttributeDescriptor { + shader_location: 1, + format: wgpu::VertexFormat::Float4, + offset: 4 * 2, + }, + ], + }], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + Pipeline { + pipeline, + constants: constant_bind_group, + constants_buffer, + } + } + + pub fn draw( + &mut self, + device: &mut wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + target: &wgpu::TextureView, + transformation: Transformation, + scale: f32, + geometries: &Vec, + bounds: Rectangle, + ) { + let uniforms = Uniforms { + transform: transformation.into(), + scale, + }; + + let constants_buffer = device + .create_buffer_mapped(1, wgpu::BufferUsage::COPY_SRC) + .fill_from_slice(&[uniforms]); + + encoder.copy_buffer_to_buffer( + &constants_buffer, + 0, + &self.constants_buffer, + 0, + std::mem::size_of::() as u64, + ); + + for geom in geometries { + let vertices_buffer = device + .create_buffer_mapped( + geom.vertices.len(), + wgpu::BufferUsage::VERTEX, + ) + .fill_from_slice(&geom.vertices); + + let indices_buffer = device + .create_buffer_mapped( + geom.indices.len(), + wgpu::BufferUsage::INDEX, + ) + .fill_from_slice(&geom.indices); + + let mut render_pass = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[ + wgpu::RenderPassColorAttachmentDescriptor { + attachment: target, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }, + ], + depth_stencil_attachment: None, + }); + + render_pass.set_pipeline(&self.pipeline); + render_pass.set_bind_group(0, &self.constants, &[]); + render_pass.set_index_buffer(&indices_buffer, 0); + render_pass.set_vertex_buffers(0, &[(&vertices_buffer, 0)]); + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); + + render_pass.draw_indexed(0..geom.indices.len() as u32, 0, 0..1); + } + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct Uniforms { + transform: [f32; 16], + scale: f32, +} + +impl Default for Uniforms { + fn default() -> Self { + Self { + transform: *Transformation::identity().as_ref(), + scale: 1.0, + } + } +} diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9f9ed8db..7587be77 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -30,6 +30,7 @@ mod quad; mod renderer; mod text; mod transformation; +mod geometry; pub(crate) use crate::image::Image; pub(crate) use quad::Quad; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 6c61f800..06121262 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,6 +1,6 @@ use iced_native::{ image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, - Vector, VerticalAlignment, + Vector, VerticalAlignment, Geometry2D, }; /// A rendering primitive. @@ -63,6 +63,11 @@ pub enum Primitive { /// The content of the clip content: Box, }, + /// A low-level geometry primitive + Geometry2D { + /// The vertices and indices of the geometry + geometry: Geometry2D, + }, } impl Default for Primitive { diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 365ef1ef..3cfd746d 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,7 +1,10 @@ -use crate::{image, quad, text, Image, Primitive, Quad, Transformation}; +use crate::{ + geometry, image, quad, text, Image, Primitive, Quad, Transformation, +}; use iced_native::{ renderer::{Debugger, Windowed}, - Background, Color, Layout, MouseCursor, Point, Rectangle, Vector, Widget, + Background, Color, Geometry2D, Layout, MouseCursor, Point, Rectangle, + Vector, Widget, }; use wgpu::{ @@ -24,6 +27,7 @@ pub struct Renderer { quad_pipeline: quad::Pipeline, image_pipeline: crate::image::Pipeline, text_pipeline: text::Pipeline, + geometry_pipeline: crate::geometry::Pipeline, } struct Layer<'a> { @@ -31,6 +35,7 @@ struct Layer<'a> { offset: Vector, quads: Vec, images: Vec, + geometries: Vec, text: Vec>, } @@ -42,6 +47,7 @@ impl<'a> Layer<'a> { quads: Vec::new(), images: Vec::new(), text: Vec::new(), + geometries: Vec::new(), } } } @@ -64,6 +70,7 @@ impl Renderer { let text_pipeline = text::Pipeline::new(&mut device); let quad_pipeline = quad::Pipeline::new(&mut device); let image_pipeline = crate::image::Pipeline::new(&mut device); + let geometry_pipeline = geometry::Pipeline::new(&mut device); Self { device, @@ -71,6 +78,7 @@ impl Renderer { quad_pipeline, image_pipeline, text_pipeline, + geometry_pipeline, } } @@ -244,6 +252,9 @@ impl Renderer { scale: [bounds.width, bounds.height], }); } + Primitive::Geometry2D { geometry } => { + layer.geometries.push(geometry.clone()); + } Primitive::Clip { bounds, offset, @@ -401,6 +412,24 @@ impl Renderer { }, ); } + + if layer.geometries.len() > 0 { + let translated = transformation + * Transformation::translate( + -(layer.offset.x as f32) * dpi, + -(layer.offset.y as f32) * dpi, + ); + + self.geometry_pipeline.draw( + &mut self.device, + encoder, + target, + translated, + dpi, + &layer.geometries, + bounds, + ); + } } } diff --git a/wgpu/src/shader/geom2d.frag b/wgpu/src/shader/geom2d.frag new file mode 100644 index 00000000..e39c45e7 --- /dev/null +++ b/wgpu/src/shader/geom2d.frag @@ -0,0 +1,8 @@ +#version 450 + +layout(location = 0) in vec4 i_Color; +layout(location = 0) out vec4 o_Color; + +void main() { + o_Color = i_Color; +} diff --git a/wgpu/src/shader/geom2d.frag.spv b/wgpu/src/shader/geom2d.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..c0165bcac9ab1cd9ba6bc39cb74afb19590a49e0 GIT binary patch literal 372 zcmYk1%MQU%5Qayql)6U3PAc||1tJkP7B<~^0Fl@Bty5@;7i>%`EHr=Jk?S4$Avk8ut`Ob)^ZB;8P6X!#AL8vJrMMpk(4baP1 zSF?wT0Q4tV6K<{znMW@UHBT{t@=7c{8w&husq_WERJ~BV0j-4-_y7O^ literal 0 HcmV?d00001 diff --git a/wgpu/src/shader/geom2d.vert b/wgpu/src/shader/geom2d.vert new file mode 100644 index 00000000..fd86ecd6 --- /dev/null +++ b/wgpu/src/shader/geom2d.vert @@ -0,0 +1,17 @@ +#version 450 + +layout(location = 0) in vec2 i_Position; +layout(location = 1) in vec4 i_Color; + +layout(location = 0) out vec4 o_Color; + +layout (set = 0, binding = 0) uniform Globals { + mat4 u_Transform; + float u_Scale; +}; + +void main() { + vec2 p_Position = i_Position * u_Scale; + gl_Position = u_Transform * vec4(p_Position, 0.0, 1.0); + o_Color = i_Color; +} diff --git a/wgpu/src/shader/geom2d.vert.spv b/wgpu/src/shader/geom2d.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..c15c74512f8fcbae271ee1c9f15c0fd7fac61046 GIT binary patch literal 1468 zcmY+E%We}v5Jj8#kw732LLNYH?3j0mVF3sU@lueSMHWFuY%LQE8foH*{E!eUz5t0| z;;Yyoan5+!khW^7@2%>p>N_Ks=9=>%oCyp39){^!4s$ReEQV_C+XtP4)@b~x_4vsn zGnPUrPc-LZIGgXwJdb`*ti*2)|BC~aQ0Dh9w*q5@lkQ1vzUZ zr?@h`LTIPi$6h*OvTBZ@!le6t*c*&KXTxLIO3pjmq}w^_rG1!EST>PWA>%s!OWHl` z4?pyW&d%}#bK&pKIg5M^T}Y`Nxt>Xi!tv;Y%fht-X^1QZ*bI~#Z=1JBu!^A z=TRS*dZ<&@-OJK!m}50d3fv~H7B$SZ4^{_P1>5HtaWiL6bG+Pe>AyVhVcu)3%^aR} ze*37=Hs*@BF@<@bsE_lw>@8*RY+v9UUM0WYVC&*7~leqP`>v*$0sd*0bLcrM}P#5JDkBsc9@&Na1{ zy!F&r{p41`m+^JXo;w9zDX{ZgVQ;SW%-_J*F_-z`tC;6E!PoHS%GKDZU7XpNX5CG^ z8X0#kvEQ0poFnRN{uaD*csJwrXkxC2Z|3OxEA#KMx0b!FFZSKZ8GnFx<`@_67Ti<5 z7kjCx%QL@W{En^VJM+K5ck}|RKacsI-jJnctC%{gr8&;KhROdR$204g=j30~#hP-~ z@V<4-8tPyT@7}=b1-8aE=DByAvB#}~!_Bzc1?PPa>Fk~FVCEWAN45J&4P$pP` Date: Wed, 1 Jan 2020 17:27:14 +0100 Subject: [PATCH 07/16] add(widget): primitive progressbar widget --- core/src/background.rs | 2 +- examples/progressbar.rs | 51 +++++++++ native/src/widget.rs | 3 + native/src/widget/progressbar.rs | 135 ++++++++++++++++++++++++ native/src/widget/text_input.rs | 3 +- wgpu/src/renderer/widget.rs | 1 + wgpu/src/renderer/widget/progressbar.rs | 43 ++++++++ winit/src/conversion.rs | 3 +- winit/src/debug/basic.rs | 3 +- 9 files changed, 239 insertions(+), 5 deletions(-) create mode 100644 examples/progressbar.rs create mode 100644 native/src/widget/progressbar.rs create mode 100644 wgpu/src/renderer/widget/progressbar.rs diff --git a/core/src/background.rs b/core/src/background.rs index 2f75e45c..e1a37ddc 100644 --- a/core/src/background.rs +++ b/core/src/background.rs @@ -12,4 +12,4 @@ impl From for Background { fn from(color: Color) -> Self { Background::Color(color) } -} \ No newline at end of file +} diff --git a/examples/progressbar.rs b/examples/progressbar.rs new file mode 100644 index 00000000..4663f8df --- /dev/null +++ b/examples/progressbar.rs @@ -0,0 +1,51 @@ +use iced::{slider, Column, Element, Sandbox, Settings, Slider}; +use iced_winit::Progressbar; + +pub fn main() { + Progress::run(Settings::default()) +} + +#[derive(Default)] +struct Progress { + value: f32, + progressbar_slider: slider::State, +} + +#[derive(Debug, Clone, Copy)] +enum Message { + SliderChanged(f32), +} + +impl Sandbox for Progress { + type Message = Message; + + fn new() -> Self { + Self::default() + } + + fn title(&self) -> String { + String::from("A simple Progressbar") + } + + fn update(&mut self, message: Message) { + match message { + Message::SliderChanged(x) => { + self.value = x; + } + } + } + + fn view(&mut self) -> Element { + Column::new() + .padding(20) + .push(Progressbar::new(0.0..=100.0, self.value)) + .padding(20) + .push(Slider::new( + &mut self.progressbar_slider, + 0.0..=100.0, + self.value, + Message::SliderChanged, + )) + .into() + } +} diff --git a/native/src/widget.rs b/native/src/widget.rs index dcc99645..d899da58 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -25,6 +25,7 @@ pub mod checkbox; pub mod column; pub mod container; pub mod image; +pub mod progressbar; pub mod radio; pub mod row; pub mod scrollable; @@ -45,6 +46,8 @@ pub use container::Container; #[doc(no_inline)] pub use image::Image; #[doc(no_inline)] +pub use progressbar::Progressbar; +#[doc(no_inline)] pub use radio::Radio; #[doc(no_inline)] pub use row::Row; diff --git a/native/src/widget/progressbar.rs b/native/src/widget/progressbar.rs new file mode 100644 index 00000000..a6725f2c --- /dev/null +++ b/native/src/widget/progressbar.rs @@ -0,0 +1,135 @@ +//! Display a progressbar +//! +//! +//! [`Progressbar`]: struct.Progressbar.html +use crate::{ + layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, +}; + +use std::{hash::Hash, ops::RangeInclusive}; + +/// A progressbar +/// +/// # Example +/// +/// ``` +/// # use iced_native::Progressbar; +/// +/// Progressbar::new(0.0..=100.0, value); +/// ``` +/// +/// TODO: Get a progressbar render +/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) +#[allow(missing_debug_implementations)] +pub struct Progressbar { + range: RangeInclusive, + value: f32, + width: Length, +} + +impl Progressbar { + /// Creates a new [`Progressbar`]. + /// + /// It expects: + /// * an inclusive range of possible values + /// * the current value of the [`Progressbar`] + /// + /// [`Progressbar`]: struct.Progressbar.html + pub fn new(range: RangeInclusive, value: f32) -> Self { + Progressbar { + value: value.max(*range.start()).min(*range.end()), + range, + width: Length::Fill, + } + } + + /// Sets the width of the [`Progressbar`]. + /// + /// [`Progressbar`]: struct.Progressbar.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } +} + +impl Widget for Progressbar +where + Renderer: self::Renderer, +{ + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + Length::Shrink + } + + fn layout( + &self, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let limits = limits + .width(self.width) + .height(Length::Units(renderer.height() as u16)); + + let size = limits.resolve(Size::ZERO); + + layout::Node::new(size) + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + _cursor_position: Point, + ) -> Renderer::Output { + renderer.draw(layout.bounds(), self.range.clone(), self.value) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.width.hash(state); + } +} + +/// The renderer of a [`Progressbar`]. +/// +/// Your [renderer] will need to implement this trait before being +/// able to use a [`Progressbar`] in your user interface. +/// +/// [`Progressbar`]: struct.Progressbar.html +/// [renderer]: ../../renderer/index.html +pub trait Renderer: crate::Renderer { + /// Returns the height of the [`Progressbar`]. + /// + /// [`Progressbar`]: struct.Progressbar.html + fn height(&self) -> u32; + + /// Draws a [`Progressbar`]. + /// + /// It receives: + /// * the local state of the [`Progressbar`] + /// * the bounds of the [`Progressbar`] + /// * the range of values of the [`Progressbar`] + /// * the current value of the [`Progressbar`] + /// + /// [`Progressbar`]: struct.Progressbar.html + /// [`State`]: struct.State.html + /// [`Class`]: enum.Class.html + fn draw( + &self, + bounds: Rectangle, + range: RangeInclusive, + value: f32, + ) -> Self::Output; +} + +impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +where + Renderer: self::Renderer, + Message: 'static, +{ + fn from(progressbar: Progressbar) -> Element<'a, Message, Renderer> { + Element::new(progressbar) + } +} diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 1d1c32a2..c994b7ba 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -633,7 +633,8 @@ impl Value { .unwrap_or(self.len()) } - /// Returns a new [`Value`] containing the graphemes until the given `index`. + /// Returns a new [`Value`] containing the graphemes until the given + /// `index`. /// /// [`Value`]: struct.Value.html pub fn until(&self, index: usize) -> Self { diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs index f82631d5..94ebd10e 100644 --- a/wgpu/src/renderer/widget.rs +++ b/wgpu/src/renderer/widget.rs @@ -2,6 +2,7 @@ mod button; mod checkbox; mod column; mod image; +mod progressbar; mod radio; mod row; mod scrollable; diff --git a/wgpu/src/renderer/widget/progressbar.rs b/wgpu/src/renderer/widget/progressbar.rs new file mode 100644 index 00000000..3c62e54d --- /dev/null +++ b/wgpu/src/renderer/widget/progressbar.rs @@ -0,0 +1,43 @@ +use crate::{Primitive, Renderer}; +use iced_native::{progressbar, Background, Color, MouseCursor, Rectangle}; + +impl progressbar::Renderer for Renderer { + fn height(&self) -> u32 { + 30 + } + + fn draw( + &self, + bounds: Rectangle, + range: std::ops::RangeInclusive, + value: f32, + ) -> Self::Output { + let (range_start, range_end) = range.into_inner(); + let active_progress_width = bounds.width + * ((value - range_start) / (range_end - range_start).max(1.0)); + + let background = Primitive::Group { + primitives: vec![Primitive::Quad { + bounds: Rectangle { ..bounds }, + background: Color::from_rgb(0.6, 0.6, 0.6).into(), + border_radius: 5, + }], + }; + + let active_progress = Primitive::Quad { + bounds: Rectangle { + width: active_progress_width, + ..bounds + }, + background: Background::Color([0.0, 0.95, 0.0].into()), + border_radius: 4, + }; + + ( + Primitive::Group { + primitives: vec![background, active_progress], + }, + MouseCursor::OutOfBounds, + ) + } +} diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 0537d853..279b975a 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -50,7 +50,8 @@ pub fn button_state(element_state: winit::event::ElementState) -> ButtonState { } } -/// Convert some `ModifiersState` from [`winit`] to an [`iced_native`] modifiers state. +/// Convert some `ModifiersState` from [`winit`] to an [`iced_native`] modifiers +/// state. /// /// [`winit`]: https://github.com/rust-windowing/winit /// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native diff --git a/winit/src/debug/basic.rs b/winit/src/debug/basic.rs index c9da392c..d46edba6 100644 --- a/winit/src/debug/basic.rs +++ b/winit/src/debug/basic.rs @@ -1,5 +1,4 @@ -use std::collections::VecDeque; -use std::time; +use std::{collections::VecDeque, time}; #[derive(Debug)] pub struct Debug { From bf8f83decc039494d310f6ecbb05cbab2c241cbf Mon Sep 17 00:00:00 2001 From: Songtronix Date: Thu, 2 Jan 2020 14:10:18 +0100 Subject: [PATCH 08/16] change(widget): custom coloring for progressbar --- examples/progressbar.rs | 26 +++++++++++----- native/src/widget/progressbar.rs | 41 ++++++++++++++++++++++--- wgpu/src/renderer/widget/progressbar.rs | 12 ++++++-- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/examples/progressbar.rs b/examples/progressbar.rs index 4663f8df..c4ebf248 100644 --- a/examples/progressbar.rs +++ b/examples/progressbar.rs @@ -1,8 +1,17 @@ -use iced::{slider, Column, Element, Sandbox, Settings, Slider}; +use iced::{ + settings::Window, slider, Background, Color, Column, Element, Sandbox, + Settings, Slider, +}; use iced_winit::Progressbar; pub fn main() { - Progress::run(Settings::default()) + Progress::run(Settings { + window: Window { + size: (700, 300), + resizable: true, + decorations: true, + }, + }) } #[derive(Default)] @@ -29,17 +38,20 @@ impl Sandbox for Progress { fn update(&mut self, message: Message) { match message { - Message::SliderChanged(x) => { - self.value = x; - } + Message::SliderChanged(x) => self.value = x, } } fn view(&mut self) -> Element { Column::new() .padding(20) - .push(Progressbar::new(0.0..=100.0, self.value)) - .padding(20) + .push( + Progressbar::new(0.0..=100.0, self.value) + .background(Background::Color(Color::from_rgb( + 0.6, 0.6, 0.6, + ))) + .active_color(Color::from_rgb(0.0, 0.95, 0.0)), + ) .push(Slider::new( &mut self.progressbar_slider, 0.0..=100.0, diff --git a/native/src/widget/progressbar.rs b/native/src/widget/progressbar.rs index a6725f2c..fc55a803 100644 --- a/native/src/widget/progressbar.rs +++ b/native/src/widget/progressbar.rs @@ -3,7 +3,8 @@ //! //! [`Progressbar`]: struct.Progressbar.html use crate::{ - layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, + layout, Background, Color, Element, Hasher, Layout, Length, Point, + Rectangle, Size, Widget, }; use std::{hash::Hash, ops::RangeInclusive}; @@ -14,17 +15,19 @@ use std::{hash::Hash, ops::RangeInclusive}; /// /// ``` /// # use iced_native::Progressbar; -/// +/// +/// let value = 50.0; /// Progressbar::new(0.0..=100.0, value); /// ``` /// -/// TODO: Get a progressbar render -/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) +/// ![Default Progressbar](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) #[allow(missing_debug_implementations)] pub struct Progressbar { range: RangeInclusive, value: f32, width: Length, + background: Option, + active_color: Option, } impl Progressbar { @@ -40,6 +43,8 @@ impl Progressbar { value: value.max(*range.start()).min(*range.end()), range, width: Length::Fill, + background: None, + active_color: None, } } @@ -50,6 +55,22 @@ impl Progressbar { self.width = width; self } + + /// Sets the background of the [`Progressbar`]. + /// + /// [`Progressbar`]: struct.Progressbar.html + pub fn background(mut self, background: Background) -> Self { + self.background = Some(background); + self + } + + /// Sets the active color of the [`Progressbar`]. + /// + /// [`Progressbar`]: struct.Progressbar.html + pub fn active_color(mut self, active_color: Color) -> Self { + self.active_color = Some(active_color); + self + } } impl Widget for Progressbar @@ -84,7 +105,13 @@ where layout: Layout<'_>, _cursor_position: Point, ) -> Renderer::Output { - renderer.draw(layout.bounds(), self.range.clone(), self.value) + renderer.draw( + layout.bounds(), + self.range.clone(), + self.value, + self.background, + self.active_color, + ) } fn hash_layout(&self, state: &mut Hasher) { @@ -112,6 +139,8 @@ pub trait Renderer: crate::Renderer { /// * the bounds of the [`Progressbar`] /// * the range of values of the [`Progressbar`] /// * the current value of the [`Progressbar`] + /// * maybe a specific background of the [`Progressbar`] + /// * maybe a specific active color of the [`Progressbar`] /// /// [`Progressbar`]: struct.Progressbar.html /// [`State`]: struct.State.html @@ -121,6 +150,8 @@ pub trait Renderer: crate::Renderer { bounds: Rectangle, range: RangeInclusive, value: f32, + background: Option, + active_color: Option, ) -> Self::Output; } diff --git a/wgpu/src/renderer/widget/progressbar.rs b/wgpu/src/renderer/widget/progressbar.rs index 3c62e54d..f621343d 100644 --- a/wgpu/src/renderer/widget/progressbar.rs +++ b/wgpu/src/renderer/widget/progressbar.rs @@ -11,6 +11,8 @@ impl progressbar::Renderer for Renderer { bounds: Rectangle, range: std::ops::RangeInclusive, value: f32, + background: Option, + active_color: Option, ) -> Self::Output { let (range_start, range_end) = range.into_inner(); let active_progress_width = bounds.width @@ -19,7 +21,9 @@ impl progressbar::Renderer for Renderer { let background = Primitive::Group { primitives: vec![Primitive::Quad { bounds: Rectangle { ..bounds }, - background: Color::from_rgb(0.6, 0.6, 0.6).into(), + background: background + .unwrap_or(Background::Color([0.6, 0.6, 0.6].into())) + .into(), border_radius: 5, }], }; @@ -29,8 +33,10 @@ impl progressbar::Renderer for Renderer { width: active_progress_width, ..bounds }, - background: Background::Color([0.0, 0.95, 0.0].into()), - border_radius: 4, + background: Background::Color( + active_color.unwrap_or([0.0, 0.95, 0.0].into()), + ), + border_radius: 5, }; ( From 986f01237f227ad2eaabda982324fc26840cb12b Mon Sep 17 00:00:00 2001 From: Songtronix Date: Thu, 2 Jan 2020 18:07:00 +0100 Subject: [PATCH 09/16] change(widget): make height adjustable at widget level addtionally rename Progressbar to ProgressBar --- examples/{progressbar.rs => progress_bar.rs} | 15 +-- native/src/widget.rs | 4 +- .../{progressbar.rs => progress_bar.rs} | 91 ++++++++++--------- wgpu/src/renderer/widget.rs | 2 +- .../{progressbar.rs => progress_bar.rs} | 8 +- 5 files changed, 61 insertions(+), 59 deletions(-) rename examples/{progressbar.rs => progress_bar.rs} (82%) rename native/src/widget/{progressbar.rs => progress_bar.rs} (57%) rename wgpu/src/renderer/widget/{progressbar.rs => progress_bar.rs} (88%) diff --git a/examples/progressbar.rs b/examples/progress_bar.rs similarity index 82% rename from examples/progressbar.rs rename to examples/progress_bar.rs index c4ebf248..56f54903 100644 --- a/examples/progressbar.rs +++ b/examples/progress_bar.rs @@ -1,8 +1,8 @@ use iced::{ - settings::Window, slider, Background, Color, Column, Element, Sandbox, - Settings, Slider, + settings::Window, slider, Background, Color, Column, Element, Length, + Sandbox, Settings, Slider, }; -use iced_winit::Progressbar; +use iced_winit::ProgressBar; pub fn main() { Progress::run(Settings { @@ -17,7 +17,7 @@ pub fn main() { #[derive(Default)] struct Progress { value: f32, - progressbar_slider: slider::State, + progress_bar_slider: slider::State, } #[derive(Debug, Clone, Copy)] @@ -46,14 +46,15 @@ impl Sandbox for Progress { Column::new() .padding(20) .push( - Progressbar::new(0.0..=100.0, self.value) + ProgressBar::new(0.0..=100.0, self.value) .background(Background::Color(Color::from_rgb( 0.6, 0.6, 0.6, ))) - .active_color(Color::from_rgb(0.0, 0.95, 0.0)), + .active_color(Color::from_rgb(0.0, 0.95, 0.0)) + .height(Length::Units(30)), ) .push(Slider::new( - &mut self.progressbar_slider, + &mut self.progress_bar_slider, 0.0..=100.0, self.value, Message::SliderChanged, diff --git a/native/src/widget.rs b/native/src/widget.rs index d899da58..ccc9b47e 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -25,7 +25,7 @@ pub mod checkbox; pub mod column; pub mod container; pub mod image; -pub mod progressbar; +pub mod progress_bar; pub mod radio; pub mod row; pub mod scrollable; @@ -46,7 +46,7 @@ pub use container::Container; #[doc(no_inline)] pub use image::Image; #[doc(no_inline)] -pub use progressbar::Progressbar; +pub use progress_bar::ProgressBar; #[doc(no_inline)] pub use radio::Radio; #[doc(no_inline)] diff --git a/native/src/widget/progressbar.rs b/native/src/widget/progress_bar.rs similarity index 57% rename from native/src/widget/progressbar.rs rename to native/src/widget/progress_bar.rs index fc55a803..f9b87026 100644 --- a/native/src/widget/progressbar.rs +++ b/native/src/widget/progress_bar.rs @@ -1,7 +1,7 @@ -//! Display a progressbar +//! Display a ProgressBar //! //! -//! [`Progressbar`]: struct.Progressbar.html +//! [`ProgressBar`]: struct.ProgressBar.html use crate::{ layout, Background, Color, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, @@ -9,71 +9,83 @@ use crate::{ use std::{hash::Hash, ops::RangeInclusive}; -/// A progressbar +const DEFAULT_HEIGHT: Length = Length::Units(30); + +/// A ProgressBar /// /// # Example /// /// ``` -/// # use iced_native::Progressbar; -/// +/// # use iced_native::ProgressBar; +/// /// let value = 50.0; -/// Progressbar::new(0.0..=100.0, value); +/// ProgressBar::new(0.0..=100.0, value); /// ``` /// -/// ![Default Progressbar](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) +/// ![Default ProgressBar](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) #[allow(missing_debug_implementations)] -pub struct Progressbar { +pub struct ProgressBar { range: RangeInclusive, value: f32, width: Length, + height: Length, background: Option, active_color: Option, } -impl Progressbar { - /// Creates a new [`Progressbar`]. +impl ProgressBar { + /// Creates a new [`ProgressBar`]. /// /// It expects: /// * an inclusive range of possible values - /// * the current value of the [`Progressbar`] + /// * the current value of the [`ProgressBar`] /// - /// [`Progressbar`]: struct.Progressbar.html + /// [`ProgressBar`]: struct.ProgressBar.html pub fn new(range: RangeInclusive, value: f32) -> Self { - Progressbar { + ProgressBar { value: value.max(*range.start()).min(*range.end()), range, width: Length::Fill, + height: DEFAULT_HEIGHT, background: None, active_color: None, } } - /// Sets the width of the [`Progressbar`]. + /// Sets the width of the [`ProgressBar`]. /// - /// [`Progressbar`]: struct.Progressbar.html + /// [`ProgressBar`]: struct.ProgressBar.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } - /// Sets the background of the [`Progressbar`]. + /// Sets the height of the [`ProgressBar`]. /// - /// [`Progressbar`]: struct.Progressbar.html + /// [`ProgressBar`]: struct.ProgressBar.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + /// Sets the background of the [`ProgressBar`]. + /// + /// [`ProgressBar`]: struct.ProgressBar.html pub fn background(mut self, background: Background) -> Self { self.background = Some(background); self } - /// Sets the active color of the [`Progressbar`]. + /// Sets the active color of the [`ProgressBar`]. /// - /// [`Progressbar`]: struct.Progressbar.html + /// [`ProgressBar`]: struct.ProgressBar.html pub fn active_color(mut self, active_color: Color) -> Self { self.active_color = Some(active_color); self } } -impl Widget for Progressbar +impl Widget for ProgressBar where Renderer: self::Renderer, { @@ -82,17 +94,15 @@ where } fn height(&self) -> Length { - Length::Shrink + self.height } fn layout( &self, - renderer: &Renderer, + _renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { - let limits = limits - .width(self.width) - .height(Length::Units(renderer.height() as u16)); + let limits = limits.width(self.width).height(self.height); let size = limits.resolve(Size::ZERO); @@ -119,30 +129,25 @@ where } } -/// The renderer of a [`Progressbar`]. +/// The renderer of a [`ProgressBar`]. /// /// Your [renderer] will need to implement this trait before being -/// able to use a [`Progressbar`] in your user interface. +/// able to use a [`ProgressBar`] in your user interface. /// -/// [`Progressbar`]: struct.Progressbar.html +/// [`ProgressBar`]: struct.ProgressBar.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { - /// Returns the height of the [`Progressbar`]. - /// - /// [`Progressbar`]: struct.Progressbar.html - fn height(&self) -> u32; - - /// Draws a [`Progressbar`]. + /// Draws a [`ProgressBar`]. /// /// It receives: - /// * the local state of the [`Progressbar`] - /// * the bounds of the [`Progressbar`] - /// * the range of values of the [`Progressbar`] - /// * the current value of the [`Progressbar`] - /// * maybe a specific background of the [`Progressbar`] - /// * maybe a specific active color of the [`Progressbar`] + /// * the local state of the [`ProgressBar`] + /// * the bounds of the [`ProgressBar`] + /// * the range of values of the [`ProgressBar`] + /// * the current value of the [`ProgressBar`] + /// * maybe a specific background of the [`ProgressBar`] + /// * maybe a specific active color of the [`ProgressBar`] /// - /// [`Progressbar`]: struct.Progressbar.html + /// [`ProgressBar`]: struct.ProgressBar.html /// [`State`]: struct.State.html /// [`Class`]: enum.Class.html fn draw( @@ -155,12 +160,12 @@ pub trait Renderer: crate::Renderer { ) -> Self::Output; } -impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> where Renderer: self::Renderer, Message: 'static, { - fn from(progressbar: Progressbar) -> Element<'a, Message, Renderer> { + fn from(progressbar: ProgressBar) -> Element<'a, Message, Renderer> { Element::new(progressbar) } } diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs index 94ebd10e..32187c10 100644 --- a/wgpu/src/renderer/widget.rs +++ b/wgpu/src/renderer/widget.rs @@ -2,7 +2,7 @@ mod button; mod checkbox; mod column; mod image; -mod progressbar; +mod progress_bar; mod radio; mod row; mod scrollable; diff --git a/wgpu/src/renderer/widget/progressbar.rs b/wgpu/src/renderer/widget/progress_bar.rs similarity index 88% rename from wgpu/src/renderer/widget/progressbar.rs rename to wgpu/src/renderer/widget/progress_bar.rs index f621343d..3550df23 100644 --- a/wgpu/src/renderer/widget/progressbar.rs +++ b/wgpu/src/renderer/widget/progress_bar.rs @@ -1,11 +1,7 @@ use crate::{Primitive, Renderer}; -use iced_native::{progressbar, Background, Color, MouseCursor, Rectangle}; - -impl progressbar::Renderer for Renderer { - fn height(&self) -> u32 { - 30 - } +use iced_native::{progress_bar, Background, Color, MouseCursor, Rectangle}; +impl progress_bar::Renderer for Renderer { fn draw( &self, bounds: Rectangle, From 5ca98b113e49bfb2372b245a985f957611a0a1ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 2 Jan 2020 19:25:00 +0100 Subject: [PATCH 10/16] Rename `Geometry2D` to `Mesh2D` and move it to `iced_wgpu` --- core/src/geometry.rs | 20 -- core/src/lib.rs | 2 - examples/geometry.rs | 194 ++++++++---------- native/src/lib.rs | 2 +- wgpu/src/lib.rs | 3 +- wgpu/src/primitive.rs | 14 +- wgpu/src/renderer.rs | 57 +++-- .../src/shader/{geom2d.frag => triangle.frag} | 0 .../{geom2d.frag.spv => triangle.frag.spv} | Bin 372 -> 372 bytes .../src/shader/{geom2d.vert => triangle.vert} | 0 .../{geom2d.vert.spv => triangle.vert.spv} | Bin 1468 -> 1468 bytes wgpu/src/{geometry.rs => triangle.rs} | 90 +++++--- 12 files changed, 184 insertions(+), 198 deletions(-) delete mode 100644 core/src/geometry.rs rename wgpu/src/shader/{geom2d.frag => triangle.frag} (100%) rename wgpu/src/shader/{geom2d.frag.spv => triangle.frag.spv} (82%) rename wgpu/src/shader/{geom2d.vert => triangle.vert} (100%) rename wgpu/src/shader/{geom2d.vert.spv => triangle.vert.spv} (95%) rename wgpu/src/{geometry.rs => triangle.rs} (75%) diff --git a/core/src/geometry.rs b/core/src/geometry.rs deleted file mode 100644 index f04ce42e..00000000 --- a/core/src/geometry.rs +++ /dev/null @@ -1,20 +0,0 @@ -/// A two-dimensional vertex which has a color -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct Vertex2D { - /// The vertex position - pub position: [f32; 2], - /// The vertex color in rgba - pub color: [f32; 4], -} - -/// A set of [`Vertex2D`] and indices for drawing some 2D geometry on the GPU. -/// -/// [`Vertex2D`]: struct.Vertex2D.html -#[derive(Clone, Debug)] -pub struct Geometry2D { - /// The vertices for this geometry - pub vertices: Vec, - /// The indices for this geometry - pub indices: Vec, -} diff --git a/core/src/lib.rs b/core/src/lib.rs index 881f56c9..821b09c1 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -23,7 +23,6 @@ mod length; mod point; mod rectangle; mod vector; -mod geometry; pub use align::{Align, HorizontalAlignment, VerticalAlignment}; pub use background::Background; @@ -33,7 +32,6 @@ pub use length::Length; pub use point::Point; pub use rectangle::Rectangle; pub use vector::Vector; -pub use geometry::{Vertex2D, Geometry2D}; #[cfg(feature = "command")] mod command; diff --git a/examples/geometry.rs b/examples/geometry.rs index feb7684e..ae6c9ca0 100644 --- a/examples/geometry.rs +++ b/examples/geometry.rs @@ -11,24 +11,25 @@ mod rainbow { // if you wish to, by creating your own `Renderer` trait, which could be // implemented by `iced_wgpu` and other renderers. use iced_native::{ - layout, Element, Geometry2D, Hasher, Layout, Length, - MouseCursor, Point, Size, Vertex2D, Widget, + layout, Element, Hasher, Layout, Length, MouseCursor, Point, Size, + Widget, + }; + use iced_wgpu::{ + triangle::{Mesh2D, Vertex2D}, + Primitive, Renderer, }; - use iced_wgpu::{Primitive, Renderer}; - pub struct Rainbow { - dimen: u16, - } + pub struct Rainbow; impl Rainbow { - pub fn new(dimen: u16) -> Self { - Self { dimen } + pub fn new() -> Self { + Self } } impl Widget for Rainbow { fn width(&self) -> Length { - Length::Shrink + Length::Fill } fn height(&self) -> Length { @@ -38,19 +39,14 @@ mod rainbow { fn layout( &self, _renderer: &Renderer, - _limits: &layout::Limits, + limits: &layout::Limits, ) -> layout::Node { - layout::Node::new(Size::new( - f32::from(self.dimen), - f32::from(self.dimen), - )) + let size = limits.width(Length::Fill).resolve(Size::ZERO); + + layout::Node::new(Size::new(size.width, size.width)) } - fn hash_layout(&self, state: &mut Hasher) { - use std::hash::Hash; - - self.dimen.hash(state); - } + fn hash_layout(&self, _state: &mut Hasher) {} fn draw( &self, @@ -88,58 +84,56 @@ mod rainbow { let posn_l = [b.x, b.y + (b.height / 2.0)]; ( - Primitive::Geometry2D { - geometry: Geometry2D { - vertices: vec![ - Vertex2D { - position: posn_center, - color: [1.0, 1.0, 1.0, 1.0], - }, - Vertex2D { - position: posn_tl, - color: color_r, - }, - Vertex2D { - position: posn_t, - color: color_o, - }, - Vertex2D { - position: posn_tr, - color: color_y, - }, - Vertex2D { - position: posn_r, - color: color_g, - }, - Vertex2D { - position: posn_br, - color: color_gb, - }, - Vertex2D { - position: posn_b, - color: color_b, - }, - Vertex2D { - position: posn_bl, - color: color_i, - }, - Vertex2D { - position: posn_l, - color: color_v, - }, - ], - indices: vec![ - 0, 1, 2, // TL - 0, 2, 3, // T - 0, 3, 4, // TR - 0, 4, 5, // R - 0, 5, 6, // BR - 0, 6, 7, // B - 0, 7, 8, // BL - 0, 8, 1, // L - ], - }, - }, + Primitive::Mesh2D(std::sync::Arc::new(Mesh2D { + vertices: vec![ + Vertex2D { + position: posn_center, + color: [1.0, 1.0, 1.0, 1.0], + }, + Vertex2D { + position: posn_tl, + color: color_r, + }, + Vertex2D { + position: posn_t, + color: color_o, + }, + Vertex2D { + position: posn_tr, + color: color_y, + }, + Vertex2D { + position: posn_r, + color: color_g, + }, + Vertex2D { + position: posn_br, + color: color_gb, + }, + Vertex2D { + position: posn_b, + color: color_b, + }, + Vertex2D { + position: posn_bl, + color: color_i, + }, + Vertex2D { + position: posn_l, + color: color_v, + }, + ], + indices: vec![ + 0, 1, 2, // TL + 0, 2, 3, // T + 0, 3, 4, // TR + 0, 4, 5, // R + 0, 5, 6, // BR + 0, 6, 7, // B + 0, 7, 8, // BL + 0, 8, 1, // L + ], + })), MouseCursor::OutOfBounds, ) } @@ -153,35 +147,24 @@ mod rainbow { } use iced::{ - scrollable, settings::Window, Align, Column, Container, Element, - Length, Sandbox, Scrollable, Settings, Text, + scrollable, Align, Column, Container, Element, Length, Sandbox, Scrollable, + Settings, Text, }; use rainbow::Rainbow; pub fn main() { - Example::run(Settings { - window: Window { - size: (660, 660), - resizable: true, - decorations: true, - }, - }) + Example::run(Settings::default()) } struct Example { - dimen: u16, scroll: scrollable::State, } -#[derive(Debug, Clone, Copy)] -enum Message {} - impl Sandbox for Example { - type Message = Message; + type Message = (); fn new() -> Self { Example { - dimen: 500, scroll: scrollable::State::new(), } } @@ -190,37 +173,36 @@ impl Sandbox for Example { String::from("Custom 2D geometry - Iced") } - fn update(&mut self, _: Message) {} + fn update(&mut self, _: ()) {} - fn view(&mut self) -> Element { + fn view(&mut self) -> Element<()> { let content = Column::new() .padding(20) .spacing(20) .max_width(500) .align_items(Align::Start) - .push(Rainbow::new(self.dimen)) - .push( - Text::new(String::from("In this example we draw a custom widget Rainbow, using the \ - Geometry2D primitive. This primitive supplies a list of triangles, expressed as vertices and indices.")) - .width(Length::Shrink), - ) - .push( - Text::new(String::from("Move your cursor over it, and see the center vertex follow you!")) - .width(Length::Shrink), - ) - .push( - Text::new(String::from("Every Vertex2D defines its own color. You could use the \ - Geometry2D primitive to render virtually any two-dimensional geometry for your widget.")) - .width(Length::Shrink), - ); + .push(Rainbow::new()) + .push(Text::new( + "In this example we draw a custom widget Rainbow, using \ + the Mesh2D primitive. This primitive supplies a list of \ + triangles, expressed as vertices and indices.", + )) + .push(Text::new( + "Move your cursor over it, and see the center vertex \ + follow you!", + )) + .push(Text::new( + "Every Vertex2D defines its own color. You could use the \ + Mesh2D primitive to render virtually any two-dimensional \ + geometry for your widget.", + )); - let scrollable = - Scrollable::new(&mut self.scroll).push(Container::new(content)); + let scrollable = Scrollable::new(&mut self.scroll) + .push(Container::new(content).width(Length::Fill).center_x()); Container::new(scrollable) .width(Length::Fill) .height(Length::Fill) - .center_x() .center_y() .into() } diff --git a/native/src/lib.rs b/native/src/lib.rs index 6f6af159..8dcacb2b 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -55,7 +55,7 @@ mod user_interface; pub use iced_core::{ Align, Background, Color, Command, Font, HorizontalAlignment, Length, - Point, Rectangle, Vector, VerticalAlignment, Geometry2D, Vertex2D, + Point, Rectangle, Vector, VerticalAlignment, }; pub use clipboard::Clipboard; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 7587be77..972f56af 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -24,13 +24,14 @@ #![deny(unused_results)] #![deny(unsafe_code)] #![deny(rust_2018_idioms)] +pub mod triangle; + mod image; mod primitive; mod quad; mod renderer; mod text; mod transformation; -mod geometry; pub(crate) use crate::image::Image; pub(crate) use quad::Quad; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 06121262..815ba3b0 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,8 +1,11 @@ use iced_native::{ image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, - Vector, VerticalAlignment, Geometry2D, + Vector, VerticalAlignment, }; +use crate::triangle; +use std::sync::Arc; + /// A rendering primitive. #[derive(Debug, Clone)] pub enum Primitive { @@ -63,11 +66,10 @@ pub enum Primitive { /// The content of the clip content: Box, }, - /// A low-level geometry primitive - Geometry2D { - /// The vertices and indices of the geometry - geometry: Geometry2D, - }, + /// A low-level primitive to render a mesh of triangles. + /// + /// It can be used to render many kinds of geometry freely. + Mesh2D(Arc), } impl Default for Primitive { diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 3cfd746d..050daca9 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,12 +1,11 @@ use crate::{ - geometry, image, quad, text, Image, Primitive, Quad, Transformation, + image, quad, text, triangle, Image, Primitive, Quad, Transformation, }; use iced_native::{ renderer::{Debugger, Windowed}, - Background, Color, Geometry2D, Layout, MouseCursor, Point, Rectangle, - Vector, Widget, + Background, Color, Layout, MouseCursor, Point, Rectangle, Vector, Widget, }; - +use std::sync::Arc; use wgpu::{ Adapter, BackendBit, CommandEncoderDescriptor, Device, DeviceDescriptor, Extensions, Limits, PowerPreference, Queue, RequestAdapterOptions, @@ -27,7 +26,7 @@ pub struct Renderer { quad_pipeline: quad::Pipeline, image_pipeline: crate::image::Pipeline, text_pipeline: text::Pipeline, - geometry_pipeline: crate::geometry::Pipeline, + triangle_pipeline: crate::triangle::Pipeline, } struct Layer<'a> { @@ -35,7 +34,7 @@ struct Layer<'a> { offset: Vector, quads: Vec, images: Vec, - geometries: Vec, + meshes: Vec>, text: Vec>, } @@ -47,7 +46,7 @@ impl<'a> Layer<'a> { quads: Vec::new(), images: Vec::new(), text: Vec::new(), - geometries: Vec::new(), + meshes: Vec::new(), } } } @@ -70,7 +69,7 @@ impl Renderer { let text_pipeline = text::Pipeline::new(&mut device); let quad_pipeline = quad::Pipeline::new(&mut device); let image_pipeline = crate::image::Pipeline::new(&mut device); - let geometry_pipeline = geometry::Pipeline::new(&mut device); + let triangle_pipeline = triangle::Pipeline::new(&mut device); Self { device, @@ -78,7 +77,7 @@ impl Renderer { quad_pipeline, image_pipeline, text_pipeline, - geometry_pipeline, + triangle_pipeline, } } @@ -252,8 +251,8 @@ impl Renderer { scale: [bounds.width, bounds.height], }); } - Primitive::Geometry2D { geometry } => { - layer.geometries.push(geometry.clone()); + Primitive::Mesh2D(mesh) => { + layer.meshes.push(mesh.clone()); } Primitive::Clip { bounds, @@ -333,6 +332,24 @@ impl Renderer { ) { let bounds = layer.bounds * dpi; + if layer.meshes.len() > 0 { + let translated = transformation + * Transformation::translate( + -(layer.offset.x as f32) * dpi, + -(layer.offset.y as f32) * dpi, + ); + + self.triangle_pipeline.draw( + &mut self.device, + encoder, + target, + translated, + dpi, + &layer.meshes, + bounds, + ); + } + if layer.quads.len() > 0 { self.quad_pipeline.draw( &mut self.device, @@ -412,24 +429,6 @@ impl Renderer { }, ); } - - if layer.geometries.len() > 0 { - let translated = transformation - * Transformation::translate( - -(layer.offset.x as f32) * dpi, - -(layer.offset.y as f32) * dpi, - ); - - self.geometry_pipeline.draw( - &mut self.device, - encoder, - target, - translated, - dpi, - &layer.geometries, - bounds, - ); - } } } diff --git a/wgpu/src/shader/geom2d.frag b/wgpu/src/shader/triangle.frag similarity index 100% rename from wgpu/src/shader/geom2d.frag rename to wgpu/src/shader/triangle.frag diff --git a/wgpu/src/shader/geom2d.frag.spv b/wgpu/src/shader/triangle.frag.spv similarity index 82% rename from wgpu/src/shader/geom2d.frag.spv rename to wgpu/src/shader/triangle.frag.spv index c0165bcac9ab1cd9ba6bc39cb74afb19590a49e0..11201872ec63d8b77e22fbee6a8731f2f5ed96a2 100644 GIT binary patch delta 18 Zcmeyu^o5C&nMs+Qfq{{MeIsW!BLF8J15*G1 delta 18 Zcmeyu^o5C&nMs+Qfq{{MV@) delta 18 ZcmdnPy@#8VnMs+Qfq{{MV, + meshes: &Vec>, bounds: Rectangle, ) { let uniforms = Uniforms { @@ -148,39 +149,39 @@ impl Pipeline { std::mem::size_of::() as u64, ); - for geom in geometries { + let mut render_pass = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[ + wgpu::RenderPassColorAttachmentDescriptor { + attachment: target, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }, + ], + depth_stencil_attachment: None, + }); + + for mesh in meshes { let vertices_buffer = device .create_buffer_mapped( - geom.vertices.len(), + mesh.vertices.len(), wgpu::BufferUsage::VERTEX, ) - .fill_from_slice(&geom.vertices); + .fill_from_slice(&mesh.vertices); let indices_buffer = device .create_buffer_mapped( - geom.indices.len(), + mesh.indices.len(), wgpu::BufferUsage::INDEX, ) - .fill_from_slice(&geom.indices); - - let mut render_pass = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, - resolve_target: None, - load_op: wgpu::LoadOp::Load, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 0.0, - }, - }, - ], - depth_stencil_attachment: None, - }); + .fill_from_slice(&mesh.indices); render_pass.set_pipeline(&self.pipeline); render_pass.set_bind_group(0, &self.constants, &[]); @@ -193,7 +194,7 @@ impl Pipeline { bounds.height, ); - render_pass.draw_indexed(0..geom.indices.len() as u32, 0, 0..1); + render_pass.draw_indexed(0..mesh.indices.len() as u32, 0, 0..1); } } } @@ -213,3 +214,26 @@ impl Default for Uniforms { } } } + +/// A two-dimensional vertex with some color in __linear__ RGBA. +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Vertex2D { + /// The vertex position + pub position: [f32; 2], + /// The vertex color in __linear__ RGBA. + pub color: [f32; 4], +} + +/// A set of [`Vertex2D`] and indices representing a list of triangles. +/// +/// [`Vertex2D`]: struct.Vertex2D.html +#[derive(Clone, Debug)] +pub struct Mesh2D { + /// The vertices of the mesh + pub vertices: Vec, + /// The list of vertex indices that defines the triangles of the mesh. + /// + /// Therefore, this list should always have a length that is a multiple of 3. + pub indices: Vec, +} From dc094df214a4eab53d3fa8bdf8087fef5a37e9b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 2 Jan 2020 19:27:54 +0100 Subject: [PATCH 11/16] Remove empty `geometry` file in `iced_native` --- native/src/widget/geometry.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 native/src/widget/geometry.rs diff --git a/native/src/widget/geometry.rs b/native/src/widget/geometry.rs deleted file mode 100644 index e69de29b..00000000 From 0b663ca82aa4fccb95ada3dd01d82cbaec6acc24 Mon Sep 17 00:00:00 2001 From: Songtronix Date: Fri, 3 Jan 2020 16:41:16 +0100 Subject: [PATCH 12/16] add(web): support password field --- web/src/widget/text_input.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/web/src/widget/text_input.rs b/web/src/widget/text_input.rs index 99792c84..eedc25bc 100644 --- a/web/src/widget/text_input.rs +++ b/web/src/widget/text_input.rs @@ -32,6 +32,7 @@ pub struct TextInput<'a, Message> { _state: &'a mut State, placeholder: String, value: String, + is_secure: bool, width: Length, max_width: Length, padding: u16, @@ -64,6 +65,7 @@ impl<'a, Message> TextInput<'a, Message> { _state: state, placeholder: String::from(placeholder), value: String::from(value), + is_secure: false, width: Length::Fill, max_width: Length::Shrink, padding: 0, @@ -73,6 +75,14 @@ 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 @@ -161,6 +171,10 @@ where "value", bumpalo::format!(in bump, "{}", self.value).into_bump_str(), ) + .attr( + "type", + bumpalo::format!(in bump, "{}", if self.is_secure { "password" } else { "text" }).into_bump_str(), + ) .on("input", move |root, vdom, event| { let text_input = match event.target().and_then(|t| { t.dyn_into::().ok() From 9116afaf59f5ea697bed55ed3d11e2afd76ad4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 3 Jan 2020 18:23:19 +0100 Subject: [PATCH 13/16] Move `DEFAULT_HEIGHT` constant to `Renderer` Also fixes some minor documentation issues. --- native/src/widget/progress_bar.rs | 39 ++++++++++++------------ wgpu/src/renderer/widget/progress_bar.rs | 2 ++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index f9b87026..d61ec4f2 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -1,7 +1,4 @@ -//! Display a ProgressBar -//! -//! -//! [`ProgressBar`]: struct.ProgressBar.html +//! Provide progress feedback to your users. use crate::{ layout, Background, Color, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, @@ -9,26 +6,24 @@ use crate::{ use std::{hash::Hash, ops::RangeInclusive}; -const DEFAULT_HEIGHT: Length = Length::Units(30); - -/// A ProgressBar +/// A bar that displays progress. /// /// # Example -/// /// ``` /// # use iced_native::ProgressBar; -/// +/// # /// let value = 50.0; +/// /// ProgressBar::new(0.0..=100.0, value); /// ``` /// -/// ![Default ProgressBar](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) +/// ![Progress bar drawn with `iced_wgpu`](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) #[allow(missing_debug_implementations)] pub struct ProgressBar { range: RangeInclusive, value: f32, width: Length, - height: Length, + height: Option, background: Option, active_color: Option, } @@ -46,7 +41,7 @@ impl ProgressBar { value: value.max(*range.start()).min(*range.end()), range, width: Length::Fill, - height: DEFAULT_HEIGHT, + height: None, background: None, active_color: None, } @@ -64,7 +59,7 @@ impl ProgressBar { /// /// [`ProgressBar`]: struct.ProgressBar.html pub fn height(mut self, height: Length) -> Self { - self.height = height; + self.height = Some(height); self } @@ -95,6 +90,7 @@ where fn height(&self) -> Length { self.height + .unwrap_or(Length::Units(Renderer::DEFAULT_HEIGHT)) } fn layout( @@ -102,7 +98,10 @@ where _renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { - let limits = limits.width(self.width).height(self.height); + let limits = limits.width(self.width).height( + self.height + .unwrap_or(Length::Units(Renderer::DEFAULT_HEIGHT)), + ); let size = limits.resolve(Size::ZERO); @@ -137,10 +136,14 @@ where /// [`ProgressBar`]: struct.ProgressBar.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer { + /// The default height of a [`ProgressBar`]. + /// + /// [`ProgressBar`]: struct.ProgressBar.html + const DEFAULT_HEIGHT: u16; + /// Draws a [`ProgressBar`]. /// /// It receives: - /// * the local state of the [`ProgressBar`] /// * the bounds of the [`ProgressBar`] /// * the range of values of the [`ProgressBar`] /// * the current value of the [`ProgressBar`] @@ -148,8 +151,6 @@ pub trait Renderer: crate::Renderer { /// * maybe a specific active color of the [`ProgressBar`] /// /// [`ProgressBar`]: struct.ProgressBar.html - /// [`State`]: struct.State.html - /// [`Class`]: enum.Class.html fn draw( &self, bounds: Rectangle, @@ -165,7 +166,7 @@ where Renderer: self::Renderer, Message: 'static, { - fn from(progressbar: ProgressBar) -> Element<'a, Message, Renderer> { - Element::new(progressbar) + fn from(progress_bar: ProgressBar) -> Element<'a, Message, Renderer> { + Element::new(progress_bar) } } diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs index 3550df23..8ed4bab7 100644 --- a/wgpu/src/renderer/widget/progress_bar.rs +++ b/wgpu/src/renderer/widget/progress_bar.rs @@ -2,6 +2,8 @@ use crate::{Primitive, Renderer}; use iced_native::{progress_bar, Background, Color, MouseCursor, Rectangle}; impl progress_bar::Renderer for Renderer { + const DEFAULT_HEIGHT: u16 = 30; + fn draw( &self, bounds: Rectangle, From 60ac4faca0e61ddebaa89c0535390cc3f1180a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 3 Jan 2020 18:33:47 +0100 Subject: [PATCH 14/16] Hash `height` of `ProgressBar` in `hash_layout` --- native/src/widget/progress_bar.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index d61ec4f2..b1d4fd92 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -125,6 +125,7 @@ where fn hash_layout(&self, state: &mut Hasher) { self.width.hash(state); + self.height.hash(state); } } From 43de28ae1515ace34758656f228444898459d85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Sat, 4 Jan 2020 14:14:28 +0100 Subject: [PATCH 15/16] Expose `ProgressBar` in `iced` crate --- examples/progress_bar.rs | 3 +-- src/native.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/progress_bar.rs b/examples/progress_bar.rs index 56f54903..525019b4 100644 --- a/examples/progress_bar.rs +++ b/examples/progress_bar.rs @@ -1,8 +1,7 @@ use iced::{ settings::Window, slider, Background, Color, Column, Element, Length, - Sandbox, Settings, Slider, + ProgressBar, Sandbox, Settings, Slider, }; -use iced_winit::ProgressBar; pub fn main() { Progress::run(Settings { diff --git a/src/native.rs b/src/native.rs index cf48a391..022cf337 100644 --- a/src/native.rs +++ b/src/native.rs @@ -85,7 +85,7 @@ pub mod widget { pub use iced_winit::svg::{Handle, Svg}; } - pub use iced_winit::{Checkbox, Radio, Text}; + pub use iced_winit::{Checkbox, ProgressBar, Radio, Text}; #[doc(no_inline)] pub use { From cc529a1803972604b122c19c0104e71532fff993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 8 Jan 2020 03:22:05 +0100 Subject: [PATCH 16/16] Add a note about cross-compatibility in `master` Fixes #145 --- web/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/README.md b/web/README.md index 762f6c83..6a3da7b4 100644 --- a/web/README.md +++ b/web/README.md @@ -39,7 +39,11 @@ cargo build --example tour --target wasm32-unknown-unknown wasm-bindgen ../target/wasm32-unknown-unknown/debug/examples/tour.wasm --out-dir tour --web ``` -Then, we need to create an `.html` file to load our application: +*__Note:__ Keep in mind that Iced is still in early exploration stages and most of the work needs to happen on the native side of the ecosystem. At this stage, it is important to be able to batch work without having to constantly jump back and forth. Because of this, there is currently no requirement for the `master` branch to contain a cross-platform API at all times. If you hit an issue when building an example and want to help, it may be a good way to [start contributing]!* + +[start contributing]: ../CONTRIBUTING.md + +Once the example is compiled, we need to create an `.html` file to load our application: ```html