summaryrefslogtreecommitdiffstats
path: root/wgpu
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-29 02:00:28 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-29 02:00:28 +0200
commit0cde20b3550ede81bc7ddef628b91eec225aa8af (patch)
tree56920437979012cceb49718f2dd4ce27d5ba5d40 /wgpu
parent67b6f044e870df41be92cdc79f571682b97a5d0d (diff)
parente11b5c614f5bf73c137b8b4f24f56047617527eb (diff)
downloadiced-0cde20b3550ede81bc7ddef628b91eec225aa8af.tar.gz
iced-0cde20b3550ede81bc7ddef628b91eec225aa8af.tar.bz2
iced-0cde20b3550ede81bc7ddef628b91eec225aa8af.zip
Merge branch 'master' into improvement/update-wgpu_glyph
Diffstat (limited to 'wgpu')
-rw-r--r--wgpu/Cargo.toml15
-rw-r--r--wgpu/fonts/Lato-Regular.ttfbin75136 -> 0 bytes
-rw-r--r--wgpu/fonts/OFL.txt93
-rw-r--r--wgpu/src/backend.rs276
-rw-r--r--wgpu/src/defaults.rs32
-rw-r--r--wgpu/src/image.rs57
-rw-r--r--wgpu/src/lib.rs23
-rw-r--r--wgpu/src/primitive.rs107
-rw-r--r--wgpu/src/quad.rs30
-rw-r--r--wgpu/src/renderer.rs524
-rw-r--r--wgpu/src/renderer/widget.rs19
-rw-r--r--wgpu/src/renderer/widget/button.rs93
-rw-r--r--wgpu/src/renderer/widget/checkbox.rs63
-rw-r--r--wgpu/src/renderer/widget/column.rs34
-rw-r--r--wgpu/src/renderer/widget/container.rs48
-rw-r--r--wgpu/src/renderer/widget/image.rs22
-rw-r--r--wgpu/src/renderer/widget/pane_grid.rs93
-rw-r--r--wgpu/src/renderer/widget/progress_bar.rs54
-rw-r--r--wgpu/src/renderer/widget/radio.rs63
-rw-r--r--wgpu/src/renderer/widget/row.rs34
-rw-r--r--wgpu/src/renderer/widget/scrollable.rs125
-rw-r--r--wgpu/src/renderer/widget/slider.rs106
-rw-r--r--wgpu/src/renderer/widget/space.rs8
-rw-r--r--wgpu/src/renderer/widget/svg.rs22
-rw-r--r--wgpu/src/renderer/widget/text.rs61
-rw-r--r--wgpu/src/renderer/widget/text_input.rs254
-rw-r--r--wgpu/src/settings.rs29
-rw-r--r--wgpu/src/target.rs14
-rw-r--r--wgpu/src/text.rs21
-rw-r--r--wgpu/src/text/font.rs37
-rw-r--r--wgpu/src/text/icons.ttfbin4912 -> 0 bytes
-rw-r--r--wgpu/src/transformation.rs54
-rw-r--r--wgpu/src/triangle.rs70
-rw-r--r--wgpu/src/viewport.rs29
-rw-r--r--wgpu/src/widget.rs17
-rw-r--r--wgpu/src/widget/button.rs2
-rw-r--r--wgpu/src/widget/canvas.rs226
-rw-r--r--wgpu/src/widget/canvas/cache.rs108
-rw-r--r--wgpu/src/widget/canvas/cursor.rs72
-rw-r--r--wgpu/src/widget/canvas/event.rs10
-rw-r--r--wgpu/src/widget/canvas/fill.rs20
-rw-r--r--wgpu/src/widget/canvas/frame.rs367
-rw-r--r--wgpu/src/widget/canvas/geometry.rs34
-rw-r--r--wgpu/src/widget/canvas/path.rs79
-rw-r--r--wgpu/src/widget/canvas/path/arc.rs44
-rw-r--r--wgpu/src/widget/canvas/path/builder.rs180
-rw-r--r--wgpu/src/widget/canvas/program.rs85
-rw-r--r--wgpu/src/widget/canvas/stroke.rs115
-rw-r--r--wgpu/src/widget/canvas/text.rs49
-rw-r--r--wgpu/src/widget/checkbox.rs2
-rw-r--r--wgpu/src/widget/container.rs2
-rw-r--r--wgpu/src/widget/progress_bar.rs2
-rw-r--r--wgpu/src/widget/radio.rs2
-rw-r--r--wgpu/src/widget/scrollable.rs2
-rw-r--r--wgpu/src/widget/slider.rs2
-rw-r--r--wgpu/src/widget/text.rs7
-rw-r--r--wgpu/src/widget/text_input.rs2
-rw-r--r--wgpu/src/window.rs6
-rw-r--r--wgpu/src/window/compositor.rs (renamed from wgpu/src/window/backend.rs)44
-rw-r--r--wgpu/src/window/swap_chain.rs61
60 files changed, 415 insertions, 3635 deletions
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index 5f86972d..3bbc57a0 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -9,16 +9,16 @@ repository = "https://github.com/hecrj/iced"
[features]
svg = ["resvg"]
-canvas = ["lyon"]
+canvas = ["iced_graphics/canvas"]
[dependencies]
wgpu = "0.5"
wgpu_glyph = "0.9"
-zerocopy = "0.3"
glyph_brush = "0.7"
+zerocopy = "0.3"
+bytemuck = "1.2"
raw-window-handle = "0.3"
glam = "0.8"
-font-kit = "0.6"
log = "0.4"
guillotiere = "0.5"
# Pin `gfx-memory` until https://github.com/gfx-rs/wgpu-rs/issues/261 is
@@ -29,9 +29,10 @@ gfx-memory = "=0.1.1"
version = "0.2"
path = "../native"
-[dependencies.iced_style]
+[dependencies.iced_graphics]
version = "0.1"
-path = "../style"
+path = "../graphics"
+features = ["font-source", "font-fallback", "font-icons"]
[dependencies.image]
version = "0.23"
@@ -42,10 +43,6 @@ version = "0.9"
features = ["raqote-backend"]
optional = true
-[dependencies.lyon]
-version = "0.15"
-optional = true
-
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
all-features = true
diff --git a/wgpu/fonts/Lato-Regular.ttf b/wgpu/fonts/Lato-Regular.ttf
deleted file mode 100644
index 33eba8b1..00000000
--- a/wgpu/fonts/Lato-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/wgpu/fonts/OFL.txt b/wgpu/fonts/OFL.txt
deleted file mode 100644
index dfca0da4..00000000
--- a/wgpu/fonts/OFL.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name "Lato"
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
new file mode 100644
index 00000000..29fc8677
--- /dev/null
+++ b/wgpu/src/backend.rs
@@ -0,0 +1,276 @@
+use crate::quad;
+use crate::text;
+use crate::triangle;
+use crate::{Settings, Transformation};
+use iced_graphics::backend;
+use iced_graphics::font;
+use iced_graphics::layer::Layer;
+use iced_graphics::{Primitive, Viewport};
+use iced_native::mouse;
+use iced_native::{Font, HorizontalAlignment, Size, VerticalAlignment};
+
+#[cfg(any(feature = "image", feature = "svg"))]
+use crate::image;
+
+/// A [`wgpu`] graphics backend for [`iced`].
+///
+/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
+/// [`iced`]: https://github.com/hecrj/iced
+#[derive(Debug)]
+pub struct Backend {
+ quad_pipeline: quad::Pipeline,
+ text_pipeline: text::Pipeline,
+ triangle_pipeline: triangle::Pipeline,
+
+ #[cfg(any(feature = "image", feature = "svg"))]
+ image_pipeline: image::Pipeline,
+}
+
+impl Backend {
+ /// Creates a new [`Renderer`].
+ ///
+ /// [`Renderer`]: struct.Renderer.html
+ pub fn new(device: &wgpu::Device, settings: Settings) -> Self {
+ let text_pipeline =
+ text::Pipeline::new(device, settings.format, settings.default_font);
+ let quad_pipeline = quad::Pipeline::new(device, settings.format);
+ let triangle_pipeline = triangle::Pipeline::new(
+ device,
+ settings.format,
+ settings.antialiasing,
+ );
+
+ #[cfg(any(feature = "image", feature = "svg"))]
+ let image_pipeline = image::Pipeline::new(device, settings.format);
+
+ Self {
+ quad_pipeline,
+ text_pipeline,
+ triangle_pipeline,
+
+ #[cfg(any(feature = "image", feature = "svg"))]
+ image_pipeline,
+ }
+ }
+
+ /// Draws the provided primitives in the given [`Target`].
+ ///
+ /// The text provided as overlay will be renderer on top of the primitives.
+ /// This is useful for rendering debug information.
+ ///
+ /// [`Target`]: struct.Target.html
+ pub fn draw<T: AsRef<str>>(
+ &mut self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ frame: &wgpu::TextureView,
+ viewport: &Viewport,
+ (primitive, mouse_interaction): &(Primitive, mouse::Interaction),
+ overlay_text: &[T],
+ ) -> mouse::Interaction {
+ log::debug!("Drawing");
+
+ let target_size = viewport.physical_size();
+ let scale_factor = viewport.scale_factor() as f32;
+ let transformation = viewport.projection();
+
+ let mut layers = Layer::generate(primitive, viewport);
+ layers.push(Layer::overlay(overlay_text, viewport));
+
+ for layer in layers {
+ self.flush(
+ device,
+ scale_factor,
+ transformation,
+ &layer,
+ encoder,
+ &frame,
+ target_size.width,
+ target_size.height,
+ );
+ }
+
+ #[cfg(any(feature = "image", feature = "svg"))]
+ self.image_pipeline.trim_cache();
+
+ *mouse_interaction
+ }
+
+ fn flush(
+ &mut self,
+ device: &wgpu::Device,
+ scale_factor: f32,
+ transformation: Transformation,
+ layer: &Layer<'_>,
+ encoder: &mut wgpu::CommandEncoder,
+ target: &wgpu::TextureView,
+ target_width: u32,
+ target_height: u32,
+ ) {
+ let bounds = (layer.bounds * scale_factor).round();
+
+ if !layer.quads.is_empty() {
+ self.quad_pipeline.draw(
+ device,
+ encoder,
+ &layer.quads,
+ transformation,
+ scale_factor,
+ bounds,
+ target,
+ );
+ }
+
+ if !layer.meshes.is_empty() {
+ let scaled = transformation
+ * Transformation::scale(scale_factor, scale_factor);
+
+ self.triangle_pipeline.draw(
+ device,
+ encoder,
+ target,
+ target_width,
+ target_height,
+ scaled,
+ scale_factor,
+ &layer.meshes,
+ );
+ }
+
+ #[cfg(any(feature = "image", feature = "svg"))]
+ {
+ if !layer.images.is_empty() {
+ let scaled = transformation
+ * Transformation::scale(scale_factor, scale_factor);
+
+ self.image_pipeline.draw(
+ device,
+ encoder,
+ &layer.images,
+ scaled,
+ bounds,
+ target,
+ scale_factor,
+ );
+ }
+ }
+
+ if !layer.text.is_empty() {
+ for text in layer.text.iter() {
+ // Target physical coordinates directly to avoid blurry text
+ let text = wgpu_glyph::Section {
+ // TODO: We `round` here to avoid rerasterizing text when
+ // its position changes slightly. This can make text feel a
+ // bit "jumpy". We may be able to do better once we improve
+ // our text rendering/caching pipeline.
+ screen_position: (
+ (text.bounds.x * scale_factor).round(),
+ (text.bounds.y * scale_factor).round(),
+ ),
+ // TODO: Fix precision issues with some scale factors.
+ //
+ // The `ceil` here can cause some words to render on the
+ // same line when they should not.
+ //
+ // Ideally, `wgpu_glyph` should be able to compute layout
+ // using logical positions, and then apply the proper
+ // scaling when rendering. This would ensure that both
+ // measuring and rendering follow the same layout rules.
+ bounds: (
+ (text.bounds.width * scale_factor).ceil(),
+ (text.bounds.height * scale_factor).ceil(),
+ ),
+ text: vec![wgpu_glyph::Text {
+ text: text.content,
+ scale: wgpu_glyph::ab_glyph::PxScale {
+ x: text.size * scale_factor,
+ y: text.size * scale_factor,
+ },
+ font_id: self.text_pipeline.find_font(text.font),
+ extra: wgpu_glyph::Extra {
+ color: text.color,
+ z: 0.0,
+ },
+ }],
+ layout: wgpu_glyph::Layout::default()
+ .h_align(match text.horizontal_alignment {
+ HorizontalAlignment::Left => {
+ wgpu_glyph::HorizontalAlign::Left
+ }
+ HorizontalAlignment::Center => {
+ wgpu_glyph::HorizontalAlign::Center
+ }
+ HorizontalAlignment::Right => {
+ wgpu_glyph::HorizontalAlign::Right
+ }
+ })
+ .v_align(match text.vertical_alignment {
+ VerticalAlignment::Top => {
+ wgpu_glyph::VerticalAlign::Top
+ }
+ VerticalAlignment::Center => {
+ wgpu_glyph::VerticalAlign::Center
+ }
+ VerticalAlignment::Bottom => {
+ wgpu_glyph::VerticalAlign::Bottom
+ }
+ }),
+ ..Default::default()
+ };
+
+ self.text_pipeline.queue(text);
+ }
+
+ self.text_pipeline.draw_queued(
+ device,
+ encoder,
+ target,
+ transformation,
+ wgpu_glyph::Region {
+ x: bounds.x,
+ y: bounds.y,
+ width: bounds.width,
+ height: bounds.height,
+ },
+ );
+ }
+ }
+}
+
+impl iced_graphics::Backend for Backend {
+ fn trim_measurements(&mut self) {
+ self.text_pipeline.trim_measurement_cache()
+ }
+}
+
+impl backend::Text for Backend {
+ const ICON_FONT: Font = font::ICONS;
+ const CHECKMARK_ICON: char = font::CHECKMARK_ICON;
+
+ fn measure(
+ &self,
+ contents: &str,
+ size: f32,
+ font: Font,
+ bounds: Size,
+ ) -> (f32, f32) {
+ self.text_pipeline.measure(contents, size, font, bounds)
+ }
+}
+
+#[cfg(feature = "image")]
+impl backend::Image for Backend {
+ fn dimensions(&self, handle: &iced_native::image::Handle) -> (u32, u32) {
+ self.image_pipeline.dimensions(handle)
+ }
+}
+
+#[cfg(feature = "svg")]
+impl backend::Svg for Backend {
+ fn viewport_dimensions(
+ &self,
+ handle: &iced_native::svg::Handle,
+ ) -> (u32, u32) {
+ self.image_pipeline.viewport_dimensions(handle)
+ }
+}
diff --git a/wgpu/src/defaults.rs b/wgpu/src/defaults.rs
deleted file mode 100644
index 11718a87..00000000
--- a/wgpu/src/defaults.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//! Use default styling attributes to inherit styles.
-use iced_native::Color;
-
-/// Some default styling attributes.
-#[derive(Debug, Clone, Copy)]
-pub struct Defaults {
- /// Text styling
- pub text: Text,
-}
-
-impl Default for Defaults {
- fn default() -> Defaults {
- Defaults {
- text: Text::default(),
- }
- }
-}
-
-/// Some default text styling attributes.
-#[derive(Debug, Clone, Copy)]
-pub struct Text {
- /// The default color of text
- pub color: Color,
-}
-
-impl Default for Text {
- fn default() -> Text {
- Text {
- color: Color::BLACK,
- }
- }
-}
diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index ea5dc09d..49f1d29c 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -9,6 +9,7 @@ mod vector;
use crate::Transformation;
use atlas::Atlas;
+use iced_graphics::layer;
use iced_native::Rectangle;
use std::cell::RefCell;
use std::mem;
@@ -282,7 +283,7 @@ impl Pipeline {
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
- images: &[Image],
+ images: &[layer::Image],
transformation: Transformation,
bounds: Rectangle<u32>,
target: &wgpu::TextureView,
@@ -297,31 +298,48 @@ impl Pipeline {
let mut vector_cache = self.vector_cache.borrow_mut();
for image in images {
- match &image.handle {
+ match &image {
#[cfg(feature = "image")]
- Handle::Raster(handle) => {
+ layer::Image::Raster { handle, bounds } => {
if let Some(atlas_entry) = raster_cache.upload(
handle,
device,
encoder,
&mut self.texture_atlas,
) {
- add_instances(image, atlas_entry, instances);
+ add_instances(
+ [bounds.x, bounds.y],
+ [bounds.width, bounds.height],
+ atlas_entry,
+ instances,
+ );
}
}
+ #[cfg(not(feature = "image"))]
+ layer::Image::Raster { .. } => {}
+
#[cfg(feature = "svg")]
- Handle::Vector(handle) => {
+ layer::Image::Vector { handle, bounds } => {
+ let size = [bounds.width, bounds.height];
+
if let Some(atlas_entry) = vector_cache.upload(
handle,
- image.size,
+ size,
_scale,
device,
encoder,
&mut self.texture_atlas,
) {
- add_instances(image, atlas_entry, instances);
+ add_instances(
+ [bounds.x, bounds.y],
+ size,
+ atlas_entry,
+ instances,
+ );
}
}
+ #[cfg(not(feature = "svg"))]
+ layer::Image::Vector { .. } => {}
}
}
@@ -437,20 +455,6 @@ impl Pipeline {
}
}
-pub struct Image {
- pub handle: Handle,
- pub position: [f32; 2],
- pub size: [f32; 2],
-}
-
-pub enum Handle {
- #[cfg(feature = "image")]
- Raster(image::Handle),
-
- #[cfg(feature = "svg")]
- Vector(svg::Handle),
-}
-
#[repr(C)]
#[derive(Clone, Copy, AsBytes)]
pub struct Vertex {
@@ -495,22 +499,23 @@ struct Uniforms {
}
fn add_instances(
- image: &Image,
+ image_position: [f32; 2],
+ image_size: [f32; 2],
entry: &atlas::Entry,
instances: &mut Vec<Instance>,
) {
match entry {
atlas::Entry::Contiguous(allocation) => {
- add_instance(image.position, image.size, allocation, instances);
+ add_instance(image_position, image_size, allocation, instances);
}
atlas::Entry::Fragmented { fragments, size } => {
- let scaling_x = image.size[0] / size.0 as f32;
- let scaling_y = image.size[1] / size.1 as f32;
+ let scaling_x = image_size[0] / size.0 as f32;
+ let scaling_y = image_size[1] / size.1 as f32;
for fragment in fragments {
let allocation = &fragment.allocation;
- let [x, y] = image.position;
+ let [x, y] = image_position;
let (fragment_x, fragment_y) = fragment.position;
let (fragment_width, fragment_height) = allocation.size();
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 799c1f34..0c351eea 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -27,34 +27,31 @@
#![forbid(rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg))]
-pub mod defaults;
pub mod settings;
pub mod triangle;
pub mod widget;
pub mod window;
-mod primitive;
+mod backend;
mod quad;
-mod renderer;
-mod target;
mod text;
-mod transformation;
-mod viewport;
+pub use iced_graphics::{Defaults, Primitive, Viewport};
pub use wgpu;
-pub use defaults::Defaults;
-pub use primitive::Primitive;
-pub use renderer::Renderer;
+pub use backend::Backend;
pub use settings::Settings;
-pub use target::Target;
-pub use viewport::Viewport;
#[doc(no_inline)]
pub use widget::*;
-pub(crate) use quad::Quad;
-pub(crate) use transformation::Transformation;
+pub(crate) use iced_graphics::Transformation;
#[cfg(any(feature = "image", feature = "svg"))]
mod image;
+
+/// A [`wgpu`] graphics renderer for [`iced`].
+///
+/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
+/// [`iced`]: https://github.com/hecrj/iced
+pub type Renderer = iced_graphics::Renderer<Backend>;
diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs
deleted file mode 100644
index e73227ef..00000000
--- a/wgpu/src/primitive.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-use iced_native::{
- image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, Size,
- Vector, VerticalAlignment,
-};
-
-use crate::triangle;
-use std::sync::Arc;
-
-/// A rendering primitive.
-#[derive(Debug, Clone)]
-pub enum Primitive {
- /// An empty primitive
- None,
- /// A group of primitives
- Group {
- /// The primitives of the group
- primitives: Vec<Primitive>,
- },
- /// A text primitive
- Text {
- /// The contents of the text
- content: String,
- /// The bounds of the text
- bounds: Rectangle,
- /// The color of the text
- color: Color,
- /// The size of the text
- size: f32,
- /// The font of the text
- font: Font,
- /// The horizontal alignment of the text
- horizontal_alignment: HorizontalAlignment,
- /// The vertical alignment of the text
- vertical_alignment: VerticalAlignment,
- },
- /// A quad primitive
- Quad {
- /// The bounds of the quad
- bounds: Rectangle,
- /// The background of the quad
- background: Background,
- /// The border radius of the quad
- border_radius: u16,
- /// The border width of the quad
- border_width: u16,
- /// The border color of the quad
- border_color: Color,
- },
- /// An image primitive
- Image {
- /// The handle of the image
- handle: image::Handle,
- /// The bounds of the image
- bounds: Rectangle,
- },
- /// An SVG primitive
- Svg {
- /// The path of the SVG file
- handle: svg::Handle,
-
- /// The bounds of the viewport
- bounds: Rectangle,
- },
- /// A clip primitive
- Clip {
- /// The bounds of the clip
- bounds: Rectangle,
- /// The offset transformation of the clip
- offset: Vector<u32>,
- /// The content of the clip
- content: Box<Primitive>,
- },
- /// A primitive that applies a translation
- Translate {
- /// The translation vector
- translation: Vector,
-
- /// The primitive to translate
- content: Box<Primitive>,
- },
- /// A low-level primitive to render a mesh of triangles.
- ///
- /// It can be used to render many kinds of geometry freely.
- Mesh2D {
- /// The size of the drawable region of the mesh.
- ///
- /// Any geometry that falls out of this region will be clipped.
- size: Size,
-
- /// The vertex and index buffers of the mesh
- buffers: triangle::Mesh2D,
- },
- /// A cached primitive.
- ///
- /// This can be useful if you are implementing a widget where primitive
- /// generation is expensive.
- Cached {
- /// The cached primitive
- cache: Arc<Primitive>,
- },
-}
-
-impl Default for Primitive {
- fn default() -> Primitive {
- Primitive::None
- }
-}
diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs
index 0c2d2244..0b62f44f 100644
--- a/wgpu/src/quad.rs
+++ b/wgpu/src/quad.rs
@@ -1,4 +1,5 @@
use crate::Transformation;
+use iced_graphics::layer;
use iced_native::Rectangle;
use std::mem;
@@ -107,7 +108,7 @@ impl Pipeline {
}],
},
wgpu::VertexBufferDescriptor {
- stride: mem::size_of::<Quad>() as u64,
+ stride: mem::size_of::<layer::Quad>() as u64,
step_mode: wgpu::InputStepMode::Instance,
attributes: &[
wgpu::VertexAttributeDescriptor {
@@ -161,7 +162,7 @@ impl Pipeline {
let instances = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
- size: mem::size_of::<Quad>() as u64 * Quad::MAX as u64,
+ size: mem::size_of::<layer::Quad>() as u64 * MAX_INSTANCES as u64,
usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
});
@@ -179,7 +180,7 @@ impl Pipeline {
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
- instances: &[Quad],
+ instances: &[layer::Quad],
transformation: Transformation,
scale: f32,
bounds: Rectangle<u32>,
@@ -204,11 +205,11 @@ impl Pipeline {
let total = instances.len();
while i < total {
- let end = (i + Quad::MAX).min(total);
+ let end = (i + MAX_INSTANCES).min(total);
let amount = end - i;
let instance_buffer = device.create_buffer_with_data(
- &instances[i..end].as_bytes(),
+ bytemuck::cast_slice(&instances[i..end]),
wgpu::BufferUsage::COPY_SRC,
);
@@ -217,7 +218,7 @@ impl Pipeline {
0,
&self.instances,
0,
- (mem::size_of::<Quad>() * amount) as u64,
+ (mem::size_of::<layer::Quad>() * amount) as u64,
);
{
@@ -260,7 +261,7 @@ impl Pipeline {
);
}
- i += Quad::MAX;
+ i += MAX_INSTANCES;
}
}
}
@@ -288,20 +289,7 @@ const QUAD_VERTS: [Vertex; 4] = [
},
];
-#[repr(C)]
-#[derive(Debug, Clone, Copy, AsBytes)]
-pub struct Quad {
- pub position: [f32; 2],
- pub scale: [f32; 2],
- pub color: [f32; 4],
- pub border_color: [f32; 4],
- pub border_radius: f32,
- pub border_width: f32,
-}
-
-impl Quad {
- const MAX: usize = 100_000;
-}
+const MAX_INSTANCES: usize = 100_000;
#[repr(C)]
#[derive(Debug, Clone, Copy, AsBytes)]
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
deleted file mode 100644
index f3a7c288..00000000
--- a/wgpu/src/renderer.rs
+++ /dev/null
@@ -1,524 +0,0 @@
-use crate::{
- quad, text, triangle, Defaults, Primitive, Quad, Settings, Target,
- Transformation,
-};
-
-#[cfg(any(feature = "image", feature = "svg"))]
-use crate::image::{self, Image};
-
-use iced_native::{
- layout, mouse, Background, Color, Font, HorizontalAlignment, Layout, Point,
- Rectangle, Size, Vector, VerticalAlignment, Widget,
-};
-
-mod widget;
-
-/// A [`wgpu`] renderer.
-///
-/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
-#[derive(Debug)]
-pub struct Renderer {
- quad_pipeline: quad::Pipeline,
- text_pipeline: text::Pipeline,
- triangle_pipeline: triangle::Pipeline,
-
- #[cfg(any(feature = "image", feature = "svg"))]
- image_pipeline: image::Pipeline,
-}
-
-struct Layer<'a> {
- bounds: Rectangle<u32>,
- quads: Vec<Quad>,
- meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>,
- text: Vec<Text<'a>>,
-
- #[cfg(any(feature = "image", feature = "svg"))]
- images: Vec<Image>,
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct Text<'a> {
- pub content: &'a str,
- pub bounds: Rectangle,
- pub color: [f32; 4],
- pub size: f32,
- pub font: Font,
- pub horizontal_alignment: HorizontalAlignment,
- pub vertical_alignment: VerticalAlignment,
-}
-
-impl<'a> Layer<'a> {
- pub fn new(bounds: Rectangle<u32>) -> Self {
- Self {
- bounds,
- quads: Vec::new(),
- text: Vec::new(),
- meshes: Vec::new(),
-
- #[cfg(any(feature = "image", feature = "svg"))]
- images: Vec::new(),
- }
- }
-
- pub fn intersection(&self, rectangle: Rectangle) -> Option<Rectangle<u32>> {
- let layer_bounds: Rectangle<f32> = self.bounds.into();
-
- layer_bounds.intersection(&rectangle).map(Into::into)
- }
-}
-
-impl Renderer {
- /// Creates a new [`Renderer`].
- ///
- /// [`Renderer`]: struct.Renderer.html
- pub fn new(device: &wgpu::Device, settings: Settings) -> Self {
- let text_pipeline =
- text::Pipeline::new(device, settings.format, settings.default_font);
- let quad_pipeline = quad::Pipeline::new(device, settings.format);
- let triangle_pipeline = triangle::Pipeline::new(
- device,
- settings.format,
- settings.antialiasing,
- );
-
- #[cfg(any(feature = "image", feature = "svg"))]
- let image_pipeline = image::Pipeline::new(device, settings.format);
-
- Self {
- quad_pipeline,
- text_pipeline,
- triangle_pipeline,
-
- #[cfg(any(feature = "image", feature = "svg"))]
- image_pipeline,
- }
- }
-
- /// Draws the provided primitives in the given [`Target`].
- ///
- /// The text provided as overlay will be renderer on top of the primitives.
- /// This is useful for rendering debug information.
- ///
- /// [`Target`]: struct.Target.html
- pub fn draw<T: AsRef<str>>(
- &mut self,
- device: &wgpu::Device,
- encoder: &mut wgpu::CommandEncoder,
- target: Target<'_>,
- (primitive, mouse_interaction): &(Primitive, mouse::Interaction),
- scale_factor: f64,
- overlay: &[T],
- ) -> mouse::Interaction {
- log::debug!("Drawing");
-
- let (width, height) = target.viewport.dimensions();
- let scale_factor = scale_factor as f32;
- let transformation = target.viewport.transformation();
-
- let mut layers = Vec::new();
-
- layers.push(Layer::new(Rectangle {
- x: 0,
- y: 0,
- width,
- height,
- }));
-
- self.draw_primitive(Vector::new(0.0, 0.0), primitive, &mut layers);
- self.draw_overlay(overlay, &mut layers);
-
- for layer in layers {
- self.flush(
- device,
- scale_factor,
- transformation,
- &layer,
- encoder,
- target.texture,
- width,
- height,
- );
- }
-
- #[cfg(any(feature = "image", feature = "svg"))]
- self.image_pipeline.trim_cache();
-
- *mouse_interaction
- }
-
- fn draw_primitive<'a>(
- &mut self,
- translation: Vector,
- primitive: &'a Primitive,
- layers: &mut Vec<Layer<'a>>,
- ) {
- match primitive {
- Primitive::None => {}
- Primitive::Group { primitives } => {
- // TODO: Inspect a bit and regroup (?)
- for primitive in primitives {
- self.draw_primitive(translation, primitive, layers)
- }
- }
- Primitive::Text {
- content,
- bounds,
- size,
- color,
- font,
- horizontal_alignment,
- vertical_alignment,
- } => {
- let layer = layers.last_mut().unwrap();
-
- layer.text.push(Text {
- content,
- bounds: *bounds + translation,
- size: *size,
- color: color.into_linear(),
- font: *font,
- horizontal_alignment: *horizontal_alignment,
- vertical_alignment: *vertical_alignment,
- });
- }
- Primitive::Quad {
- bounds,
- background,
- border_radius,
- border_width,
- border_color,
- } => {
- let layer = layers.last_mut().unwrap();
-
- // TODO: Move some of these computations to the GPU (?)
- layer.quads.push(Quad {
- position: [
- bounds.x + translation.x,
- bounds.y + translation.y,
- ],
- scale: [bounds.width, bounds.height],
- color: match background {
- Background::Color(color) => color.into_linear(),
- },
- border_radius: *border_radius as f32,
- border_width: *border_width as f32,
- border_color: border_color.into_linear(),
- });
- }
- Primitive::Mesh2D { size, buffers } => {
- let layer = layers.last_mut().unwrap();
-
- // Only draw visible content
- if let Some(clip_bounds) = layer.intersection(Rectangle::new(
- Point::new(translation.x, translation.y),
- *size,
- )) {
- layer.meshes.push((
- translation,
- clip_bounds.into(),
- buffers,
- ));
- }
- }
- Primitive::Clip {
- bounds,
- offset,
- content,
- } => {
- let layer = layers.last_mut().unwrap();
-
- // Only draw visible content
- if let Some(clip_bounds) =
- layer.intersection(*bounds + translation)
- {
- let clip_layer = Layer::new(clip_bounds.into());
- let new_layer = Layer::new(layer.bounds);
-
- layers.push(clip_layer);
- self.draw_primitive(
- translation
- - Vector::new(offset.x as f32, offset.y as f32),
- content,
- layers,
- );
- layers.push(new_layer);
- }
- }
- Primitive::Translate {
- translation: new_translation,
- content,
- } => {
- self.draw_primitive(
- translation + *new_translation,
- &content,
- layers,
- );
- }
-
- Primitive::Cached { cache } => {
- self.draw_primitive(translation, &cache, layers);
- }
-
- #[cfg(feature = "image")]
- Primitive::Image { handle, bounds } => {
- let layer = layers.last_mut().unwrap();
-
- layer.images.push(Image {
- handle: image::Handle::Raster(handle.clone()),
- position: [
- bounds.x + translation.x,
- bounds.y + translation.y,
- ],
- size: [bounds.width, bounds.height],
- });
- }
- #[cfg(not(feature = "image"))]
- Primitive::Image { .. } => {}
-
- #[cfg(feature = "svg")]
- Primitive::Svg { handle, bounds } => {
- let layer = layers.last_mut().unwrap();
-
- layer.images.push(Image {
- handle: image::Handle::Vector(handle.clone()),
- position: [
- bounds.x + translation.x,
- bounds.y + translation.y,
- ],
- size: [bounds.width, bounds.height],
- });
- }
- #[cfg(not(feature = "svg"))]
- Primitive::Svg { .. } => {}
- }
- }
-
- fn draw_overlay<'a, T: AsRef<str>>(
- &mut self,
- lines: &'a [T],
- layers: &mut Vec<Layer<'a>>,
- ) {
- let first = layers.first().unwrap();
- let mut overlay = Layer::new(first.bounds);
-
- for (i, line) in lines.iter().enumerate() {
- let text = Text {
- content: line.as_ref(),
- bounds: Rectangle::new(
- Point::new(11.0, 11.0 + 25.0 * i as f32),
- Size::INFINITY,
- ),
- color: [0.9, 0.9, 0.9, 1.0],
- size: 20.0,
- font: Font::Default,
- horizontal_alignment: HorizontalAlignment::Left,
- vertical_alignment: VerticalAlignment::Top,
- };
-
- overlay.text.push(text);
-
- overlay.text.push(Text {
- bounds: text.bounds + Vector::new(-1.0, -1.0),
- color: [0.0, 0.0, 0.0, 1.0],
- ..text
- });
- }
-
- layers.push(overlay);
- }
-
- fn flush(
- &mut self,
- device: &wgpu::Device,
- scale_factor: f32,
- transformation: Transformation,
- layer: &Layer<'_>,
- encoder: &mut wgpu::CommandEncoder,
- target: &wgpu::TextureView,
- target_width: u32,
- target_height: u32,
- ) {
- let bounds = layer.bounds * scale_factor;
-
- if !layer.quads.is_empty() {
- self.quad_pipeline.draw(
- device,
- encoder,
- &layer.quads,
- transformation,
- scale_factor,
- bounds,
- target,
- );
- }
-
- if !layer.meshes.is_empty() {
- let scaled = transformation
- * Transformation::scale(scale_factor, scale_factor);
-
- self.triangle_pipeline.draw(
- device,
- encoder,
- target,
- target_width,
- target_height,
- scaled,
- scale_factor,
- &layer.meshes,
- );
- }
-
- #[cfg(any(feature = "image", feature = "svg"))]
- {
- if !layer.images.is_empty() {
- let scaled = transformation
- * Transformation::scale(scale_factor, scale_factor);
-
- self.image_pipeline.draw(
- device,
- encoder,
- &layer.images,
- scaled,
- bounds,
- target,
- scale_factor,
- );
- }
- }
-
- if !layer.text.is_empty() {
- for text in layer.text.iter() {
- // Target physical coordinates directly to avoid blurry text
- let text = wgpu_glyph::Section {
- // TODO: We `round` here to avoid rerasterizing text when
- // its position changes slightly. This can make text feel a
- // bit "jumpy". We may be able to do better once we improve
- // our text rendering/caching pipeline.
- screen_position: (
- (text.bounds.x * scale_factor).round(),
- (text.bounds.y * scale_factor).round(),
- ),
- // TODO: Fix precision issues with some scale factors.
- //
- // The `ceil` here can cause some words to render on the
- // same line when they should not.
- //
- // Ideally, `wgpu_glyph` should be able to compute layout
- // using logical positions, and then apply the proper
- // scaling when rendering. This would ensure that both
- // measuring and rendering follow the same layout rules.
- bounds: (
- (text.bounds.width * scale_factor).ceil(),
- (text.bounds.height * scale_factor).ceil(),
- ),
- text: vec![wgpu_glyph::Text {
- text: text.content,
- scale: wgpu_glyph::ab_glyph::PxScale {
- x: text.size * scale_factor,
- y: text.size * scale_factor,
- },
- font_id: self.text_pipeline.find_font(text.font),
- extra: wgpu_glyph::Extra {
- color: text.color,
- z: 0.0,
- },
- }],
- layout: wgpu_glyph::Layout::default()
- .h_align(match text.horizontal_alignment {
- HorizontalAlignment::Left => {
- wgpu_glyph::HorizontalAlign::Left
- }
- HorizontalAlignment::Center => {
- wgpu_glyph::HorizontalAlign::Center
- }
- HorizontalAlignment::Right => {
- wgpu_glyph::HorizontalAlign::Right
- }
- })
- .v_align(match text.vertical_alignment {
- VerticalAlignment::Top => {
- wgpu_glyph::VerticalAlign::Top
- }
- VerticalAlignment::Center => {
- wgpu_glyph::VerticalAlign::Center
- }
- VerticalAlignment::Bottom => {
- wgpu_glyph::VerticalAlign::Bottom
- }
- }),
- ..Default::default()
- };
-
- self.text_pipeline.queue(text);
- }
-
- self.text_pipeline.draw_queued(
- device,
- encoder,
- target,
- transformation,
- wgpu_glyph::Region {
- x: bounds.x,
- y: bounds.y,
- width: bounds.width,
- height: bounds.height,
- },
- );
- }
- }
-}
-
-impl iced_native::Renderer for Renderer {
- type Output = (Primitive, mouse::Interaction);
- type Defaults = Defaults;
-
- fn layout<'a, Message>(
- &mut self,
- element: &iced_native::Element<'a, Message, Self>,
- limits: &iced_native::layout::Limits,
- ) -> iced_native::layout::Node {
- let node = element.layout(self, limits);
-
- self.text_pipeline.clear_measurement_cache();
-
- node
- }
-}
-
-impl layout::Debugger for Renderer {
- fn explain<Message>(
- &mut self,
- defaults: &Defaults,
- widget: &dyn Widget<Message, Self>,
- layout: Layout<'_>,
- cursor_position: Point,
- color: Color,
- ) -> Self::Output {
- let mut primitives = Vec::new();
- let (primitive, cursor) =
- widget.draw(self, defaults, layout, cursor_position);
-
- 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/wgpu/src/renderer/widget.rs
deleted file mode 100644
index 37421fbe..00000000
--- a/wgpu/src/renderer/widget.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-mod button;
-mod checkbox;
-mod column;
-mod container;
-mod pane_grid;
-mod progress_bar;
-mod radio;
-mod row;
-mod scrollable;
-mod slider;
-mod space;
-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/wgpu/src/renderer/widget/button.rs
deleted file mode 100644
index eb225038..00000000
--- a/wgpu/src/renderer/widget/button.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer};
-use iced_native::{
- mouse, Background, Color, Element, Layout, Point, Rectangle, Vector,
-};
-
-impl iced_native::button::Renderer for Renderer {
- const DEFAULT_PADDING: u16 = 5;
-
- type Style = Box<dyn StyleSheet>;
-
- fn draw<Message>(
- &mut self,
- _defaults: &Defaults,
- bounds: Rectangle,
- cursor_position: Point,
- is_disabled: bool,
- is_pressed: bool,
- style: &Box<dyn StyleSheet>,
- content: &Element<'_, Message, Self>,
- content_layout: Layout<'_>,
- ) -> Self::Output {
- let is_mouse_over = bounds.contains(cursor_position);
-
- let styling = if is_disabled {
- style.disabled()
- } else if is_mouse_over {
- if is_pressed {
- style.pressed()
- } else {
- style.hovered()
- }
- } else {
- style.active()
- };
-
- let (content, _) = content.draw(
- self,
- &Defaults {
- text: defaults::Text {
- color: styling.text_color,
- },
- },
- content_layout,
- cursor_position,
- );
-
- (
- if styling.background.is_some() || styling.border_width > 0 {
- let background = Primitive::Quad {
- bounds,
- background: styling
- .background
- .unwrap_or(Background::Color(Color::TRANSPARENT)),
- border_radius: styling.border_radius,
- border_width: styling.border_width,
- border_color: styling.border_color,
- };
-
- if styling.shadow_offset == Vector::default() {
- Primitive::Group {
- primitives: vec![background, content],
- }
- } else {
- // TODO: Implement proper shadow support
- let shadow = Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + styling.shadow_offset.x,
- y: bounds.y + styling.shadow_offset.y,
- ..bounds
- },
- background: Background::Color(
- [0.0, 0.0, 0.0, 0.5].into(),
- ),
- border_radius: styling.border_radius,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- };
-
- Primitive::Group {
- primitives: vec![shadow, background, content],
- }
- }
- } else {
- content
- },
- if is_mouse_over {
- mouse::Interaction::Pointer
- } else {
- mouse::Interaction::default()
- },
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs
deleted file mode 100644
index 0340bf62..00000000
--- a/wgpu/src/renderer/widget/checkbox.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use crate::{checkbox::StyleSheet, Primitive, Renderer};
-use iced_native::{
- checkbox, mouse, HorizontalAlignment, Rectangle, VerticalAlignment,
-};
-
-impl checkbox::Renderer for Renderer {
- type Style = Box<dyn StyleSheet>;
-
- const DEFAULT_SIZE: u16 = 20;
- const DEFAULT_SPACING: u16 = 15;
-
- fn draw(
- &mut self,
- bounds: Rectangle,
- is_checked: bool,
- is_mouse_over: bool,
- (label, _): Self::Output,
- style_sheet: &Self::Style,
- ) -> Self::Output {
- let style = if is_mouse_over {
- style_sheet.hovered(is_checked)
- } else {
- style_sheet.active(is_checked)
- };
-
- let checkbox = Primitive::Quad {
- bounds,
- background: style.background,
- border_radius: style.border_radius,
- border_width: style.border_width,
- border_color: style.border_color,
- };
-
- (
- Primitive::Group {
- primitives: if is_checked {
- let check = Primitive::Text {
- content: crate::text::CHECKMARK_ICON.to_string(),
- font: crate::text::BUILTIN_ICONS,
- size: bounds.height * 0.7,
- bounds: Rectangle {
- x: bounds.center_x(),
- y: bounds.center_y(),
- ..bounds
- },
- color: style.checkmark_color,
- horizontal_alignment: HorizontalAlignment::Center,
- vertical_alignment: VerticalAlignment::Center,
- };
-
- vec![checkbox, check, label]
- } else {
- vec![checkbox, label]
- },
- },
- if is_mouse_over {
- mouse::Interaction::Pointer
- } else {
- mouse::Interaction::default()
- },
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/column.rs b/wgpu/src/renderer/widget/column.rs
deleted file mode 100644
index b853276d..00000000
--- a/wgpu/src/renderer/widget/column.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{column, mouse, Element, Layout, Point};
-
-impl column::Renderer for Renderer {
- fn draw<Message>(
- &mut self,
- defaults: &Self::Defaults,
- content: &[Element<'_, Message, Self>],
- layout: Layout<'_>,
- cursor_position: Point,
- ) -> Self::Output {
- let mut mouse_interaction = mouse::Interaction::default();
-
- (
- Primitive::Group {
- primitives: content
- .iter()
- .zip(layout.children())
- .map(|(child, layout)| {
- let (primitive, new_mouse_interaction) =
- child.draw(self, defaults, layout, cursor_position);
-
- if new_mouse_interaction > mouse_interaction {
- mouse_interaction = new_mouse_interaction;
- }
-
- primitive
- })
- .collect(),
- },
- mouse_interaction,
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs
deleted file mode 100644
index 30cc3f07..00000000
--- a/wgpu/src/renderer/widget/container.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use crate::{container, defaults, Defaults, Primitive, Renderer};
-use iced_native::{Background, Color, Element, Layout, Point, Rectangle};
-
-impl iced_native::container::Renderer for Renderer {
- type Style = Box<dyn container::StyleSheet>;
-
- fn draw<Message>(
- &mut self,
- defaults: &Defaults,
- bounds: Rectangle,
- cursor_position: Point,
- style_sheet: &Self::Style,
- content: &Element<'_, Message, Self>,
- content_layout: Layout<'_>,
- ) -> Self::Output {
- let style = style_sheet.style();
-
- let defaults = Defaults {
- text: defaults::Text {
- color: style.text_color.unwrap_or(defaults.text.color),
- },
- };
-
- let (content, mouse_interaction) =
- content.draw(self, &defaults, content_layout, cursor_position);
-
- if style.background.is_some() || style.border_width > 0 {
- let quad = Primitive::Quad {
- bounds,
- background: style
- .background
- .unwrap_or(Background::Color(Color::TRANSPARENT)),
- border_radius: style.border_radius,
- border_width: style.border_width,
- border_color: style.border_color,
- };
-
- (
- Primitive::Group {
- primitives: vec![quad, content],
- },
- mouse_interaction,
- )
- } else {
- (content, mouse_interaction)
- }
- }
-}
diff --git a/wgpu/src/renderer/widget/image.rs b/wgpu/src/renderer/widget/image.rs
deleted file mode 100644
index c4c04984..00000000
--- a/wgpu/src/renderer/widget/image.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{image, mouse, Layout};
-
-impl image::Renderer for Renderer {
- fn dimensions(&self, handle: &image::Handle) -> (u32, u32) {
- self.image_pipeline.dimensions(handle)
- }
-
- fn draw(
- &mut self,
- handle: image::Handle,
- layout: Layout<'_>,
- ) -> Self::Output {
- (
- Primitive::Image {
- handle,
- bounds: layout.bounds(),
- },
- mouse::Interaction::default(),
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/pane_grid.rs b/wgpu/src/renderer/widget/pane_grid.rs
deleted file mode 100644
index 2253e4af..00000000
--- a/wgpu/src/renderer/widget/pane_grid.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{
- mouse,
- pane_grid::{self, Axis, Pane},
- Element, Layout, Point, Rectangle, Vector,
-};
-
-impl pane_grid::Renderer for Renderer {
- fn draw<Message>(
- &mut self,
- defaults: &Self::Defaults,
- content: &[(Pane, Element<'_, Message, Self>)],
- dragging: Option<Pane>,
- resizing: Option<Axis>,
- layout: Layout<'_>,
- cursor_position: Point,
- ) -> Self::Output {
- let pane_cursor_position = if dragging.is_some() {
- // TODO: Remove once cursor availability is encoded in the type
- // system
- Point::new(-1.0, -1.0)
- } else {
- cursor_position
- };
-
- let mut mouse_interaction = mouse::Interaction::default();
- let mut dragged_pane = None;
-
- let mut panes: Vec<_> = content
- .iter()
- .zip(layout.children())
- .enumerate()
- .map(|(i, ((id, pane), layout))| {
- let (primitive, new_mouse_interaction) =
- pane.draw(self, defaults, layout, pane_cursor_position);
-
- if new_mouse_interaction > mouse_interaction {
- mouse_interaction = new_mouse_interaction;
- }
-
- if Some(*id) == dragging {
- dragged_pane = Some((i, layout));
- }
-
- primitive
- })
- .collect();
-
- let primitives = if let Some((index, layout)) = dragged_pane {
- let pane = panes.remove(index);
- let bounds = layout.bounds();
-
- // TODO: Fix once proper layering is implemented.
- // This is a pretty hacky way to achieve layering.
- let clip = Primitive::Clip {
- bounds: Rectangle {
- x: cursor_position.x - bounds.width / 2.0,
- y: cursor_position.y - bounds.height / 2.0,
- width: bounds.width + 0.5,
- height: bounds.height + 0.5,
- },
- offset: Vector::new(0, 0),
- content: Box::new(Primitive::Translate {
- translation: Vector::new(
- cursor_position.x - bounds.x - bounds.width / 2.0,
- cursor_position.y - bounds.y - bounds.height / 2.0,
- ),
- content: Box::new(pane),
- }),
- };
-
- panes.push(clip);
-
- panes
- } else {
- panes
- };
-
- (
- Primitive::Group { primitives },
- if dragging.is_some() {
- mouse::Interaction::Grabbing
- } else if let Some(axis) = resizing {
- match axis {
- Axis::Horizontal => mouse::Interaction::ResizingVertically,
- Axis::Vertical => mouse::Interaction::ResizingHorizontally,
- }
- } else {
- mouse_interaction
- },
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs
deleted file mode 100644
index 2baeeb14..00000000
--- a/wgpu/src/renderer/widget/progress_bar.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use crate::{progress_bar::StyleSheet, Primitive, Renderer};
-use iced_native::{mouse, progress_bar, Color, Rectangle};
-
-impl progress_bar::Renderer for Renderer {
- type Style = Box<dyn StyleSheet>;
-
- const DEFAULT_HEIGHT: u16 = 30;
-
- fn draw(
- &self,
- bounds: Rectangle,
- range: std::ops::RangeInclusive<f32>,
- value: f32,
- style_sheet: &Self::Style,
- ) -> Self::Output {
- let style = style_sheet.style();
-
- 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: style.background,
- border_radius: style.border_radius,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- }],
- };
-
- (
- if active_progress_width > 0.0 {
- let bar = Primitive::Quad {
- bounds: Rectangle {
- width: active_progress_width,
- ..bounds
- },
- background: style.bar,
- border_radius: style.border_radius,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- };
-
- Primitive::Group {
- primitives: vec![background, bar],
- }
- } else {
- background
- },
- mouse::Interaction::default(),
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs
deleted file mode 100644
index cee0deb6..00000000
--- a/wgpu/src/renderer/widget/radio.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use crate::{radio::StyleSheet, 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 {
- type Style = Box<dyn StyleSheet>;
-
- const DEFAULT_SIZE: u16 = SIZE as u16;
- const DEFAULT_SPACING: u16 = 15;
-
- fn draw(
- &mut self,
- bounds: Rectangle,
- is_selected: bool,
- is_mouse_over: bool,
- (label, _): Self::Output,
- style_sheet: &Self::Style,
- ) -> Self::Output {
- let style = if is_mouse_over {
- style_sheet.hovered()
- } else {
- style_sheet.active()
- };
-
- let radio = Primitive::Quad {
- bounds,
- background: style.background,
- border_radius: (SIZE / 2.0) as u16,
- border_width: style.border_width,
- border_color: style.border_color,
- };
-
- (
- Primitive::Group {
- primitives: if is_selected {
- let radio_circle = Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + DOT_SIZE / 2.0,
- y: bounds.y + DOT_SIZE / 2.0,
- width: bounds.width - DOT_SIZE,
- height: bounds.height - DOT_SIZE,
- },
- background: Background::Color(style.dot_color),
- border_radius: (DOT_SIZE / 2.0) as u16,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- };
-
- vec![radio, radio_circle, label]
- } else {
- vec![radio, label]
- },
- },
- if is_mouse_over {
- mouse::Interaction::Pointer
- } else {
- mouse::Interaction::default()
- },
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/row.rs b/wgpu/src/renderer/widget/row.rs
deleted file mode 100644
index d0b7ef09..00000000
--- a/wgpu/src/renderer/widget/row.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{mouse, row, Element, Layout, Point};
-
-impl row::Renderer for Renderer {
- fn draw<Message>(
- &mut self,
- defaults: &Self::Defaults,
- children: &[Element<'_, Message, Self>],
- layout: Layout<'_>,
- cursor_position: Point,
- ) -> Self::Output {
- let mut mouse_interaction = mouse::Interaction::default();
-
- (
- Primitive::Group {
- primitives: children
- .iter()
- .zip(layout.children())
- .map(|(child, layout)| {
- let (primitive, new_mouse_interaction) =
- child.draw(self, defaults, layout, cursor_position);
-
- if new_mouse_interaction > mouse_interaction {
- mouse_interaction = new_mouse_interaction;
- }
-
- primitive
- })
- .collect(),
- },
- mouse_interaction,
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs
deleted file mode 100644
index 8a400b82..00000000
--- a/wgpu/src/renderer/widget/scrollable.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{mouse, scrollable, Background, Color, Rectangle, Vector};
-
-const SCROLLBAR_WIDTH: u16 = 10;
-const SCROLLBAR_MARGIN: u16 = 2;
-
-impl scrollable::Renderer for Renderer {
- type Style = Box<dyn iced_style::scrollable::StyleSheet>;
-
- fn scrollbar(
- &self,
- bounds: Rectangle,
- content_bounds: Rectangle,
- offset: u32,
- ) -> Option<scrollable::Scrollbar> {
- if content_bounds.height > bounds.height {
- let scrollbar_bounds = Rectangle {
- x: bounds.x + bounds.width
- - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
- y: bounds.y,
- width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
- height: bounds.height,
- };
-
- let ratio = bounds.height / content_bounds.height;
- let scrollbar_height = bounds.height * ratio;
- let y_offset = offset as f32 * ratio;
-
- let scroller_bounds = Rectangle {
- x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
- y: scrollbar_bounds.y + y_offset,
- width: scrollbar_bounds.width - f32::from(2 * SCROLLBAR_MARGIN),
- height: scrollbar_height,
- };
-
- Some(scrollable::Scrollbar {
- bounds: scrollbar_bounds,
- scroller: scrollable::Scroller {
- bounds: scroller_bounds,
- },
- })
- } else {
- None
- }
- }
-
- fn draw(
- &mut self,
- state: &scrollable::State,
- bounds: Rectangle,
- _content_bounds: Rectangle,
- is_mouse_over: bool,
- is_mouse_over_scrollbar: bool,
- scrollbar: Option<scrollable::Scrollbar>,
- offset: u32,
- style_sheet: &Self::Style,
- (content, mouse_interaction): Self::Output,
- ) -> Self::Output {
- (
- if let Some(scrollbar) = scrollbar {
- let clip = Primitive::Clip {
- bounds,
- offset: Vector::new(0, offset),
- content: Box::new(content),
- };
-
- let style = if state.is_scroller_grabbed() {
- style_sheet.dragging()
- } else if is_mouse_over_scrollbar {
- style_sheet.hovered()
- } else {
- style_sheet.active()
- };
-
- let is_scrollbar_visible =
- style.background.is_some() || style.border_width > 0;
-
- let scroller = if is_mouse_over
- || state.is_scroller_grabbed()
- || is_scrollbar_visible
- {
- Primitive::Quad {
- bounds: scrollbar.scroller.bounds,
- background: Background::Color(style.scroller.color),
- border_radius: style.scroller.border_radius,
- border_width: style.scroller.border_width,
- border_color: style.scroller.border_color,
- }
- } else {
- Primitive::None
- };
-
- let scrollbar = if is_scrollbar_visible {
- Primitive::Quad {
- bounds: Rectangle {
- x: scrollbar.bounds.x + f32::from(SCROLLBAR_MARGIN),
- width: scrollbar.bounds.width
- - f32::from(2 * SCROLLBAR_MARGIN),
- ..scrollbar.bounds
- },
- background: style
- .background
- .unwrap_or(Background::Color(Color::TRANSPARENT)),
- border_radius: style.border_radius,
- border_width: style.border_width,
- border_color: style.border_color,
- }
- } else {
- Primitive::None
- };
-
- Primitive::Group {
- primitives: vec![clip, scrollbar, scroller],
- }
- } else {
- content
- },
- if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
- mouse::Interaction::Idle
- } else {
- mouse_interaction
- },
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs
deleted file mode 100644
index 220feace..00000000
--- a/wgpu/src/renderer/widget/slider.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-use crate::{
- slider::{HandleShape, StyleSheet},
- Primitive, Renderer,
-};
-use iced_native::{mouse, slider, Background, Color, Point, Rectangle};
-
-const HANDLE_HEIGHT: f32 = 22.0;
-
-impl slider::Renderer for Renderer {
- type Style = Box<dyn StyleSheet>;
-
- fn height(&self) -> u32 {
- 30
- }
-
- fn draw(
- &mut self,
- bounds: Rectangle,
- cursor_position: Point,
- range: std::ops::RangeInclusive<f32>,
- value: f32,
- is_dragging: bool,
- style_sheet: &Self::Style,
- ) -> Self::Output {
- let is_mouse_over = bounds.contains(cursor_position);
-
- let style = if is_dragging {
- style_sheet.dragging()
- } else if is_mouse_over {
- style_sheet.hovered()
- } else {
- style_sheet.active()
- };
-
- let rail_y = bounds.y + (bounds.height / 2.0).round();
-
- let (rail_top, rail_bottom) = (
- Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x,
- y: rail_y,
- width: bounds.width,
- height: 2.0,
- },
- background: Background::Color(style.rail_colors.0),
- border_radius: 0,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- },
- Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x,
- y: rail_y + 2.0,
- width: bounds.width,
- height: 2.0,
- },
- background: Background::Color(style.rail_colors.1),
- border_radius: 0,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- },
- );
-
- let (range_start, range_end) = range.into_inner();
-
- let (handle_width, handle_height, handle_border_radius) =
- match style.handle.shape {
- HandleShape::Circle { radius } => {
- (f32::from(radius * 2), f32::from(radius * 2), radius)
- }
- HandleShape::Rectangle {
- width,
- border_radius,
- } => (f32::from(width), HANDLE_HEIGHT, border_radius),
- };
-
- let handle_offset = (bounds.width - handle_width)
- * ((value - range_start) / (range_end - range_start).max(1.0));
-
- let handle = Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + handle_offset.round(),
- y: rail_y - handle_height / 2.0,
- width: handle_width,
- height: handle_height,
- },
- background: Background::Color(style.handle.color),
- border_radius: handle_border_radius,
- border_width: style.handle.border_width,
- border_color: style.handle.border_color,
- };
-
- (
- Primitive::Group {
- primitives: vec![rail_top, rail_bottom, handle],
- },
- if is_dragging {
- mouse::Interaction::Grabbing
- } else if is_mouse_over {
- mouse::Interaction::Grab
- } else {
- mouse::Interaction::default()
- },
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/space.rs b/wgpu/src/renderer/widget/space.rs
deleted file mode 100644
index 225f7e6c..00000000
--- a/wgpu/src/renderer/widget/space.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{mouse, space, Rectangle};
-
-impl space::Renderer for Renderer {
- fn draw(&mut self, _bounds: Rectangle) -> Self::Output {
- (Primitive::None, mouse::Interaction::default())
- }
-}
diff --git a/wgpu/src/renderer/widget/svg.rs b/wgpu/src/renderer/widget/svg.rs
deleted file mode 100644
index f6d6d0ba..00000000
--- a/wgpu/src/renderer/widget/svg.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{mouse, svg, Layout};
-
-impl svg::Renderer for Renderer {
- fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) {
- self.image_pipeline.viewport_dimensions(handle)
- }
-
- fn draw(
- &mut self,
- handle: svg::Handle,
- layout: Layout<'_>,
- ) -> Self::Output {
- (
- Primitive::Svg {
- handle,
- bounds: layout.bounds(),
- },
- mouse::Interaction::default(),
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/text.rs b/wgpu/src/renderer/widget/text.rs
deleted file mode 100644
index 4605ed06..00000000
--- a/wgpu/src/renderer/widget/text.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::{Primitive, Renderer};
-use iced_native::{
- mouse, text, Color, Font, HorizontalAlignment, Rectangle, Size,
- VerticalAlignment,
-};
-
-use std::f32;
-
-impl text::Renderer for Renderer {
- type Font = Font;
-
- const DEFAULT_SIZE: u16 = 20;
-
- fn measure(
- &self,
- content: &str,
- size: u16,
- font: Font,
- bounds: Size,
- ) -> (f32, f32) {
- self.text_pipeline
- .measure(content, f32::from(size), font, bounds)
- }
-
- fn draw(
- &mut self,
- defaults: &Self::Defaults,
- bounds: Rectangle,
- content: &str,
- size: u16,
- font: Font,
- color: Option<Color>,
- horizontal_alignment: HorizontalAlignment,
- vertical_alignment: VerticalAlignment,
- ) -> Self::Output {
- let x = match horizontal_alignment {
- iced_native::HorizontalAlignment::Left => bounds.x,
- iced_native::HorizontalAlignment::Center => bounds.center_x(),
- iced_native::HorizontalAlignment::Right => bounds.x + bounds.width,
- };
-
- let y = match vertical_alignment {
- iced_native::VerticalAlignment::Top => bounds.y,
- iced_native::VerticalAlignment::Center => bounds.center_y(),
- iced_native::VerticalAlignment::Bottom => bounds.y + bounds.height,
- };
-
- (
- Primitive::Text {
- content: content.to_string(),
- size: f32::from(size),
- bounds: Rectangle { x, y, ..bounds },
- color: color.unwrap_or(defaults.text.color),
- font,
- horizontal_alignment,
- vertical_alignment,
- },
- mouse::Interaction::default(),
- )
- }
-}
diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs
deleted file mode 100644
index 5799dba7..00000000
--- a/wgpu/src/renderer/widget/text_input.rs
+++ /dev/null
@@ -1,254 +0,0 @@
-use crate::{text_input::StyleSheet, Primitive, Renderer};
-
-use iced_native::{
- mouse,
- text_input::{self, cursor},
- Background, Color, Font, HorizontalAlignment, Point, Rectangle, Size,
- Vector, VerticalAlignment,
-};
-use std::f32;
-
-impl text_input::Renderer for Renderer {
- type Style = Box<dyn StyleSheet>;
-
- fn default_size(&self) -> u16 {
- // TODO: Make this configurable
- 20
- }
-
- fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 {
- let (width, _) = self.text_pipeline.measure(
- value,
- f32::from(size),
- font,
- Size::INFINITY,
- );
-
- width
- }
-
- fn offset(
- &self,
- text_bounds: Rectangle,
- font: Font,
- size: u16,
- value: &text_input::Value,
- state: &text_input::State,
- ) -> f32 {
- if state.is_focused() {
- let cursor = state.cursor();
-
- let focus_position = match cursor.state(value) {
- cursor::State::Index(i) => i,
- cursor::State::Selection { end, .. } => end,
- };
-
- let (_, offset) = measure_cursor_and_scroll_offset(
- self,
- text_bounds,
- value,
- size,
- focus_position,
- font,
- );
-
- offset
- } else {
- 0.0
- }
- }
-
- fn draw(
- &mut self,
- bounds: Rectangle,
- text_bounds: Rectangle,
- cursor_position: Point,
- font: Font,
- size: u16,
- placeholder: &str,
- value: &text_input::Value,
- state: &text_input::State,
- style_sheet: &Self::Style,
- ) -> Self::Output {
- let is_mouse_over = bounds.contains(cursor_position);
-
- let style = if state.is_focused() {
- style_sheet.focused()
- } else if is_mouse_over {
- style_sheet.hovered()
- } else {
- style_sheet.active()
- };
-
- let input = Primitive::Quad {
- bounds,
- background: style.background,
- border_radius: style.border_radius,
- border_width: style.border_width,
- border_color: style.border_color,
- };
-
- let text = value.to_string();
-
- let text_value = Primitive::Text {
- content: if text.is_empty() {
- placeholder.to_string()
- } else {
- text.clone()
- },
- color: if text.is_empty() {
- style_sheet.placeholder_color()
- } else {
- style_sheet.value_color()
- },
- font,
- bounds: Rectangle {
- y: text_bounds.center_y(),
- width: f32::INFINITY,
- ..text_bounds
- },
- size: f32::from(size),
- horizontal_alignment: HorizontalAlignment::Left,
- vertical_alignment: VerticalAlignment::Center,
- };
-
- let (contents_primitive, offset) = if state.is_focused() {
- let cursor = state.cursor();
-
- let (cursor_primitive, offset) = match cursor.state(value) {
- cursor::State::Index(position) => {
- let (text_value_width, offset) =
- measure_cursor_and_scroll_offset(
- self,
- text_bounds,
- value,
- size,
- position,
- font,
- );
-
- (
- Primitive::Quad {
- bounds: Rectangle {
- x: text_bounds.x + text_value_width,
- y: text_bounds.y,
- width: 1.0,
- height: text_bounds.height,
- },
- background: Background::Color(
- style_sheet.value_color(),
- ),
- border_radius: 0,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- },
- offset,
- )
- }
- cursor::State::Selection { start, end } => {
- let left = start.min(end);
- let right = end.max(start);
-
- let (left_position, left_offset) =
- measure_cursor_and_scroll_offset(
- self,
- text_bounds,
- value,
- size,
- left,
- font,
- );
-
- let (right_position, right_offset) =
- measure_cursor_and_scroll_offset(
- self,
- text_bounds,
- value,
- size,
- right,
- font,
- );
-
- let width = right_position - left_position;
-
- (
- Primitive::Quad {
- bounds: Rectangle {
- x: text_bounds.x + left_position,
- y: text_bounds.y,
- width,
- height: text_bounds.height,
- },
- background: Background::Color(
- style_sheet.selection_color(),
- ),
- border_radius: 0,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- },
- if end == right {
- right_offset
- } else {
- left_offset
- },
- )
- }
- };
-
- (
- Primitive::Group {
- primitives: vec![cursor_primitive, text_value],
- },
- Vector::new(offset as u32, 0),
- )
- } else {
- (text_value, Vector::new(0, 0))
- };
-
- let text_width = self.measure_value(
- if text.is_empty() { placeholder } else { &text },
- size,
- font,
- );
-
- let contents = if text_width > text_bounds.width {
- Primitive::Clip {
- bounds: text_bounds,
- offset,
- content: Box::new(contents_primitive),
- }
- } else {
- contents_primitive
- };
-
- (
- Primitive::Group {
- primitives: vec![input, contents],
- },
- if is_mouse_over {
- mouse::Interaction::Text
- } else {
- mouse::Interaction::default()
- },
- )
- }
-}
-
-fn measure_cursor_and_scroll_offset(
- renderer: &Renderer,
- text_bounds: Rectangle,
- value: &text_input::Value,
- size: u16,
- cursor_index: usize,
- font: Font,
-) -> (f32, f32) {
- use iced_native::text_input::Renderer;
-
- let text_before_cursor = value.until(cursor_index).to_string();
-
- let text_value_width =
- renderer.measure_value(&text_before_cursor, size, font);
- let offset = ((text_value_width + 5.0) - text_bounds.width).max(0.0);
-
- (text_value_width, offset)
-}
diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs
index 5ee245b6..8378d734 100644
--- a/wgpu/src/settings.rs
+++ b/wgpu/src/settings.rs
@@ -1,6 +1,5 @@
-//! Configure a [`Renderer`].
-//!
-//! [`Renderer`]: struct.Renderer.html
+//! Configure a renderer.
+pub use iced_graphics::Antialiasing;
/// The settings of a [`Renderer`].
///
@@ -30,27 +29,3 @@ impl Default for Settings {
}
}
}
-
-/// An antialiasing strategy.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Antialiasing {
- /// Multisample AA with 2 samples
- MSAAx2,
- /// Multisample AA with 4 samples
- MSAAx4,
- /// Multisample AA with 8 samples
- MSAAx8,
- /// Multisample AA with 16 samples
- MSAAx16,
-}
-
-impl Antialiasing {
- pub(crate) fn sample_count(self) -> u32 {
- match self {
- Antialiasing::MSAAx2 => 2,
- Antialiasing::MSAAx4 => 4,
- Antialiasing::MSAAx8 => 8,
- Antialiasing::MSAAx16 => 16,
- }
- }
-}
diff --git a/wgpu/src/target.rs b/wgpu/src/target.rs
deleted file mode 100644
index 1e72c0c3..00000000
--- a/wgpu/src/target.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use crate::Viewport;
-
-/// A rendering target.
-#[derive(Debug)]
-pub struct Target<'a> {
- /// The texture where graphics will be rendered.
- pub texture: &'a wgpu::TextureView,
-
- /// The viewport of the target.
- ///
- /// Most of the time, you will want this to match the dimensions of the
- /// texture.
- pub viewport: &'a Viewport,
-}
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 7b6bef6c..5ee7b856 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -1,24 +1,12 @@
-mod font;
-
use crate::Transformation;
-
+use iced_graphics::font;
use std::{cell::RefCell, collections::HashMap};
use wgpu_glyph::ab_glyph;
-pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External {
- name: "iced_wgpu icons",
- bytes: include_bytes!("text/icons.ttf"),
-};
-
-pub const CHECKMARK_ICON: char = '\u{F00C}';
-
-const FALLBACK_FONT: &[u8] = include_bytes!("../fonts/Lato-Regular.ttf");
-
#[derive(Debug)]
pub struct Pipeline {
draw_brush: RefCell<wgpu_glyph::GlyphBrush<()>>,
draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>,
-
measure_brush: RefCell<glyph_brush::GlyphBrush<()>>,
}
@@ -35,7 +23,7 @@ impl Pipeline {
default_font.map(|slice| slice.to_vec()).unwrap_or_else(|| {
font_source
.load(&[font::Family::SansSerif, font::Family::Serif])
- .unwrap_or_else(|_| FALLBACK_FONT.to_vec())
+ .unwrap_or_else(|_| font::FALLBACK.to_vec())
});
let font = ab_glyph::FontArc::try_from_vec(default_font)
@@ -45,7 +33,7 @@ impl Pipeline {
embedded font..."
);
- ab_glyph::FontArc::try_from_slice(FALLBACK_FONT)
+ ab_glyph::FontArc::try_from_slice(font::FALLBACK)
.expect("Load fallback font")
});
@@ -61,7 +49,6 @@ impl Pipeline {
Pipeline {
draw_brush: RefCell::new(draw_brush),
draw_font_map: RefCell::new(HashMap::new()),
-
measure_brush: RefCell::new(measure_brush),
}
}
@@ -121,7 +108,7 @@ impl Pipeline {
}
}
- pub fn clear_measurement_cache(&mut self) {
+ pub fn trim_measurement_cache(&mut self) {
// TODO: We should probably use a `GlyphCalculator` for this. However,
// it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop.
// This makes stuff quite inconvenient. A manual method for trimming the
diff --git a/wgpu/src/text/font.rs b/wgpu/src/text/font.rs
deleted file mode 100644
index 7346ccdb..00000000
--- a/wgpu/src/text/font.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-pub use font_kit::{
- error::SelectionError as LoadError, family_name::FamilyName as Family,
-};
-
-pub struct Source {
- raw: font_kit::source::SystemSource,
-}
-
-impl Source {
- pub fn new() -> Self {
- Source {
- raw: font_kit::source::SystemSource::new(),
- }
- }
-
- pub fn load(&self, families: &[Family]) -> Result<Vec<u8>, LoadError> {
- let font = self.raw.select_best_match(
- families,
- &font_kit::properties::Properties::default(),
- )?;
-
- match font {
- font_kit::handle::Handle::Path { path, .. } => {
- use std::io::Read;
-
- let mut buf = Vec::new();
- let mut reader = std::fs::File::open(path).expect("Read font");
- let _ = reader.read_to_end(&mut buf);
-
- Ok(buf)
- }
- font_kit::handle::Handle::Memory { bytes, .. } => {
- Ok(bytes.as_ref().clone())
- }
- }
- }
-}
diff --git a/wgpu/src/text/icons.ttf b/wgpu/src/text/icons.ttf
deleted file mode 100644
index 1c832f86..00000000
--- a/wgpu/src/text/icons.ttf
+++ /dev/null
Binary files differ
diff --git a/wgpu/src/transformation.rs b/wgpu/src/transformation.rs
deleted file mode 100644
index ff3b1d00..00000000
--- a/wgpu/src/transformation.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use glam::{Mat4, Vec3, Vec4};
-use std::ops::Mul;
-
-/// A 2D transformation matrix.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Transformation(Mat4);
-
-impl Transformation {
- /// Get the identity transformation.
- pub fn identity() -> Transformation {
- Transformation(Mat4::identity())
- }
-
- /// Creates an orthographic projection.
- #[rustfmt::skip]
- pub fn orthographic(width: u32, height: u32) -> Transformation {
- Transformation(Mat4::from_cols(
- Vec4::new(2.0 / width as f32, 0.0, 0.0, 0.0),
- Vec4::new(0.0, -2.0 / height as f32, 0.0, 0.0),
- Vec4::new(0.0, 0.0, -1.0, 0.0),
- Vec4::new(-1.0, 1.0, 0.0, 1.0)
- ))
- }
-
- /// Creates a translate transformation.
- pub fn translate(x: f32, y: f32) -> Transformation {
- Transformation(Mat4::from_translation(Vec3::new(x, y, 0.0)))
- }
-
- /// Creates a scale transformation.
- pub fn scale(x: f32, y: f32) -> Transformation {
- Transformation(Mat4::from_scale(Vec3::new(x, y, 1.0)))
- }
-}
-
-impl Mul for Transformation {
- type Output = Self;
-
- fn mul(self, rhs: Self) -> Self {
- Transformation(self.0 * rhs.0)
- }
-}
-
-impl AsRef<[f32; 16]> for Transformation {
- fn as_ref(&self) -> &[f32; 16] {
- self.0.as_ref()
- }
-}
-
-impl From<Transformation> for [f32; 16] {
- fn from(t: Transformation) -> [f32; 16] {
- *t.as_ref()
- }
-}
diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs
index 3e68a269..22a27143 100644
--- a/wgpu/src/triangle.rs
+++ b/wgpu/src/triangle.rs
@@ -1,9 +1,11 @@
//! Draw meshes of triangles.
use crate::{settings, Transformation};
-use iced_native::{Rectangle, Vector};
+use iced_graphics::layer;
use std::mem;
use zerocopy::AsBytes;
+pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
+
mod msaa;
const UNIFORM_BUFFER_SIZE: usize = 100;
@@ -168,9 +170,9 @@ impl Pipeline {
],
}],
},
- sample_count: antialiasing
- .map(|a| a.sample_count())
- .unwrap_or(1),
+ sample_count: u32::from(
+ antialiasing.map(|a| a.sample_count()).unwrap_or(1),
+ ),
sample_mask: !0,
alpha_to_coverage_enabled: false,
});
@@ -202,14 +204,16 @@ impl Pipeline {
target_height: u32,
transformation: Transformation,
scale_factor: f32,
- meshes: &[(Vector, Rectangle<u32>, &Mesh2D)],
+ meshes: &[layer::Mesh<'_>],
) {
// This looks a bit crazy, but we are just counting how many vertices
// and indices we will need to handle.
// TODO: Improve readability
let (total_vertices, total_indices) = meshes
.iter()
- .map(|(_, _, mesh)| (mesh.vertices.len(), mesh.indices.len()))
+ .map(|layer::Mesh { buffers, .. }| {
+ (buffers.vertices.len(), buffers.indices.len())
+ })
.fold((0, 0), |(total_v, total_i), (v, i)| {
(total_v + v, total_i + i)
});
@@ -230,18 +234,18 @@ impl Pipeline {
let mut last_index = 0;
// We upload everything upfront
- for (origin, _, mesh) in meshes {
+ for mesh in meshes {
let transform = (transformation
- * Transformation::translate(origin.x, origin.y))
+ * Transformation::translate(mesh.origin.x, mesh.origin.y))
.into();
let vertex_buffer = device.create_buffer_with_data(
- mesh.vertices.as_bytes(),
+ bytemuck::cast_slice(&mesh.buffers.vertices),
wgpu::BufferUsage::COPY_SRC,
);
let index_buffer = device.create_buffer_with_data(
- mesh.indices.as_bytes(),
+ mesh.buffers.indices.as_bytes(),
wgpu::BufferUsage::COPY_SRC,
);
@@ -250,7 +254,8 @@ impl Pipeline {
0,
&self.vertex_buffer.raw,
(std::mem::size_of::<Vertex2D>() * last_vertex) as u64,
- (std::mem::size_of::<Vertex2D>() * mesh.vertices.len()) as u64,
+ (std::mem::size_of::<Vertex2D>() * mesh.buffers.vertices.len())
+ as u64,
);
encoder.copy_buffer_to_buffer(
@@ -258,18 +263,19 @@ impl Pipeline {
0,
&self.index_buffer.raw,
(std::mem::size_of::<u32>() * last_index) as u64,
- (std::mem::size_of::<u32>() * mesh.indices.len()) as u64,
+ (std::mem::size_of::<u32>() * mesh.buffers.indices.len())
+ as u64,
);
uniforms.push(transform);
offsets.push((
last_vertex as u64,
last_index as u64,
- mesh.indices.len(),
+ mesh.buffers.indices.len(),
));
- last_vertex += mesh.vertices.len();
- last_index += mesh.indices.len();
+ last_vertex += mesh.buffers.vertices.len();
+ last_index += mesh.buffers.indices.len();
}
let uniforms_buffer = device.create_buffer_with_data(
@@ -320,13 +326,14 @@ impl Pipeline {
for (i, (vertex_offset, index_offset, indices)) in
offsets.into_iter().enumerate()
{
- let bounds = meshes[i].1 * scale_factor;
+ let clip_bounds =
+ (meshes[i].clip_bounds * scale_factor).round();
render_pass.set_scissor_rect(
- bounds.x,
- bounds.y,
- bounds.width,
- bounds.height,
+ clip_bounds.x,
+ clip_bounds.y,
+ clip_bounds.width,
+ clip_bounds.height,
);
render_pass.set_bind_group(
@@ -387,26 +394,3 @@ impl From<Transformation> for Uniforms {
}
}
}
-
-/// A two-dimensional vertex with some color in __linear__ RGBA.
-#[repr(C)]
-#[derive(Copy, Clone, Debug, AsBytes)]
-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<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>,
-}
diff --git a/wgpu/src/viewport.rs b/wgpu/src/viewport.rs
deleted file mode 100644
index 66242468..00000000
--- a/wgpu/src/viewport.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use crate::Transformation;
-
-/// A viewing region for displaying computer graphics.
-#[derive(Debug)]
-pub struct Viewport {
- width: u32,
- height: u32,
- transformation: Transformation,
-}
-
-impl Viewport {
- /// Creates a new [`Viewport`] with the given dimensions.
- pub fn new(width: u32, height: u32) -> Viewport {
- Viewport {
- width,
- height,
- transformation: Transformation::orthographic(width, height),
- }
- }
-
- /// Returns the dimensions of the [`Viewport`].
- pub fn dimensions(&self) -> (u32, u32) {
- (self.width, self.height)
- }
-
- pub(crate) fn transformation(&self) -> Transformation {
- self.transformation
- }
-}
diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs
index 32ccad17..d17b7a5d 100644
--- a/wgpu/src/widget.rs
+++ b/wgpu/src/widget.rs
@@ -7,6 +7,8 @@
//! ```
//! use iced_wgpu::{button, Button};
//! ```
+use crate::Renderer;
+
pub mod button;
pub mod checkbox;
pub mod container;
@@ -17,8 +19,6 @@ pub mod scrollable;
pub mod slider;
pub mod text_input;
-mod text;
-
#[doc(no_inline)]
pub use button::Button;
#[doc(no_inline)]
@@ -38,8 +38,6 @@ 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;
@@ -47,3 +45,14 @@ pub mod canvas;
#[cfg(feature = "canvas")]
#[doc(no_inline)]
pub use canvas::Canvas;
+
+pub use iced_native::Space;
+
+/// A container that distributes its contents vertically.
+pub type Column<'a, Message> = iced_native::Column<'a, Message, Renderer>;
+
+/// A container that distributes its contents horizontally.
+pub type Row<'a, Message> = iced_native::Row<'a, Message, Renderer>;
+
+/// A paragraph of text.
+pub type Text = iced_native::Text<Renderer>;
diff --git a/wgpu/src/widget/button.rs b/wgpu/src/widget/button.rs
index b738c55e..fee7a7f8 100644
--- a/wgpu/src/widget/button.rs
+++ b/wgpu/src/widget/button.rs
@@ -6,8 +6,8 @@
//! [`State`]: struct.State.html
use crate::Renderer;
+pub use iced_graphics::button::{Style, StyleSheet};
pub use iced_native::button::State;
-pub use iced_style::button::{Style, StyleSheet};
/// A widget that produces a message when clicked.
///
diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs
index 2fc10ea0..bef34857 100644
--- a/wgpu/src/widget/canvas.rs
+++ b/wgpu/src/widget/canvas.rs
@@ -6,228 +6,4 @@
//!
//! [`Canvas`]: struct.Canvas.html
//! [`Frame`]: struct.Frame.html
-use crate::{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_wgpu::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: Program<Message>> Widget<Message, Renderer>
- for Canvas<Message, P>
-{
- 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);
- 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,
- _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,
- _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: Program<Message> + 'a> From<Canvas<Message, P>>
- for Element<'a, Message, Renderer>
-where
- Message: 'static,
-{
- fn from(canvas: Canvas<Message, P>) -> Element<'a, Message, Renderer> {
- Element::new(canvas)
- }
-}
+pub use iced_graphics::canvas::*;
diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs
deleted file mode 100644
index 4b28d164..00000000
--- a/wgpu/src/widget/canvas/cache.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-use crate::{
- canvas::{Frame, Geometry},
- Primitive,
-};
-
-use iced_native::Size;
-use std::{cell::RefCell, sync::Arc};
-
-enum State {
- Empty,
- Filled {
- bounds: Size,
- primitive: Arc<Primitive>,
- },
-}
-
-impl Default for State {
- fn default() -> Self {
- State::Empty
- }
-}
-/// A simple cache that stores generated [`Geometry`] to avoid recomputation.
-///
-/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer
-/// change or it is explicitly cleared.
-///
-/// [`Layer`]: ../trait.Layer.html
-/// [`Cache`]: struct.Cache.html
-/// [`Geometry`]: struct.Geometry.html
-#[derive(Debug, Default)]
-pub struct Cache {
- state: RefCell<State>,
-}
-
-impl Cache {
- /// Creates a new empty [`Cache`].
- ///
- /// [`Cache`]: struct.Cache.html
- pub fn new() -> Self {
- Cache {
- state: Default::default(),
- }
- }
-
- /// Clears the [`Cache`], forcing a redraw the next time it is used.
- ///
- /// [`Cache`]: struct.Cache.html
- pub fn clear(&mut self) {
- *self.state.borrow_mut() = State::Empty;
- }
-
- /// Draws [`Geometry`] using the provided closure and stores it in the
- /// [`Cache`].
- ///
- /// The closure will only be called when
- /// - the bounds have changed since the previous draw call.
- /// - the [`Cache`] is empty or has been explicitly cleared.
- ///
- /// Otherwise, the previously stored [`Geometry`] will be returned. The
- /// [`Cache`] is not cleared in this case. In other words, it will keep
- /// returning the stored [`Geometry`] if needed.
- ///
- /// [`Cache`]: struct.Cache.html
- pub fn draw(&self, bounds: Size, draw_fn: impl Fn(&mut Frame)) -> Geometry {
- use std::ops::Deref;
-
- if let State::Filled {
- bounds: cached_bounds,
- primitive,
- } = self.state.borrow().deref()
- {
- if *cached_bounds == bounds {
- return Geometry::from_primitive(Primitive::Cached {
- cache: primitive.clone(),
- });
- }
- }
-
- let mut frame = Frame::new(bounds);
- draw_fn(&mut frame);
-
- let primitive = {
- let geometry = frame.into_geometry();
-
- Arc::new(geometry.into_primitive())
- };
-
- *self.state.borrow_mut() = State::Filled {
- bounds,
- primitive: primitive.clone(),
- };
-
- Geometry::from_primitive(Primitive::Cached { cache: primitive })
- }
-}
-
-impl std::fmt::Debug for State {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- State::Empty => write!(f, "Empty"),
- State::Filled { primitive, bounds } => f
- .debug_struct("Filled")
- .field("primitive", primitive)
- .field("bounds", bounds)
- .finish(),
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/cursor.rs b/wgpu/src/widget/canvas/cursor.rs
deleted file mode 100644
index 456760ea..00000000
--- a/wgpu/src/widget/canvas/cursor.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use iced_native::{Point, Rectangle};
-
-/// The mouse cursor state.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Cursor {
- /// The cursor has a defined position.
- Available(Point),
-
- /// The cursor is currently unavailable (i.e. out of bounds or busy).
- Unavailable,
-}
-
-impl Cursor {
- // TODO: Remove this once this type is used in `iced_native` to encode
- // proper cursor availability
- pub(crate) fn from_window_position(position: Point) -> Self {
- if position.x < 0.0 || position.y < 0.0 {
- Cursor::Unavailable
- } else {
- Cursor::Available(position)
- }
- }
-
- /// Returns the absolute position of the [`Cursor`], if available.
- ///
- /// [`Cursor`]: enum.Cursor.html
- pub fn position(&self) -> Option<Point> {
- match self {
- Cursor::Available(position) => Some(*position),
- Cursor::Unavailable => None,
- }
- }
-
- /// Returns the relative position of the [`Cursor`] inside the given bounds,
- /// if available.
- ///
- /// If the [`Cursor`] is not over the provided bounds, this method will
- /// return `None`.
- ///
- /// [`Cursor`]: enum.Cursor.html
- pub fn position_in(&self, bounds: &Rectangle) -> Option<Point> {
- if self.is_over(bounds) {
- self.position_from(bounds.position())
- } else {
- None
- }
- }
-
- /// Returns the relative position of the [`Cursor`] from the given origin,
- /// if available.
- ///
- /// [`Cursor`]: enum.Cursor.html
- pub fn position_from(&self, origin: Point) -> Option<Point> {
- match self {
- Cursor::Available(position) => {
- Some(Point::new(position.x - origin.x, position.y - origin.y))
- }
- Cursor::Unavailable => None,
- }
- }
-
- /// Returns whether the [`Cursor`] is currently over the provided bounds
- /// or not.
- ///
- /// [`Cursor`]: enum.Cursor.html
- pub fn is_over(&self, bounds: &Rectangle) -> bool {
- match self {
- Cursor::Available(position) => bounds.contains(*position),
- Cursor::Unavailable => false,
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/event.rs b/wgpu/src/widget/canvas/event.rs
deleted file mode 100644
index ad11f51e..00000000
--- a/wgpu/src/widget/canvas/event.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use iced_native::mouse;
-
-/// A [`Canvas`] event.
-///
-/// [`Canvas`]: struct.Event.html
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Event {
- /// A mouse event.
- Mouse(mouse::Event),
-}
diff --git a/wgpu/src/widget/canvas/fill.rs b/wgpu/src/widget/canvas/fill.rs
deleted file mode 100644
index a2010e45..00000000
--- a/wgpu/src/widget/canvas/fill.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use iced_native::Color;
-
-/// The style used to fill geometry.
-#[derive(Debug, Clone, Copy)]
-pub enum Fill {
- /// Fill with a color.
- Color(Color),
-}
-
-impl Default for Fill {
- fn default() -> Fill {
- Fill::Color(Color::BLACK)
- }
-}
-
-impl From<Color> for Fill {
- fn from(color: Color) -> Fill {
- Fill::Color(color)
- }
-}
diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs
deleted file mode 100644
index 5262ab4e..00000000
--- a/wgpu/src/widget/canvas/frame.rs
+++ /dev/null
@@ -1,367 +0,0 @@
-use iced_native::{Point, Rectangle, Size, Vector};
-
-use crate::{
- canvas::{Fill, Geometry, Path, Stroke, Text},
- triangle, Primitive,
-};
-
-/// The frame of a [`Canvas`].
-///
-/// [`Canvas`]: struct.Canvas.html
-#[derive(Debug)]
-pub struct Frame {
- size: Size,
- buffers: lyon::tessellation::VertexBuffers<triangle::Vertex2D, u32>,
- primitives: Vec<Primitive>,
- transforms: Transforms,
-}
-
-#[derive(Debug)]
-struct Transforms {
- previous: Vec<Transform>,
- current: Transform,
-}
-
-#[derive(Debug, Clone, Copy)]
-struct Transform {
- raw: lyon::math::Transform,
- is_identity: bool,
-}
-
-impl Frame {
- /// Creates a new empty [`Frame`] with the given dimensions.
- ///
- /// The default coordinate system of a [`Frame`] has its origin at the
- /// top-left corner of its bounds.
- ///
- /// [`Frame`]: struct.Frame.html
- pub fn new(size: Size) -> Frame {
- Frame {
- size,
- buffers: lyon::tessellation::VertexBuffers::new(),
- primitives: Vec::new(),
- transforms: Transforms {
- previous: Vec::new(),
- current: Transform {
- raw: lyon::math::Transform::identity(),
- is_identity: true,
- },
- },
- }
- }
-
- /// Returns the width of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn width(&self) -> f32 {
- self.size.width
- }
-
- /// Returns the width of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn height(&self) -> f32 {
- self.size.height
- }
-
- /// Returns the dimensions of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn size(&self) -> Size {
- self.size
- }
-
- /// Returns the coordinate of the center of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn center(&self) -> Point {
- Point::new(self.size.width / 2.0, self.size.height / 2.0)
- }
-
- /// Draws the given [`Path`] on the [`Frame`] by filling it with the
- /// provided style.
- ///
- /// [`Path`]: path/struct.Path.html
- /// [`Frame`]: struct.Frame.html
- pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
- use lyon::tessellation::{
- BuffersBuilder, FillOptions, FillTessellator,
- };
-
- let mut buffers = BuffersBuilder::new(
- &mut self.buffers,
- FillVertex(match fill.into() {
- Fill::Color(color) => color.into_linear(),
- }),
- );
-
- let mut tessellator = FillTessellator::new();
-
- let result = if self.transforms.current.is_identity {
- tessellator.tessellate_path(
- path.raw(),
- &FillOptions::default(),
- &mut buffers,
- )
- } else {
- let path = path.transformed(&self.transforms.current.raw);
-
- tessellator.tessellate_path(
- path.raw(),
- &FillOptions::default(),
- &mut buffers,
- )
- };
-
- let _ = result.expect("Tessellate path");
- }
-
- /// Draws an axis-aligned rectangle given its top-left corner coordinate and
- /// its `Size` on the [`Frame`] by filling it with the provided style.
- ///
- /// [`Frame`]: struct.Frame.html
- pub fn fill_rectangle(
- &mut self,
- top_left: Point,
- size: Size,
- fill: impl Into<Fill>,
- ) {
- use lyon::tessellation::{BuffersBuilder, FillOptions};
-
- let mut buffers = BuffersBuilder::new(
- &mut self.buffers,
- FillVertex(match fill.into() {
- Fill::Color(color) => color.into_linear(),
- }),
- );
-
- let top_left =
- self.transforms.current.raw.transform_point(
- lyon::math::Point::new(top_left.x, top_left.y),
- );
-
- let size =
- self.transforms.current.raw.transform_vector(
- lyon::math::Vector::new(size.width, size.height),
- );
-
- let _ = lyon::tessellation::basic_shapes::fill_rectangle(
- &lyon::math::Rect::new(top_left, size.into()),
- &FillOptions::default(),
- &mut buffers,
- )
- .expect("Fill rectangle");
- }
-
- /// Draws the stroke of the given [`Path`] on the [`Frame`] with the
- /// provided style.
- ///
- /// [`Path`]: path/struct.Path.html
- /// [`Frame`]: struct.Frame.html
- pub fn stroke(&mut self, path: &Path, stroke: impl Into<Stroke>) {
- use lyon::tessellation::{
- BuffersBuilder, StrokeOptions, StrokeTessellator,
- };
-
- let stroke = stroke.into();
-
- let mut buffers = BuffersBuilder::new(
- &mut self.buffers,
- StrokeVertex(stroke.color.into_linear()),
- );
-
- let mut tessellator = StrokeTessellator::new();
-
- let mut options = StrokeOptions::default();
- options.line_width = stroke.width;
- options.start_cap = stroke.line_cap.into();
- options.end_cap = stroke.line_cap.into();
- options.line_join = stroke.line_join.into();
-
- let result = if self.transforms.current.is_identity {
- tessellator.tessellate_path(path.raw(), &options, &mut buffers)
- } else {
- let path = path.transformed(&self.transforms.current.raw);
-
- tessellator.tessellate_path(path.raw(), &options, &mut buffers)
- };
-
- let _ = result.expect("Stroke path");
- }
-
- /// Draws the characters of the given [`Text`] on the [`Frame`], filling
- /// them with the given color.
- ///
- /// __Warning:__ Text currently does not work well with rotations and scale
- /// transforms! The position will be correctly transformed, but the
- /// resulting glyphs will not be rotated or scaled properly.
- ///
- /// Additionally, all text will be rendered on top of all the layers of
- /// a [`Canvas`]. Therefore, it is currently only meant to be used for
- /// overlays, which is the most common use case.
- ///
- /// Support for vectorial text is planned, and should address all these
- /// limitations.
- ///
- /// [`Text`]: struct.Text.html
- /// [`Frame`]: struct.Frame.html
- /// [`Canvas`]: struct.Canvas.html
- pub fn fill_text(&mut self, text: impl Into<Text>) {
- use std::f32;
-
- let text = text.into();
-
- let position = if self.transforms.current.is_identity {
- text.position
- } else {
- let transformed = self.transforms.current.raw.transform_point(
- lyon::math::Point::new(text.position.x, text.position.y),
- );
-
- Point::new(transformed.x, transformed.y)
- };
-
- // TODO: Use vectorial text instead of primitive
- self.primitives.push(Primitive::Text {
- content: text.content,
- bounds: Rectangle {
- x: position.x,
- y: position.y,
- width: f32::INFINITY,
- height: f32::INFINITY,
- },
- color: text.color,
- size: text.size,
- font: text.font,
- horizontal_alignment: text.horizontal_alignment,
- vertical_alignment: text.vertical_alignment,
- });
- }
-
- /// Stores the current transform of the [`Frame`] and executes the given
- /// drawing operations, restoring the transform afterwards.
- ///
- /// This method is useful to compose transforms and perform drawing
- /// operations in different coordinate systems.
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) {
- self.transforms.previous.push(self.transforms.current);
-
- f(self);
-
- self.transforms.current = self.transforms.previous.pop().unwrap();
- }
-
- /// Applies a translation to the current transform of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn translate(&mut self, translation: Vector) {
- self.transforms.current.raw = self
- .transforms
- .current
- .raw
- .pre_translate(lyon::math::Vector::new(
- translation.x,
- translation.y,
- ));
- self.transforms.current.is_identity = false;
- }
-
- /// Applies a rotation to the current transform of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn rotate(&mut self, angle: f32) {
- self.transforms.current.raw = self
- .transforms
- .current
- .raw
- .pre_rotate(lyon::math::Angle::radians(-angle));
- self.transforms.current.is_identity = false;
- }
-
- /// Applies a scaling to the current transform of the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- #[inline]
- pub fn scale(&mut self, scale: f32) {
- self.transforms.current.raw =
- self.transforms.current.raw.pre_scale(scale, scale);
- self.transforms.current.is_identity = false;
- }
-
- /// Produces the [`Geometry`] representing everything drawn on the [`Frame`].
- ///
- /// [`Frame`]: struct.Frame.html
- /// [`Geometry`]: struct.Geometry.html
- pub fn into_geometry(mut self) -> Geometry {
- if !self.buffers.indices.is_empty() {
- self.primitives.push(Primitive::Mesh2D {
- size: self.size,
- buffers: triangle::Mesh2D {
- vertices: self.buffers.vertices,
- indices: self.buffers.indices,
- },
- });
- }
-
- Geometry::from_primitive(Primitive::Group {
- primitives: self.primitives,
- })
- }
-}
-
-struct FillVertex([f32; 4]);
-
-impl lyon::tessellation::BasicVertexConstructor<triangle::Vertex2D>
- for FillVertex
-{
- fn new_vertex(
- &mut self,
- position: lyon::math::Point,
- ) -> triangle::Vertex2D {
- triangle::Vertex2D {
- position: [position.x, position.y],
- color: self.0,
- }
- }
-}
-
-impl lyon::tessellation::FillVertexConstructor<triangle::Vertex2D>
- for FillVertex
-{
- fn new_vertex(
- &mut self,
- position: lyon::math::Point,
- _attributes: lyon::tessellation::FillAttributes<'_>,
- ) -> triangle::Vertex2D {
- triangle::Vertex2D {
- position: [position.x, position.y],
- color: self.0,
- }
- }
-}
-
-struct StrokeVertex([f32; 4]);
-
-impl lyon::tessellation::StrokeVertexConstructor<triangle::Vertex2D>
- for StrokeVertex
-{
- fn new_vertex(
- &mut self,
- position: lyon::math::Point,
- _attributes: lyon::tessellation::StrokeAttributes<'_, '_>,
- ) -> triangle::Vertex2D {
- triangle::Vertex2D {
- position: [position.x, position.y],
- color: self.0,
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs
deleted file mode 100644
index 4cadee39..00000000
--- a/wgpu/src/widget/canvas/geometry.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use crate::Primitive;
-
-/// A bunch of shapes that can be drawn.
-///
-/// [`Geometry`] can be easily generated with a [`Frame`] or stored in a
-/// [`Cache`].
-///
-/// [`Geometry`]: struct.Geometry.html
-/// [`Frame`]: struct.Frame.html
-/// [`Cache`]: struct.Cache.html
-#[derive(Debug, Clone)]
-pub struct Geometry(Primitive);
-
-impl Geometry {
- pub(crate) fn from_primitive(primitive: Primitive) -> Self {
- Self(primitive)
- }
-
- /// Turns the [`Geometry`] into a [`Primitive`].
- ///
- /// This can be useful if you are building a custom widget.
- ///
- /// [`Geometry`]: struct.Geometry.html
- /// [`Primitive`]: ../enum.Primitive.html
- pub fn into_primitive(self) -> Primitive {
- self.0
- }
-}
-
-impl From<Geometry> for Primitive {
- fn from(geometry: Geometry) -> Primitive {
- geometry.0
- }
-}
diff --git a/wgpu/src/widget/canvas/path.rs b/wgpu/src/widget/canvas/path.rs
deleted file mode 100644
index c26bf187..00000000
--- a/wgpu/src/widget/canvas/path.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-//! Build different kinds of 2D shapes.
-pub mod arc;
-
-mod builder;
-
-#[doc(no_inline)]
-pub use arc::Arc;
-pub use builder::Builder;
-
-use iced_native::{Point, Size};
-
-/// An immutable set of points that may or may not be connected.
-///
-/// A single [`Path`] can represent different kinds of 2D shapes!
-///
-/// [`Path`]: struct.Path.html
-#[derive(Debug, Clone)]
-pub struct Path {
- raw: lyon::path::Path,
-}
-
-impl Path {
- /// Creates a new [`Path`] with the provided closure.
- ///
- /// Use the [`Builder`] to configure your [`Path`].
- ///
- /// [`Path`]: struct.Path.html
- /// [`Builder`]: struct.Builder.html
- pub fn new(f: impl FnOnce(&mut Builder)) -> Self {
- let mut builder = Builder::new();
-
- // TODO: Make it pure instead of side-effect-based (?)
- f(&mut builder);
-
- builder.build()
- }
-
- /// Creates a new [`Path`] representing a line segment given its starting
- /// and end points.
- ///
- /// [`Path`]: struct.Path.html
- pub fn line(from: Point, to: Point) -> Self {
- Self::new(|p| {
- p.move_to(from);
- p.line_to(to);
- })
- }
-
- /// Creates a new [`Path`] representing a rectangle given its top-left
- /// corner coordinate and its `Size`.
- ///
- /// [`Path`]: struct.Path.html
- pub fn rectangle(top_left: Point, size: Size) -> Self {
- Self::new(|p| p.rectangle(top_left, size))
- }
-
- /// Creates a new [`Path`] representing a circle given its center
- /// coordinate and its radius.
- ///
- /// [`Path`]: struct.Path.html
- pub fn circle(center: Point, radius: f32) -> Self {
- Self::new(|p| p.circle(center, radius))
- }
-
- #[inline]
- pub(crate) fn raw(&self) -> &lyon::path::Path {
- &self.raw
- }
-
- #[inline]
- pub(crate) fn transformed(
- &self,
- transform: &lyon::math::Transform,
- ) -> Path {
- Path {
- raw: self.raw.transformed(transform),
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/path/arc.rs b/wgpu/src/widget/canvas/path/arc.rs
deleted file mode 100644
index 343191f1..00000000
--- a/wgpu/src/widget/canvas/path/arc.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-//! Build and draw curves.
-use iced_native::{Point, Vector};
-
-/// A segment of a differentiable curve.
-#[derive(Debug, Clone, Copy)]
-pub struct Arc {
- /// The center of the arc.
- pub center: Point,
- /// The radius of the arc.
- pub radius: f32,
- /// The start of the segment's angle, clockwise rotation.
- pub start_angle: f32,
- /// The end of the segment's angle, clockwise rotation.
- pub end_angle: f32,
-}
-
-/// An elliptical [`Arc`].
-///
-/// [`Arc`]: struct.Arc.html
-#[derive(Debug, Clone, Copy)]
-pub struct Elliptical {
- /// The center of the arc.
- pub center: Point,
- /// The radii of the arc's ellipse, defining its axes.
- pub radii: Vector,
- /// The rotation of the arc's ellipse.
- pub rotation: f32,
- /// The start of the segment's angle, clockwise rotation.
- pub start_angle: f32,
- /// The end of the segment's angle, clockwise rotation.
- pub end_angle: f32,
-}
-
-impl From<Arc> for Elliptical {
- fn from(arc: Arc) -> Elliptical {
- Elliptical {
- center: arc.center,
- radii: Vector::new(arc.radius, arc.radius),
- rotation: 0.0,
- start_angle: arc.start_angle,
- end_angle: arc.end_angle,
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/path/builder.rs b/wgpu/src/widget/canvas/path/builder.rs
deleted file mode 100644
index 6511fa52..00000000
--- a/wgpu/src/widget/canvas/path/builder.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-use crate::canvas::path::{arc, Arc, Path};
-
-use iced_native::{Point, Size};
-use lyon::path::builder::{Build, FlatPathBuilder, PathBuilder, SvgBuilder};
-
-/// A [`Path`] builder.
-///
-/// Once a [`Path`] is built, it can no longer be mutated.
-///
-/// [`Path`]: struct.Path.html
-#[allow(missing_debug_implementations)]
-pub struct Builder {
- raw: lyon::path::builder::SvgPathBuilder<lyon::path::Builder>,
-}
-
-impl Builder {
- /// Creates a new [`Builder`].
- ///
- /// [`Builder`]: struct.Builder.html
- pub fn new() -> Builder {
- Builder {
- raw: lyon::path::Path::builder().with_svg(),
- }
- }
-
- /// Moves the starting point of a new sub-path to the given `Point`.
- #[inline]
- pub fn move_to(&mut self, point: Point) {
- let _ = self.raw.move_to(lyon::math::Point::new(point.x, point.y));
- }
-
- /// Connects the last point in the [`Path`] to the given `Point` with a
- /// straight line.
- ///
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn line_to(&mut self, point: Point) {
- let _ = self.raw.line_to(lyon::math::Point::new(point.x, point.y));
- }
-
- /// Adds an [`Arc`] to the [`Path`] from `start_angle` to `end_angle` in
- /// a clockwise direction.
- ///
- /// [`Arc`]: struct.Arc.html
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn arc(&mut self, arc: Arc) {
- self.ellipse(arc.into());
- }
-
- /// Adds a circular arc to the [`Path`] with the given control points and
- /// radius.
- ///
- /// The arc is connected to the previous point by a straight line, if
- /// necessary.
- ///
- /// [`Path`]: struct.Path.html
- pub fn arc_to(&mut self, a: Point, b: Point, radius: f32) {
- use lyon::{math, path};
-
- let a = math::Point::new(a.x, a.y);
-
- if self.raw.current_position() != a {
- let _ = self.raw.line_to(a);
- }
-
- let _ = self.raw.arc_to(
- math::Vector::new(radius, radius),
- math::Angle::radians(0.0),
- path::ArcFlags::default(),
- math::Point::new(b.x, b.y),
- );
- }
-
- /// Adds an [`Ellipse`] to the [`Path`] using a clockwise direction.
- ///
- /// [`Ellipse`]: struct.Arc.html
- /// [`Path`]: struct.Path.html
- pub fn ellipse(&mut self, arc: arc::Elliptical) {
- use lyon::{geom, math};
-
- let arc = geom::Arc {
- center: math::Point::new(arc.center.x, arc.center.y),
- radii: math::Vector::new(arc.radii.x, arc.radii.y),
- x_rotation: math::Angle::radians(arc.rotation),
- start_angle: math::Angle::radians(arc.start_angle),
- sweep_angle: math::Angle::radians(arc.end_angle),
- };
-
- let _ = self.raw.move_to(arc.sample(0.0));
-
- arc.for_each_quadratic_bezier(&mut |curve| {
- let _ = self.raw.quadratic_bezier_to(curve.ctrl, curve.to);
- });
- }
-
- /// Adds a cubic Bézier curve to the [`Path`] given its two control points
- /// and its end point.
- ///
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn bezier_curve_to(
- &mut self,
- control_a: Point,
- control_b: Point,
- to: Point,
- ) {
- use lyon::math;
-
- let _ = self.raw.cubic_bezier_to(
- math::Point::new(control_a.x, control_a.y),
- math::Point::new(control_b.x, control_b.y),
- math::Point::new(to.x, to.y),
- );
- }
-
- /// Adds a quadratic Bézier curve to the [`Path`] given its control point
- /// and its end point.
- ///
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn quadratic_curve_to(&mut self, control: Point, to: Point) {
- use lyon::math;
-
- let _ = self.raw.quadratic_bezier_to(
- math::Point::new(control.x, control.y),
- math::Point::new(to.x, to.y),
- );
- }
-
- /// Adds a rectangle to the [`Path`] given its top-left corner coordinate
- /// and its `Size`.
- ///
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn rectangle(&mut self, top_left: Point, size: Size) {
- self.move_to(top_left);
- self.line_to(Point::new(top_left.x + size.width, top_left.y));
- self.line_to(Point::new(
- top_left.x + size.width,
- top_left.y + size.height,
- ));
- self.line_to(Point::new(top_left.x, top_left.y + size.height));
- self.close();
- }
-
- /// Adds a circle to the [`Path`] given its center coordinate and its
- /// radius.
- ///
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn circle(&mut self, center: Point, radius: f32) {
- self.arc(Arc {
- center,
- radius,
- start_angle: 0.0,
- end_angle: 2.0 * std::f32::consts::PI,
- });
- }
-
- /// Closes the current sub-path in the [`Path`] with a straight line to
- /// the starting point.
- ///
- /// [`Path`]: struct.Path.html
- #[inline]
- pub fn close(&mut self) {
- self.raw.close()
- }
-
- /// Builds the [`Path`] of this [`Builder`].
- ///
- /// [`Path`]: struct.Path.html
- /// [`Builder`]: struct.Builder.html
- #[inline]
- pub fn build(self) -> Path {
- Path {
- raw: self.raw.build(),
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs
deleted file mode 100644
index 725d9d72..00000000
--- a/wgpu/src/widget/canvas/program.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-use crate::canvas::{Cursor, Event, Geometry};
-use iced_native::{mouse, Rectangle};
-
-/// The state and logic of a [`Canvas`].
-///
-/// A [`Program`] can mutate internal state and produce messages for an
-/// application.
-///
-/// [`Canvas`]: struct.Canvas.html
-/// [`Program`]: trait.Program.html
-pub trait Program<Message> {
- /// Updates the state of the [`Program`].
- ///
- /// When a [`Program`] is used in a [`Canvas`], the runtime will call this
- /// method for each [`Event`].
- ///
- /// This method can optionally return a `Message` to notify an application
- /// of any meaningful interactions.
- ///
- /// By default, this method does and returns nothing.
- ///
- /// [`Program`]: trait.Program.html
- /// [`Canvas`]: struct.Canvas.html
- /// [`Event`]: enum.Event.html
- fn update(
- &mut self,
- _event: Event,
- _bounds: Rectangle,
- _cursor: Cursor,
- ) -> Option<Message> {
- None
- }
-
- /// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
- ///
- /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a
- /// [`Cache`].
- ///
- /// [`Program`]: trait.Program.html
- /// [`Geometry`]: struct.Geometry.html
- /// [`Frame`]: struct.Frame.html
- /// [`Cache`]: struct.Cache.html
- fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry>;
-
- /// Returns the current mouse interaction of the [`Program`].
- ///
- /// The interaction returned will be in effect even if the cursor position
- /// is out of bounds of the program's [`Canvas`].
- ///
- /// [`Program`]: trait.Program.html
- /// [`Canvas`]: struct.Canvas.html
- fn mouse_interaction(
- &self,
- _bounds: Rectangle,
- _cursor: Cursor,
- ) -> mouse::Interaction {
- mouse::Interaction::default()
- }
-}
-
-impl<T, Message> Program<Message> for &mut T
-where
- T: Program<Message>,
-{
- fn update(
- &mut self,
- event: Event,
- bounds: Rectangle,
- cursor: Cursor,
- ) -> Option<Message> {
- T::update(self, event, bounds, cursor)
- }
-
- fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry> {
- T::draw(self, bounds, cursor)
- }
-
- fn mouse_interaction(
- &self,
- bounds: Rectangle,
- cursor: Cursor,
- ) -> mouse::Interaction {
- T::mouse_interaction(self, bounds, cursor)
- }
-}
diff --git a/wgpu/src/widget/canvas/stroke.rs b/wgpu/src/widget/canvas/stroke.rs
deleted file mode 100644
index 5b6fc56a..00000000
--- a/wgpu/src/widget/canvas/stroke.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-use iced_native::Color;
-
-/// The style of a stroke.
-#[derive(Debug, Clone, Copy)]
-pub struct Stroke {
- /// The color of the stroke.
- pub color: Color,
- /// The distance between the two edges of the stroke.
- pub width: f32,
- /// The shape to be used at the end of open subpaths when they are stroked.
- pub line_cap: LineCap,
- /// The shape to be used at the corners of paths or basic shapes when they
- /// are stroked.
- pub line_join: LineJoin,
-}
-
-impl Stroke {
- /// Sets the color of the [`Stroke`].
- ///
- /// [`Stroke`]: struct.Stroke.html
- pub fn with_color(self, color: Color) -> Stroke {
- Stroke { color, ..self }
- }
-
- /// Sets the width of the [`Stroke`].
- ///
- /// [`Stroke`]: struct.Stroke.html
- pub fn with_width(self, width: f32) -> Stroke {
- Stroke { width, ..self }
- }
-
- /// Sets the [`LineCap`] of the [`Stroke`].
- ///
- /// [`LineCap`]: enum.LineCap.html
- /// [`Stroke`]: struct.Stroke.html
- pub fn with_line_cap(self, line_cap: LineCap) -> Stroke {
- Stroke { line_cap, ..self }
- }
-
- /// Sets the [`LineJoin`] of the [`Stroke`].
- ///
- /// [`LineJoin`]: enum.LineJoin.html
- /// [`Stroke`]: struct.Stroke.html
- pub fn with_line_join(self, line_join: LineJoin) -> Stroke {
- Stroke { line_join, ..self }
- }
-}
-
-impl Default for Stroke {
- fn default() -> Stroke {
- Stroke {
- color: Color::BLACK,
- width: 1.0,
- line_cap: LineCap::default(),
- line_join: LineJoin::default(),
- }
- }
-}
-
-/// The shape used at the end of open subpaths when they are stroked.
-#[derive(Debug, Clone, Copy)]
-pub enum LineCap {
- /// The stroke for each sub-path does not extend beyond its two endpoints.
- Butt,
- /// At the end of each sub-path, the shape representing the stroke will be
- /// extended by a square.
- Square,
- /// At the end of each sub-path, the shape representing the stroke will be
- /// extended by a semicircle.
- Round,
-}
-
-impl Default for LineCap {
- fn default() -> LineCap {
- LineCap::Butt
- }
-}
-
-impl From<LineCap> for lyon::tessellation::LineCap {
- fn from(line_cap: LineCap) -> lyon::tessellation::LineCap {
- match line_cap {
- LineCap::Butt => lyon::tessellation::LineCap::Butt,
- LineCap::Square => lyon::tessellation::LineCap::Square,
- LineCap::Round => lyon::tessellation::LineCap::Round,
- }
- }
-}
-
-/// The shape used at the corners of paths or basic shapes when they are
-/// stroked.
-#[derive(Debug, Clone, Copy)]
-pub enum LineJoin {
- /// A sharp corner.
- Miter,
- /// A round corner.
- Round,
- /// A bevelled corner.
- Bevel,
-}
-
-impl Default for LineJoin {
- fn default() -> LineJoin {
- LineJoin::Miter
- }
-}
-
-impl From<LineJoin> for lyon::tessellation::LineJoin {
- fn from(line_join: LineJoin) -> lyon::tessellation::LineJoin {
- match line_join {
- LineJoin::Miter => lyon::tessellation::LineJoin::Miter,
- LineJoin::Round => lyon::tessellation::LineJoin::Round,
- LineJoin::Bevel => lyon::tessellation::LineJoin::Bevel,
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/text.rs b/wgpu/src/widget/canvas/text.rs
deleted file mode 100644
index c4cae30e..00000000
--- a/wgpu/src/widget/canvas/text.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use iced_native::{Color, Font, HorizontalAlignment, Point, VerticalAlignment};
-
-/// A bunch of text that can be drawn to a canvas
-#[derive(Debug, Clone)]
-pub struct Text {
- /// The contents of the text
- pub content: String,
- /// The position where to begin drawing the text (top-left corner coordinates)
- pub position: Point,
- /// The color of the text
- pub color: Color,
- /// The size of the text
- pub size: f32,
- /// The font of the text
- pub font: Font,
- /// The horizontal alignment of the text
- pub horizontal_alignment: HorizontalAlignment,
- /// The vertical alignment of the text
- pub vertical_alignment: VerticalAlignment,
-}
-
-impl Default for Text {
- fn default() -> Text {
- Text {
- content: String::new(),
- position: Point::ORIGIN,
- color: Color::BLACK,
- size: 16.0,
- font: Font::Default,
- horizontal_alignment: HorizontalAlignment::Left,
- vertical_alignment: VerticalAlignment::Top,
- }
- }
-}
-
-impl From<String> for Text {
- fn from(content: String) -> Text {
- Text {
- content,
- ..Default::default()
- }
- }
-}
-
-impl From<&str> for Text {
- fn from(content: &str) -> Text {
- String::from(content).into()
- }
-}
diff --git a/wgpu/src/widget/checkbox.rs b/wgpu/src/widget/checkbox.rs
index da0d7a84..d27d77cc 100644
--- a/wgpu/src/widget/checkbox.rs
+++ b/wgpu/src/widget/checkbox.rs
@@ -1,7 +1,7 @@
//! Show toggle controls using checkboxes.
use crate::Renderer;
-pub use iced_style::checkbox::{Style, StyleSheet};
+pub use iced_graphics::checkbox::{Style, StyleSheet};
/// A box that can be checked.
///
diff --git a/wgpu/src/widget/container.rs b/wgpu/src/widget/container.rs
index 9a93a246..bc26cef2 100644
--- a/wgpu/src/widget/container.rs
+++ b/wgpu/src/widget/container.rs
@@ -1,7 +1,7 @@
//! Decorate content and apply alignment.
use crate::Renderer;
-pub use iced_style::container::{Style, StyleSheet};
+pub use iced_graphics::container::{Style, StyleSheet};
/// An element decorating some content.
///
diff --git a/wgpu/src/widget/progress_bar.rs b/wgpu/src/widget/progress_bar.rs
index 770bcea8..a636a3a6 100644
--- a/wgpu/src/widget/progress_bar.rs
+++ b/wgpu/src/widget/progress_bar.rs
@@ -6,7 +6,7 @@
//! [`ProgressBar`]: type.ProgressBar.html
use crate::Renderer;
-pub use iced_style::progress_bar::{Style, StyleSheet};
+pub use iced_graphics::progress_bar::{Style, StyleSheet};
/// A bar that displays progress.
///
diff --git a/wgpu/src/widget/radio.rs b/wgpu/src/widget/radio.rs
index 6e5cf042..0b843d1f 100644
--- a/wgpu/src/widget/radio.rs
+++ b/wgpu/src/widget/radio.rs
@@ -1,7 +1,7 @@
//! Create choices using radio buttons.
use crate::Renderer;
-pub use iced_style::radio::{Style, StyleSheet};
+pub use iced_graphics::radio::{Style, StyleSheet};
/// A circular button representing a choice.
///
diff --git a/wgpu/src/widget/scrollable.rs b/wgpu/src/widget/scrollable.rs
index 1d236105..fabb4318 100644
--- a/wgpu/src/widget/scrollable.rs
+++ b/wgpu/src/widget/scrollable.rs
@@ -1,8 +1,8 @@
//! Navigate an endless amount of content with a scrollbar.
use crate::Renderer;
+pub use iced_graphics::scrollable::{Scrollbar, Scroller, StyleSheet};
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.
diff --git a/wgpu/src/widget/slider.rs b/wgpu/src/widget/slider.rs
index 4e47978f..cf036829 100644
--- a/wgpu/src/widget/slider.rs
+++ b/wgpu/src/widget/slider.rs
@@ -6,8 +6,8 @@
//! [`State`]: struct.State.html
use crate::Renderer;
+pub use iced_graphics::slider::{Handle, HandleShape, Style, StyleSheet};
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.
diff --git a/wgpu/src/widget/text.rs b/wgpu/src/widget/text.rs
deleted file mode 100644
index 1053ea97..00000000
--- a/wgpu/src/widget/text.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//! 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 = iced_native::Text<Renderer>;
diff --git a/wgpu/src/widget/text_input.rs b/wgpu/src/widget/text_input.rs
index 260fe3a6..1da3fbe6 100644
--- a/wgpu/src/widget/text_input.rs
+++ b/wgpu/src/widget/text_input.rs
@@ -6,8 +6,8 @@
//! [`State`]: struct.State.html
use crate::Renderer;
+pub use iced_graphics::text_input::{Style, StyleSheet};
pub use iced_native::text_input::State;
-pub use iced_style::text_input::{Style, StyleSheet};
/// A field that can be filled with text.
///
diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs
index b7adad82..aac5fb9e 100644
--- a/wgpu/src/window.rs
+++ b/wgpu/src/window.rs
@@ -1,6 +1,4 @@
//! Display rendering results on windows.
-mod backend;
-mod swap_chain;
+mod compositor;
-pub use backend::Backend;
-pub use swap_chain::SwapChain;
+pub use compositor::Compositor;
diff --git a/wgpu/src/window/backend.rs b/wgpu/src/window/compositor.rs
index 2924ce5d..600bc81c 100644
--- a/wgpu/src/window/backend.rs
+++ b/wgpu/src/window/compositor.rs
@@ -1,23 +1,24 @@
-use crate::{window::SwapChain, Renderer, Settings, Target};
+use crate::{Renderer, Settings};
+use iced_graphics::Viewport;
use iced_native::{futures, mouse};
use raw_window_handle::HasRawWindowHandle;
/// A window graphics backend for iced powered by `wgpu`.
#[derive(Debug)]
-pub struct Backend {
+pub struct Compositor {
device: wgpu::Device,
queue: wgpu::Queue,
format: wgpu::TextureFormat,
}
-impl iced_native::window::Backend for Backend {
+impl iced_graphics::window::Compositor for Compositor {
type Settings = Settings;
type Renderer = Renderer;
type Surface = wgpu::Surface;
- type SwapChain = SwapChain;
+ type SwapChain = wgpu::SwapChain;
- fn new(settings: Self::Settings) -> (Backend, Renderer) {
+ fn new(settings: Self::Settings) -> (Self, Renderer) {
let (mut device, queue) = futures::executor::block_on(async {
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
@@ -43,10 +44,11 @@ impl iced_native::window::Backend for Backend {
.await
});
- let renderer = Renderer::new(&mut device, settings);
+ let renderer =
+ Renderer::new(crate::Backend::new(&mut device, settings));
(
- Backend {
+ Self {
device,
queue,
format: settings.format,
@@ -67,19 +69,28 @@ impl iced_native::window::Backend for Backend {
surface: &Self::Surface,
width: u32,
height: u32,
- ) -> SwapChain {
- SwapChain::new(&self.device, surface, self.format, width, height)
+ ) -> Self::SwapChain {
+ self.device.create_swap_chain(
+ surface,
+ &wgpu::SwapChainDescriptor {
+ usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
+ format: self.format,
+ width,
+ height,
+ present_mode: wgpu::PresentMode::Mailbox,
+ },
+ )
}
fn draw<T: AsRef<str>>(
&mut self,
renderer: &mut Self::Renderer,
- swap_chain: &mut SwapChain,
+ swap_chain: &mut Self::SwapChain,
+ viewport: &Viewport,
output: &<Self::Renderer as iced_native::Renderer>::Output,
- scale_factor: f64,
overlay: &[T],
) -> mouse::Interaction {
- let (frame, viewport) = swap_chain.next_frame().expect("Next frame");
+ let frame = swap_chain.get_next_texture().expect("Next frame");
let mut encoder = self.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None },
@@ -101,15 +112,12 @@ impl iced_native::window::Backend for Backend {
depth_stencil_attachment: None,
});
- let mouse_interaction = renderer.draw(
+ let mouse_interaction = renderer.backend_mut().draw(
&mut self.device,
&mut encoder,
- Target {
- texture: &frame.view,
- viewport,
- },
+ &frame.view,
+ viewport,
output,
- scale_factor,
overlay,
);
diff --git a/wgpu/src/window/swap_chain.rs b/wgpu/src/window/swap_chain.rs
deleted file mode 100644
index 72e58a50..00000000
--- a/wgpu/src/window/swap_chain.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::Viewport;
-
-/// The rendering target of a window.
-///
-/// It represents a series of virtual framebuffers with a scale factor.
-#[derive(Debug)]
-pub struct SwapChain {
- raw: wgpu::SwapChain,
- viewport: Viewport,
-}
-
-impl SwapChain {}
-
-impl SwapChain {
- /// Creates a new [`SwapChain`] for the given surface.
- ///
- /// [`SwapChain`]: struct.SwapChain.html
- pub fn new(
- device: &wgpu::Device,
- surface: &wgpu::Surface,
- format: wgpu::TextureFormat,
- width: u32,
- height: u32,
- ) -> SwapChain {
- SwapChain {
- raw: new_swap_chain(surface, format, width, height, device),
- viewport: Viewport::new(width, height),
- }
- }
-
- /// Returns the next frame of the [`SwapChain`] alongside its [`Viewport`].
- ///
- /// [`SwapChain`]: struct.SwapChain.html
- /// [`Viewport`]: ../struct.Viewport.html
- pub fn next_frame(
- &mut self,
- ) -> Result<(wgpu::SwapChainOutput, &Viewport), wgpu::TimeOut> {
- let viewport = &self.viewport;
-
- self.raw.get_next_texture().map(|output| (output, viewport))
- }
-}
-
-fn new_swap_chain(
- surface: &wgpu::Surface,
- format: wgpu::TextureFormat,
- width: u32,
- height: u32,
- device: &wgpu::Device,
-) -> wgpu::SwapChain {
- device.create_swap_chain(
- &surface,
- &wgpu::SwapChainDescriptor {
- usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
- format,
- width,
- height,
- present_mode: wgpu::PresentMode::Mailbox,
- },
- )
-}