diff options
author | 2024-02-02 14:54:56 +0100 | |
---|---|---|
committer | 2024-02-02 14:54:56 +0100 | |
commit | aea172543cb49f1f1e3625f60b49336f59e26c00 (patch) | |
tree | e99e7a55873678ac37fd695a0f46c1350b30dd2f | |
parent | 759f0e922598504705b543185bc7140a652b726a (diff) | |
parent | b3adf3184594c9bf60e0548a0362d30c512f3966 (diff) | |
download | iced-aea172543cb49f1f1e3625f60b49336f59e26c00.tar.gz iced-aea172543cb49f1f1e3625f60b49336f59e26c00.tar.bz2 iced-aea172543cb49f1f1e3625f60b49336f59e26c00.zip |
Merge pull request #2120 from iced-rs/transform-primitive
`Transform` primitive
Diffstat (limited to '')
36 files changed, 623 insertions, 293 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml index 32dd3df2..2360e822 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -12,6 +12,7 @@ keywords.workspace = true [dependencies] bitflags.workspace = true +glam.workspace = true log.workspace = true num-traits.workspace = true smol_str.workspace = true diff --git a/core/src/lib.rs b/core/src/lib.rs index bbc973f0..002336ee 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -49,6 +49,7 @@ mod rectangle; mod shadow; mod shell; mod size; +mod transformation; mod vector; pub use alignment::Alignment; @@ -75,6 +76,7 @@ pub use shadow::Shadow; pub use shell::Shell; pub use size::Size; pub use text::Text; +pub use transformation::Transformation; pub use vector::Vector; pub use widget::Widget; diff --git a/core/src/mouse/interaction.rs b/core/src/mouse/interaction.rs index 072033fd..6ad66229 100644 --- a/core/src/mouse/interaction.rs +++ b/core/src/mouse/interaction.rs @@ -13,4 +13,5 @@ pub enum Interaction { ResizingHorizontally, ResizingVertically, NotAllowed, + ZoomIn, } diff --git a/core/src/pixels.rs b/core/src/pixels.rs index 6a9e5c88..425c0028 100644 --- a/core/src/pixels.rs +++ b/core/src/pixels.rs @@ -26,3 +26,11 @@ impl From<Pixels> for f32 { pixels.0 } } + +impl std::ops::Mul<f32> for Pixels { + type Output = Pixels; + + fn mul(self, rhs: f32) -> Self { + Pixels(self.0 * rhs) + } +} diff --git a/core/src/renderer.rs b/core/src/renderer.rs index 0af74bb3..1139b41c 100644 --- a/core/src/renderer.rs +++ b/core/src/renderer.rs @@ -5,7 +5,9 @@ mod null; #[cfg(debug_assertions)] pub use null::Null; -use crate::{Background, Border, Color, Rectangle, Shadow, Size, Vector}; +use crate::{ + Background, Border, Color, Rectangle, Shadow, Size, Transformation, Vector, +}; /// A component that can be used by widgets to draw themselves on a screen. pub trait Renderer: Sized { @@ -14,12 +16,24 @@ pub trait Renderer: Sized { /// The layer will clip its contents to the provided `bounds`. fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)); - /// Applies a `translation` to the primitives recorded in the given closure. + /// Applies a [`Transformation`] to the primitives recorded in the given closure. + fn with_transformation( + &mut self, + transformation: Transformation, + f: impl FnOnce(&mut Self), + ); + + /// Applies a translation to the primitives recorded in the given closure. fn with_translation( &mut self, translation: Vector, f: impl FnOnce(&mut Self), - ); + ) { + self.with_transformation( + Transformation::translate(translation.x, translation.y), + f, + ); + } /// Fills a [`Quad`] with the provided [`Background`]. fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>); diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index 455daa42..75a3c8b6 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -1,7 +1,9 @@ use crate::alignment; use crate::renderer::{self, Renderer}; use crate::text::{self, Text}; -use crate::{Background, Color, Font, Pixels, Point, Rectangle, Size, Vector}; +use crate::{ + Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, +}; use std::borrow::Cow; @@ -21,9 +23,9 @@ impl Null { impl Renderer for Null { fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {} - fn with_translation( + fn with_transformation( &mut self, - _translation: Vector, + _transformation: Transformation, _f: impl FnOnce(&mut Self), ) { } diff --git a/core/src/transformation.rs b/core/src/transformation.rs new file mode 100644 index 00000000..b2c488b0 --- /dev/null +++ b/core/src/transformation.rs @@ -0,0 +1,119 @@ +use crate::{Point, Rectangle, Size, Vector}; + +use glam::{Mat4, Vec3, Vec4}; +use std::ops::Mul; + +/// A 2D transformation matrix. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Transformation(Mat4); + +impl Transformation { + /// A [`Transformation`] that preserves whatever is transformed. + pub const IDENTITY: Self = Self(Mat4::IDENTITY); + + /// Creates an orthographic projection. + #[rustfmt::skip] + pub fn orthographic(width: u32, height: u32) -> Transformation { + Transformation(Mat4::orthographic_rh_gl( + 0.0, width as f32, + height as f32, 0.0, + -1.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 uniform scaling transformation. + pub fn scale(scaling: f32) -> Transformation { + Transformation(Mat4::from_scale(Vec3::new(scaling, scaling, 1.0))) + } + + /// Returns the scale factor of the [`Transformation`]. + pub fn scale_factor(&self) -> f32 { + self.0.x_axis.x + } + + /// Returns the translation of the [`Transformation`]. + pub fn translation(&self) -> Vector { + Vector::new(self.0.w_axis.x, self.0.w_axis.y) + } +} + +impl Mul for Transformation { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + Transformation(self.0 * rhs.0) + } +} + +impl Mul<Transformation> for Point { + type Output = Self; + + fn mul(self, transformation: Transformation) -> Self { + let point = transformation + .0 + .mul_vec4(Vec4::new(self.x, self.y, 1.0, 1.0)); + + Point::new(point.x, point.y) + } +} + +impl Mul<Transformation> for Vector { + type Output = Self; + + fn mul(self, transformation: Transformation) -> Self { + let new_vector = transformation + .0 + .mul_vec4(Vec4::new(self.x, self.y, 1.0, 0.0)); + + Vector::new(new_vector.x, new_vector.y) + } +} + +impl Mul<Transformation> for Size { + type Output = Self; + + fn mul(self, transformation: Transformation) -> Self { + let new_size = transformation.0.mul_vec4(Vec4::new( + self.width, + self.height, + 1.0, + 0.0, + )); + + Size::new(new_size.x, new_size.y) + } +} + +impl Mul<Transformation> for Rectangle { + type Output = Self; + + fn mul(self, transformation: Transformation) -> Self { + let position = self.position(); + let size = self.size(); + + Self::new(position * transformation, size * transformation) + } +} + +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() + } +} + +impl From<Transformation> for Mat4 { + fn from(transformation: Transformation) -> Self { + transformation.0 + } +} diff --git a/examples/bezier_tool/Cargo.toml b/examples/bezier_tool/Cargo.toml index b2547ff1..e5624097 100644 --- a/examples/bezier_tool/Cargo.toml +++ b/examples/bezier_tool/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["canvas"] +iced.features = ["canvas", "debug"] diff --git a/examples/loupe/Cargo.toml b/examples/loupe/Cargo.toml new file mode 100644 index 00000000..466905ba --- /dev/null +++ b/examples/loupe/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "loupe" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2021" +publish = false + +[dependencies] +iced.workspace = true +iced.features = ["advanced", "debug"]
\ No newline at end of file diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs new file mode 100644 index 00000000..8602edb7 --- /dev/null +++ b/examples/loupe/src/main.rs @@ -0,0 +1,185 @@ +use iced::widget::{button, column, container, text}; +use iced::{Alignment, Element, Length, Sandbox, Settings}; + +use loupe::loupe; + +pub fn main() -> iced::Result { + Counter::run(Settings::default()) +} + +struct Counter { + value: i32, +} + +#[derive(Debug, Clone, Copy)] +enum Message { + IncrementPressed, + DecrementPressed, +} + +impl Sandbox for Counter { + type Message = Message; + + fn new() -> Self { + Self { value: 0 } + } + + fn title(&self) -> String { + String::from("Counter - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::IncrementPressed => { + self.value += 1; + } + Message::DecrementPressed => { + self.value -= 1; + } + } + } + + fn view(&self) -> Element<Message> { + container(loupe( + 3.0, + column![ + button("Increment").on_press(Message::IncrementPressed), + text(self.value).size(50), + button("Decrement").on_press(Message::DecrementPressed) + ] + .padding(20) + .align_items(Alignment::Center), + )) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } +} + +mod loupe { + use iced::advanced::layout::{self, Layout}; + use iced::advanced::renderer; + use iced::advanced::widget::{self, Widget}; + use iced::advanced::Renderer as _; + use iced::mouse; + use iced::{ + Color, Element, Length, Rectangle, Renderer, Size, Theme, + Transformation, + }; + + pub fn loupe<'a, Message>( + zoom: f32, + content: impl Into<Element<'a, Message>>, + ) -> Loupe<'a, Message> + where + Message: 'static, + { + Loupe { + zoom, + content: content.into().explain(Color::BLACK), + } + } + + pub struct Loupe<'a, Message> { + zoom: f32, + content: Element<'a, Message>, + } + + impl<'a, Message> Widget<Message, Theme, Renderer> for Loupe<'a, Message> { + fn tag(&self) -> widget::tree::Tag { + self.content.as_widget().tag() + } + + fn state(&self) -> widget::tree::State { + self.content.as_widget().state() + } + + fn children(&self) -> Vec<widget::Tree> { + self.content.as_widget().children() + } + + fn diff(&self, tree: &mut widget::Tree) { + self.content.as_widget().diff(tree); + } + + fn size(&self) -> Size<Length> { + self.content.as_widget().size() + } + + fn layout( + &self, + tree: &mut widget::Tree, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + self.content.as_widget().layout(tree, renderer, limits) + } + + fn draw( + &self, + tree: &widget::Tree, + renderer: &mut Renderer, + theme: &Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + ) { + let bounds = layout.bounds(); + + if let Some(position) = cursor.position_in(bounds) { + renderer.with_layer(bounds, |renderer| { + renderer.with_transformation( + Transformation::translate( + bounds.x + position.x * (1.0 - self.zoom), + bounds.y + position.y * (1.0 - self.zoom), + ) * Transformation::scale(self.zoom) + * Transformation::translate(-bounds.x, -bounds.y), + |renderer| { + self.content.as_widget().draw( + tree, + renderer, + theme, + style, + layout, + mouse::Cursor::Unavailable, + viewport, + ); + }, + ); + }); + } else { + self.content.as_widget().draw( + tree, renderer, theme, style, layout, cursor, viewport, + ); + } + } + + fn mouse_interaction( + &self, + _state: &widget::Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + _viewport: &Rectangle, + _renderer: &Renderer, + ) -> mouse::Interaction { + if cursor.is_over(layout.bounds()) { + mouse::Interaction::ZoomIn + } else { + mouse::Interaction::Idle + } + } + } + + impl<'a, Message> From<Loupe<'a, Message>> + for Element<'a, Message, Theme, Renderer> + where + Message: 'a, + { + fn from(loupe: Loupe<'a, Message>) -> Self { + Self::new(loupe) + } + } +} diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml index 4f323f9e..907f3705 100644 --- a/graphics/Cargo.toml +++ b/graphics/Cargo.toml @@ -26,7 +26,6 @@ iced_futures.workspace = true bitflags.workspace = true bytemuck.workspace = true cosmic-text.workspace = true -glam.workspace = true half.workspace = true log.workspace = true once_cell.workspace = true diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index ba9192ef..8edf69d7 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -102,10 +102,10 @@ impl<T: Damage> Damage for Primitive<T> { .fold(Rectangle::with_size(Size::ZERO), |a, b| { Rectangle::union(&a, &b) }), - Self::Translate { - translation, + Self::Transform { + transformation, content, - } => content.bounds() + *translation, + } => content.bounds() * *transformation, Self::Cache { content } => content.bounds(), Self::Custom(custom) => custom.bounds(), } @@ -144,19 +144,19 @@ fn regions<T: Damage>(a: &Primitive<T>, b: &Primitive<T>) -> Vec<Rectangle> { } } ( - Primitive::Translate { - translation: translation_a, + Primitive::Transform { + transformation: transformation_a, content: content_a, }, - Primitive::Translate { - translation: translation_b, + Primitive::Transform { + transformation: transformation_b, content: content_b, }, ) => { - if translation_a == translation_b { + if transformation_a == transformation_b { return regions(content_a, content_b) .into_iter() - .map(|r| r + *translation_a) + .map(|r| r * *transformation_a) .collect(); } } diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 76de56bf..aa9d00e8 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -19,7 +19,6 @@ mod antialiasing; mod error; mod primitive; -mod transformation; mod viewport; pub mod backend; @@ -46,7 +45,6 @@ pub use gradient::Gradient; pub use mesh::Mesh; pub use primitive::Primitive; pub use renderer::Renderer; -pub use transformation::Transformation; pub use viewport::Viewport; pub use iced_core as core; diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index aed59e1a..6929b0a1 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -4,7 +4,8 @@ use crate::core::image; use crate::core::svg; use crate::core::text; use crate::core::{ - Background, Border, Color, Font, Pixels, Point, Rectangle, Shadow, Vector, + Background, Border, Color, Font, Pixels, Point, Rectangle, Shadow, + Transformation, Vector, }; use crate::text::editor; use crate::text::paragraph; @@ -104,12 +105,12 @@ pub enum Primitive<T> { /// The content of the clip content: Box<Primitive<T>>, }, - /// A primitive that applies a translation - Translate { - /// The translation vector - translation: Vector, + /// A primitive that applies a [`Transformation`] + Transform { + /// The [`Transformation`] + transformation: Transformation, - /// The primitive to translate + /// The primitive to transform content: Box<Primitive<T>>, }, /// A cached primitive. @@ -125,12 +126,12 @@ pub enum Primitive<T> { } impl<T> Primitive<T> { - /// Creates a [`Primitive::Group`]. + /// Groups the current [`Primitive`]. pub fn group(primitives: Vec<Self>) -> Self { Self::Group { primitives } } - /// Creates a [`Primitive::Clip`]. + /// Clips the current [`Primitive`]. pub fn clip(self, bounds: Rectangle) -> Self { Self::Clip { bounds, @@ -138,10 +139,21 @@ impl<T> Primitive<T> { } } - /// Creates a [`Primitive::Translate`]. + /// Translates the current [`Primitive`]. pub fn translate(self, translation: Vector) -> Self { - Self::Translate { - translation, + Self::Transform { + transformation: Transformation::translate( + translation.x, + translation.y, + ), + content: Box::new(self), + } + } + + /// Transforms the current [`Primitive`]. + pub fn transform(self, transformation: Transformation) -> Self { + Self::Transform { + transformation, content: Box::new(self), } } diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index cb07c23b..143f348b 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -6,7 +6,7 @@ use crate::core::renderer; use crate::core::svg; use crate::core::text::Text; use crate::core::{ - Background, Color, Font, Pixels, Point, Rectangle, Size, Vector, + Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, }; use crate::text; use crate::Primitive; @@ -73,20 +73,20 @@ impl<B: Backend> Renderer<B> { } /// Starts recording a translation. - pub fn start_translation(&mut self) -> Vec<Primitive<B::Primitive>> { + pub fn start_transformation(&mut self) -> Vec<Primitive<B::Primitive>> { std::mem::take(&mut self.primitives) } /// Ends the recording of a translation. - pub fn end_translation( + pub fn end_transformation( &mut self, primitives: Vec<Primitive<B::Primitive>>, - translation: Vector, + transformation: Transformation, ) { let layer = std::mem::replace(&mut self.primitives, primitives); self.primitives - .push(Primitive::group(layer).translate(translation)); + .push(Primitive::group(layer).transform(transformation)); } } @@ -99,16 +99,16 @@ impl<B: Backend> iced_core::Renderer for Renderer<B> { self.end_layer(current, bounds); } - fn with_translation( + fn with_transformation( &mut self, - translation: Vector, + transformation: Transformation, f: impl FnOnce(&mut Self), ) { - let current = self.start_translation(); + let current = self.start_transformation(); f(self); - self.end_translation(current, translation); + self.end_transformation(current, transformation); } fn fill_quad( diff --git a/graphics/src/transformation.rs b/graphics/src/transformation.rs deleted file mode 100644 index cf0457a4..00000000 --- a/graphics/src/transformation.rs +++ /dev/null @@ -1,59 +0,0 @@ -use glam::{Mat4, Vec3}; -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::orthographic_rh_gl( - 0.0, width as f32, - height as f32, 0.0, - -1.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() - } -} - -impl From<Transformation> for Mat4 { - fn from(transformation: Transformation) -> Self { - transformation.0 - } -} diff --git a/graphics/src/viewport.rs b/graphics/src/viewport.rs index 5792555d..dc8e21d3 100644 --- a/graphics/src/viewport.rs +++ b/graphics/src/viewport.rs @@ -1,6 +1,4 @@ -use crate::Transformation; - -use iced_core::Size; +use crate::core::{Size, Transformation}; /// A viewing region for displaying computer graphics. #[derive(Debug, Clone)] diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs index cd2140dc..f09ccfbf 100644 --- a/renderer/src/geometry.rs +++ b/renderer/src/geometry.rs @@ -2,14 +2,18 @@ mod cache; pub use cache::Cache; -use crate::core::{Point, Rectangle, Size, Vector}; +use crate::core::{Point, Rectangle, Size, Transformation, Vector}; use crate::graphics::geometry::{Fill, Path, Stroke, Text}; use crate::Renderer; -pub enum Frame { - TinySkia(iced_tiny_skia::geometry::Frame), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::geometry::Frame), +macro_rules! delegate { + ($frame:expr, $name:ident, $body:expr) => { + match $frame { + Self::TinySkia($name) => $body, + #[cfg(feature = "wgpu")] + Self::Wgpu($name) => $body, + } + }; } pub enum Geometry { @@ -18,14 +22,24 @@ pub enum Geometry { Wgpu(iced_wgpu::Primitive), } -macro_rules! delegate { - ($frame:expr, $name:ident, $body:expr) => { - match $frame { - Self::TinySkia($name) => $body, +impl Geometry { + pub fn transform(self, transformation: Transformation) -> Self { + match self { + Self::TinySkia(primitive) => { + Self::TinySkia(primitive.transform(transformation)) + } #[cfg(feature = "wgpu")] - Self::Wgpu($name) => $body, + Self::Wgpu(primitive) => { + Self::Wgpu(primitive.transform(transformation)) + } } - }; + } +} + +pub enum Frame { + TinySkia(iced_tiny_skia::geometry::Frame), + #[cfg(feature = "wgpu")] + Wgpu(iced_wgpu::geometry::Frame), } impl Frame { diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index a7df414b..757c264d 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -22,7 +22,9 @@ pub use geometry::Geometry; use crate::core::renderer; use crate::core::text::{self, Text}; -use crate::core::{Background, Color, Font, Pixels, Point, Rectangle, Vector}; +use crate::core::{ + Background, Color, Font, Pixels, Point, Rectangle, Transformation, +}; use crate::graphics::text::Editor; use crate::graphics::text::Paragraph; use crate::graphics::Mesh; @@ -97,20 +99,20 @@ impl core::Renderer for Renderer { } } - fn with_translation( + fn with_transformation( &mut self, - translation: Vector, + transformation: Transformation, f: impl FnOnce(&mut Self), ) { match self { Self::TinySkia(renderer) => { - let primitives = renderer.start_translation(); + let primitives = renderer.start_transformation(); f(self); match self { Self::TinySkia(renderer) => { - renderer.end_translation(primitives, translation); + renderer.end_transformation(primitives, transformation); } #[cfg(feature = "wgpu")] _ => unreachable!(), @@ -118,14 +120,14 @@ impl core::Renderer for Renderer { } #[cfg(feature = "wgpu")] Self::Wgpu(renderer) => { - let primitives = renderer.start_translation(); + let primitives = renderer.start_transformation(); f(self); match self { #[cfg(feature = "wgpu")] Self::Wgpu(renderer) => { - renderer.end_translation(primitives, translation); + renderer.end_transformation(primitives, transformation); } _ => unreachable!(), } @@ -193,7 +193,8 @@ pub use crate::core::color; pub use crate::core::gradient; pub use crate::core::{ Alignment, Background, Border, Color, ContentFit, Degrees, Gradient, - Length, Padding, Pixels, Point, Radians, Rectangle, Shadow, Size, Vector, + Length, Padding, Pixels, Point, Radians, Rectangle, Shadow, Size, + Transformation, Vector, }; pub mod clipboard { diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 468bcb7e..44f5c151 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,6 +1,8 @@ use tiny_skia::Size; -use crate::core::{Background, Color, Gradient, Rectangle, Vector}; +use crate::core::{ + Background, Color, Gradient, Rectangle, Transformation, Vector, +}; use crate::graphics::backend; use crate::graphics::text; use crate::graphics::Viewport; @@ -106,7 +108,7 @@ impl Backend { clip_mask, region, scale_factor, - Vector::ZERO, + Transformation::IDENTITY, ); } @@ -146,7 +148,7 @@ impl Backend { clip_mask: &mut tiny_skia::Mask, clip_bounds: Rectangle, scale_factor: f32, - translation: Vector, + transformation: Transformation, ) { match primitive { Primitive::Quad { @@ -164,7 +166,7 @@ impl Backend { "Quad with non-normal height!" ); - let physical_bounds = (*bounds + translation) * scale_factor; + let physical_bounds = (*bounds * transformation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -173,11 +175,8 @@ impl Backend { let clip_mask = (!physical_bounds.is_within(&clip_bounds)) .then_some(clip_mask as &_); - let transform = tiny_skia::Transform::from_translate( - translation.x, - translation.y, - ) - .post_scale(scale_factor, scale_factor); + let transform = into_transform(transformation) + .post_scale(scale_factor, scale_factor); // Make sure the border radius is not larger than the bounds let border_width = border @@ -199,7 +198,7 @@ impl Backend { y: bounds.y + shadow.offset.y - shadow.blur_radius, width: bounds.width + shadow.blur_radius * 2.0, height: bounds.height + shadow.blur_radius * 2.0, - } + translation) + } * transformation) * scale_factor; let radii = fill_border_radius @@ -451,7 +450,7 @@ impl Backend { clip_bounds: text_clip_bounds, } => { let physical_bounds = - (*text_clip_bounds + translation) * scale_factor; + *text_clip_bounds * transformation * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -462,11 +461,12 @@ impl Backend { self.text_pipeline.draw_paragraph( paragraph, - *position + translation, + *position, *color, scale_factor, pixels, clip_mask, + transformation, ); } Primitive::Editor { @@ -476,7 +476,7 @@ impl Backend { clip_bounds: text_clip_bounds, } => { let physical_bounds = - (*text_clip_bounds + translation) * scale_factor; + (*text_clip_bounds * transformation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -487,11 +487,12 @@ impl Backend { self.text_pipeline.draw_editor( editor, - *position + translation, + *position, *color, scale_factor, pixels, clip_mask, + transformation, ); } Primitive::Text { @@ -507,7 +508,7 @@ impl Backend { clip_bounds: text_clip_bounds, } => { let physical_bounds = - (*text_clip_bounds + translation) * scale_factor; + *text_clip_bounds * transformation * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -518,7 +519,7 @@ impl Backend { self.text_pipeline.draw_cached( content, - *bounds + translation, + *bounds, *color, *size, *line_height, @@ -529,6 +530,7 @@ impl Backend { scale_factor, pixels, clip_mask, + transformation, ); } Primitive::RawText(text::Raw { @@ -542,7 +544,7 @@ impl Backend { }; let physical_bounds = - (*text_clip_bounds + translation) * scale_factor; + *text_clip_bounds * transformation * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -553,11 +555,12 @@ impl Backend { self.text_pipeline.draw_raw( &buffer, - *position + translation, + *position, *color, scale_factor, pixels, clip_mask, + transformation, ); } #[cfg(feature = "image")] @@ -566,7 +569,7 @@ impl Backend { filter_method, bounds, } => { - let physical_bounds = (*bounds + translation) * scale_factor; + let physical_bounds = (*bounds * transformation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -575,11 +578,8 @@ impl Backend { let clip_mask = (!physical_bounds.is_within(&clip_bounds)) .then_some(clip_mask as &_); - let transform = tiny_skia::Transform::from_translate( - translation.x, - translation.y, - ) - .post_scale(scale_factor, scale_factor); + let transform = into_transform(transformation) + .post_scale(scale_factor, scale_factor); self.raster_pipeline.draw( handle, @@ -602,7 +602,7 @@ impl Backend { bounds, color, } => { - let physical_bounds = (*bounds + translation) * scale_factor; + let physical_bounds = (*bounds * transformation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -614,7 +614,7 @@ impl Backend { self.vector_pipeline.draw( handle, *color, - (*bounds + translation) * scale_factor, + (*bounds * transformation) * scale_factor, pixels, clip_mask, ); @@ -637,7 +637,7 @@ impl Backend { y: bounds.y(), width: bounds.width(), height: bounds.height(), - } + translation) + } * transformation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -651,11 +651,8 @@ impl Backend { path, paint, *rule, - tiny_skia::Transform::from_translate( - translation.x, - translation.y, - ) - .post_scale(scale_factor, scale_factor), + into_transform(transformation) + .post_scale(scale_factor, scale_factor), clip_mask, ); } @@ -671,7 +668,7 @@ impl Backend { y: bounds.y(), width: bounds.width(), height: bounds.height(), - } + translation) + } * transformation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -685,11 +682,8 @@ impl Backend { path, paint, stroke, - tiny_skia::Transform::from_translate( - translation.x, - translation.y, - ) - .post_scale(scale_factor, scale_factor), + into_transform(transformation) + .post_scale(scale_factor, scale_factor), clip_mask, ); } @@ -701,12 +695,12 @@ impl Backend { clip_mask, clip_bounds, scale_factor, - translation, + transformation, ); } } - Primitive::Translate { - translation: offset, + Primitive::Transform { + transformation: new_transformation, content, } => { self.draw_primitive( @@ -715,11 +709,11 @@ impl Backend { clip_mask, clip_bounds, scale_factor, - translation + *offset, + transformation * *new_transformation, ); } Primitive::Clip { bounds, content } => { - let bounds = (*bounds + translation) * scale_factor; + let bounds = (*bounds * transformation) * scale_factor; if bounds == clip_bounds { self.draw_primitive( @@ -728,7 +722,7 @@ impl Backend { clip_mask, bounds, scale_factor, - translation, + transformation, ); } else if let Some(bounds) = clip_bounds.intersection(&bounds) { if bounds.x + bounds.width <= 0.0 @@ -749,7 +743,7 @@ impl Backend { clip_mask, bounds, scale_factor, - translation, + transformation, ); adjust_clip_mask(clip_mask, clip_bounds); @@ -762,7 +756,7 @@ impl Backend { clip_mask, clip_bounds, scale_factor, - translation, + transformation, ); } } @@ -780,6 +774,19 @@ fn into_color(color: Color) -> tiny_skia::Color { .expect("Convert color from iced to tiny_skia") } +fn into_transform(transformation: Transformation) -> tiny_skia::Transform { + let translation = transformation.translation(); + + tiny_skia::Transform { + sx: transformation.scale_factor(), + kx: 0.0, + ky: 0.0, + sy: transformation.scale_factor(), + tx: translation.x, + ty: translation.y, + } +} + fn rounded_rectangle( bounds: Rectangle, border_radius: [f32; 4], diff --git a/tiny_skia/src/geometry.rs b/tiny_skia/src/geometry.rs index 74a08d38..f7518731 100644 --- a/tiny_skia/src/geometry.rs +++ b/tiny_skia/src/geometry.rs @@ -1,5 +1,5 @@ use crate::core::text::LineHeight; -use crate::core::{Pixels, Point, Rectangle, Size, Vector}; +use crate::core::{Pixels, Point, Rectangle, Size, Transformation, Vector}; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::stroke::{self, Stroke}; use crate::graphics::geometry::{Path, Style, Text}; @@ -181,8 +181,8 @@ impl Frame { } pub fn clip(&mut self, frame: Self, at: Point) { - self.primitives.push(Primitive::Translate { - translation: Vector::new(at.x, at.y), + self.primitives.push(Primitive::Transform { + transformation: Transformation::translate(at.x, at.y), content: Box::new(frame.into_primitive()), }); } diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index 9413e311..c16037cf 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -1,6 +1,8 @@ use crate::core::alignment; use crate::core::text::{LineHeight, Shaping}; -use crate::core::{Color, Font, Pixels, Point, Rectangle, Size}; +use crate::core::{ + Color, Font, Pixels, Point, Rectangle, Size, Transformation, +}; use crate::graphics::text::cache::{self, Cache}; use crate::graphics::text::editor; use crate::graphics::text::font_system; @@ -42,6 +44,7 @@ impl Pipeline { scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, + transformation: Transformation, ) { use crate::core::text::Paragraph as _; @@ -62,6 +65,7 @@ impl Pipeline { scale_factor, pixels, clip_mask, + transformation, ); } @@ -73,6 +77,7 @@ impl Pipeline { scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, + transformation: Transformation, ) { use crate::core::text::Editor as _; @@ -93,6 +98,7 @@ impl Pipeline { scale_factor, pixels, clip_mask, + transformation, ); } @@ -110,6 +116,7 @@ impl Pipeline { scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, + transformation: Transformation, ) { let line_height = f32::from(line_height.to_absolute(size)); @@ -145,6 +152,7 @@ impl Pipeline { scale_factor, pixels, clip_mask, + transformation, ); } @@ -156,6 +164,7 @@ impl Pipeline { scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, + transformation: Transformation, ) { let mut font_system = font_system().write().expect("Write font system"); @@ -172,6 +181,7 @@ impl Pipeline { scale_factor, pixels, clip_mask, + transformation, ); } @@ -192,8 +202,9 @@ fn draw( scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, + transformation: Transformation, ) { - let bounds = bounds * scale_factor; + let bounds = bounds * transformation * scale_factor; let x = match horizontal_alignment { alignment::Horizontal::Left => bounds.x, @@ -211,7 +222,8 @@ fn draw( for run in buffer.layout_runs() { for glyph in run.glyphs { - let physical_glyph = glyph.physical((x, y), scale_factor); + let physical_glyph = glyph + .physical((x, y), scale_factor * transformation.scale_factor()); if let Some((buffer, placement)) = glyph_cache.allocate( physical_glyph.cache_key, @@ -229,7 +241,10 @@ fn draw( pixels.draw_pixmap( physical_glyph.x + placement.left, physical_glyph.y - placement.top - + (run.line_y * scale_factor).round() as i32, + + (run.line_y + * scale_factor + * transformation.scale_factor()) + .round() as i32, pixmap, &tiny_skia::PixmapPaint::default(), tiny_skia::Transform::identity(), diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 25134d68..77b6fa83 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -1,7 +1,7 @@ -use crate::core::{Color, Size}; +use crate::core::{Color, Size, Transformation}; use crate::graphics::backend; use crate::graphics::color; -use crate::graphics::{Transformation, Viewport}; +use crate::graphics::Viewport; use crate::primitive::pipeline; use crate::primitive::{self, Primitive}; use crate::quad; @@ -147,8 +147,8 @@ impl Backend { } if !layer.meshes.is_empty() { - let scaled = transformation - * Transformation::scale(scale_factor, scale_factor); + let scaled = + transformation * Transformation::scale(scale_factor); self.triangle_pipeline.prepare( device, @@ -161,8 +161,8 @@ impl Backend { #[cfg(any(feature = "image", feature = "svg"))] { if !layer.images.is_empty() { - let scaled = transformation - * Transformation::scale(scale_factor, scale_factor); + let scaled = + transformation * Transformation::scale(scale_factor); self.image_pipeline.prepare( device, diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index a4d4fb1f..8cfcfff0 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -1,6 +1,6 @@ //! Build and draw geometry. use crate::core::text::LineHeight; -use crate::core::{Pixels, Point, Rectangle, Size, Vector}; +use crate::core::{Pixels, Point, Rectangle, Size, Transformation, Vector}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::{ @@ -435,7 +435,7 @@ impl Frame { pub fn clip(&mut self, frame: Frame, at: Point) { let size = frame.size(); let primitives = frame.into_primitives(); - let translation = Vector::new(at.x, at.y); + let transformation = Transformation::translate(at.x, at.y); let (text, meshes) = primitives .into_iter() @@ -443,12 +443,12 @@ impl Frame { self.primitives.push(Primitive::Group { primitives: vec![ - Primitive::Translate { - translation, + Primitive::Transform { + transformation, content: Box::new(Primitive::Group { primitives: meshes }), }, - Primitive::Translate { - translation, + Primitive::Transform { + transformation, content: Box::new(Primitive::Clip { bounds: Rectangle::with_size(size), content: Box::new(Primitive::Group { diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 1e5d3ee0..06c22870 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -8,8 +8,7 @@ mod vector; use atlas::Atlas; -use crate::core::{Rectangle, Size}; -use crate::graphics::Transformation; +use crate::core::{Rectangle, Size, Transformation}; use crate::layer; use crate::Buffer; diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index e213c95f..cc767c25 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -12,7 +12,9 @@ pub use text::Text; use crate::core; use crate::core::alignment; -use crate::core::{Color, Font, Pixels, Point, Rectangle, Size, Vector}; +use crate::core::{ + Color, Font, Pixels, Point, Rectangle, Size, Transformation, Vector, +}; use crate::graphics; use crate::graphics::color; use crate::graphics::Viewport; @@ -104,7 +106,7 @@ impl<'a> Layer<'a> { for primitive in primitives { Self::process_primitive( &mut layers, - Vector::new(0.0, 0.0), + Transformation::IDENTITY, primitive, 0, ); @@ -115,7 +117,7 @@ impl<'a> Layer<'a> { fn process_primitive( layers: &mut Vec<Self>, - translation: Vector, + transformation: Transformation, primitive: &'a Primitive, current_layer: usize, ) { @@ -130,9 +132,10 @@ impl<'a> Layer<'a> { layer.text.push(Text::Paragraph { paragraph: paragraph.clone(), - position: *position + translation, + position: *position, color: *color, - clip_bounds: *clip_bounds + translation, + clip_bounds: *clip_bounds, + transformation, }); } Primitive::Editor { @@ -145,9 +148,10 @@ impl<'a> Layer<'a> { layer.text.push(Text::Editor { editor: editor.clone(), - position: *position + translation, + position: *position, color: *color, - clip_bounds: *clip_bounds + translation, + clip_bounds: *clip_bounds, + transformation, }); } Primitive::Text { @@ -166,31 +170,24 @@ impl<'a> Layer<'a> { layer.text.push(Text::Cached(text::Cached { content, - bounds: *bounds + translation, - size: *size, + bounds: *bounds + transformation.translation(), + size: *size * transformation.scale_factor(), line_height: *line_height, color: *color, font: *font, horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, shaping: *shaping, - clip_bounds: *clip_bounds + translation, + clip_bounds: *clip_bounds * transformation, })); } - graphics::Primitive::RawText(graphics::text::Raw { - buffer, - position, - color, - clip_bounds, - }) => { + graphics::Primitive::RawText(raw) => { let layer = &mut layers[current_layer]; - layer.text.push(Text::Raw(graphics::text::Raw { - buffer: buffer.clone(), - position: *position + translation, - color: *color, - clip_bounds: *clip_bounds + translation, - })); + layer.text.push(Text::Raw { + raw: raw.clone(), + transformation, + }); } Primitive::Quad { bounds, @@ -199,12 +196,10 @@ impl<'a> Layer<'a> { shadow, } => { let layer = &mut layers[current_layer]; + let bounds = *bounds * transformation; let quad = Quad { - position: [ - bounds.x + translation.x, - bounds.y + translation.y, - ], + position: [bounds.x, bounds.y], size: [bounds.width, bounds.height], border_color: color::pack(border.color), border_radius: border.radius.into(), @@ -226,7 +221,7 @@ impl<'a> Layer<'a> { layer.images.push(Image::Raster { handle: handle.clone(), filter_method: *filter_method, - bounds: *bounds + translation, + bounds: *bounds * transformation, }); } Primitive::Svg { @@ -239,7 +234,7 @@ impl<'a> Layer<'a> { layer.images.push(Image::Vector { handle: handle.clone(), color: *color, - bounds: *bounds + translation, + bounds: *bounds * transformation, }); } Primitive::Group { primitives } => { @@ -247,7 +242,7 @@ impl<'a> Layer<'a> { for primitive in primitives { Self::process_primitive( layers, - translation, + transformation, primitive, current_layer, ); @@ -255,7 +250,7 @@ impl<'a> Layer<'a> { } Primitive::Clip { bounds, content } => { let layer = &mut layers[current_layer]; - let translated_bounds = *bounds + translation; + let translated_bounds = *bounds * transformation; // Only draw visible content if let Some(clip_bounds) = @@ -266,19 +261,19 @@ impl<'a> Layer<'a> { Self::process_primitive( layers, - translation, + transformation, content, layers.len() - 1, ); } } - Primitive::Translate { - translation: new_translation, + Primitive::Transform { + transformation: new_transformation, content, } => { Self::process_primitive( layers, - translation + *new_translation, + transformation * *new_transformation, content, current_layer, ); @@ -286,7 +281,7 @@ impl<'a> Layer<'a> { Primitive::Cache { content } => { Self::process_primitive( layers, - translation, + transformation, content, current_layer, ); @@ -296,20 +291,15 @@ impl<'a> Layer<'a> { graphics::Mesh::Solid { buffers, size } => { let layer = &mut layers[current_layer]; - let bounds = Rectangle::new( - Point::new(translation.x, translation.y), - *size, - ); + let bounds = + Rectangle::with_size(*size) * transformation; // Only draw visible content if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { layer.meshes.push(Mesh::Solid { - origin: Point::new( - translation.x, - translation.y, - ), + transformation, buffers, clip_bounds, }); @@ -318,20 +308,15 @@ impl<'a> Layer<'a> { graphics::Mesh::Gradient { buffers, size } => { let layer = &mut layers[current_layer]; - let bounds = Rectangle::new( - Point::new(translation.x, translation.y), - *size, - ); + let bounds = + Rectangle::with_size(*size) * transformation; // Only draw visible content if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { layer.meshes.push(Mesh::Gradient { - origin: Point::new( - translation.x, - translation.y, - ), + transformation, buffers, clip_bounds, }); @@ -340,7 +325,7 @@ impl<'a> Layer<'a> { }, primitive::Custom::Pipeline(pipeline) => { let layer = &mut layers[current_layer]; - let bounds = pipeline.bounds + translation; + let bounds = pipeline.bounds * transformation; if let Some(clip_bounds) = layer.bounds.intersection(&bounds) diff --git a/wgpu/src/layer/mesh.rs b/wgpu/src/layer/mesh.rs index 7c6206cd..5ed7c654 100644 --- a/wgpu/src/layer/mesh.rs +++ b/wgpu/src/layer/mesh.rs @@ -1,5 +1,5 @@ //! A collection of triangle primitives. -use crate::core::{Point, Rectangle}; +use crate::core::{Rectangle, Transformation}; use crate::graphics::mesh; /// A mesh of triangles. @@ -7,8 +7,8 @@ use crate::graphics::mesh; pub enum Mesh<'a> { /// A mesh of triangles with a solid color. Solid { - /// The origin of the vertices of the [`Mesh`]. - origin: Point, + /// The [`Transformation`] for the vertices of the [`Mesh`]. + transformation: Transformation, /// The vertex and index buffers of the [`Mesh`]. buffers: &'a mesh::Indexed<mesh::SolidVertex2D>, @@ -18,8 +18,8 @@ pub enum Mesh<'a> { }, /// A mesh of triangles with a gradient color. Gradient { - /// The origin of the vertices of the [`Mesh`]. - origin: Point, + /// The [`Transformation`] for the vertices of the [`Mesh`]. + transformation: Transformation, /// The vertex and index buffers of the [`Mesh`]. buffers: &'a mesh::Indexed<mesh::GradientVertex2D>, @@ -31,11 +31,10 @@ pub enum Mesh<'a> { impl Mesh<'_> { /// Returns the origin of the [`Mesh`]. - pub fn origin(&self) -> Point { + pub fn transformation(&self) -> Transformation { match self { - Self::Solid { origin, .. } | Self::Gradient { origin, .. } => { - *origin - } + Self::Solid { transformation, .. } + | Self::Gradient { transformation, .. } => *transformation, } } diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index 37ee5247..b3a00130 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -1,6 +1,6 @@ use crate::core::alignment; use crate::core::text; -use crate::core::{Color, Font, Pixels, Point, Rectangle}; +use crate::core::{Color, Font, Pixels, Point, Rectangle, Transformation}; use crate::graphics; use crate::graphics::text::editor; use crate::graphics::text::paragraph; @@ -15,6 +15,7 @@ pub enum Text<'a> { position: Point, color: Color, clip_bounds: Rectangle, + transformation: Transformation, }, /// An editor. #[allow(missing_docs)] @@ -23,11 +24,16 @@ pub enum Text<'a> { position: Point, color: Color, clip_bounds: Rectangle, + transformation: Transformation, }, /// Some cached text. Cached(Cached<'a>), /// Some raw text. - Raw(graphics::text::Raw), + #[allow(missing_docs)] + Raw { + raw: graphics::text::Raw, + transformation: Transformation, + }, } #[derive(Debug, Clone)] diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index cda1bec9..b932f54f 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -4,9 +4,9 @@ mod solid; use gradient::Gradient; use solid::Solid; -use crate::core::{Background, Rectangle}; +use crate::core::{Background, Rectangle, Transformation}; +use crate::graphics; use crate::graphics::color; -use crate::graphics::{self, Transformation}; use bytemuck::{Pod, Zeroable}; @@ -319,7 +319,7 @@ impl Uniforms { impl Default for Uniforms { fn default() -> Self { Self { - transform: *Transformation::identity().as_ref(), + transform: *Transformation::IDENTITY.as_ref(), scale: 1.0, _padding: [0.0; 3], } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index dca09cb8..6fa1922d 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -1,5 +1,5 @@ use crate::core::alignment; -use crate::core::{Rectangle, Size}; +use crate::core::{Rectangle, Size, Transformation}; use crate::graphics::color; use crate::graphics::text::cache::{self, Cache}; use crate::graphics::text::{font_system, to_color, Editor, Paragraph}; @@ -109,7 +109,9 @@ impl Pipeline { Some(Allocation::Cache(key)) } - Text::Raw(text) => text.buffer.upgrade().map(Allocation::Raw), + Text::Raw { raw, .. } => { + raw.buffer.upgrade().map(Allocation::Raw) + } }) .collect(); @@ -124,11 +126,13 @@ impl Pipeline { vertical_alignment, color, clip_bounds, + transformation, ) = match section { Text::Paragraph { position, color, clip_bounds, + transformation, .. } => { use crate::core::text::Paragraph as _; @@ -145,12 +149,14 @@ impl Pipeline { paragraph.vertical_alignment(), *color, *clip_bounds, + *transformation, ) } Text::Editor { position, color, clip_bounds, + transformation, .. } => { use crate::core::text::Editor as _; @@ -167,6 +173,7 @@ impl Pipeline { alignment::Vertical::Top, *color, *clip_bounds, + *transformation, ) } Text::Cached(text) => { @@ -186,9 +193,13 @@ impl Pipeline { text.vertical_alignment, text.color, text.clip_bounds, + Transformation::IDENTITY, ) } - Text::Raw(text) => { + Text::Raw { + raw, + transformation, + } => { let Some(Allocation::Raw(buffer)) = allocation else { return None; }; @@ -198,18 +209,19 @@ impl Pipeline { ( buffer.as_ref(), Rectangle::new( - text.position, + raw.position, Size::new(width, height), ), alignment::Horizontal::Left, alignment::Vertical::Top, - text.color, - text.clip_bounds, + raw.color, + raw.clip_bounds, + *transformation, ) } }; - let bounds = bounds * scale_factor; + let bounds = bounds * transformation * scale_factor; let left = match horizontal_alignment { alignment::Horizontal::Left => bounds.x, @@ -227,14 +239,15 @@ impl Pipeline { alignment::Vertical::Bottom => bounds.y - bounds.height, }; - let clip_bounds = - layer_bounds.intersection(&(clip_bounds * scale_factor))?; + let clip_bounds = layer_bounds.intersection( + &(clip_bounds * transformation * scale_factor), + )?; Some(glyphon::TextArea { buffer, left, top, - scale: scale_factor, + scale: scale_factor * transformation.scale_factor(), bounds: glyphon::TextBounds { left: clip_bounds.x as i32, top: clip_bounds.y as i32, diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 69270a73..2bb6f307 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -1,8 +1,8 @@ //! Draw meshes of triangles. mod msaa; -use crate::core::Size; -use crate::graphics::{Antialiasing, Transformation}; +use crate::core::{Size, Transformation}; +use crate::graphics::Antialiasing; use crate::layer::mesh::{self, Mesh}; use crate::Buffer; @@ -98,12 +98,10 @@ impl Layer { let mut index_offset = 0; for mesh in meshes { - let origin = mesh.origin(); let indices = mesh.indices(); - let uniforms = Uniforms::new( - transformation * Transformation::translate(origin.x, origin.y), - ); + let uniforms = + Uniforms::new(transformation * mesh.transformation()); index_offset += self.index_buffer.write(queue, index_offset, indices); diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index b95e6206..0eda0191 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -15,7 +15,7 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget, + Clipboard, Element, Length, Rectangle, Shell, Size, Transformation, Widget, }; use crate::graphics::geometry; @@ -207,8 +207,8 @@ where let state = tree.state.downcast_ref::<P::State>(); - renderer.with_translation( - Vector::new(bounds.x, bounds.y), + renderer.with_transformation( + Transformation::translate(bounds.x, bounds.y), |renderer| { renderer.draw( self.program.draw(state, renderer, theme, bounds, cursor), diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index f76c6088..4f9a265a 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -962,22 +962,21 @@ pub fn draw<Theme, Renderer, T>( if let Some(cursor_position) = cursor.position() { let bounds = layout.bounds(); - renderer.with_translation( - cursor_position - - Point::new(bounds.x + origin.x, bounds.y + origin.y), - |renderer| { - renderer.with_layer(bounds, |renderer| { - draw_pane( - pane, - renderer, - default_style, - layout, - pane_cursor, - viewport, - ); - }); - }, - ); + let translation = cursor_position + - Point::new(bounds.x + origin.x, bounds.y + origin.y); + + renderer.with_translation(translation, |renderer| { + renderer.with_layer(bounds, |renderer| { + draw_pane( + pane, + renderer, + default_style, + layout, + pane_cursor, + viewport, + ); + }); + }); } } diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index 91c0a97b..6a748e63 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -119,11 +119,12 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> { }); }); - let translation = Vector::new(bounds.x, bounds.y); - - renderer.with_translation(translation, |renderer| { - renderer.draw(vec![geometry]); - }); + renderer.with_translation( + bounds.position() - Point::ORIGIN, + |renderer| { + renderer.draw(vec![geometry]); + }, + ); } } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index eceb1604..ef789296 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -385,6 +385,7 @@ pub fn mouse_interaction( } Interaction::ResizingVertically => winit::window::CursorIcon::NsResize, Interaction::NotAllowed => winit::window::CursorIcon::NotAllowed, + Interaction::ZoomIn => winit::window::CursorIcon::ZoomIn, } } |