diff options
author | 2020-05-19 17:15:44 +0200 | |
---|---|---|
committer | 2020-05-19 17:15:44 +0200 | |
commit | 05af8d00d4c0f7b8e0ece85224fd90a92da86da8 (patch) | |
tree | 98e4774a2c0d4a2a0a01aff1d772f89c4cb0aa5e /graphics/src | |
parent | d4743183d40c6044ce6fa39e2a52919a32912cda (diff) | |
download | iced-05af8d00d4c0f7b8e0ece85224fd90a92da86da8.tar.gz iced-05af8d00d4c0f7b8e0ece85224fd90a92da86da8.tar.bz2 iced-05af8d00d4c0f7b8e0ece85224fd90a92da86da8.zip |
Draft new `iced_graphics` crate :tada:
Diffstat (limited to '')
-rw-r--r-- | graphics/src/backend.rs | 30 | ||||
-rw-r--r-- | graphics/src/defaults.rs (renamed from glow/src/defaults.rs) | 0 | ||||
-rw-r--r-- | graphics/src/lib.rs | 15 | ||||
-rw-r--r-- | graphics/src/primitive.rs (renamed from glow/src/primitive.rs) | 0 | ||||
-rw-r--r-- | graphics/src/renderer.rs | 86 | ||||
-rw-r--r-- | graphics/src/renderer/widget.rs (renamed from wgpu/src/renderer/widget.rs) | 8 | ||||
-rw-r--r-- | graphics/src/renderer/widget/button.rs (renamed from wgpu/src/renderer/widget/button.rs) | 9 | ||||
-rw-r--r-- | graphics/src/renderer/widget/checkbox.rs (renamed from wgpu/src/renderer/widget/checkbox.rs) | 13 | ||||
-rw-r--r-- | graphics/src/renderer/widget/column.rs (renamed from glow/src/renderer/widget/column.rs) | 11 | ||||
-rw-r--r-- | graphics/src/renderer/widget/container.rs (renamed from glow/src/renderer/widget/container.rs) | 9 | ||||
-rw-r--r-- | graphics/src/renderer/widget/image.rs (renamed from wgpu/src/renderer/widget/image.rs) | 12 | ||||
-rw-r--r-- | graphics/src/renderer/widget/pane_grid.rs (renamed from glow/src/renderer/widget/pane_grid.rs) | 15 | ||||
-rw-r--r-- | graphics/src/renderer/widget/progress_bar.rs (renamed from glow/src/renderer/widget/progress_bar.rs) | 8 | ||||
-rw-r--r-- | graphics/src/renderer/widget/radio.rs (renamed from glow/src/renderer/widget/radio.rs) | 7 | ||||
-rw-r--r-- | graphics/src/renderer/widget/row.rs (renamed from wgpu/src/renderer/widget/row.rs) | 11 | ||||
-rw-r--r-- | graphics/src/renderer/widget/scrollable.rs (renamed from glow/src/renderer/widget/scrollable.rs) | 11 | ||||
-rw-r--r-- | graphics/src/renderer/widget/slider.rs (renamed from wgpu/src/renderer/widget/slider.rs) | 15 | ||||
-rw-r--r-- | graphics/src/renderer/widget/space.rs | 13 | ||||
-rw-r--r-- | graphics/src/renderer/widget/svg.rs (renamed from wgpu/src/renderer/widget/svg.rs) | 8 | ||||
-rw-r--r-- | graphics/src/renderer/widget/text.rs (renamed from glow/src/renderer/widget/text.rs) | 8 | ||||
-rw-r--r-- | graphics/src/renderer/widget/text_input.rs (renamed from wgpu/src/renderer/widget/text_input.rs) | 30 | ||||
-rw-r--r-- | graphics/src/triangle.rs | 26 | ||||
-rw-r--r-- | graphics/src/widget.rs | 49 | ||||
-rw-r--r-- | graphics/src/widget/button.rs | 16 | ||||
-rw-r--r-- | graphics/src/widget/canvas.rs | 236 | ||||
-rw-r--r-- | graphics/src/widget/canvas/cache.rs (renamed from wgpu/src/widget/canvas/cache.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/cursor.rs (renamed from wgpu/src/widget/canvas/cursor.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/event.rs (renamed from wgpu/src/widget/canvas/event.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/fill.rs (renamed from wgpu/src/widget/canvas/fill.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/frame.rs (renamed from wgpu/src/widget/canvas/frame.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/geometry.rs (renamed from wgpu/src/widget/canvas/geometry.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/path.rs (renamed from wgpu/src/widget/canvas/path.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/path/arc.rs (renamed from wgpu/src/widget/canvas/path/arc.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/path/builder.rs (renamed from wgpu/src/widget/canvas/path/builder.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/program.rs (renamed from wgpu/src/widget/canvas/program.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/stroke.rs (renamed from wgpu/src/widget/canvas/stroke.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/canvas/text.rs (renamed from wgpu/src/widget/canvas/text.rs) | 0 | ||||
-rw-r--r-- | graphics/src/widget/checkbox.rs | 10 | ||||
-rw-r--r-- | graphics/src/widget/container.rs | 11 | ||||
-rw-r--r-- | graphics/src/widget/pane_grid.rs | 25 | ||||
-rw-r--r-- | graphics/src/widget/progress_bar.rs | 15 | ||||
-rw-r--r-- | graphics/src/widget/radio.rs | 11 | ||||
-rw-r--r-- | graphics/src/widget/scrollable.rs | 13 | ||||
-rw-r--r-- | graphics/src/widget/slider.rs | 17 | ||||
-rw-r--r-- | graphics/src/widget/text.rs | 7 | ||||
-rw-r--r-- | graphics/src/widget/text_input.rs | 16 |
46 files changed, 712 insertions, 59 deletions
diff --git a/graphics/src/backend.rs b/graphics/src/backend.rs new file mode 100644 index 00000000..3fcb42f7 --- /dev/null +++ b/graphics/src/backend.rs @@ -0,0 +1,30 @@ +use iced_native::image; +use iced_native::svg; +use iced_native::{Font, Size}; + +pub trait Backend { + fn trim_measurements(&mut self) {} +} + +pub trait Text { + const ICON_FONT: Font; + const CHECKMARK_ICON: char; + + fn measure( + &self, + contents: &str, + size: f32, + font: Font, + bounds: Size, + ) -> (f32, f32); + + fn space_width(&self, size: f32) -> f32; +} + +pub trait Image { + fn dimensions(&self, handle: &image::Handle) -> (u32, u32); +} + +pub trait Svg { + fn viewport_dimensions(&self, handle: &svg::Handle) -> (u32, u32); +} diff --git a/glow/src/defaults.rs b/graphics/src/defaults.rs index 11718a87..11718a87 100644 --- a/glow/src/defaults.rs +++ b/graphics/src/defaults.rs diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs new file mode 100644 index 00000000..596f72a4 --- /dev/null +++ b/graphics/src/lib.rs @@ -0,0 +1,15 @@ +mod defaults; +mod primitive; +mod renderer; +mod widget; + +pub mod backend; +pub mod triangle; + +#[doc(no_inline)] +pub use widget::*; + +pub use backend::Backend; +pub use defaults::Defaults; +pub use primitive::Primitive; +pub use renderer::Renderer; diff --git a/glow/src/primitive.rs b/graphics/src/primitive.rs index e73227ef..e73227ef 100644 --- a/glow/src/primitive.rs +++ b/graphics/src/primitive.rs diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs new file mode 100644 index 00000000..836ed58d --- /dev/null +++ b/graphics/src/renderer.rs @@ -0,0 +1,86 @@ +mod widget; + +use crate::{Backend, Defaults, Primitive}; +use iced_native::layout::{self, Layout}; +use iced_native::mouse; +use iced_native::{Background, Color, Element, Point, Widget}; + +pub struct Renderer<B> { + backend: B, +} + +impl<B> Renderer<B> { + pub fn new(backend: B) -> Self { + Self { backend } + } + + pub fn backend(&self) -> &B { + &self.backend + } + + pub fn backend_mut(&mut self) -> &mut B { + &mut self.backend + } +} + +impl<B> iced_native::Renderer for Renderer<B> +where + B: Backend, +{ + type Output = (Primitive, mouse::Interaction); + type Defaults = Defaults; + + fn layout<'a, Message>( + &mut self, + element: &Element<'a, Message, Self>, + limits: &layout::Limits, + ) -> layout::Node { + let layout = element.layout(self, limits); + + self.backend.trim_measurements(); + + layout + } +} + +impl<B> layout::Debugger for Renderer<B> +where + B: Backend, +{ + fn explain<Message>( + &mut self, + defaults: &Defaults, + widget: &dyn Widget<Message, Self>, + layout: Layout<'_>, + cursor_position: Point, + color: Color, + ) -> Self::Output { + let (primitive, cursor) = + widget.draw(self, defaults, layout, cursor_position); + + let mut primitives = Vec::new(); + + explain_layout(layout, color, &mut primitives); + primitives.push(primitive); + + (Primitive::Group { primitives }, cursor) + } +} + +fn explain_layout( + layout: Layout<'_>, + color: Color, + primitives: &mut Vec<Primitive>, +) { + primitives.push(Primitive::Quad { + bounds: layout.bounds(), + background: Background::Color(Color::TRANSPARENT), + border_radius: 0, + border_width: 1, + border_color: [0.6, 0.6, 0.6, 0.5].into(), + }); + + for child in layout.children() { + explain_layout(child, color, primitives); + } +} diff --git a/wgpu/src/renderer/widget.rs b/graphics/src/renderer/widget.rs index 37421fbe..b652fdcf 100644 --- a/wgpu/src/renderer/widget.rs +++ b/graphics/src/renderer/widget.rs @@ -2,6 +2,7 @@ mod button; mod checkbox; mod column; mod container; +mod image; mod pane_grid; mod progress_bar; mod radio; @@ -9,11 +10,6 @@ mod row; mod scrollable; mod slider; mod space; +mod svg; mod text; mod text_input; - -#[cfg(feature = "svg")] -mod svg; - -#[cfg(feature = "image")] -mod image; diff --git a/wgpu/src/renderer/widget/button.rs b/graphics/src/renderer/widget/button.rs index eb225038..6ee60df4 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/graphics/src/renderer/widget/button.rs @@ -1,9 +1,14 @@ -use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer}; +use crate::{ + button::StyleSheet, defaults, Backend, Defaults, Primitive, Renderer, +}; use iced_native::{ mouse, Background, Color, Element, Layout, Point, Rectangle, Vector, }; -impl iced_native::button::Renderer for Renderer { +impl<B> iced_native::button::Renderer for Renderer<B> +where + B: Backend, +{ const DEFAULT_PADDING: u16 = 5; type Style = Box<dyn StyleSheet>; diff --git a/wgpu/src/renderer/widget/checkbox.rs b/graphics/src/renderer/widget/checkbox.rs index 0340bf62..75168629 100644 --- a/wgpu/src/renderer/widget/checkbox.rs +++ b/graphics/src/renderer/widget/checkbox.rs @@ -1,9 +1,14 @@ -use crate::{checkbox::StyleSheet, Primitive, Renderer}; +use crate::backend::{self, Backend}; +use crate::checkbox::StyleSheet; +use crate::{Primitive, Renderer}; use iced_native::{ checkbox, mouse, HorizontalAlignment, Rectangle, VerticalAlignment, }; -impl checkbox::Renderer for Renderer { +impl<B> checkbox::Renderer for Renderer<B> +where + B: Backend + backend::Text, +{ type Style = Box<dyn StyleSheet>; const DEFAULT_SIZE: u16 = 20; @@ -35,8 +40,8 @@ impl checkbox::Renderer for Renderer { Primitive::Group { primitives: if is_checked { let check = Primitive::Text { - content: crate::text::CHECKMARK_ICON.to_string(), - font: crate::text::BUILTIN_ICONS, + content: B::CHECKMARK_ICON.to_string(), + font: B::ICON_FONT, size: bounds.height * 0.7, bounds: Rectangle { x: bounds.center_x(), diff --git a/glow/src/renderer/widget/column.rs b/graphics/src/renderer/widget/column.rs index b853276d..b70d2338 100644 --- a/glow/src/renderer/widget/column.rs +++ b/graphics/src/renderer/widget/column.rs @@ -1,7 +1,12 @@ -use crate::{Primitive, Renderer}; -use iced_native::{column, mouse, Element, Layout, Point}; +use crate::{Backend, Primitive, Renderer}; +use iced_native::column; +use iced_native::mouse; +use iced_native::{Element, Layout, Point}; -impl column::Renderer for Renderer { +impl<B> column::Renderer for Renderer<B> +where + B: Backend, +{ fn draw<Message>( &mut self, defaults: &Self::Defaults, diff --git a/glow/src/renderer/widget/container.rs b/graphics/src/renderer/widget/container.rs index 30cc3f07..a1f6a211 100644 --- a/glow/src/renderer/widget/container.rs +++ b/graphics/src/renderer/widget/container.rs @@ -1,7 +1,12 @@ -use crate::{container, defaults, Defaults, Primitive, Renderer}; +use crate::container; +use crate::defaults::{self, Defaults}; +use crate::{Backend, Primitive, Renderer}; use iced_native::{Background, Color, Element, Layout, Point, Rectangle}; -impl iced_native::container::Renderer for Renderer { +impl<B> iced_native::container::Renderer for Renderer<B> +where + B: Backend, +{ type Style = Box<dyn container::StyleSheet>; fn draw<Message>( diff --git a/wgpu/src/renderer/widget/image.rs b/graphics/src/renderer/widget/image.rs index c4c04984..3092237f 100644 --- a/wgpu/src/renderer/widget/image.rs +++ b/graphics/src/renderer/widget/image.rs @@ -1,9 +1,15 @@ +use crate::backend::{self, Backend}; use crate::{Primitive, Renderer}; -use iced_native::{image, mouse, Layout}; +use iced_native::image; +use iced_native::mouse; +use iced_native::Layout; -impl image::Renderer for Renderer { +impl<B> image::Renderer for Renderer<B> +where + B: Backend + backend::Image, +{ fn dimensions(&self, handle: &image::Handle) -> (u32, u32) { - self.image_pipeline.dimensions(handle) + self.backend().dimensions(handle) } fn draw( diff --git a/glow/src/renderer/widget/pane_grid.rs b/graphics/src/renderer/widget/pane_grid.rs index 2253e4af..3fa171f5 100644 --- a/glow/src/renderer/widget/pane_grid.rs +++ b/graphics/src/renderer/widget/pane_grid.rs @@ -1,11 +1,12 @@ -use crate::{Primitive, Renderer}; -use iced_native::{ - mouse, - pane_grid::{self, Axis, Pane}, - Element, Layout, Point, Rectangle, Vector, -}; +use crate::{Backend, Primitive, Renderer}; +use iced_native::mouse; +use iced_native::pane_grid::{self, Axis, Pane}; +use iced_native::{Element, Layout, Point, Rectangle, Vector}; -impl pane_grid::Renderer for Renderer { +impl<B> pane_grid::Renderer for Renderer<B> +where + B: Backend, +{ fn draw<Message>( &mut self, defaults: &Self::Defaults, diff --git a/glow/src/renderer/widget/progress_bar.rs b/graphics/src/renderer/widget/progress_bar.rs index 2baeeb14..d8a145a4 100644 --- a/glow/src/renderer/widget/progress_bar.rs +++ b/graphics/src/renderer/widget/progress_bar.rs @@ -1,7 +1,11 @@ -use crate::{progress_bar::StyleSheet, Primitive, Renderer}; +use crate::progress_bar::StyleSheet; +use crate::{Backend, Primitive, Renderer}; use iced_native::{mouse, progress_bar, Color, Rectangle}; -impl progress_bar::Renderer for Renderer { +impl<B> progress_bar::Renderer for Renderer<B> +where + B: Backend, +{ type Style = Box<dyn StyleSheet>; const DEFAULT_HEIGHT: u16 = 30; diff --git a/glow/src/renderer/widget/radio.rs b/graphics/src/renderer/widget/radio.rs index cee0deb6..4da2b60a 100644 --- a/glow/src/renderer/widget/radio.rs +++ b/graphics/src/renderer/widget/radio.rs @@ -1,10 +1,13 @@ -use crate::{radio::StyleSheet, Primitive, Renderer}; +use crate::{radio::StyleSheet, Backend, Primitive, Renderer}; use iced_native::{mouse, radio, Background, Color, Rectangle}; const SIZE: f32 = 28.0; const DOT_SIZE: f32 = SIZE / 2.0; -impl radio::Renderer for Renderer { +impl<B> radio::Renderer for Renderer<B> +where + B: Backend, +{ type Style = Box<dyn StyleSheet>; const DEFAULT_SIZE: u16 = SIZE as u16; diff --git a/wgpu/src/renderer/widget/row.rs b/graphics/src/renderer/widget/row.rs index d0b7ef09..b0bb0d2e 100644 --- a/wgpu/src/renderer/widget/row.rs +++ b/graphics/src/renderer/widget/row.rs @@ -1,7 +1,12 @@ -use crate::{Primitive, Renderer}; -use iced_native::{mouse, row, Element, Layout, Point}; +use crate::{Backend, Primitive, Renderer}; +use iced_native::mouse; +use iced_native::row; +use iced_native::{Element, Layout, Point}; -impl row::Renderer for Renderer { +impl<B> row::Renderer for Renderer<B> +where + B: Backend, +{ fn draw<Message>( &mut self, defaults: &Self::Defaults, diff --git a/glow/src/renderer/widget/scrollable.rs b/graphics/src/renderer/widget/scrollable.rs index 8a400b82..8db17bec 100644 --- a/glow/src/renderer/widget/scrollable.rs +++ b/graphics/src/renderer/widget/scrollable.rs @@ -1,10 +1,15 @@ -use crate::{Primitive, Renderer}; -use iced_native::{mouse, scrollable, Background, Color, Rectangle, Vector}; +use crate::{Backend, Primitive, Renderer}; +use iced_native::mouse; +use iced_native::scrollable; +use iced_native::{Background, Color, Rectangle, Vector}; const SCROLLBAR_WIDTH: u16 = 10; const SCROLLBAR_MARGIN: u16 = 2; -impl scrollable::Renderer for Renderer { +impl<B> scrollable::Renderer for Renderer<B> +where + B: Backend, +{ type Style = Box<dyn iced_style::scrollable::StyleSheet>; fn scrollbar( diff --git a/wgpu/src/renderer/widget/slider.rs b/graphics/src/renderer/widget/slider.rs index 220feace..95c843d0 100644 --- a/wgpu/src/renderer/widget/slider.rs +++ b/graphics/src/renderer/widget/slider.rs @@ -1,12 +1,15 @@ -use crate::{ - slider::{HandleShape, StyleSheet}, - Primitive, Renderer, -}; -use iced_native::{mouse, slider, Background, Color, Point, Rectangle}; +use crate::slider::{HandleShape, StyleSheet}; +use crate::{Backend, Primitive, Renderer}; +use iced_native::mouse; +use iced_native::slider; +use iced_native::{Background, Color, Point, Rectangle}; const HANDLE_HEIGHT: f32 = 22.0; -impl slider::Renderer for Renderer { +impl<B> slider::Renderer for Renderer<B> +where + B: Backend, +{ type Style = Box<dyn StyleSheet>; fn height(&self) -> u32 { diff --git a/graphics/src/renderer/widget/space.rs b/graphics/src/renderer/widget/space.rs new file mode 100644 index 00000000..d0e82f8d --- /dev/null +++ b/graphics/src/renderer/widget/space.rs @@ -0,0 +1,13 @@ +use crate::{Backend, Primitive, Renderer}; +use iced_native::mouse; +use iced_native::space; +use iced_native::Rectangle; + +impl<B> space::Renderer for Renderer<B> +where + B: Backend, +{ + fn draw(&mut self, _bounds: Rectangle) -> Self::Output { + (Primitive::None, mouse::Interaction::default()) + } +} diff --git a/wgpu/src/renderer/widget/svg.rs b/graphics/src/renderer/widget/svg.rs index f6d6d0ba..4d80869e 100644 --- a/wgpu/src/renderer/widget/svg.rs +++ b/graphics/src/renderer/widget/svg.rs @@ -1,9 +1,13 @@ +use crate::backend::{self, Backend}; use crate::{Primitive, Renderer}; use iced_native::{mouse, svg, Layout}; -impl svg::Renderer for Renderer { +impl<B> svg::Renderer for Renderer<B> +where + B: Backend + backend::Svg, +{ fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) { - self.image_pipeline.viewport_dimensions(handle) + self.backend().viewport_dimensions(handle) } fn draw( diff --git a/glow/src/renderer/widget/text.rs b/graphics/src/renderer/widget/text.rs index 4605ed06..45cb1be2 100644 --- a/glow/src/renderer/widget/text.rs +++ b/graphics/src/renderer/widget/text.rs @@ -1,3 +1,4 @@ +use crate::backend::{self, Backend}; use crate::{Primitive, Renderer}; use iced_native::{ mouse, text, Color, Font, HorizontalAlignment, Rectangle, Size, @@ -6,7 +7,10 @@ use iced_native::{ use std::f32; -impl text::Renderer for Renderer { +impl<B> text::Renderer for Renderer<B> +where + B: Backend + backend::Text, +{ type Font = Font; const DEFAULT_SIZE: u16 = 20; @@ -18,7 +22,7 @@ impl text::Renderer for Renderer { font: Font, bounds: Size, ) -> (f32, f32) { - self.text_pipeline + self.backend() .measure(content, f32::from(size), font, bounds) } diff --git a/wgpu/src/renderer/widget/text_input.rs b/graphics/src/renderer/widget/text_input.rs index 57be6692..33807b0f 100644 --- a/wgpu/src/renderer/widget/text_input.rs +++ b/graphics/src/renderer/widget/text_input.rs @@ -1,4 +1,6 @@ -use crate::{text_input::StyleSheet, Primitive, Renderer}; +use crate::backend::{self, Backend}; +use crate::text_input::StyleSheet; +use crate::{Primitive, Renderer}; use iced_native::{ mouse, @@ -8,7 +10,10 @@ use iced_native::{ }; use std::f32; -impl text_input::Renderer for Renderer { +impl<B> text_input::Renderer for Renderer<B> +where + B: Backend + backend::Text, +{ type Style = Box<dyn StyleSheet>; fn default_size(&self) -> u16 { @@ -17,17 +22,15 @@ impl text_input::Renderer for Renderer { } fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 { - let (mut width, _) = self.text_pipeline.measure( - value, - f32::from(size), - font, - Size::INFINITY, - ); + let backend = self.backend(); + + let (mut width, _) = + backend.measure(value, f32::from(size), font, Size::INFINITY); let spaces_around = value.len() - value.trim().len(); if spaces_around > 0 { - let space_width = self.text_pipeline.space_width(size as f32); + let space_width = backend.space_width(size as f32); width += spaces_around as f32 * space_width; } @@ -241,14 +244,17 @@ impl text_input::Renderer for Renderer { } } -fn measure_cursor_and_scroll_offset( - renderer: &Renderer, +fn measure_cursor_and_scroll_offset<B>( + renderer: &Renderer<B>, text_bounds: Rectangle, value: &text_input::Value, size: u16, cursor_index: usize, font: Font, -) -> (f32, f32) { +) -> (f32, f32) +where + B: Backend + backend::Text, +{ use iced_native::text_input::Renderer; let text_before_cursor = value.until(cursor_index).to_string(); diff --git a/graphics/src/triangle.rs b/graphics/src/triangle.rs new file mode 100644 index 00000000..2b157e3a --- /dev/null +++ b/graphics/src/triangle.rs @@ -0,0 +1,26 @@ +/// 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<Vertex2D>, + /// 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<u32>, +} + +/// A two-dimensional vertex with some color in __linear__ RGBA. +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct Vertex2D { + /// The vertex position + pub position: [f32; 2], + /// The vertex color in __linear__ RGBA. + pub color: [f32; 4], +} + +unsafe impl bytemuck::Zeroable for Vertex2D {} +unsafe impl bytemuck::Pod for Vertex2D {} diff --git a/graphics/src/widget.rs b/graphics/src/widget.rs new file mode 100644 index 00000000..6a8e814b --- /dev/null +++ b/graphics/src/widget.rs @@ -0,0 +1,49 @@ +//! Use the widgets supported out-of-the-box. +//! +//! # Re-exports +//! For convenience, the contents of this module are available at the root +//! module. Therefore, you can directly type: +//! +//! ``` +//! use iced_graphics::{button, Button}; +//! ``` +pub mod button; +pub mod checkbox; +pub mod container; +pub mod pane_grid; +pub mod progress_bar; +pub mod radio; +pub mod scrollable; +pub mod slider; +pub mod text_input; + +mod text; + +#[doc(no_inline)] +pub use button::Button; +#[doc(no_inline)] +pub use checkbox::Checkbox; +#[doc(no_inline)] +pub use container::Container; +#[doc(no_inline)] +pub use pane_grid::PaneGrid; +#[doc(no_inline)] +pub use progress_bar::ProgressBar; +#[doc(no_inline)] +pub use radio::Radio; +#[doc(no_inline)] +pub use scrollable::Scrollable; +#[doc(no_inline)] +pub use slider::Slider; +#[doc(no_inline)] +pub use text_input::TextInput; + +pub use text::Text; + +#[cfg(feature = "canvas")] +#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))] +pub mod canvas; + +#[cfg(feature = "canvas")] +#[doc(no_inline)] +pub use canvas::Canvas; diff --git a/graphics/src/widget/button.rs b/graphics/src/widget/button.rs new file mode 100644 index 00000000..9debf5c3 --- /dev/null +++ b/graphics/src/widget/button.rs @@ -0,0 +1,16 @@ +//! Allow your users to perform actions by pressing a button. +//! +//! A [`Button`] has some local [`State`]. +//! +//! [`Button`]: type.Button.html +//! [`State`]: struct.State.html +use crate::Renderer; + +pub use iced_native::button::State; +pub use iced_style::button::{Style, StyleSheet}; + +/// A widget that produces a message when clicked. +/// +/// This is an alias of an `iced_native` button with an `iced_wgpu::Renderer`. +pub type Button<'a, Message, Backend> = + iced_native::Button<'a, Message, Renderer<Backend>>; diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs new file mode 100644 index 00000000..d393a5c5 --- /dev/null +++ b/graphics/src/widget/canvas.rs @@ -0,0 +1,236 @@ +//! Draw 2D graphics for your users. +//! +//! A [`Canvas`] widget can be used to draw different kinds of 2D shapes in a +//! [`Frame`]. It can be used for animation, data visualization, game graphics, +//! and more! +//! +//! [`Canvas`]: struct.Canvas.html +//! [`Frame`]: struct.Frame.html +use crate::{Backend, Defaults, Primitive, Renderer}; +use iced_native::{ + layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point, Size, + Vector, Widget, +}; +use std::hash::Hash; +use std::marker::PhantomData; + +pub mod path; + +mod cache; +mod cursor; +mod event; +mod fill; +mod frame; +mod geometry; +mod program; +mod stroke; +mod text; + +pub use cache::Cache; +pub use cursor::Cursor; +pub use event::Event; +pub use fill::Fill; +pub use frame::Frame; +pub use geometry::Geometry; +pub use path::Path; +pub use program::Program; +pub use stroke::{LineCap, LineJoin, Stroke}; +pub use text::Text; + +/// A widget capable of drawing 2D graphics. +/// +/// [`Canvas`]: struct.Canvas.html +/// +/// # Examples +/// The repository has a couple of [examples] showcasing how to use a +/// [`Canvas`]: +/// +/// - [`clock`], an application that uses the [`Canvas`] widget to draw a clock +/// and its hands to display the current time. +/// - [`game_of_life`], an interactive version of the Game of Life, invented by +/// John Conway. +/// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget +/// and showcasing how to compose different transforms. +/// +/// [examples]: https://github.com/hecrj/iced/tree/master/examples +/// [`clock`]: https://github.com/hecrj/iced/tree/master/examples/clock +/// [`game_of_life`]: https://github.com/hecrj/iced/tree/master/examples/game_of_life +/// [`solar_system`]: https://github.com/hecrj/iced/tree/master/examples/solar_system +/// +/// ## Drawing a simple circle +/// If you want to get a quick overview, here's how we can draw a simple circle: +/// +/// ```no_run +/// # mod iced { +/// # pub use iced_graphics::canvas; +/// # pub use iced_native::{Color, Rectangle}; +/// # } +/// use iced::canvas::{self, Canvas, Cursor, Fill, Frame, Geometry, Path, Program}; +/// use iced::{Color, Rectangle}; +/// +/// // First, we define the data we need for drawing +/// #[derive(Debug)] +/// struct Circle { +/// radius: f32, +/// } +/// +/// // Then, we implement the `Program` trait +/// impl Program<()> for Circle { +/// fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec<Geometry>{ +/// // We prepare a new `Frame` +/// let mut frame = Frame::new(bounds.size()); +/// +/// // We create a `Path` representing a simple circle +/// let circle = Path::circle(frame.center(), self.radius); +/// +/// // And fill it with some color +/// frame.fill(&circle, Fill::Color(Color::BLACK)); +/// +/// // Finally, we produce the geometry +/// vec![frame.into_geometry()] +/// } +/// } +/// +/// // Finally, we simply use our `Circle` to create the `Canvas`! +/// let canvas = Canvas::new(Circle { radius: 50.0 }); +/// ``` +#[derive(Debug)] +pub struct Canvas<Message, P: Program<Message>> { + width: Length, + height: Length, + program: P, + phantom: PhantomData<Message>, +} + +impl<Message, P: Program<Message>> Canvas<Message, P> { + const DEFAULT_SIZE: u16 = 100; + + /// Creates a new [`Canvas`]. + /// + /// [`Canvas`]: struct.Canvas.html + pub fn new(program: P) -> Self { + Canvas { + width: Length::Units(Self::DEFAULT_SIZE), + height: Length::Units(Self::DEFAULT_SIZE), + program, + phantom: PhantomData, + } + } + + /// Sets the width of the [`Canvas`]. + /// + /// [`Canvas`]: struct.Canvas.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Canvas`]. + /// + /// [`Canvas`]: struct.Canvas.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } +} + +impl<Message, P, B> Widget<Message, Renderer<B>> for Canvas<Message, P> +where + P: Program<Message>, + B: Backend, +{ + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + self.height + } + + fn layout( + &self, + _renderer: &Renderer<B>, + limits: &layout::Limits, + ) -> layout::Node { + let limits = limits.width(self.width).height(self.height); + let size = limits.resolve(Size::ZERO); + + layout::Node::new(size) + } + + fn on_event( + &mut self, + event: iced_native::Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec<Message>, + _renderer: &Renderer<B>, + _clipboard: Option<&dyn Clipboard>, + ) { + let bounds = layout.bounds(); + + let canvas_event = match event { + iced_native::Event::Mouse(mouse_event) => { + Some(Event::Mouse(mouse_event)) + } + _ => None, + }; + + let cursor = Cursor::from_window_position(cursor_position); + + if let Some(canvas_event) = canvas_event { + if let Some(message) = + self.program.update(canvas_event, bounds, cursor) + { + messages.push(message); + } + } + } + + fn draw( + &self, + _renderer: &mut Renderer<B>, + _defaults: &Defaults, + layout: Layout<'_>, + cursor_position: Point, + ) -> (Primitive, mouse::Interaction) { + let bounds = layout.bounds(); + let translation = Vector::new(bounds.x, bounds.y); + let cursor = Cursor::from_window_position(cursor_position); + + ( + Primitive::Translate { + translation, + content: Box::new(Primitive::Group { + primitives: self + .program + .draw(bounds, cursor) + .into_iter() + .map(Geometry::into_primitive) + .collect(), + }), + }, + self.program.mouse_interaction(bounds, cursor), + ) + } + + fn hash_layout(&self, state: &mut Hasher) { + struct Marker; + std::any::TypeId::of::<Marker>().hash(state); + + self.width.hash(state); + self.height.hash(state); + } +} + +impl<'a, Message, P, B> From<Canvas<Message, P>> + for Element<'a, Message, Renderer<B>> +where + Message: 'static, + P: Program<Message> + 'a, + B: Backend, +{ + fn from(canvas: Canvas<Message, P>) -> Element<'a, Message, Renderer<B>> { + Element::new(canvas) + } +} diff --git a/wgpu/src/widget/canvas/cache.rs b/graphics/src/widget/canvas/cache.rs index 4b28d164..4b28d164 100644 --- a/wgpu/src/widget/canvas/cache.rs +++ b/graphics/src/widget/canvas/cache.rs diff --git a/wgpu/src/widget/canvas/cursor.rs b/graphics/src/widget/canvas/cursor.rs index 456760ea..456760ea 100644 --- a/wgpu/src/widget/canvas/cursor.rs +++ b/graphics/src/widget/canvas/cursor.rs diff --git a/wgpu/src/widget/canvas/event.rs b/graphics/src/widget/canvas/event.rs index ad11f51e..ad11f51e 100644 --- a/wgpu/src/widget/canvas/event.rs +++ b/graphics/src/widget/canvas/event.rs diff --git a/wgpu/src/widget/canvas/fill.rs b/graphics/src/widget/canvas/fill.rs index a2010e45..a2010e45 100644 --- a/wgpu/src/widget/canvas/fill.rs +++ b/graphics/src/widget/canvas/fill.rs diff --git a/wgpu/src/widget/canvas/frame.rs b/graphics/src/widget/canvas/frame.rs index 5262ab4e..5262ab4e 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/graphics/src/widget/canvas/frame.rs diff --git a/wgpu/src/widget/canvas/geometry.rs b/graphics/src/widget/canvas/geometry.rs index 4cadee39..4cadee39 100644 --- a/wgpu/src/widget/canvas/geometry.rs +++ b/graphics/src/widget/canvas/geometry.rs diff --git a/wgpu/src/widget/canvas/path.rs b/graphics/src/widget/canvas/path.rs index c26bf187..c26bf187 100644 --- a/wgpu/src/widget/canvas/path.rs +++ b/graphics/src/widget/canvas/path.rs diff --git a/wgpu/src/widget/canvas/path/arc.rs b/graphics/src/widget/canvas/path/arc.rs index 343191f1..343191f1 100644 --- a/wgpu/src/widget/canvas/path/arc.rs +++ b/graphics/src/widget/canvas/path/arc.rs diff --git a/wgpu/src/widget/canvas/path/builder.rs b/graphics/src/widget/canvas/path/builder.rs index 6511fa52..6511fa52 100644 --- a/wgpu/src/widget/canvas/path/builder.rs +++ b/graphics/src/widget/canvas/path/builder.rs diff --git a/wgpu/src/widget/canvas/program.rs b/graphics/src/widget/canvas/program.rs index 725d9d72..725d9d72 100644 --- a/wgpu/src/widget/canvas/program.rs +++ b/graphics/src/widget/canvas/program.rs diff --git a/wgpu/src/widget/canvas/stroke.rs b/graphics/src/widget/canvas/stroke.rs index 5b6fc56a..5b6fc56a 100644 --- a/wgpu/src/widget/canvas/stroke.rs +++ b/graphics/src/widget/canvas/stroke.rs diff --git a/wgpu/src/widget/canvas/text.rs b/graphics/src/widget/canvas/text.rs index c4cae30e..c4cae30e 100644 --- a/wgpu/src/widget/canvas/text.rs +++ b/graphics/src/widget/canvas/text.rs diff --git a/graphics/src/widget/checkbox.rs b/graphics/src/widget/checkbox.rs new file mode 100644 index 00000000..3c8b58de --- /dev/null +++ b/graphics/src/widget/checkbox.rs @@ -0,0 +1,10 @@ +//! Show toggle controls using checkboxes. +use crate::Renderer; + +pub use iced_style::checkbox::{Style, StyleSheet}; + +/// A box that can be checked. +/// +/// This is an alias of an `iced_native` checkbox with an `iced_wgpu::Renderer`. +pub type Checkbox<Message, Backend> = + iced_native::Checkbox<Message, Renderer<Backend>>; diff --git a/graphics/src/widget/container.rs b/graphics/src/widget/container.rs new file mode 100644 index 00000000..c4c4e5ba --- /dev/null +++ b/graphics/src/widget/container.rs @@ -0,0 +1,11 @@ +//! Decorate content and apply alignment. +use crate::Renderer; + +pub use iced_style::container::{Style, StyleSheet}; + +/// An element decorating some content. +/// +/// This is an alias of an `iced_native` container with a default +/// `Renderer`. +pub type Container<'a, Message, Backend> = + iced_native::Container<'a, Message, Renderer<Backend>>; diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs new file mode 100644 index 00000000..34be8ee7 --- /dev/null +++ b/graphics/src/widget/pane_grid.rs @@ -0,0 +1,25 @@ +//! Let your users split regions of your application and organize layout dynamically. +//! +//! [](https://gfycat.com/mixedflatjellyfish) +//! +//! # Example +//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, +//! drag and drop, and hotkey support. +//! +//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.1/examples/pane_grid +//! [`PaneGrid`]: type.PaneGrid.html +use crate::Renderer; + +pub use iced_native::pane_grid::{ + Axis, Direction, DragEvent, Focus, KeyPressEvent, Pane, ResizeEvent, Split, + State, +}; + +/// A collection of panes distributed using either vertical or horizontal splits +/// to completely fill the space available. +/// +/// [](https://gfycat.com/mixedflatjellyfish) +/// +/// This is an alias of an `iced_native` pane grid with an `iced_wgpu::Renderer`. +pub type PaneGrid<'a, Message, Backend> = + iced_native::PaneGrid<'a, Message, Renderer<Backend>>; diff --git a/graphics/src/widget/progress_bar.rs b/graphics/src/widget/progress_bar.rs new file mode 100644 index 00000000..c1e5702e --- /dev/null +++ b/graphics/src/widget/progress_bar.rs @@ -0,0 +1,15 @@ +//! Allow your users to visually track the progress of a computation. +//! +//! A [`ProgressBar`] has a range of possible values and a current value, +//! as well as a length, height and style. +//! +//! [`ProgressBar`]: type.ProgressBar.html +use crate::Renderer; + +pub use iced_style::progress_bar::{Style, StyleSheet}; + +/// A bar that displays progress. +/// +/// This is an alias of an `iced_native` progress bar with an +/// `iced_wgpu::Renderer`. +pub type ProgressBar<Backend> = iced_native::ProgressBar<Renderer<Backend>>; diff --git a/graphics/src/widget/radio.rs b/graphics/src/widget/radio.rs new file mode 100644 index 00000000..c621a26a --- /dev/null +++ b/graphics/src/widget/radio.rs @@ -0,0 +1,11 @@ +//! Create choices using radio buttons. +use crate::Renderer; + +pub use iced_style::radio::{Style, StyleSheet}; + +/// A circular button representing a choice. +/// +/// This is an alias of an `iced_native` radio button with an +/// `iced_wgpu::Renderer`. +pub type Radio<Message, Backend> = + iced_native::Radio<Message, Renderer<Backend>>; diff --git a/graphics/src/widget/scrollable.rs b/graphics/src/widget/scrollable.rs new file mode 100644 index 00000000..61eae587 --- /dev/null +++ b/graphics/src/widget/scrollable.rs @@ -0,0 +1,13 @@ +//! Navigate an endless amount of content with a scrollbar. +use crate::Renderer; + +pub use iced_native::scrollable::State; +pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; + +/// A widget that can vertically display an infinite amount of content +/// with a scrollbar. +/// +/// This is an alias of an `iced_native` scrollable with a default +/// `Renderer`. +pub type Scrollable<'a, Message, Backend> = + iced_native::Scrollable<'a, Message, Renderer<Backend>>; diff --git a/graphics/src/widget/slider.rs b/graphics/src/widget/slider.rs new file mode 100644 index 00000000..035c7c41 --- /dev/null +++ b/graphics/src/widget/slider.rs @@ -0,0 +1,17 @@ +//! 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::Renderer; + +pub use iced_native::slider::State; +pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; + +/// An horizontal bar and a handle that selects a single value from a range of +/// values. +/// +/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. +pub type Slider<'a, Message, Backend> = + iced_native::Slider<'a, Message, Renderer<Backend>>; diff --git a/graphics/src/widget/text.rs b/graphics/src/widget/text.rs new file mode 100644 index 00000000..ec0349f9 --- /dev/null +++ b/graphics/src/widget/text.rs @@ -0,0 +1,7 @@ +//! Write some text for your users to read. +use crate::Renderer; + +/// A paragraph of text. +/// +/// This is an alias of an `iced_native` text with an `iced_wgpu::Renderer`. +pub type Text<Backend> = iced_native::Text<Renderer<Backend>>; diff --git a/graphics/src/widget/text_input.rs b/graphics/src/widget/text_input.rs new file mode 100644 index 00000000..8015626b --- /dev/null +++ b/graphics/src/widget/text_input.rs @@ -0,0 +1,16 @@ +//! Display fields that can be filled with text. +//! +//! A [`TextInput`] has some local [`State`]. +//! +//! [`TextInput`]: struct.TextInput.html +//! [`State`]: struct.State.html +use crate::Renderer; + +pub use iced_native::text_input::State; +pub use iced_style::text_input::{Style, StyleSheet}; + +/// A field that can be filled with text. +/// +/// This is an alias of an `iced_native` text input with an `iced_wgpu::Renderer`. +pub type TextInput<'a, Message, Backend> = + iced_native::TextInput<'a, Message, Renderer<Backend>>; |