summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-05-02 15:21:22 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-05-02 17:28:28 +0200
commita57313b23ecb9843856ca0ea08635b6121fcb2cb (patch)
tree42a88a4e42031ae99ae87aeb92fea85ab590b01e
parent09a6bcfffc24f5abdc8709403bab7ae1e01563f1 (diff)
downloadiced-a57313b23ecb9843856ca0ea08635b6121fcb2cb.tar.gz
iced-a57313b23ecb9843856ca0ea08635b6121fcb2cb.tar.bz2
iced-a57313b23ecb9843856ca0ea08635b6121fcb2cb.zip
Simplify image rotation API and its internals
-rw-r--r--core/src/angle.rs6
-rw-r--r--core/src/content_fit.rs3
-rw-r--r--core/src/image.rs5
-rw-r--r--core/src/lib.rs2
-rw-r--r--core/src/rectangle.rs16
-rw-r--r--core/src/renderer/null.rs9
-rw-r--r--core/src/rotation.rs71
-rw-r--r--core/src/size.rs14
-rw-r--r--core/src/svg.rs5
-rw-r--r--core/src/vector.rs3
-rw-r--r--graphics/src/image.rs12
-rw-r--r--renderer/src/fallback.rs12
-rw-r--r--src/lib.rs4
-rw-r--r--tiny_skia/src/engine.rs26
-rw-r--r--tiny_skia/src/layer.rs10
-rw-r--r--tiny_skia/src/lib.rs11
-rw-r--r--wgpu/src/image/mod.rs24
-rw-r--r--wgpu/src/layer.rs10
-rw-r--r--wgpu/src/lib.rs20
-rw-r--r--wgpu/src/shader/image.wgsl21
-rw-r--r--widget/src/image.rs70
-rw-r--r--widget/src/image/viewer.rs7
-rw-r--r--widget/src/svg.rs81
23 files changed, 218 insertions, 224 deletions
diff --git a/core/src/angle.rs b/core/src/angle.rs
index dc3c0e93..69630717 100644
--- a/core/src/angle.rs
+++ b/core/src/angle.rs
@@ -65,6 +65,12 @@ impl From<u8> for Radians {
}
}
+impl From<Radians> for f32 {
+ fn from(radians: Radians) -> Self {
+ radians.0
+ }
+}
+
impl From<Radians> for f64 {
fn from(radians: Radians) -> Self {
Self::from(radians.0)
diff --git a/core/src/content_fit.rs b/core/src/content_fit.rs
index 6bbedc7a..56d2ffa6 100644
--- a/core/src/content_fit.rs
+++ b/core/src/content_fit.rs
@@ -11,7 +11,7 @@ use crate::Size;
/// in CSS, see [Mozilla's docs][1], or run the `tour` example
///
/// [1]: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
-#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, Default)]
pub enum ContentFit {
/// Scale as big as it can be without needing to crop or hide parts.
///
@@ -23,6 +23,7 @@ pub enum ContentFit {
/// This is a great fit for when you need to display an image without losing
/// any part of it, particularly when the image itself is the focus of the
/// screen.
+ #[default]
Contain,
/// Scale the image to cover all of the bounding box, cropping if needed.
diff --git a/core/src/image.rs b/core/src/image.rs
index 5d1ab441..91a7fd36 100644
--- a/core/src/image.rs
+++ b/core/src/image.rs
@@ -1,7 +1,7 @@
//! Load and draw raster graphics.
pub use bytes::Bytes;
-use crate::{Rectangle, Size};
+use crate::{Radians, Rectangle, Size};
use rustc_hash::FxHasher;
use std::hash::{Hash, Hasher};
@@ -173,7 +173,6 @@ pub trait Renderer: crate::Renderer {
handle: Self::Handle,
filter_method: FilterMethod,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
);
}
diff --git a/core/src/lib.rs b/core/src/lib.rs
index da3ddcac..32156441 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -65,7 +65,7 @@ pub use pixels::Pixels;
pub use point::Point;
pub use rectangle::Rectangle;
pub use renderer::Renderer;
-pub use rotation::RotationLayout;
+pub use rotation::Rotation;
pub use shadow::Shadow;
pub use shell::Shell;
pub use size::Size;
diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs
index 2ab50137..fb66131a 100644
--- a/core/src/rectangle.rs
+++ b/core/src/rectangle.rs
@@ -227,3 +227,19 @@ where
}
}
}
+
+impl<T> std::ops::Mul<Vector<T>> for Rectangle<T>
+where
+ T: std::ops::Mul<Output = T> + Copy,
+{
+ type Output = Rectangle<T>;
+
+ fn mul(self, scale: Vector<T>) -> Self {
+ Rectangle {
+ x: self.x * scale.x,
+ y: self.y * scale.y,
+ width: self.width * scale.x,
+ height: self.height * scale.y,
+ }
+ }
+}
diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs
index d2dcfe4d..91519b40 100644
--- a/core/src/renderer/null.rs
+++ b/core/src/renderer/null.rs
@@ -4,7 +4,8 @@ use crate::renderer::{self, Renderer};
use crate::svg;
use crate::text::{self, Text};
use crate::{
- Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
+ Background, Color, Font, Pixels, Point, Radians, Rectangle, Size,
+ Transformation,
};
impl Renderer for () {
@@ -171,8 +172,7 @@ impl image::Renderer for () {
_handle: Self::Handle,
_filter_method: image::FilterMethod,
_bounds: Rectangle,
- _rotation: f32,
- _scale: Size,
+ _rotation: Radians,
) {
}
}
@@ -187,8 +187,7 @@ impl svg::Renderer for () {
_handle: svg::Handle,
_color: Option<Color>,
_bounds: Rectangle,
- _rotation: f32,
- _scale: Size,
+ _rotation: Radians,
) {
}
}
diff --git a/core/src/rotation.rs b/core/src/rotation.rs
index 821aa494..ebb85f3c 100644
--- a/core/src/rotation.rs
+++ b/core/src/rotation.rs
@@ -1,37 +1,68 @@
-//! Control the rotation of some content (like an image) with the `RotationLayout` within a
-//! space.
-use crate::Size;
+//! Control the rotation of some content (like an image) within a space.
+use crate::{Radians, Size};
/// The strategy used to rotate the content.
///
/// This is used to control the behavior of the layout when the content is rotated
/// by a certain angle.
-#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
-pub enum RotationLayout {
- /// The layout is kept exactly as it was before the rotation.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Rotation {
+ /// The element will float while rotating. The layout will be kept exactly as it was
+ /// before the rotation.
///
/// This is especially useful when used for animations, as it will avoid the
/// layout being shifted or resized when smoothly i.e. an icon.
- Keep,
- /// The layout is adjusted to fit the rotated content.
+ ///
+ /// This is the default.
+ Floating(Radians),
+ /// The element will be solid while rotating. The layout will be adjusted to fit
+ /// the rotated content.
///
/// This allows you to rotate an image and have the layout adjust to fit the new
/// size of the image.
- Change,
+ Solid(Radians),
}
-impl RotationLayout {
- /// Applies the rotation to the layout while respecting the [`RotationLayout`] strategy.
- /// The rotation is given in radians.
- pub fn apply_to_size(&self, size: Size, rotation: f32) -> Size {
+impl Rotation {
+ /// Returns the angle of the [`Rotation`] in [`Radians`].
+ pub fn radians(self) -> Radians {
+ match self {
+ Rotation::Floating(radians) | Rotation::Solid(radians) => radians,
+ }
+ }
+
+ /// Rotates the given [`Size`].
+ pub fn apply(self, size: Size) -> Size {
match self {
- Self::Keep => size,
- Self::Change => Size {
- width: (size.width * rotation.cos()).abs()
- + (size.height * rotation.sin()).abs(),
- height: (size.width * rotation.sin()).abs()
- + (size.height * rotation.cos()).abs(),
- },
+ Self::Floating(_) => size,
+ Self::Solid(rotation) => {
+ let radians = f32::from(rotation);
+
+ Size {
+ width: (size.width * radians.cos()).abs()
+ + (size.height * radians.sin()).abs(),
+ height: (size.width * radians.sin()).abs()
+ + (size.height * radians.cos()).abs(),
+ }
+ }
}
}
}
+
+impl Default for Rotation {
+ fn default() -> Self {
+ Self::Floating(Radians(0.0))
+ }
+}
+
+impl From<Radians> for Rotation {
+ fn from(radians: Radians) -> Self {
+ Self::Floating(radians)
+ }
+}
+
+impl From<f32> for Rotation {
+ fn from(radians: f32) -> Self {
+ Self::Floating(Radians(radians))
+ }
+}
diff --git a/core/src/size.rs b/core/src/size.rs
index c2b5671a..66be2d85 100644
--- a/core/src/size.rs
+++ b/core/src/size.rs
@@ -113,3 +113,17 @@ where
}
}
}
+
+impl<T> std::ops::Mul<Vector<T>> for Size<T>
+where
+ T: std::ops::Mul<Output = T> + Copy,
+{
+ type Output = Size<T>;
+
+ fn mul(self, scale: Vector<T>) -> Self::Output {
+ Size {
+ width: self.width * scale.x,
+ height: self.height * scale.y,
+ }
+ }
+}
diff --git a/core/src/svg.rs b/core/src/svg.rs
index 74dd7f4a..01f102e3 100644
--- a/core/src/svg.rs
+++ b/core/src/svg.rs
@@ -1,5 +1,5 @@
//! Load and draw vector graphics.
-use crate::{Color, Rectangle, Size};
+use crate::{Color, Radians, Rectangle, Size};
use rustc_hash::FxHasher;
use std::borrow::Cow;
@@ -100,7 +100,6 @@ pub trait Renderer: crate::Renderer {
handle: Handle,
color: Option<Color>,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
);
}
diff --git a/core/src/vector.rs b/core/src/vector.rs
index 1380c3b3..049e648f 100644
--- a/core/src/vector.rs
+++ b/core/src/vector.rs
@@ -18,6 +18,9 @@ impl<T> Vector<T> {
impl Vector {
/// The zero [`Vector`].
pub const ZERO: Self = Self::new(0.0, 0.0);
+
+ /// The unit [`Vector`].
+ pub const UNIT: Self = Self::new(0.0, 0.0);
}
impl<T> std::ops::Add for Vector<T>
diff --git a/graphics/src/image.rs b/graphics/src/image.rs
index 083248bf..4fd6998d 100644
--- a/graphics/src/image.rs
+++ b/graphics/src/image.rs
@@ -2,7 +2,7 @@
#[cfg(feature = "image")]
pub use ::image as image_rs;
-use crate::core::{image, svg, Color, Rectangle, Size};
+use crate::core::{image, svg, Color, Radians, Rectangle};
/// A raster or vector image.
#[derive(Debug, Clone, PartialEq)]
@@ -19,10 +19,7 @@ pub enum Image {
bounds: Rectangle,
/// The rotation of the image in radians
- rotation: f32,
-
- /// The scale of the image after rotation
- scale: Size,
+ rotation: Radians,
},
/// A vector image.
Vector {
@@ -36,10 +33,7 @@ pub enum Image {
bounds: Rectangle,
/// The rotation of the image in radians
- rotation: f32,
-
- /// The scale of the image after rotation
- scale: Size,
+ rotation: Radians,
},
}
diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs
index 37e6ac43..a077031b 100644
--- a/renderer/src/fallback.rs
+++ b/renderer/src/fallback.rs
@@ -3,7 +3,7 @@ use crate::core::image;
use crate::core::renderer;
use crate::core::svg;
use crate::core::{
- self, Background, Color, Point, Rectangle, Size, Transformation,
+ self, Background, Color, Point, Radians, Rectangle, Size, Transformation,
};
use crate::graphics;
use crate::graphics::compositor;
@@ -154,13 +154,12 @@ where
handle: Self::Handle,
filter_method: image::FilterMethod,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
delegate!(
self,
renderer,
- renderer.draw_image(handle, filter_method, bounds, rotation, scale)
+ renderer.draw_image(handle, filter_method, bounds, rotation)
);
}
}
@@ -179,13 +178,12 @@ where
handle: svg::Handle,
color: Option<Color>,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
delegate!(
self,
renderer,
- renderer.draw_svg(handle, color, bounds, rotation, scale)
+ renderer.draw_svg(handle, color, bounds, rotation)
);
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 9d07fed6..50ee7ecc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -200,8 +200,8 @@ pub use crate::core::gradient;
pub use crate::core::theme;
pub use crate::core::{
Alignment, Background, Border, Color, ContentFit, Degrees, Gradient,
- Length, Padding, Pixels, Point, Radians, Rectangle, RotationLayout, Shadow,
- Size, Theme, Transformation, Vector,
+ Length, Padding, Pixels, Point, Radians, Rectangle, Rotation, Shadow, Size,
+ Theme, Transformation, Vector,
};
pub mod clipboard {
diff --git a/tiny_skia/src/engine.rs b/tiny_skia/src/engine.rs
index 564d3752..e9935bdb 100644
--- a/tiny_skia/src/engine.rs
+++ b/tiny_skia/src/engine.rs
@@ -551,7 +551,6 @@ impl Engine {
filter_method,
bounds,
rotation,
- scale,
} => {
let physical_bounds = *bounds * transformation;
@@ -563,11 +562,13 @@ impl Engine {
.then_some(clip_mask as &_);
let center = physical_bounds.center();
- let transform = into_transform(transformation)
- .post_rotate_at(rotation.to_degrees(), center.x, center.y)
- .post_translate(-center.x, -center.y)
- .post_scale(scale.width, scale.height)
- .post_translate(center.x, center.y);
+ let radians = f32::from(*rotation);
+
+ let transform = into_transform(transformation).post_rotate_at(
+ radians.to_degrees(),
+ center.x,
+ center.y,
+ );
self.raster_pipeline.draw(
handle,
@@ -584,7 +585,6 @@ impl Engine {
color,
bounds,
rotation,
- scale,
} => {
let physical_bounds = *bounds * transformation;
@@ -596,11 +596,13 @@ impl Engine {
.then_some(clip_mask as &_);
let center = physical_bounds.center();
- let transform = into_transform(transformation)
- .post_rotate_at(rotation.to_degrees(), center.x, center.y)
- .post_translate(-center.x, -center.y)
- .post_scale(scale.width, scale.height)
- .post_translate(center.x, center.y);
+ let radians = f32::from(*rotation);
+
+ let transform = into_transform(transformation).post_rotate_at(
+ radians.to_degrees(),
+ center.x,
+ center.y,
+ );
self.vector_pipeline.draw(
handle,
diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs
index e9651814..c8a31ba3 100644
--- a/tiny_skia/src/layer.rs
+++ b/tiny_skia/src/layer.rs
@@ -1,5 +1,5 @@
use crate::core::{
- image, renderer::Quad, svg, Background, Color, Point, Rectangle, Size,
+ image, renderer::Quad, svg, Background, Color, Point, Radians, Rectangle,
Transformation,
};
use crate::graphics::damage;
@@ -121,15 +121,13 @@ impl Layer {
filter_method: image::FilterMethod,
bounds: Rectangle,
transformation: Transformation,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let image = Image::Raster {
handle,
filter_method,
bounds: bounds * transformation,
rotation,
- scale,
};
self.images.push(image);
@@ -141,15 +139,13 @@ impl Layer {
color: Option<Color>,
bounds: Rectangle,
transformation: Transformation,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let svg = Image::Vector {
handle,
color,
bounds: bounds * transformation,
rotation,
- scale,
};
self.images.push(svg);
diff --git a/tiny_skia/src/lib.rs b/tiny_skia/src/lib.rs
index 4e3ebad3..75aaaf92 100644
--- a/tiny_skia/src/lib.rs
+++ b/tiny_skia/src/lib.rs
@@ -29,7 +29,7 @@ pub use geometry::Geometry;
use crate::core::renderer;
use crate::core::{
- Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
+ Background, Color, Font, Pixels, Point, Radians, Rectangle, Transformation,
};
use crate::engine::Engine;
use crate::graphics::compositor;
@@ -377,8 +377,7 @@ impl core::image::Renderer for Renderer {
handle: Self::Handle,
filter_method: core::image::FilterMethod,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let (layer, transformation) = self.layers.current_mut();
layer.draw_image(
@@ -387,7 +386,6 @@ impl core::image::Renderer for Renderer {
bounds,
transformation,
rotation,
- scale,
);
}
}
@@ -406,11 +404,10 @@ impl core::svg::Renderer for Renderer {
handle: core::svg::Handle,
color: Option<Color>,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let (layer, transformation) = self.layers.current_mut();
- layer.draw_svg(handle, color, bounds, transformation, rotation, scale);
+ layer.draw_svg(handle, color, bounds, transformation, rotation);
}
}
diff --git a/wgpu/src/image/mod.rs b/wgpu/src/image/mod.rs
index 69f8a8ca..3ec341fc 100644
--- a/wgpu/src/image/mod.rs
+++ b/wgpu/src/image/mod.rs
@@ -141,14 +141,12 @@ impl Pipeline {
2 => Float32x2,
// Rotation
3 => Float32,
- // Scale
- 4 => Float32x2,
// Atlas position
- 5 => Float32x2,
+ 4 => Float32x2,
// Atlas scale
- 6 => Float32x2,
+ 5 => Float32x2,
// Layer
- 7 => Sint32,
+ 6 => Sint32,
),
}],
},
@@ -232,7 +230,6 @@ impl Pipeline {
filter_method,
bounds,
rotation,
- scale,
} => {
if let Some(atlas_entry) =
cache.upload_raster(device, encoder, handle)
@@ -240,8 +237,7 @@ impl Pipeline {
add_instances(
[bounds.x, bounds.y],
[bounds.width, bounds.height],
- *rotation,
- [scale.width, scale.height],
+ f32::from(*rotation),
atlas_entry,
match filter_method {
crate::core::image::FilterMethod::Nearest => {
@@ -263,7 +259,6 @@ impl Pipeline {
color,
bounds,
rotation,
- scale,
} => {
let size = [bounds.width, bounds.height];
@@ -278,8 +273,7 @@ impl Pipeline {
add_instances(
[bounds.x, bounds.y],
size,
- *rotation,
- [scale.width, scale.height],
+ f32::from(*rotation),
atlas_entry,
nearest_instances,
);
@@ -510,7 +504,6 @@ struct Instance {
_center: [f32; 2],
_size: [f32; 2],
_rotation: f32,
- _scale: [f32; 2],
_position_in_atlas: [f32; 2],
_size_in_atlas: [f32; 2],
_layer: u32,
@@ -530,7 +523,6 @@ fn add_instances(
image_position: [f32; 2],
image_size: [f32; 2],
rotation: f32,
- scale: [f32; 2],
entry: &atlas::Entry,
instances: &mut Vec<Instance>,
) {
@@ -546,7 +538,6 @@ fn add_instances(
center,
image_size,
rotation,
- scale,
allocation,
instances,
);
@@ -576,8 +567,7 @@ fn add_instances(
];
add_instance(
- position, center, size, rotation, scale, allocation,
- instances,
+ position, center, size, rotation, allocation, instances,
);
}
}
@@ -590,7 +580,6 @@ fn add_instance(
center: [f32; 2],
size: [f32; 2],
rotation: f32,
- scale: [f32; 2],
allocation: &atlas::Allocation,
instances: &mut Vec<Instance>,
) {
@@ -603,7 +592,6 @@ fn add_instance(
_center: center,
_size: size,
_rotation: rotation,
- _scale: scale,
_position_in_atlas: [
(x as f32 + 0.5) / atlas::SIZE as f32,
(y as f32 + 0.5) / atlas::SIZE as f32,
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 648ec476..e0242c59 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -1,5 +1,5 @@
use crate::core::{
- renderer, Background, Color, Point, Rectangle, Size, Transformation,
+ renderer, Background, Color, Point, Radians, Rectangle, Transformation,
};
use crate::graphics;
use crate::graphics::color;
@@ -118,15 +118,13 @@ impl Layer {
filter_method: crate::core::image::FilterMethod,
bounds: Rectangle,
transformation: Transformation,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let image = Image::Raster {
handle,
filter_method,
bounds: bounds * transformation,
rotation,
- scale,
};
self.images.push(image);
@@ -138,15 +136,13 @@ impl Layer {
color: Option<Color>,
bounds: Rectangle,
transformation: Transformation,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let svg = Image::Vector {
handle,
color,
bounds: bounds * transformation,
rotation,
- scale,
};
self.images.push(svg);
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index a42d71c3..6920067b 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -61,7 +61,8 @@ pub use settings::Settings;
pub use geometry::Geometry;
use crate::core::{
- Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
+ Background, Color, Font, Pixels, Point, Radians, Rectangle, Size,
+ Transformation, Vector,
};
use crate::graphics::text::{Editor, Paragraph};
use crate::graphics::Viewport;
@@ -378,7 +379,6 @@ impl Renderer {
use crate::core::alignment;
use crate::core::text::Renderer as _;
use crate::core::Renderer as _;
- use crate::core::Vector;
self.with_layer(
Rectangle::with_size(viewport.logical_size()),
@@ -517,8 +517,7 @@ impl core::image::Renderer for Renderer {
handle: Self::Handle,
filter_method: core::image::FilterMethod,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let (layer, transformation) = self.layers.current_mut();
layer.draw_image(
@@ -527,7 +526,6 @@ impl core::image::Renderer for Renderer {
bounds,
transformation,
rotation,
- scale,
);
}
}
@@ -543,18 +541,10 @@ impl core::svg::Renderer for Renderer {
handle: core::svg::Handle,
color_filter: Option<Color>,
bounds: Rectangle,
- rotation: f32,
- scale: Size,
+ rotation: Radians,
) {
let (layer, transformation) = self.layers.current_mut();
- layer.draw_svg(
- handle,
- color_filter,
- bounds,
- transformation,
- rotation,
- scale,
- );
+ layer.draw_svg(handle, color_filter, bounds, transformation, rotation);
}
}
diff --git a/wgpu/src/shader/image.wgsl b/wgpu/src/shader/image.wgsl
index de962098..71bf939c 100644
--- a/wgpu/src/shader/image.wgsl
+++ b/wgpu/src/shader/image.wgsl
@@ -10,12 +10,11 @@ struct VertexInput {
@builtin(vertex_index) vertex_index: u32,
@location(0) pos: vec2<f32>,
@location(1) center: vec2<f32>,
- @location(2) image_size: vec2<f32>,
+ @location(2) scale: vec2<f32>,
@location(3) rotation: f32,
- @location(4) scale: vec2<f32>,
- @location(5) atlas_pos: vec2<f32>,
- @location(6) atlas_scale: vec2<f32>,
- @location(7) layer: i32,
+ @location(4) atlas_pos: vec2<f32>,
+ @location(5) atlas_scale: vec2<f32>,
+ @location(6) layer: i32,
}
struct VertexOutput {
@@ -36,7 +35,7 @@ fn vs_main(input: VertexInput) -> VertexOutput {
out.layer = f32(input.layer);
// Calculate the vertex position and move the center to the origin
- v_pos = input.pos + v_pos * input.image_size - input.center;
+ v_pos = input.pos + v_pos * input.scale - input.center;
// Apply the rotation around the center of the image
let cos_rot = cos(input.rotation);
@@ -48,16 +47,8 @@ fn vs_main(input: VertexInput) -> VertexOutput {
vec4<f32>(0.0, 0.0, 0.0, 1.0)
);
- // Scale the image and then translate to the final position by moving the center to the position
- let scale_translate = mat4x4<f32>(
- vec4<f32>(input.scale.x, 0.0, 0.0, 0.0),
- vec4<f32>(0.0, input.scale.y, 0.0, 0.0),
- vec4<f32>(0.0, 0.0, 1.0, 0.0),
- vec4<f32>(input.center, 0.0, 1.0)
- );
-
// Calculate the final position of the vertex
- out.position = globals.transform * scale_translate * rotate * vec4<f32>(v_pos, 0.0, 1.0);
+ out.position = globals.transform * (vec4<f32>(input.center, 0.0, 0.0) + rotate * vec4<f32>(v_pos, 0.0, 1.0));
return out;
}
diff --git a/widget/src/image.rs b/widget/src/image.rs
index 3a0a5e53..45209a91 100644
--- a/widget/src/image.rs
+++ b/widget/src/image.rs
@@ -1,6 +1,5 @@
//! Display images in your user interface.
pub mod viewer;
-use iced_renderer::core::{Point, RotationLayout};
pub use viewer::Viewer;
use crate::core::image;
@@ -9,7 +8,8 @@ use crate::core::mouse;
use crate::core::renderer;
use crate::core::widget::Tree;
use crate::core::{
- ContentFit, Element, Layout, Length, Rectangle, Size, Widget,
+ ContentFit, Element, Layout, Length, Point, Rectangle, Rotation, Size,
+ Vector, Widget,
};
pub use image::{FilterMethod, Handle};
@@ -37,8 +37,7 @@ pub struct Image<Handle> {
height: Length,
content_fit: ContentFit,
filter_method: FilterMethod,
- rotation: f32,
- rotation_layout: RotationLayout,
+ rotation: Rotation,
}
impl<Handle> Image<Handle> {
@@ -48,10 +47,9 @@ impl<Handle> Image<Handle> {
handle: handle.into(),
width: Length::Shrink,
height: Length::Shrink,
- content_fit: ContentFit::Contain,
+ content_fit: ContentFit::default(),
filter_method: FilterMethod::default(),
- rotation: 0.0,
- rotation_layout: RotationLayout::Change,
+ rotation: Rotation::default(),
}
}
@@ -81,15 +79,9 @@ impl<Handle> Image<Handle> {
self
}
- /// Rotates the [`Image`] by the given angle in radians.
- pub fn rotation(mut self, degrees: f32) -> Self {
- self.rotation = degrees;
- self
- }
-
- /// Sets the [`RotationLayout`] of the [`Image`].
- pub fn rotation_layout(mut self, rotation_layout: RotationLayout) -> Self {
- self.rotation_layout = rotation_layout;
+ /// Applies the given [`Rotation`] to the [`Image`].
+ pub fn rotation(mut self, rotation: impl Into<Rotation>) -> Self {
+ self.rotation = rotation.into();
self
}
}
@@ -102,8 +94,7 @@ pub fn layout<Renderer, Handle>(
width: Length,
height: Length,
content_fit: ContentFit,
- rotation: f32,
- rotation_layout: RotationLayout,
+ rotation: Rotation,
) -> layout::Node
where
Renderer: image::Renderer<Handle = Handle>,
@@ -114,7 +105,7 @@ where
Size::new(image_size.width as f32, image_size.height as f32);
// The rotated size of the image
- let rotated_size = rotation_layout.apply_to_size(image_size, rotation);
+ let rotated_size = rotation.apply(image_size);
// The size to be available to the widget prior to `Shrink`ing
let raw_size = limits.resolve(width, height, rotated_size);
@@ -144,45 +135,44 @@ pub fn draw<Renderer, Handle>(
handle: &Handle,
content_fit: ContentFit,
filter_method: FilterMethod,
- rotation: f32,
- rotation_layout: RotationLayout,
+ rotation: Rotation,
) where
Renderer: image::Renderer<Handle = Handle>,
Handle: Clone,
{
let Size { width, height } = renderer.measure_image(handle);
let image_size = Size::new(width as f32, height as f32);
- let rotated_size = rotation_layout.apply_to_size(image_size, rotation);
+ let rotated_size = rotation.apply(image_size);
let bounds = layout.bounds();
let adjusted_fit = content_fit.fit(rotated_size, bounds.size());
- let scale = Size::new(
+
+ let scale = Vector::new(
adjusted_fit.width / rotated_size.width,
adjusted_fit.height / rotated_size.height,
);
- let render = |renderer: &mut Renderer| {
- let position = match content_fit {
- ContentFit::None => Point::new(
- bounds.position().x
- + (rotated_size.width - image_size.width) / 2.0,
- bounds.position().y
- + (rotated_size.height - image_size.height) / 2.0,
- ),
- _ => Point::new(
- bounds.center_x() - image_size.width / 2.0,
- bounds.center_y() - image_size.height / 2.0,
- ),
- };
+ let final_size = image_size * scale;
+
+ let position = match content_fit {
+ ContentFit::None => Point::new(
+ bounds.x + (rotated_size.width - adjusted_fit.width) / 2.0,
+ bounds.y + (rotated_size.height - adjusted_fit.height) / 2.0,
+ ),
+ _ => Point::new(
+ bounds.center_x() - final_size.width / 2.0,
+ bounds.center_y() - final_size.height / 2.0,
+ ),
+ };
- let drawing_bounds = Rectangle::new(position, image_size);
+ let drawing_bounds = Rectangle::new(position, final_size);
+ let render = |renderer: &mut Renderer| {
renderer.draw_image(
handle.clone(),
filter_method,
drawing_bounds,
- rotation,
- scale,
+ rotation.radians(),
);
};
@@ -221,7 +211,6 @@ where
self.height,
self.content_fit,
self.rotation,
- self.rotation_layout,
)
}
@@ -242,7 +231,6 @@ where
self.content_fit,
self.filter_method,
self.rotation,
- self.rotation_layout,
);
}
}
diff --git a/widget/src/image/viewer.rs b/widget/src/image/viewer.rs
index ccdfdebb..ee4c0fba 100644
--- a/widget/src/image/viewer.rs
+++ b/widget/src/image/viewer.rs
@@ -6,8 +6,8 @@ use crate::core::mouse;
use crate::core::renderer;
use crate::core::widget::tree::{self, Tree};
use crate::core::{
- Clipboard, Element, Layout, Length, Pixels, Point, Rectangle, Shell, Size,
- Vector, Widget,
+ Clipboard, Element, Layout, Length, Pixels, Point, Radians, Rectangle,
+ Shell, Size, Vector, Widget,
};
/// A frame that displays an image with the ability to zoom in/out and pan.
@@ -341,8 +341,7 @@ where
y: bounds.y,
..Rectangle::with_size(image_size)
},
- 0.0,
- Size::UNIT,
+ Radians(0.0),
);
});
});
diff --git a/widget/src/svg.rs b/widget/src/svg.rs
index 21946af8..c1fccba1 100644
--- a/widget/src/svg.rs
+++ b/widget/src/svg.rs
@@ -5,8 +5,8 @@ use crate::core::renderer;
use crate::core::svg;
use crate::core::widget::Tree;
use crate::core::{
- Color, ContentFit, Element, Layout, Length, Point, Rectangle,
- RotationLayout, Size, Theme, Widget,
+ Color, ContentFit, Element, Layout, Length, Point, Rectangle, Rotation,
+ Size, Theme, Vector, Widget,
};
use std::path::PathBuf;
@@ -29,8 +29,7 @@ where
height: Length,
content_fit: ContentFit,
class: Theme::Class<'a>,
- rotation: f32,
- rotation_layout: RotationLayout,
+ rotation: Rotation,
}
impl<'a, Theme> Svg<'a, Theme>
@@ -45,8 +44,7 @@ where
height: Length::Shrink,
content_fit: ContentFit::Contain,
class: Theme::default(),
- rotation: 0.0,
- rotation_layout: RotationLayout::Change,
+ rotation: Rotation::default(),
}
}
@@ -100,15 +98,9 @@ where
self
}
- /// Rotates the [`Svg`] by the given angle in radians.
- pub fn rotation(mut self, degrees: f32) -> Self {
- self.rotation = degrees;
- self
- }
-
- /// Sets the [`RotationLayout`] of the [`Svg`].
- pub fn rotation_layout(mut self, rotation_layout: RotationLayout) -> Self {
- self.rotation_layout = rotation_layout;
+ /// Applies the given [`Rotation`] to the [`Svg`].
+ pub fn rotation(mut self, rotation: impl Into<Rotation>) -> Self {
+ self.rotation = rotation.into();
self
}
}
@@ -137,9 +129,7 @@ where
let image_size = Size::new(width as f32, height as f32);
// The rotated size of the svg
- let rotated_size = self
- .rotation_layout
- .apply_to_size(image_size, self.rotation);
+ let rotated_size = self.rotation.apply(image_size);
// The size to be available to the widget prior to `Shrink`ing
let raw_size = limits.resolve(self.width, self.height, rotated_size);
@@ -174,49 +164,46 @@ where
) {
let Size { width, height } = renderer.measure_svg(&self.handle);
let image_size = Size::new(width as f32, height as f32);
- let rotated_size = self
- .rotation_layout
- .apply_to_size(image_size, self.rotation);
+ let rotated_size = self.rotation.apply(image_size);
let bounds = layout.bounds();
let adjusted_fit = self.content_fit.fit(rotated_size, bounds.size());
- let scale = Size::new(
+ let scale = Vector::new(
adjusted_fit.width / rotated_size.width,
adjusted_fit.height / rotated_size.height,
);
+ let final_size = image_size * scale;
+
+ let position = match self.content_fit {
+ ContentFit::None => Point::new(
+ bounds.x + (rotated_size.width - adjusted_fit.width) / 2.0,
+ bounds.y + (rotated_size.height - adjusted_fit.height) / 2.0,
+ ),
+ _ => Point::new(
+ bounds.center_x() - final_size.width / 2.0,
+ bounds.center_y() - final_size.height / 2.0,
+ ),
+ };
+
+ let drawing_bounds = Rectangle::new(position, final_size);
+
let is_mouse_over = cursor.is_over(bounds);
- let render = |renderer: &mut Renderer| {
- let position = match self.content_fit {
- ContentFit::None => Point::new(
- bounds.position().x
- + (rotated_size.width - image_size.width) / 2.0,
- bounds.position().y
- + (rotated_size.height - image_size.height) / 2.0,
- ),
- _ => Point::new(
- bounds.center_x() - image_size.width / 2.0,
- bounds.center_y() - image_size.height / 2.0,
- ),
- };
-
- let drawing_bounds = Rectangle::new(position, image_size);
-
- let status = if is_mouse_over {
- Status::Hovered
- } else {
- Status::Idle
- };
-
- let style = theme.style(&self.class, status);
+ let status = if is_mouse_over {
+ Status::Hovered
+ } else {
+ Status::Idle
+ };
+ let style = theme.style(&self.class, status);
+
+ let render = |renderer: &mut Renderer| {
renderer.draw_svg(
self.handle.clone(),
style.color,
drawing_bounds,
- self.rotation,
- scale,
+ self.rotation.radians(),
);
};