From c2a68a9ac1670bd3895ca59b87c9af314e4cbd4f Mon Sep 17 00:00:00 2001 From: dtzxporter Date: Sat, 3 Feb 2024 12:26:29 -0500 Subject: [PATCH] Revert "Merge remote-tracking branch 'upstream/master' into workaround-winit-win32-issues" This reverts commit ecc6207dfa5bf34e4d6861909a6eb4c85b78155b, reversing changes made to 595a5dbf5744ce9e7b7172f5a9162b5e2c7f9d38. --- CHANGELOG.md | 116 +------------- core/Cargo.toml | 1 - core/src/angle.rs | 97 ++---------- core/src/element.rs | 16 +- core/src/lib.rs | 2 - core/src/mouse/interaction.rs | 1 - core/src/overlay.rs | 13 +- core/src/overlay/element.rs | 41 ++++- core/src/overlay/group.rs | 16 +- core/src/pixels.rs | 8 - core/src/renderer.rs | 20 +-- core/src/renderer/null.rs | 8 +- core/src/transformation.rs | 119 -------------- core/src/widget.rs | 3 +- docs/release_summary.py | 118 ++++++-------- examples/bezier_tool/Cargo.toml | 2 +- examples/checkbox/src/main.rs | 64 +++----- examples/custom_shader/src/main.rs | 7 +- examples/events/src/main.rs | 7 +- examples/game_of_life/src/main.rs | 3 +- examples/layout/src/main.rs | 3 +- examples/loading_spinners/src/circular.rs | 21 ++- examples/loupe/Cargo.toml | 10 -- examples/loupe/src/main.rs | 185 ---------------------- examples/modal/src/main.rs | 23 +-- examples/slider/src/main.rs | 38 ++--- examples/styling/src/main.rs | 7 +- examples/svg/src/main.rs | 8 +- examples/system_information/src/main.rs | 8 +- examples/toast/src/main.rs | 25 +-- examples/todos/src/main.rs | 11 +- examples/tour/src/main.rs | 33 ++-- examples/vectorial_text/src/main.rs | 7 +- graphics/Cargo.toml | 1 + graphics/src/damage.rs | 18 +-- graphics/src/geometry/path/arc.rs | 22 +-- graphics/src/geometry/path/builder.rs | 14 +- graphics/src/lib.rs | 2 + graphics/src/primitive.rs | 34 ++-- graphics/src/renderer.rs | 18 +-- graphics/src/transformation.rs | 59 +++++++ graphics/src/viewport.rs | 4 +- renderer/src/geometry.rs | 52 ++---- renderer/src/lib.rs | 16 +- runtime/src/command/action.rs | 9 +- runtime/src/overlay/nested.rs | 21 ++- runtime/src/system/information.rs | 4 +- runtime/src/user_interface.rs | 62 ++++---- src/lib.rs | 3 +- style/src/checkbox.rs | 3 - style/src/theme.rs | 40 +---- tiny_skia/src/backend.rs | 108 ++++++------- tiny_skia/src/geometry.rs | 6 +- tiny_skia/src/text.rs | 23 +-- wgpu/src/backend.rs | 12 +- wgpu/src/geometry.rs | 28 ++-- wgpu/src/image.rs | 3 +- wgpu/src/layer.rs | 89 ++++++----- wgpu/src/layer/mesh.rs | 17 +- wgpu/src/layer/text.rs | 10 +- wgpu/src/quad.rs | 6 +- wgpu/src/text.rs | 33 ++-- wgpu/src/triangle.rs | 10 +- widget/src/button.rs | 4 +- widget/src/canvas.rs | 6 +- widget/src/checkbox.rs | 55 ++----- widget/src/column.rs | 11 +- widget/src/combo_box.rs | 5 +- widget/src/container.rs | 2 - widget/src/helpers.rs | 3 +- widget/src/keyed/column.rs | 11 +- widget/src/lazy.rs | 23 ++- widget/src/lazy/component.rs | 31 +++- widget/src/lazy/responsive.rs | 23 ++- widget/src/mouse_area.rs | 73 +-------- widget/src/overlay/menu.rs | 29 ++-- widget/src/pane_grid.rs | 34 ++-- widget/src/pane_grid/content.rs | 15 +- widget/src/pane_grid/title_bar.rs | 6 +- widget/src/pick_list.rs | 7 +- widget/src/qr_code.rs | 11 +- widget/src/row.rs | 11 +- widget/src/scrollable.rs | 55 +++---- widget/src/slider.rs | 119 ++------------ widget/src/text_editor.rs | 46 ++---- widget/src/themer.rs | 19 ++- widget/src/tooltip.rs | 64 ++++---- widget/src/vertical_slider.rs | 119 ++------------ winit/src/application.rs | 3 - winit/src/conversion.rs | 1 - winit/src/multi_window.rs | 3 - 91 files changed, 840 insertions(+), 1717 deletions(-) delete mode 100644 core/src/transformation.rs delete mode 100644 examples/loupe/Cargo.toml delete mode 100644 examples/loupe/src/main.rs create mode 100644 graphics/src/transformation.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index ec3e87eacd..fdd832e495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,128 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Multi-window support. [#1964](https://github.com/iced-rs/iced/pull/1964) -- `TextEditor` widget (or multi-line text input). [#2123](https://github.com/iced-rs/iced/pull/2123) -- `Shader` widget. [#2085](https://github.com/iced-rs/iced/pull/2085) -- Shadows. [#1882](https://github.com/iced-rs/iced/pull/1882) -- Vectorial text for `Canvas`. [#2204](https://github.com/iced-rs/iced/pull/2204) -- Layout consistency. [#2192](https://github.com/iced-rs/iced/pull/2192) - Explicit text caching. [#2058](https://github.com/iced-rs/iced/pull/2058) -- Gradients in Oklab color space. [#2055](https://github.com/iced-rs/iced/pull/2055) -- `Themer` widget. [#2209](https://github.com/iced-rs/iced/pull/2209) -- `Transform` primitive. [#2120](https://github.com/iced-rs/iced/pull/2120) -- Cut functionality for `TextEditor`. [#2215](https://github.com/iced-rs/iced/pull/2215) -- Disabled support for `Checkbox`. [#2109](https://github.com/iced-rs/iced/pull/2109) -- `skip_taskbar` window setting for Windows. [#2211](https://github.com/iced-rs/iced/pull/2211) -- `fetch_maximized` and `fetch_minimized` window commands. [#2189](https://github.com/iced-rs/iced/pull/2189) -- `text_shaping` method for `Tooltip`. [#2172](https://github.com/iced-rs/iced/pull/2172) -- `hovered` styling for `Svg` widget. [#2163](https://github.com/iced-rs/iced/pull/2163) -- Customizable style for `TextEditor`. [#2159](https://github.com/iced-rs/iced/pull/2159) -- `RawText` variant for `Primitive` in `iced_graphics`. [#2158](https://github.com/iced-rs/iced/pull/2158) -- `Stream` support for `Command`. [#2150](https://github.com/iced-rs/iced/pull/2150) -- Access to bounds/content bounds from a `Scrollable` viewport. [#2072](https://github.com/iced-rs/iced/pull/2072) -- `Frame::scale_nonuniform` method. [#2070](https://github.com/iced-rs/iced/pull/2070) -- `theme::Custom::with_fn` to generate completely custom themes. [#2067](https://github.com/iced-rs/iced/pull/2067) -- `style` attribute for `Font`. [#2041](https://github.com/iced-rs/iced/pull/2041) -- Texture filtering options for `Image`. [#1894](https://github.com/iced-rs/iced/pull/1894) -- `default` and `shift_step` methods for `slider` widgets. [#2100](https://github.com/iced-rs/iced/pull/2100) -- `Custom` variant to `command::Action`. [#2146](https://github.com/iced-rs/iced/pull/2146) -- Mouse movement events for `MouseArea`. [#2147](https://github.com/iced-rs/iced/pull/2147) +- `Theme::Custom::with_fn` for custom extended palette generation. [#2067](https://github.com/iced-rs/iced/pull/2067) ### Changed -- Enable WebGPU backend in `wgpu` by default instead of WebGL. [#2068](https://github.com/iced-rs/iced/pull/2068) -- Update `glyphon` to `0.4`. [#2203](https://github.com/iced-rs/iced/pull/2203) -- Require `Send` on stored pipelines. [#2197](https://github.com/iced-rs/iced/pull/2197) -- Update `wgpu` to `0.19`, `glyphon` to `0.5`, `softbuffer` to `0.4`, `window-clipboard` to `0.4`, and `raw-window-handle` to `0.6`. [#2191](https://github.com/iced-rs/iced/pull/2191) -- Update `winit` to `0.29`. [#2169](https://github.com/iced-rs/iced/pull/2169) -- Provide actual bounds to `Shader` primitives. [#2149](https://github.com/iced-rs/iced/pull/2149) -- Deny warnings in `test` workflow. [#2135](https://github.com/iced-rs/iced/pull/2135) -- Update `wgpu` to `0.18` and `cosmic-text` to `0.10`. [#2122](https://github.com/iced-rs/iced/pull/2122) -- Compute vertex positions in the shader. [#2099](https://github.com/iced-rs/iced/pull/2099) -- Migrate twox-hash -> xxhash-rust and switch to Xxh3 for better performance. [#2080](https://github.com/iced-rs/iced/pull/2080) -- Add `keyboard` subscriptions and rename `subscription::events` to `event::listen`. [#2073](https://github.com/iced-rs/iced/pull/2073) -- Use workspace dependencies and package inheritance. [#2069](https://github.com/iced-rs/iced/pull/2069) -- Update `wgpu` to `0.17`. [#2065](https://github.com/iced-rs/iced/pull/2065) -- Support automatic style type casting for `Button`. [#2046](https://github.com/iced-rs/iced/pull/2046) -- Make `with_clip` and `with_save` in `Frame` able to return the data of the provided closure. [#1994](https://github.com/iced-rs/iced/pull/1994) -- Use `Radians` for angle fields in `Arc` and `arc::Elliptical`. [#2027](https://github.com/iced-rs/iced/pull/2027) -- Assert dimensions of quads are normal in `iced_tiny_skia`. [#2082](https://github.com/iced-rs/iced/pull/2082) -- Remove `position` from `overlay::Element`. [#2226](https://github.com/iced-rs/iced/pull/2226) +- Updated `wgpu` to `0.17`. [#2065](https://github.com/iced-rs/iced/pull/2065) +- Changed `Button::style` to take an `impl Into<...>` for consistency. [#2046](https://github.com/iced-rs/iced/pull/2046) ### Fixed -- Clipping of `TextInput` selection. [#2199](https://github.com/iced-rs/iced/pull/2199) -- `Paragraph::grapheme_position` when ligatures are present. [#2196](https://github.com/iced-rs/iced/pull/2196) -- Docs to include missing feature tags. [#2184](https://github.com/iced-rs/iced/pull/2184) -- `PaneGrid` click interaction on the top edge. [#2168](https://github.com/iced-rs/iced/pull/2168) -- `iced_wgpu` not rendering text in SVGs. [#2161](https://github.com/iced-rs/iced/pull/2161) -- Text clipping. [#2154](https://github.com/iced-rs/iced/pull/2154) -- Layout invalidation when `Tooltip` changes `overlay`. [#2143](https://github.com/iced-rs/iced/pull/2143) -- `Overlay` composition. [#2142](https://github.com/iced-rs/iced/pull/2142) -- Incorrect GIF for the `progress_bar` example. [#2141](https://github.com/iced-rs/iced/pull/2141) -- Standalone compilation of `iced_renderer` crate. [#2134](https://github.com/iced-rs/iced/pull/2134) -- Maximize window button enabled when `Settings::resizable` is `false`. [#2124](https://github.com/iced-rs/iced/pull/2124) -- Width of horizontal scrollbar in `Scrollable`. [#2084](https://github.com/iced-rs/iced/pull/2084) -- `ComboBox` widget panic on wasm. [#2078](https://github.com/iced-rs/iced/pull/2078) -- Majority of unresolved documentation links. [#2077](https://github.com/iced-rs/iced/pull/2077) -- Web examples not running. [#2076](https://github.com/iced-rs/iced/pull/2076) -- GIFs and video examples broken. [#2074](https://github.com/iced-rs/iced/pull/2074) -- `@interpolate(flat)` not used as attribute. [#2071](https://github.com/iced-rs/iced/pull/2071) -- `Checkbox` and `Toggler` hidden behind scrollbar in `styling` example. [#2062](https://github.com/iced-rs/iced/pull/2062) -- Absolute `LineHeight` sometimes being `0`. [#2059](https://github.com/iced-rs/iced/pull/2059) -- Paste while holding ALT. [#2006](https://github.com/iced-rs/iced/pull/2006) -- `Command::perform` to return a `Command`. [#2000](https://github.com/iced-rs/iced/pull/2000) -- `convert_text` not called on `Svg` trees. [#1908](https://github.com/iced-rs/iced/pull/1908) -- Unused `backend.rs` file in renderer crate. [#2182](https://github.com/iced-rs/iced/pull/2182) -- Some `clippy::pedantic` lints. [#2096](https://github.com/iced-rs/iced/pull/2096) -- Some minor clippy fixes. [#2092](https://github.com/iced-rs/iced/pull/2092) -- Clippy docs keyword quoting. [#2091](https://github.com/iced-rs/iced/pull/2091) -- Clippy map transformations. [#2090](https://github.com/iced-rs/iced/pull/2090) -- Inline format args for ease of reading. [#2089](https://github.com/iced-rs/iced/pull/2089) -- Stuck scrolling in `Scrollable` with touch events. [#1940](https://github.com/iced-rs/iced/pull/1940) -- Incorrect unit in `system::Information`. [#2223](https://github.com/iced-rs/iced/pull/2223) -- `size_hint` not being called from `element::Map`. [#2224](https://github.com/iced-rs/iced/pull/2224) -- `size_hint` not being called from `element::Explain`. [#2225](https://github.com/iced-rs/iced/pull/2225) -- Slow touch scrolling for `TextEditor` widget. [#2140](https://github.com/iced-rs/iced/pull/2140) +- Missing `width` attribute in `styling` example. [#2062](https://github.com/iced-rs/iced/pull/2062) Many thanks to... - @akshayr-mecha -- @alec-deason -- @arslee07 -- @AustinMReppert -- @avsaase -- @blazra -- @brianch -- @bungoboingo -- @Calastrophe -- @casperstorm -- @cfrenette -- @Davidster -- @Decodetalkers -- @derezzedex - @dtzxporter -- @GyulyVGC -- @hicaru -- @ids1024 -- @Imberflur -- @jhannyj -- @jhff -- @jim-ec -- @joshuamegnauth54 -- @jpttrssn -- @lufte -- @matze -- @MichalLebeda -- @MrAntix -- @nicksenger -- @Nisatru -- @nyurik -- @Remmirad -- @ripytide -- @Tahinli -- @tarkah -- @tzemanovic -- @william-shere ## [0.10.0] - 2023-07-28 ### Added diff --git a/core/Cargo.toml b/core/Cargo.toml index 2360e82291..32dd3df26a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -12,7 +12,6 @@ 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/angle.rs b/core/src/angle.rs index 30ddad834d..102b69cf5f 100644 --- a/core/src/angle.rs +++ b/core/src/angle.rs @@ -1,7 +1,7 @@ use crate::{Point, Rectangle, Vector}; use std::f32::consts::{FRAC_PI_2, PI}; -use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Sub, SubAssign}; +use std::ops::RangeInclusive; /// Degrees #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] @@ -13,26 +13,7 @@ pub struct Radians(pub f32); impl Radians { /// The range of radians of a circle. - pub const RANGE: RangeInclusive = Self(0.0)..=Self(2.0 * PI); - - /// The amount of radians in half a circle. - pub const PI: Self = Self(PI); - - /// Calculates the line in which the angle intercepts the `bounds`. - pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) { - let angle = self.0 - FRAC_PI_2; - let r = Vector::new(f32::cos(angle), f32::sin(angle)); - - let distance_to_rect = f32::max( - f32::abs(r.x * bounds.width / 2.0), - f32::abs(r.y * bounds.height / 2.0), - ); - - let start = bounds.center() - r * distance_to_rect; - let end = bounds.center() + r * distance_to_rect; - - (start, end) - } + pub const RANGE: RangeInclusive = Radians(0.0)..=Radians(2.0 * PI); } impl From for Radians { @@ -73,70 +54,20 @@ impl num_traits::FromPrimitive for Radians { } } -impl Sub for Radians { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0 - rhs.0) - } -} - -impl SubAssign for Radians { - fn sub_assign(&mut self, rhs: Self) { - self.0 = self.0 - rhs.0; - } -} - -impl Add for Radians { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl AddAssign for Radians { - fn add_assign(&mut self, rhs: Radians) { - self.0 = self.0 + rhs.0; - } -} - -impl Mul for Radians { - type Output = Self; - - fn mul(self, rhs: Radians) -> Self::Output { - Radians(self.0 * rhs.0) - } -} - -impl Mul for Radians { - type Output = Self; - - fn mul(self, rhs: f32) -> Self::Output { - Self(self.0 * rhs) - } -} - -impl Mul for f32 { - type Output = Radians; - - fn mul(self, rhs: Radians) -> Self::Output { - Radians(self * rhs.0) - } -} - -impl Div for Radians { - type Output = Self; +impl Radians { + /// Calculates the line in which the angle intercepts the `bounds`. + pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) { + let angle = self.0 - FRAC_PI_2; + let r = Vector::new(f32::cos(angle), f32::sin(angle)); - fn div(self, rhs: f32) -> Self::Output { - Radians(self.0 / rhs) - } -} + let distance_to_rect = f32::max( + f32::abs(r.x * bounds.width / 2.0), + f32::abs(r.y * bounds.height / 2.0), + ); -impl Div for Radians { - type Output = Self; + let start = bounds.center() - r * distance_to_rect; + let end = bounds.center() + r * distance_to_rect; - fn div(self, rhs: Self) -> Self::Output { - Self(self.0 / rhs.0) + (start, end) } } diff --git a/core/src/element.rs b/core/src/element.rs index 8eea90ca98..fa07ad69dd 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -308,10 +308,6 @@ where self.widget.size() } - fn size_hint(&self) -> Size { - self.widget.size_hint() - } - fn layout( &self, tree: &mut Tree, @@ -446,12 +442,11 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let mapper = &self.mapper; self.widget - .overlay(tree, layout, renderer, translation) + .overlay(tree, layout, renderer) .map(move |overlay| overlay.map(mapper)) } } @@ -482,10 +477,6 @@ where self.element.widget.size() } - fn size_hint(&self) -> Size { - self.element.widget.size_hint() - } - fn tag(&self) -> tree::Tag { self.element.widget.tag() } @@ -597,10 +588,7 @@ where state: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { - self.element - .widget - .overlay(state, layout, renderer, translation) + self.element.widget.overlay(state, layout, renderer) } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 002336ee5f..bbc973f053 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -49,7 +49,6 @@ mod rectangle; mod shadow; mod shell; mod size; -mod transformation; mod vector; pub use alignment::Alignment; @@ -76,7 +75,6 @@ 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 6ad6622926..072033fdd4 100644 --- a/core/src/mouse/interaction.rs +++ b/core/src/mouse/interaction.rs @@ -13,5 +13,4 @@ pub enum Interaction { ResizingHorizontally, ResizingVertically, NotAllowed, - ZoomIn, } diff --git a/core/src/overlay.rs b/core/src/overlay.rs index 03076a30b2..6b8cf2a66e 100644 --- a/core/src/overlay.rs +++ b/core/src/overlay.rs @@ -24,7 +24,13 @@ where /// user interface. /// /// [`Node`]: layout::Node - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node; + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + translation: Vector, + ) -> layout::Node; /// Draws the [`Overlay`] using the associated `Renderer`. fn draw( @@ -114,7 +120,6 @@ pub fn from_children<'a, Message, Theme, Renderer>( tree: &'a mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> where Renderer: crate::Renderer, @@ -124,9 +129,7 @@ where .zip(&mut tree.children) .zip(layout.children()) .filter_map(|((child, state), layout)| { - child - .as_widget_mut() - .overlay(state, layout, renderer, translation) + child.as_widget_mut().overlay(state, layout, renderer) }) .collect::>(); diff --git a/core/src/overlay/element.rs b/core/src/overlay/element.rs index 695b88b3a5..c34ab86289 100644 --- a/core/src/overlay/element.rs +++ b/core/src/overlay/element.rs @@ -12,6 +12,8 @@ use std::any::Any; /// A generic [`Overlay`]. #[allow(missing_debug_implementations)] pub struct Element<'a, Message, Theme, Renderer> { + position: Point, + translation: Vector, overlay: Box + 'a>, } @@ -21,9 +23,26 @@ where { /// Creates a new [`Element`] containing the given [`Overlay`]. pub fn new( + position: Point, overlay: Box + 'a>, ) -> Self { - Self { overlay } + Self { + position, + overlay, + translation: Vector::ZERO, + } + } + + /// Returns the position of the [`Element`]. + pub fn position(&self) -> Point { + self.position + } + + /// Translates the [`Element`]. + pub fn translate(mut self, translation: Vector) -> Self { + self.position = self.position + translation; + self.translation = self.translation + translation; + self } /// Applies a transformation to the produced message of the [`Element`]. @@ -38,6 +57,8 @@ where B: 'a, { Element { + position: self.position, + translation: self.translation, overlay: Box::new(Map::new(self.overlay, f)), } } @@ -47,8 +68,14 @@ where &mut self, renderer: &Renderer, bounds: Size, + translation: Vector, ) -> layout::Node { - self.overlay.layout(renderer, bounds) + self.overlay.layout( + renderer, + bounds, + self.position + translation, + self.translation + translation, + ) } /// Processes a runtime [`Event`]. @@ -138,8 +165,14 @@ impl<'a, A, B, Theme, Renderer> Overlay where Renderer: crate::Renderer, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { - self.content.layout(renderer, bounds) + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + translation: Vector, + ) -> layout::Node { + self.content.layout(renderer, bounds, position, translation) } fn operate( diff --git a/core/src/overlay/group.rs b/core/src/overlay/group.rs index 7e4bebd078..4e54a002c8 100644 --- a/core/src/overlay/group.rs +++ b/core/src/overlay/group.rs @@ -4,7 +4,9 @@ use crate::mouse; use crate::overlay; use crate::renderer; use crate::widget; -use crate::{Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size}; +use crate::{ + Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size, Vector, +}; /// An [`Overlay`] container that displays multiple overlay [`overlay::Element`] /// children. @@ -42,7 +44,7 @@ where /// Turns the [`Group`] into an overlay [`overlay::Element`]. pub fn overlay(self) -> overlay::Element<'a, Message, Theme, Renderer> { - overlay::Element::new(Box::new(self)) + overlay::Element::new(Point::ORIGIN, Box::new(self)) } } @@ -63,12 +65,18 @@ impl<'a, Message, Theme, Renderer> Overlay where Renderer: crate::Renderer, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + _position: Point, + translation: Vector, + ) -> layout::Node { layout::Node::with_children( bounds, self.children .iter_mut() - .map(|child| child.layout(renderer, bounds)) + .map(|child| child.layout(renderer, bounds, translation)) .collect(), ) } diff --git a/core/src/pixels.rs b/core/src/pixels.rs index 425c002865..6a9e5c8888 100644 --- a/core/src/pixels.rs +++ b/core/src/pixels.rs @@ -26,11 +26,3 @@ impl From for f32 { pixels.0 } } - -impl std::ops::Mul 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 1139b41c69..0af74bb323 100644 --- a/core/src/renderer.rs +++ b/core/src/renderer.rs @@ -5,9 +5,7 @@ mod null; #[cfg(debug_assertions)] pub use null::Null; -use crate::{ - Background, Border, Color, Rectangle, Shadow, Size, Transformation, Vector, -}; +use crate::{Background, Border, Color, Rectangle, Shadow, Size, Vector}; /// A component that can be used by widgets to draw themselves on a screen. pub trait Renderer: Sized { @@ -16,24 +14,12 @@ 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 [`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. + /// 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); diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index 75a3c8b641..455daa42f8 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -1,9 +1,7 @@ use crate::alignment; use crate::renderer::{self, Renderer}; use crate::text::{self, Text}; -use crate::{ - Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, -}; +use crate::{Background, Color, Font, Pixels, Point, Rectangle, Size, Vector}; use std::borrow::Cow; @@ -23,9 +21,9 @@ impl Null { impl Renderer for Null { fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {} - fn with_transformation( + fn with_translation( &mut self, - _transformation: Transformation, + _translation: Vector, _f: impl FnOnce(&mut Self), ) { } diff --git a/core/src/transformation.rs b/core/src/transformation.rs deleted file mode 100644 index b2c488b0b3..0000000000 --- a/core/src/transformation.rs +++ /dev/null @@ -1,119 +0,0 @@ -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 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 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 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 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 for [f32; 16] { - fn from(t: Transformation) -> [f32; 16] { - *t.as_ref() - } -} - -impl From for Mat4 { - fn from(transformation: Transformation) -> Self { - transformation.0 - } -} diff --git a/core/src/widget.rs b/core/src/widget.rs index 51326f1246..d5e2ec6fda 100644 --- a/core/src/widget.rs +++ b/core/src/widget.rs @@ -15,7 +15,7 @@ use crate::layout::{self, Layout}; use crate::mouse; use crate::overlay; use crate::renderer; -use crate::{Clipboard, Length, Rectangle, Shell, Size, Vector}; +use crate::{Clipboard, Length, Rectangle, Shell, Size}; /// A component that displays information and allows interaction. /// @@ -146,7 +146,6 @@ where _state: &'a mut Tree, _layout: Layout<'_>, _renderer: &Renderer, - _translation: Vector, ) -> Option> { None } diff --git a/docs/release_summary.py b/docs/release_summary.py index 39ec876ca6..62694d05a6 100644 --- a/docs/release_summary.py +++ b/docs/release_summary.py @@ -1,75 +1,55 @@ +import re +import sys import requests -import os - -def get_merged_prs(repo, milestone, token): - url = f'https://api.github.com/repos/{repo}/pulls' - params = { - 'state': 'closed', - 'per_page': 100, # Number of items per page, adjust as needed - } - headers = {'Authorization': f'token {token}'} - - all_prs = [] - page = 1 - - while True: - params['page'] = page - response = requests.get(url, params=params, headers=headers) - response.raise_for_status() - - prs = response.json() - - if not prs: - break # No more pages - - all_prs.extend([pr for pr in prs if pr['merged_at'] and (pr['milestone'] or {}).get('title', '') == milestone]) - page += 1 - - return all_prs - -def categorize_prs(prs): - categorized_prs = {'addition': [], 'change': [], 'fix': []} - +from typing import List, Tuple + +if len(sys.argv) < 3: + print("Usage: python release_summary.py ") + exit(1) + +TOKEN = sys.argv[1] +HEADERS = {"Authorization": f"Bearer {TOKEN}"} +PR_COMMIT_REGEX = re.compile(r"(?i)Merge pull request #(\d+).*") + +def get_merged_prs_since_release(repo: str, previous_release_branch: str) -> List[Tuple[str, int, str, str]]: + prs = [] + compare_url = f"https://api.github.com/repos/{repo}/compare/{previous_release_branch}...master?per_page=1000" + compare_response = requests.get(compare_url, headers=HEADERS) + + if compare_response.status_code == 200: + compare_data = compare_response.json() + for commit in compare_data["commits"]: + match = PR_COMMIT_REGEX.search(commit["commit"]["message"]) + if match: + pr_number = int(match.group(1)) + pr_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}" + + print(f"Querying PR {pr_number}") + pr_response = requests.get(pr_url, headers=HEADERS) + + if pr_response.status_code == 200: + pr_data = pr_response.json() + prs.append((pr_data["title"], pr_number, pr_data["html_url"], pr_data["user"]["login"])) + else: + print(f"Error fetching PR {pr_number}: {pr_response.status_code}") + else: + print(f"Error comparing branches: {compare_response.status_code}") + + return prs + +def print_pr_list(prs: List[Tuple[str, int, str, str]]): for pr in prs: - labels = [label['name'] for label in pr['labels']] - if 'addition' in labels or 'feature' in labels: - categorized_prs['addition'].append(pr) - elif 'fix' in labels or 'bug' in labels: - categorized_prs['fix'].append(pr) - elif 'change' in labels or 'improvement' in labels: - categorized_prs['change'].append(pr) - - return categorized_prs - -def get_authors(prs): - authors = set() - for pr in prs: - authors.add(pr['user']['login']) - return sorted(authors, key=str.casefold) - -def main(): - repo = 'iced-rs/iced' - milestone = '0.12' - token = os.environ['GITHUB_TOKEN'] - - prs = get_merged_prs(repo, milestone, token) - categorized_prs = categorize_prs(prs) - - for category, items in categorized_prs.items(): - print(f"### {category.capitalize()}") - - for pr in items: - print(f"- {pr['title']}. [#{pr['number']}](https://github.com/{repo}/pull/{pr['number']})") - - print("") - - print("") - - authors = get_authors(prs) + print(f"- {pr[0]}. [#{pr[1]}]({pr[2]})") - print("Many thanks to...") - for author in authors: +def print_authors(prs: List[Tuple[str, int, str, str]]): + authors = set(pr[3] for pr in prs) + print("\nAuthors:") + for author in sorted(authors, key=str.casefold): print(f"- @{author}") if __name__ == "__main__": - main() \ No newline at end of file + repo = "iced-rs/iced" + previous_release_branch = sys.argv[2] + merged_prs = get_merged_prs_since_release(repo, previous_release_branch) + print_pr_list(merged_prs) + print_authors(merged_prs) diff --git a/examples/bezier_tool/Cargo.toml b/examples/bezier_tool/Cargo.toml index e5624097c0..b2547ff1ee 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", "debug"] +iced.features = ["canvas"] diff --git a/examples/checkbox/src/main.rs b/examples/checkbox/src/main.rs index 834a8f5c37..ef1a054d9e 100644 --- a/examples/checkbox/src/main.rs +++ b/examples/checkbox/src/main.rs @@ -1,7 +1,6 @@ use iced::executor; use iced::font::{self, Font}; -use iced::theme; -use iced::widget::{checkbox, column, container, row, text}; +use iced::widget::{checkbox, column, container, text}; use iced::{Application, Command, Element, Length, Settings, Theme}; const ICON_FONT: Font = Font::with_name("icons"); @@ -12,16 +11,14 @@ pub fn main() -> iced::Result { #[derive(Default)] struct Example { - default: bool, - styled: bool, - custom: bool, + default_checkbox: bool, + custom_checkbox: bool, } #[derive(Debug, Clone, Copy)] enum Message { - DefaultToggled(bool), - CustomToggled(bool), - StyledToggled(bool), + DefaultChecked(bool), + CustomChecked(bool), FontLoaded(Result<(), font::Error>), } @@ -45,15 +42,8 @@ impl Application for Example { fn update(&mut self, message: Message) -> Command { match message { - Message::DefaultToggled(default) => { - self.default = default; - } - Message::StyledToggled(styled) => { - self.styled = styled; - } - Message::CustomToggled(custom) => { - self.custom = custom; - } + Message::DefaultChecked(value) => self.default_checkbox = value, + Message::CustomChecked(value) => self.custom_checkbox = value, Message::FontLoaded(_) => (), } @@ -61,35 +51,19 @@ impl Application for Example { } fn view(&self) -> Element { - let default_checkbox = checkbox("Default", self.default) - .on_toggle(Message::DefaultToggled); + let default_checkbox = + checkbox("Default", self.default_checkbox, Message::DefaultChecked); + let custom_checkbox = + checkbox("Custom", self.custom_checkbox, Message::CustomChecked) + .icon(checkbox::Icon { + font: ICON_FONT, + code_point: '\u{e901}', + size: None, + line_height: text::LineHeight::Relative(1.0), + shaping: text::Shaping::Basic, + }); - let styled_checkbox = |label, style| { - checkbox(label, self.styled) - .on_toggle_maybe(self.default.then_some(Message::StyledToggled)) - .style(style) - }; - - let checkboxes = row![ - styled_checkbox("Primary", theme::Checkbox::Primary), - styled_checkbox("Secondary", theme::Checkbox::Secondary), - styled_checkbox("Success", theme::Checkbox::Success), - styled_checkbox("Danger", theme::Checkbox::Danger), - ] - .spacing(20); - - let custom_checkbox = checkbox("Custom", self.custom) - .on_toggle(Message::CustomToggled) - .icon(checkbox::Icon { - font: ICON_FONT, - code_point: '\u{e901}', - size: None, - line_height: text::LineHeight::Relative(1.0), - shaping: text::Shaping::Basic, - }); - - let content = - column![default_checkbox, checkboxes, custom_checkbox].spacing(20); + let content = column![default_checkbox, custom_checkbox].spacing(22); container(content) .width(Length::Fill) diff --git a/examples/custom_shader/src/main.rs b/examples/custom_shader/src/main.rs index 9e8da3baf5..78b2fbbb31 100644 --- a/examples/custom_shader/src/main.rs +++ b/examples/custom_shader/src/main.rs @@ -89,8 +89,11 @@ impl Application for IcedCubes { .step(0.01) .width(100), ), - checkbox("Show Depth Buffer", self.scene.show_depth_buffer) - .on_toggle(Message::ShowDepthBuffer), + checkbox( + "Show Depth Buffer", + self.scene.show_depth_buffer, + Message::ShowDepthBuffer + ), ] .spacing(40); diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index d5d496c7c7..fc51ac4aac 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -85,8 +85,11 @@ impl Application for Events { .map(Element::from), ); - let toggle = checkbox("Listen to runtime events", self.enabled) - .on_toggle(Message::Toggled); + let toggle = checkbox( + "Listen to runtime events", + self.enabled, + Message::Toggled, + ); let exit = button( text("Exit") diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index b386b0cd1c..56f7afd512 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -185,8 +185,7 @@ fn view_controls<'a>( row![ playback_controls, speed_controls, - checkbox("Grid", is_grid_enabled) - .on_toggle(Message::ToggleGrid) + checkbox("Grid", is_grid_enabled, Message::ToggleGrid) .size(16) .spacing(5) .text_size(16), diff --git a/examples/layout/src/main.rs b/examples/layout/src/main.rs index b626c70dd6..6cf0e57032 100644 --- a/examples/layout/src/main.rs +++ b/examples/layout/src/main.rs @@ -86,8 +86,7 @@ impl Application for Layout { let header = row![ text(self.example.title).size(20).font(Font::MONOSPACE), horizontal_space(Length::Fill), - checkbox("Explain", self.explain) - .on_toggle(Message::ExplainToggled), + checkbox("Explain", self.explain, Message::ExplainToggled), pick_list( Theme::ALL, Some(self.theme.clone()), diff --git a/examples/loading_spinners/src/circular.rs b/examples/loading_spinners/src/circular.rs index 12670ed129..8598b20af2 100644 --- a/examples/loading_spinners/src/circular.rs +++ b/examples/loading_spinners/src/circular.rs @@ -9,8 +9,8 @@ use iced::time::Instant; use iced::widget::canvas; use iced::window::{self, RedrawRequest}; use iced::{ - Background, Color, Element, Event, Length, Radians, Rectangle, Renderer, - Size, Vector, + Background, Color, Element, Event, Length, Rectangle, Renderer, Size, + Vector, }; use super::easing::{self, Easing}; @@ -18,8 +18,8 @@ use super::easing::{self, Easing}; use std::f32::consts::PI; use std::time::Duration; -const MIN_ANGLE: Radians = Radians(PI / 8.0); -const WRAP_ANGLE: Radians = Radians(2.0 * PI - PI / 4.0); +const MIN_RADIANS: f32 = PI / 8.0; +const WRAP_RADIANS: f32 = 2.0 * PI - PI / 4.0; const BASE_ROTATION_SPEED: u32 = u32::MAX / 80; #[allow(missing_debug_implementations)] @@ -139,8 +139,7 @@ impl Animation { progress: 0.0, rotation: rotation.wrapping_add( BASE_ROTATION_SPEED.wrapping_add( - (f64::from(WRAP_ANGLE / (2.0 * Radians::PI)) * f64::MAX) - as u32, + ((WRAP_RADIANS / (2.0 * PI)) * u32::MAX as f32) as u32, ), ), last: now, @@ -319,7 +318,7 @@ where let mut builder = canvas::path::Builder::new(); - let start = Radians(state.animation.rotation() * 2.0 * PI); + let start = state.animation.rotation() * 2.0 * PI; match state.animation { Animation::Expanding { progress, .. } => { @@ -328,8 +327,8 @@ where radius: track_radius, start_angle: start, end_angle: start - + MIN_ANGLE - + WRAP_ANGLE * (self.easing.y_at_x(progress)), + + MIN_RADIANS + + WRAP_RADIANS * (self.easing.y_at_x(progress)), }); } Animation::Contracting { progress, .. } => { @@ -337,8 +336,8 @@ where center: frame.center(), radius: track_radius, start_angle: start - + WRAP_ANGLE * (self.easing.y_at_x(progress)), - end_angle: start + MIN_ANGLE + WRAP_ANGLE, + + WRAP_RADIANS * (self.easing.y_at_x(progress)), + end_angle: start + MIN_RADIANS + WRAP_RADIANS, }); } } diff --git a/examples/loupe/Cargo.toml b/examples/loupe/Cargo.toml deleted file mode 100644 index 466905bae0..0000000000 --- a/examples/loupe/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "loupe" -version = "0.1.0" -authors = ["Héctor Ramón Jiménez "] -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 deleted file mode 100644 index 8602edb7df..0000000000 --- a/examples/loupe/src/main.rs +++ /dev/null @@ -1,185 +0,0 @@ -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 { - 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>, - ) -> 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 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 { - self.content.as_widget().children() - } - - fn diff(&self, tree: &mut widget::Tree) { - self.content.as_widget().diff(tree); - } - - fn size(&self) -> Size { - 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> - for Element<'a, Message, Theme, Renderer> - where - Message: 'a, - { - fn from(loupe: Loupe<'a, Message>) -> Self { - Self::new(loupe) - } - } -} diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs index 6fe951ee51..c2a4132c66 100644 --- a/examples/modal/src/main.rs +++ b/examples/modal/src/main.rs @@ -346,15 +346,16 @@ mod modal { state: &'b mut widget::Tree, layout: Layout<'_>, _renderer: &Renderer, - translation: Vector, ) -> Option> { - Some(overlay::Element::new(Box::new(Overlay { - position: layout.position() + translation, - content: &mut self.modal, - tree: &mut state.children[1], - size: layout.bounds().size(), - on_blur: self.on_blur.clone(), - }))) + Some(overlay::Element::new( + layout.position(), + Box::new(Overlay { + content: &mut self.modal, + tree: &mut state.children[1], + size: layout.bounds().size(), + on_blur: self.on_blur.clone(), + }), + )) } fn mouse_interaction( @@ -391,7 +392,6 @@ mod modal { } struct Overlay<'a, 'b, Message, Theme, Renderer> { - position: Point, content: &'b mut Element<'a, Message, Theme, Renderer>, tree: &'b mut widget::Tree, size: Size, @@ -409,6 +409,8 @@ mod modal { &mut self, renderer: &Renderer, _bounds: Size, + position: Point, + _translation: Vector, ) -> layout::Node { let limits = layout::Limits::new(Size::ZERO, self.size) .width(Length::Fill) @@ -421,7 +423,7 @@ mod modal { .align(Alignment::Center, Alignment::Center, limits.max()); layout::Node::with_children(self.size, vec![child]) - .move_to(self.position) + .move_to(position) } fn on_event( @@ -528,7 +530,6 @@ mod modal { self.tree, layout.children().next().unwrap(), renderer, - Vector::ZERO, ) } } diff --git a/examples/slider/src/main.rs b/examples/slider/src/main.rs index f71dac01fa..e83804c223 100644 --- a/examples/slider/src/main.rs +++ b/examples/slider/src/main.rs @@ -11,22 +11,14 @@ pub enum Message { } pub struct Slider { - value: u8, - default: u8, - step: u8, - shift_step: u8, + slider_value: u8, } impl Sandbox for Slider { type Message = Message; fn new() -> Slider { - Slider { - value: 50, - default: 50, - step: 5, - shift_step: 1, - } + Slider { slider_value: 50 } } fn title(&self) -> String { @@ -36,29 +28,23 @@ impl Sandbox for Slider { fn update(&mut self, message: Message) { match message { Message::SliderChanged(value) => { - self.value = value; + self.slider_value = value; } } } fn view(&self) -> Element { - let h_slider = container( - slider(0..=100, self.value, Message::SliderChanged) - .default(self.default) - .step(self.step) - .shift_step(self.shift_step), - ) - .width(250); + let value = self.slider_value; - let v_slider = container( - vertical_slider(0..=100, self.value, Message::SliderChanged) - .default(self.default) - .step(self.step) - .shift_step(self.shift_step), - ) - .height(200); + let h_slider = + container(slider(0..=100, value, Message::SliderChanged)) + .width(250); + + let v_slider = + container(vertical_slider(0..=100, value, Message::SliderChanged)) + .height(200); - let text = text(self.value); + let text = text(format!("{value}")); container( column![ diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index 4718a12333..10f3c79dc5 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -115,8 +115,11 @@ impl Sandbox for Styling { .width(Length::Fill) .height(100); - let checkbox = checkbox("Check me!", self.checkbox_value) - .on_toggle(Message::CheckboxToggled); + let checkbox = checkbox( + "Check me!", + self.checkbox_value, + Message::CheckboxToggled, + ); let toggler = toggler( String::from("Toggle me!"), diff --git a/examples/svg/src/main.rs b/examples/svg/src/main.rs index ba93007ca8..3bf4960f8f 100644 --- a/examples/svg/src/main.rs +++ b/examples/svg/src/main.rs @@ -51,9 +51,11 @@ impl Sandbox for Tiger { }, ); - let apply_color_filter = - checkbox("Apply a color filter", self.apply_color_filter) - .on_toggle(Message::ToggleColorFilter); + let apply_color_filter = checkbox( + "Apply a color filter", + self.apply_color_filter, + Message::ToggleColorFilter, + ); container( column![ diff --git a/examples/system_information/src/main.rs b/examples/system_information/src/main.rs index 31dc92f165..507431eed1 100644 --- a/examples/system_information/src/main.rs +++ b/examples/system_information/src/main.rs @@ -102,19 +102,19 @@ impl Application for Example { )); let memory_readable = - ByteSize::b(information.memory_total).to_string(); + ByteSize::kb(information.memory_total).to_string(); let memory_total = text(format!( - "Memory (total): {} bytes ({memory_readable})", + "Memory (total): {} kb ({memory_readable})", information.memory_total, )); let memory_text = if let Some(memory_used) = information.memory_used { - let memory_readable = ByteSize::b(memory_used).to_string(); + let memory_readable = ByteSize::kb(memory_used).to_string(); - format!("{memory_used} bytes ({memory_readable})") + format!("{memory_used} kb ({memory_readable})") } else { String::from("None") }; diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs index af29660a2c..cc9875d94d 100644 --- a/examples/toast/src/main.rs +++ b/examples/toast/src/main.rs @@ -456,7 +456,6 @@ mod toast { state: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let instants = state.state.downcast_mut::>>(); @@ -466,18 +465,19 @@ mod toast { &mut content_state[0], layout, renderer, - translation, ); let toasts = (!self.toasts.is_empty()).then(|| { - overlay::Element::new(Box::new(Overlay { - position: layout.bounds().position() + translation, - toasts: &mut self.toasts, - state: toasts_state, - instants, - on_close: &self.on_close, - timeout_secs: self.timeout_secs, - })) + overlay::Element::new( + layout.bounds().position(), + Box::new(Overlay { + toasts: &mut self.toasts, + state: toasts_state, + instants, + on_close: &self.on_close, + timeout_secs: self.timeout_secs, + }), + ) }); let overlays = content.into_iter().chain(toasts).collect::>(); @@ -488,7 +488,6 @@ mod toast { } struct Overlay<'a, 'b, Message> { - position: Point, toasts: &'b mut [Element<'a, Message>], state: &'b mut [Tree], instants: &'b mut [Option], @@ -503,6 +502,8 @@ mod toast { &mut self, renderer: &Renderer, bounds: Size, + position: Point, + _translation: Vector, ) -> layout::Node { let limits = layout::Limits::new(Size::ZERO, bounds); @@ -518,7 +519,7 @@ mod toast { self.toasts, self.state, ) - .translate(Vector::new(self.position.x, self.position.y)) + .translate(Vector::new(position.x, position.y)) } fn on_event( diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 88c4c2b481..3d79f08789 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -352,10 +352,13 @@ impl Task { fn view(&self, i: usize) -> Element { match &self.state { TaskState::Idle => { - let checkbox = checkbox(&self.description, self.completed) - .on_toggle(TaskMessage::Completed) - .width(Length::Fill) - .text_shaping(text::Shaping::Advanced); + let checkbox = checkbox( + &self.description, + self.completed, + TaskMessage::Completed, + ) + .width(Length::Fill) + .text_shaping(text::Shaping::Advanced); row![ checkbox, diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index 6d24b5ec9c..b656289a9b 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -554,13 +554,11 @@ impl<'a> Step { .width(Length::Fill) .horizontal_alignment(alignment::Horizontal::Center), ) - .push( - checkbox( - "Use nearest interpolation", - filter_method == image::FilterMethod::Nearest, - ) - .on_toggle(StepMessage::ImageUseNearestToggled), - ) + .push(checkbox( + "Use nearest interpolation", + filter_method == image::FilterMethod::Nearest, + StepMessage::ImageUseNearestToggled, + )) .align_items(Alignment::Center) } @@ -618,14 +616,16 @@ impl<'a> Step { } else { text_input }) - .push( - checkbox("Enable password mode", is_secure) - .on_toggle(StepMessage::ToggleSecureInput), - ) - .push( - checkbox("Show icon", is_showing_icon) - .on_toggle(StepMessage::ToggleTextInputIcon), - ) + .push(checkbox( + "Enable password mode", + is_secure, + StepMessage::ToggleSecureInput, + )) + .push(checkbox( + "Show icon", + is_showing_icon, + StepMessage::ToggleTextInputIcon, + )) .push( "A text input produces a message every time it changes. It is \ very easy to keep track of its contents:", @@ -658,8 +658,7 @@ impl<'a> Step { .horizontal_alignment(alignment::Horizontal::Center), ) } else { - checkbox("Explain layout", debug) - .on_toggle(StepMessage::DebugToggled) + checkbox("Explain layout", debug, StepMessage::DebugToggled) .into() }) .push("Feel free to go back and take a look.") diff --git a/examples/vectorial_text/src/main.rs b/examples/vectorial_text/src/main.rs index c2212b22ca..d366b9072c 100644 --- a/examples/vectorial_text/src/main.rs +++ b/examples/vectorial_text/src/main.rs @@ -75,8 +75,11 @@ impl Sandbox for VectorialText { column![ canvas(&self.state).width(Length::Fill).height(Length::Fill), column![ - checkbox("Use Japanese", self.state.use_japanese,) - .on_toggle(Message::ToggleJapanese), + checkbox( + "Use Japanese", + self.state.use_japanese, + Message::ToggleJapanese + ), row![ slider_with_label( "Size", diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml index 907f3705ae..4f323f9e1f 100644 --- a/graphics/Cargo.toml +++ b/graphics/Cargo.toml @@ -26,6 +26,7 @@ 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 8edf69d756..ba9192efcc 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -102,10 +102,10 @@ impl Damage for Primitive { .fold(Rectangle::with_size(Size::ZERO), |a, b| { Rectangle::union(&a, &b) }), - Self::Transform { - transformation, + Self::Translate { + translation, content, - } => content.bounds() * *transformation, + } => content.bounds() + *translation, Self::Cache { content } => content.bounds(), Self::Custom(custom) => custom.bounds(), } @@ -144,19 +144,19 @@ fn regions(a: &Primitive, b: &Primitive) -> Vec { } } ( - Primitive::Transform { - transformation: transformation_a, + Primitive::Translate { + translation: translation_a, content: content_a, }, - Primitive::Transform { - transformation: transformation_b, + Primitive::Translate { + translation: translation_b, content: content_b, }, ) => { - if transformation_a == transformation_b { + if translation_a == translation_b { return regions(content_a, content_b) .into_iter() - .map(|r| r * *transformation_a) + .map(|r| r + *translation_a) .collect(); } } diff --git a/graphics/src/geometry/path/arc.rs b/graphics/src/geometry/path/arc.rs index 2600497f85..dd4fcf33a4 100644 --- a/graphics/src/geometry/path/arc.rs +++ b/graphics/src/geometry/path/arc.rs @@ -1,5 +1,5 @@ //! Build and draw curves. -use iced_core::{Point, Radians, Vector}; +use iced_core::{Point, Vector}; /// A segment of a differentiable curve. #[derive(Debug, Clone, Copy)] @@ -8,10 +8,10 @@ pub struct Arc { pub center: Point, /// The radius of the arc. pub radius: f32, - /// The start of the segment's angle, clockwise rotation from positive x-axis. - pub start_angle: Radians, - /// The end of the segment's angle, clockwise rotation from positive x-axis. - pub end_angle: Radians, + /// The start of the segment's angle in radians, clockwise rotation from positive x-axis. + pub start_angle: f32, + /// The end of the segment's angle in radians, clockwise rotation from positive x-axis. + pub end_angle: f32, } /// An elliptical [`Arc`]. @@ -22,11 +22,11 @@ pub struct Elliptical { /// The radii of the arc's ellipse. The horizontal and vertical half-dimensions of the ellipse will match the x and y values of the radii vector. pub radii: Vector, /// The clockwise rotation of the arc's ellipse. - pub rotation: Radians, - /// The start of the segment's angle, clockwise rotation from positive x-axis. - pub start_angle: Radians, - /// The end of the segment's angle, clockwise rotation from positive x-axis. - pub end_angle: Radians, + pub rotation: f32, + /// The start of the segment's angle in radians, clockwise rotation from positive x-axis. + pub start_angle: f32, + /// The end of the segment's angle in radians, clockwise rotation from positive x-axis. + pub end_angle: f32, } impl From for Elliptical { @@ -34,7 +34,7 @@ impl From for Elliptical { Elliptical { center: arc.center, radii: Vector::new(arc.radius, arc.radius), - rotation: Radians(0.0), + rotation: 0.0, start_angle: arc.start_angle, end_angle: arc.end_angle, } diff --git a/graphics/src/geometry/path/builder.rs b/graphics/src/geometry/path/builder.rs index 1ccd83f2f7..b0959fbf89 100644 --- a/graphics/src/geometry/path/builder.rs +++ b/graphics/src/geometry/path/builder.rs @@ -1,6 +1,6 @@ use crate::geometry::path::{arc, Arc, Path}; -use iced_core::{Point, Radians, Size}; +use iced_core::{Point, Size}; use lyon_path::builder::{self, SvgPathBuilder}; use lyon_path::geom; @@ -106,11 +106,9 @@ impl Builder { 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.0), - start_angle: math::Angle::radians(arc.start_angle.0), - sweep_angle: math::Angle::radians( - (arc.end_angle - arc.start_angle).0, - ), + x_rotation: math::Angle::radians(arc.rotation), + start_angle: math::Angle::radians(arc.start_angle), + sweep_angle: math::Angle::radians(arc.end_angle - arc.start_angle), }; let _ = self.raw.move_to(arc.sample(0.0)); @@ -167,8 +165,8 @@ impl Builder { self.arc(Arc { center, radius, - start_angle: Radians(0.0), - end_angle: Radians(2.0 * std::f32::consts::PI), + start_angle: 0.0, + end_angle: 2.0 * std::f32::consts::PI, }); } diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index aa9d00e891..76de56bf57 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -19,6 +19,7 @@ mod antialiasing; mod error; mod primitive; +mod transformation; mod viewport; pub mod backend; @@ -45,6 +46,7 @@ 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 6929b0a1ec..aed59e1a91 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -4,8 +4,7 @@ use crate::core::image; use crate::core::svg; use crate::core::text; use crate::core::{ - Background, Border, Color, Font, Pixels, Point, Rectangle, Shadow, - Transformation, Vector, + Background, Border, Color, Font, Pixels, Point, Rectangle, Shadow, Vector, }; use crate::text::editor; use crate::text::paragraph; @@ -105,12 +104,12 @@ pub enum Primitive { /// The content of the clip content: Box>, }, - /// A primitive that applies a [`Transformation`] - Transform { - /// The [`Transformation`] - transformation: Transformation, + /// A primitive that applies a translation + Translate { + /// The translation vector + translation: Vector, - /// The primitive to transform + /// The primitive to translate content: Box>, }, /// A cached primitive. @@ -126,12 +125,12 @@ pub enum Primitive { } impl Primitive { - /// Groups the current [`Primitive`]. + /// Creates a [`Primitive::Group`]. pub fn group(primitives: Vec) -> Self { Self::Group { primitives } } - /// Clips the current [`Primitive`]. + /// Creates a [`Primitive::Clip`]. pub fn clip(self, bounds: Rectangle) -> Self { Self::Clip { bounds, @@ -139,21 +138,10 @@ impl Primitive { } } - /// Translates the current [`Primitive`]. + /// Creates a [`Primitive::Translate`]. pub fn translate(self, translation: Vector) -> Self { - 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, + Self::Translate { + translation, content: Box::new(self), } } diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 143f348bff..cb07c23bc5 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, Transformation, + Background, Color, Font, Pixels, Point, Rectangle, Size, Vector, }; use crate::text; use crate::Primitive; @@ -73,20 +73,20 @@ impl Renderer { } /// Starts recording a translation. - pub fn start_transformation(&mut self) -> Vec> { + pub fn start_translation(&mut self) -> Vec> { std::mem::take(&mut self.primitives) } /// Ends the recording of a translation. - pub fn end_transformation( + pub fn end_translation( &mut self, primitives: Vec>, - transformation: Transformation, + translation: Vector, ) { let layer = std::mem::replace(&mut self.primitives, primitives); self.primitives - .push(Primitive::group(layer).transform(transformation)); + .push(Primitive::group(layer).translate(translation)); } } @@ -99,16 +99,16 @@ impl iced_core::Renderer for Renderer { self.end_layer(current, bounds); } - fn with_transformation( + fn with_translation( &mut self, - transformation: Transformation, + translation: Vector, f: impl FnOnce(&mut Self), ) { - let current = self.start_transformation(); + let current = self.start_translation(); f(self); - self.end_transformation(current, transformation); + self.end_translation(current, translation); } fn fill_quad( diff --git a/graphics/src/transformation.rs b/graphics/src/transformation.rs new file mode 100644 index 0000000000..cf0457a4dd --- /dev/null +++ b/graphics/src/transformation.rs @@ -0,0 +1,59 @@ +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 for [f32; 16] { + fn from(t: Transformation) -> [f32; 16] { + *t.as_ref() + } +} + +impl From for Mat4 { + fn from(transformation: Transformation) -> Self { + transformation.0 + } +} diff --git a/graphics/src/viewport.rs b/graphics/src/viewport.rs index dc8e21d327..5792555df7 100644 --- a/graphics/src/viewport.rs +++ b/graphics/src/viewport.rs @@ -1,4 +1,6 @@ -use crate::core::{Size, Transformation}; +use crate::Transformation; + +use iced_core::Size; /// A viewing region for displaying computer graphics. #[derive(Debug, Clone)] diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs index f09ccfbfa6..19ac87da2c 100644 --- a/renderer/src/geometry.rs +++ b/renderer/src/geometry.rs @@ -2,18 +2,14 @@ mod cache; pub use cache::Cache; -use crate::core::{Point, Rectangle, Size, Transformation, Vector}; +use crate::core::{Point, Rectangle, Size, Vector}; use crate::graphics::geometry::{Fill, Path, Stroke, Text}; use crate::Renderer; -macro_rules! delegate { - ($frame:expr, $name:ident, $body:expr) => { - match $frame { - Self::TinySkia($name) => $body, - #[cfg(feature = "wgpu")] - Self::Wgpu($name) => $body, - } - }; +pub enum Frame { + TinySkia(iced_tiny_skia::geometry::Frame), + #[cfg(feature = "wgpu")] + Wgpu(iced_wgpu::geometry::Frame), } pub enum Geometry { @@ -22,24 +18,14 @@ pub enum Geometry { Wgpu(iced_wgpu::Primitive), } -impl Geometry { - pub fn transform(self, transformation: Transformation) -> Self { - match self { - Self::TinySkia(primitive) => { - Self::TinySkia(primitive.transform(transformation)) - } +macro_rules! delegate { + ($frame:expr, $name:ident, $body:expr) => { + match $frame { + Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] - Self::Wgpu(primitive) => { - Self::Wgpu(primitive.transform(transformation)) - } + Self::Wgpu($name) => $body, } - } -} - -pub enum Frame { - TinySkia(iced_tiny_skia::geometry::Frame), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::geometry::Frame), + }; } impl Frame { @@ -125,14 +111,12 @@ impl Frame { /// This method is useful to compose transforms and perform drawing /// operations in different coordinate systems. #[inline] - pub fn with_save(&mut self, f: impl FnOnce(&mut Frame) -> R) -> R { + pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { delegate!(self, frame, frame.push_transform()); - let result = f(self); + f(self); delegate!(self, frame, frame.pop_transform()); - - result } /// Executes the given drawing operations within a [`Rectangle`] region, @@ -142,11 +126,7 @@ impl Frame { /// This method is useful to perform drawing operations that need to be /// clipped. #[inline] - pub fn with_clip( - &mut self, - region: Rectangle, - f: impl FnOnce(&mut Frame) -> R, - ) -> R { + pub fn with_clip(&mut self, region: Rectangle, f: impl FnOnce(&mut Frame)) { let mut frame = match self { Self::TinySkia(_) => Self::TinySkia( iced_tiny_skia::geometry::Frame::new(region.size()), @@ -157,7 +137,7 @@ impl Frame { } }; - let result = f(&mut frame); + f(&mut frame); let origin = Point::new(region.x, region.y); @@ -172,8 +152,6 @@ impl Frame { #[allow(unreachable_patterns)] _ => unreachable!(), }; - - result } /// Applies a translation to the current transform of the [`Frame`]. diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 757c264d9a..a7df414b9c 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -22,9 +22,7 @@ pub use geometry::Geometry; use crate::core::renderer; use crate::core::text::{self, Text}; -use crate::core::{ - Background, Color, Font, Pixels, Point, Rectangle, Transformation, -}; +use crate::core::{Background, Color, Font, Pixels, Point, Rectangle, Vector}; use crate::graphics::text::Editor; use crate::graphics::text::Paragraph; use crate::graphics::Mesh; @@ -99,20 +97,20 @@ impl core::Renderer for Renderer { } } - fn with_transformation( + fn with_translation( &mut self, - transformation: Transformation, + translation: Vector, f: impl FnOnce(&mut Self), ) { match self { Self::TinySkia(renderer) => { - let primitives = renderer.start_transformation(); + let primitives = renderer.start_translation(); f(self); match self { Self::TinySkia(renderer) => { - renderer.end_transformation(primitives, transformation); + renderer.end_translation(primitives, translation); } #[cfg(feature = "wgpu")] _ => unreachable!(), @@ -120,14 +118,14 @@ impl core::Renderer for Renderer { } #[cfg(feature = "wgpu")] Self::Wgpu(renderer) => { - let primitives = renderer.start_transformation(); + let primitives = renderer.start_translation(); f(self); match self { #[cfg(feature = "wgpu")] Self::Wgpu(renderer) => { - renderer.end_transformation(primitives, transformation); + renderer.end_translation(primitives, translation); } _ => unreachable!(), } diff --git a/runtime/src/command/action.rs b/runtime/src/command/action.rs index c9ffe801c4..cb0936df74 100644 --- a/runtime/src/command/action.rs +++ b/runtime/src/command/action.rs @@ -1,11 +1,11 @@ use crate::clipboard; use crate::core::widget; use crate::font; -use crate::futures::MaybeSend; use crate::system; use crate::window; -use std::any::Any; +use iced_futures::MaybeSend; + use std::borrow::Cow; use std::fmt; @@ -43,9 +43,6 @@ pub enum Action { /// The message to produce when the font has been loaded. tagger: Box) -> T>, }, - - /// A custom action supported by a specific runtime. - Custom(Box), } impl Action { @@ -75,7 +72,6 @@ impl Action { bytes, tagger: Box::new(move |result| f(tagger(result))), }, - Self::Custom(custom) => Action::Custom(custom), } } } @@ -94,7 +90,6 @@ impl fmt::Debug for Action { Self::System(action) => write!(f, "Action::System({action:?})"), Self::Widget(_action) => write!(f, "Action::Widget"), Self::LoadFont { .. } => write!(f, "Action::LoadFont"), - Self::Custom(_) => write!(f, "Action::Custom"), } } } diff --git a/runtime/src/overlay/nested.rs b/runtime/src/overlay/nested.rs index ddb9532b9f..60e2eb875e 100644 --- a/runtime/src/overlay/nested.rs +++ b/runtime/src/overlay/nested.rs @@ -4,7 +4,9 @@ use crate::core::mouse; use crate::core::overlay; use crate::core::renderer; use crate::core::widget; -use crate::core::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size}; +use crate::core::{ + Clipboard, Event, Layout, Point, Rectangle, Shell, Size, Vector, +}; /// An overlay container that displays nested overlays #[allow(missing_debug_implementations)] @@ -23,6 +25,11 @@ where Self { overlay: element } } + /// Returns the position of the [`Nested`] overlay. + pub fn position(&self) -> Point { + self.overlay.position() + } + /// Returns the layout [`Node`] of the [`Nested`] overlay. /// /// [`Node`]: layout::Node @@ -30,30 +37,36 @@ where &mut self, renderer: &Renderer, bounds: Size, + _position: Point, + translation: Vector, ) -> layout::Node { fn recurse( element: &mut overlay::Element<'_, Message, Theme, Renderer>, renderer: &Renderer, bounds: Size, + translation: Vector, ) -> layout::Node where Renderer: renderer::Renderer, { - let node = element.layout(renderer, bounds); + let node = element.layout(renderer, bounds, translation); if let Some(mut nested) = element.overlay(Layout::new(&node), renderer) { layout::Node::with_children( node.size(), - vec![node, recurse(&mut nested, renderer, bounds)], + vec![ + node, + recurse(&mut nested, renderer, bounds, translation), + ], ) } else { layout::Node::with_children(node.size(), vec![node]) } } - recurse(&mut self.overlay, renderer, bounds) + recurse(&mut self.overlay, renderer, bounds, translation) } /// Draws the [`Nested`] overlay using the associated `Renderer`. diff --git a/runtime/src/system/information.rs b/runtime/src/system/information.rs index 0f78f5e926..93e7a5a46a 100644 --- a/runtime/src/system/information.rs +++ b/runtime/src/system/information.rs @@ -18,9 +18,9 @@ pub struct Information { pub cpu_brand: String, /// The number of physical cores on the processor pub cpu_cores: Option, - /// Total RAM size, in bytes + /// Total RAM size, KB pub memory_total: u64, - /// Memory used by this process, in bytes + /// Memory used by this process, KB pub memory_used: Option, /// Underlying graphics backend for rendering pub graphics_backend: String, diff --git a/runtime/src/user_interface.rs b/runtime/src/user_interface.rs index 08431cedfa..054d56b781 100644 --- a/runtime/src/user_interface.rs +++ b/runtime/src/user_interface.rs @@ -5,7 +5,9 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::widget; use crate::core::window; -use crate::core::{Clipboard, Element, Layout, Rectangle, Shell, Size, Vector}; +use crate::core::{ + Clipboard, Element, Layout, Point, Rectangle, Shell, Size, Vector, +}; use crate::overlay; /// A set of interactive graphical elements with a specific [`Layout`]. @@ -191,12 +193,7 @@ where let mut manual_overlay = ManuallyDrop::new( self.root .as_widget_mut() - .overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - Vector::ZERO, - ) + .overlay(&mut self.state, Layout::new(&self.base), renderer) .map(overlay::Nested::new), ); @@ -204,7 +201,8 @@ where let bounds = self.bounds; let mut overlay = manual_overlay.as_mut().unwrap(); - let mut layout = overlay.layout(renderer, bounds); + let mut layout = + overlay.layout(renderer, bounds, Point::ORIGIN, Vector::ZERO); let mut event_statuses = Vec::new(); for event in events.iter().cloned() { @@ -247,7 +245,6 @@ where &mut self.state, Layout::new(&self.base), renderer, - Vector::ZERO, ) .map(overlay::Nested::new), ); @@ -259,7 +256,12 @@ where overlay = manual_overlay.as_mut().unwrap(); shell.revalidate_layout(|| { - layout = overlay.layout(renderer, bounds); + layout = overlay.layout( + renderer, + bounds, + Point::ORIGIN, + Vector::ZERO, + ); }); } @@ -449,18 +451,17 @@ where let base_cursor = if let Some(mut overlay) = self .root .as_widget_mut() - .overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - Vector::ZERO, - ) + .overlay(&mut self.state, Layout::new(&self.base), renderer) .map(overlay::Nested::new) { - let overlay_layout = self - .overlay - .take() - .unwrap_or_else(|| overlay.layout(renderer, self.bounds)); + let overlay_layout = self.overlay.take().unwrap_or_else(|| { + overlay.layout( + renderer, + self.bounds, + Point::ORIGIN, + Vector::ZERO, + ) + }); let cursor = if cursor .position() @@ -519,12 +520,7 @@ where .as_ref() .and_then(|layout| { root.as_widget_mut() - .overlay( - &mut self.state, - Layout::new(base), - renderer, - Vector::ZERO, - ) + .overlay(&mut self.state, Layout::new(base), renderer) .map(overlay::Nested::new) .map(|mut overlay| { let overlay_interaction = overlay.mouse_interaction( @@ -578,16 +574,16 @@ where if let Some(mut overlay) = self .root .as_widget_mut() - .overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - Vector::ZERO, - ) + .overlay(&mut self.state, Layout::new(&self.base), renderer) .map(overlay::Nested::new) { if self.overlay.is_none() { - self.overlay = Some(overlay.layout(renderer, self.bounds)); + self.overlay = Some(overlay.layout( + renderer, + self.bounds, + Point::ORIGIN, + Vector::ZERO, + )); } overlay.operate( diff --git a/src/lib.rs b/src/lib.rs index a49259fff4..86207d6e2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,8 +193,7 @@ 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, - Transformation, Vector, + Length, Padding, Pixels, Point, Radians, Rectangle, Shadow, Size, Vector, }; pub mod clipboard { diff --git a/style/src/checkbox.rs b/style/src/checkbox.rs index 82c1766fa9..d96ea4adb9 100644 --- a/style/src/checkbox.rs +++ b/style/src/checkbox.rs @@ -24,7 +24,4 @@ pub trait StyleSheet { /// Produces the hovered [`Appearance`] of a checkbox. fn hovered(&self, style: &Self::Style, is_checked: bool) -> Appearance; - - /// Produces the disabled [`Appearance`] of a checkbox. - fn disabled(&self, style: &Self::Style, is_checked: bool) -> Appearance; } diff --git a/style/src/theme.rs b/style/src/theme.rs index 166410ae71..8d1ff23779 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -319,7 +319,7 @@ impl checkbox::StyleSheet for Theme { Checkbox::Secondary => checkbox_appearance( palette.background.base.text, palette.background.base, - palette.background.strong, + palette.background.base, is_checked, ), Checkbox::Success => checkbox_appearance( @@ -355,7 +355,7 @@ impl checkbox::StyleSheet for Theme { Checkbox::Secondary => checkbox_appearance( palette.background.base.text, palette.background.weak, - palette.background.strong, + palette.background.base, is_checked, ), Checkbox::Success => checkbox_appearance( @@ -373,42 +373,6 @@ impl checkbox::StyleSheet for Theme { Checkbox::Custom(custom) => custom.hovered(self, is_checked), } } - - fn disabled( - &self, - style: &Self::Style, - is_checked: bool, - ) -> checkbox::Appearance { - let palette = self.extended_palette(); - - match style { - Checkbox::Primary => checkbox_appearance( - palette.primary.strong.text, - palette.background.weak, - palette.background.strong, - is_checked, - ), - Checkbox::Secondary => checkbox_appearance( - palette.background.strong.color, - palette.background.weak, - palette.background.weak, - is_checked, - ), - Checkbox::Success => checkbox_appearance( - palette.success.base.text, - palette.background.weak, - palette.success.weak, - is_checked, - ), - Checkbox::Danger => checkbox_appearance( - palette.danger.base.text, - palette.background.weak, - palette.danger.weak, - is_checked, - ), - Checkbox::Custom(custom) => custom.active(self, is_checked), - } - } } fn checkbox_appearance( diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 44f5c15146..ea4a3ec6fe 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,8 +1,6 @@ use tiny_skia::Size; -use crate::core::{ - Background, Color, Gradient, Rectangle, Transformation, Vector, -}; +use crate::core::{Background, Color, Gradient, Rectangle, Vector}; use crate::graphics::backend; use crate::graphics::text; use crate::graphics::Viewport; @@ -108,7 +106,7 @@ impl Backend { clip_mask, region, scale_factor, - Transformation::IDENTITY, + Vector::ZERO, ); } @@ -148,7 +146,7 @@ impl Backend { clip_mask: &mut tiny_skia::Mask, clip_bounds: Rectangle, scale_factor: f32, - transformation: Transformation, + translation: Vector, ) { match primitive { Primitive::Quad { @@ -157,16 +155,7 @@ impl Backend { border, shadow, } => { - debug_assert!( - bounds.width.is_normal(), - "Quad with non-normal width!" - ); - debug_assert!( - bounds.height.is_normal(), - "Quad with non-normal height!" - ); - - let physical_bounds = (*bounds * transformation) * scale_factor; + let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -175,8 +164,11 @@ impl Backend { let clip_mask = (!physical_bounds.is_within(&clip_bounds)) .then_some(clip_mask as &_); - let transform = into_transform(transformation) - .post_scale(scale_factor, scale_factor); + let transform = tiny_skia::Transform::from_translate( + translation.x, + translation.y, + ) + .post_scale(scale_factor, scale_factor); // Make sure the border radius is not larger than the bounds let border_width = border @@ -198,7 +190,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, - } * transformation) + } + translation) * scale_factor; let radii = fill_border_radius @@ -450,7 +442,7 @@ impl Backend { clip_bounds: text_clip_bounds, } => { let physical_bounds = - *text_clip_bounds * transformation * scale_factor; + (*text_clip_bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -461,12 +453,11 @@ impl Backend { self.text_pipeline.draw_paragraph( paragraph, - *position, + *position + translation, *color, scale_factor, pixels, clip_mask, - transformation, ); } Primitive::Editor { @@ -476,7 +467,7 @@ impl Backend { clip_bounds: text_clip_bounds, } => { let physical_bounds = - (*text_clip_bounds * transformation) * scale_factor; + (*text_clip_bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -487,12 +478,11 @@ impl Backend { self.text_pipeline.draw_editor( editor, - *position, + *position + translation, *color, scale_factor, pixels, clip_mask, - transformation, ); } Primitive::Text { @@ -508,7 +498,7 @@ impl Backend { clip_bounds: text_clip_bounds, } => { let physical_bounds = - *text_clip_bounds * transformation * scale_factor; + (*text_clip_bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -519,7 +509,7 @@ impl Backend { self.text_pipeline.draw_cached( content, - *bounds, + *bounds + translation, *color, *size, *line_height, @@ -530,7 +520,6 @@ impl Backend { scale_factor, pixels, clip_mask, - transformation, ); } Primitive::RawText(text::Raw { @@ -544,7 +533,7 @@ impl Backend { }; let physical_bounds = - *text_clip_bounds * transformation * scale_factor; + (*text_clip_bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -555,12 +544,11 @@ impl Backend { self.text_pipeline.draw_raw( &buffer, - *position, + *position + translation, *color, scale_factor, pixels, clip_mask, - transformation, ); } #[cfg(feature = "image")] @@ -569,7 +557,7 @@ impl Backend { filter_method, bounds, } => { - let physical_bounds = (*bounds * transformation) * scale_factor; + let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -578,8 +566,11 @@ impl Backend { let clip_mask = (!physical_bounds.is_within(&clip_bounds)) .then_some(clip_mask as &_); - let transform = into_transform(transformation) - .post_scale(scale_factor, scale_factor); + let transform = tiny_skia::Transform::from_translate( + translation.x, + translation.y, + ) + .post_scale(scale_factor, scale_factor); self.raster_pipeline.draw( handle, @@ -602,7 +593,7 @@ impl Backend { bounds, color, } => { - let physical_bounds = (*bounds * transformation) * scale_factor; + let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { return; @@ -614,7 +605,7 @@ impl Backend { self.vector_pipeline.draw( handle, *color, - (*bounds * transformation) * scale_factor, + (*bounds + translation) * scale_factor, pixels, clip_mask, ); @@ -637,7 +628,7 @@ impl Backend { y: bounds.y(), width: bounds.width(), height: bounds.height(), - } * transformation) + } + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -651,8 +642,11 @@ impl Backend { path, paint, *rule, - into_transform(transformation) - .post_scale(scale_factor, scale_factor), + tiny_skia::Transform::from_translate( + translation.x, + translation.y, + ) + .post_scale(scale_factor, scale_factor), clip_mask, ); } @@ -668,7 +662,7 @@ impl Backend { y: bounds.y(), width: bounds.width(), height: bounds.height(), - } * transformation) + } + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -682,8 +676,11 @@ impl Backend { path, paint, stroke, - into_transform(transformation) - .post_scale(scale_factor, scale_factor), + tiny_skia::Transform::from_translate( + translation.x, + translation.y, + ) + .post_scale(scale_factor, scale_factor), clip_mask, ); } @@ -695,12 +692,12 @@ impl Backend { clip_mask, clip_bounds, scale_factor, - transformation, + translation, ); } } - Primitive::Transform { - transformation: new_transformation, + Primitive::Translate { + translation: offset, content, } => { self.draw_primitive( @@ -709,11 +706,11 @@ impl Backend { clip_mask, clip_bounds, scale_factor, - transformation * *new_transformation, + translation + *offset, ); } Primitive::Clip { bounds, content } => { - let bounds = (*bounds * transformation) * scale_factor; + let bounds = (*bounds + translation) * scale_factor; if bounds == clip_bounds { self.draw_primitive( @@ -722,7 +719,7 @@ impl Backend { clip_mask, bounds, scale_factor, - transformation, + translation, ); } else if let Some(bounds) = clip_bounds.intersection(&bounds) { if bounds.x + bounds.width <= 0.0 @@ -743,7 +740,7 @@ impl Backend { clip_mask, bounds, scale_factor, - transformation, + translation, ); adjust_clip_mask(clip_mask, clip_bounds); @@ -756,7 +753,7 @@ impl Backend { clip_mask, clip_bounds, scale_factor, - transformation, + translation, ); } } @@ -774,19 +771,6 @@ 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 f751873170..74a08d384a 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, Transformation, Vector}; +use crate::core::{Pixels, Point, Rectangle, Size, 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::Transform { - transformation: Transformation::translate(at.x, at.y), + self.primitives.push(Primitive::Translate { + translation: Vector::new(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 c16037cf3d..9413e31170 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -1,8 +1,6 @@ use crate::core::alignment; use crate::core::text::{LineHeight, Shaping}; -use crate::core::{ - Color, Font, Pixels, Point, Rectangle, Size, Transformation, -}; +use crate::core::{Color, Font, Pixels, Point, Rectangle, Size}; use crate::graphics::text::cache::{self, Cache}; use crate::graphics::text::editor; use crate::graphics::text::font_system; @@ -44,7 +42,6 @@ impl Pipeline { scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, - transformation: Transformation, ) { use crate::core::text::Paragraph as _; @@ -65,7 +62,6 @@ impl Pipeline { scale_factor, pixels, clip_mask, - transformation, ); } @@ -77,7 +73,6 @@ impl Pipeline { scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, - transformation: Transformation, ) { use crate::core::text::Editor as _; @@ -98,7 +93,6 @@ impl Pipeline { scale_factor, pixels, clip_mask, - transformation, ); } @@ -116,7 +110,6 @@ 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)); @@ -152,7 +145,6 @@ impl Pipeline { scale_factor, pixels, clip_mask, - transformation, ); } @@ -164,7 +156,6 @@ 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"); @@ -181,7 +172,6 @@ impl Pipeline { scale_factor, pixels, clip_mask, - transformation, ); } @@ -202,9 +192,8 @@ fn draw( scale_factor: f32, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::Mask>, - transformation: Transformation, ) { - let bounds = bounds * transformation * scale_factor; + let bounds = bounds * scale_factor; let x = match horizontal_alignment { alignment::Horizontal::Left => bounds.x, @@ -222,8 +211,7 @@ fn draw( for run in buffer.layout_runs() { for glyph in run.glyphs { - let physical_glyph = glyph - .physical((x, y), scale_factor * transformation.scale_factor()); + let physical_glyph = glyph.physical((x, y), scale_factor); if let Some((buffer, placement)) = glyph_cache.allocate( physical_glyph.cache_key, @@ -241,10 +229,7 @@ fn draw( pixels.draw_pixmap( physical_glyph.x + placement.left, physical_glyph.y - placement.top - + (run.line_y - * scale_factor - * transformation.scale_factor()) - .round() as i32, + + (run.line_y * 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 77b6fa832e..25134d6869 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -1,7 +1,7 @@ -use crate::core::{Color, Size, Transformation}; +use crate::core::{Color, Size}; use crate::graphics::backend; use crate::graphics::color; -use crate::graphics::Viewport; +use crate::graphics::{Transformation, 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); + let scaled = transformation + * Transformation::scale(scale_factor, 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); + let scaled = transformation + * Transformation::scale(scale_factor, scale_factor); self.image_pipeline.prepare( device, diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 8cfcfff010..4d7f443ea2 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, Transformation, Vector}; +use crate::core::{Pixels, Point, Rectangle, Size, Vector}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::{ @@ -388,14 +388,12 @@ impl Frame { /// This method is useful to compose transforms and perform drawing /// operations in different coordinate systems. #[inline] - pub fn with_save(&mut self, f: impl FnOnce(&mut Frame) -> R) -> R { + pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { self.push_transform(); - let result = f(self); + f(self); self.pop_transform(); - - result } /// Pushes the current transform in the transform stack. @@ -415,27 +413,21 @@ impl Frame { /// This method is useful to perform drawing operations that need to be /// clipped. #[inline] - pub fn with_clip( - &mut self, - region: Rectangle, - f: impl FnOnce(&mut Frame) -> R, - ) -> R { + pub fn with_clip(&mut self, region: Rectangle, f: impl FnOnce(&mut Frame)) { let mut frame = Frame::new(region.size()); - let result = f(&mut frame); + f(&mut frame); let origin = Point::new(region.x, region.y); self.clip(frame, origin); - - result } /// Draws the clipped contents of the given [`Frame`] with origin at the given [`Point`]. pub fn clip(&mut self, frame: Frame, at: Point) { let size = frame.size(); let primitives = frame.into_primitives(); - let transformation = Transformation::translate(at.x, at.y); + let translation = Vector::new(at.x, at.y); let (text, meshes) = primitives .into_iter() @@ -443,12 +435,12 @@ impl Frame { self.primitives.push(Primitive::Group { primitives: vec![ - Primitive::Transform { - transformation, + Primitive::Translate { + translation, content: Box::new(Primitive::Group { primitives: meshes }), }, - Primitive::Transform { - transformation, + Primitive::Translate { + translation, 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 06c22870bd..1e5d3ee0d9 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -8,7 +8,8 @@ mod vector; use atlas::Atlas; -use crate::core::{Rectangle, Size, Transformation}; +use crate::core::{Rectangle, Size}; +use crate::graphics::Transformation; use crate::layer; use crate::Buffer; diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index cc767c2575..e213c95f18 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -12,9 +12,7 @@ pub use text::Text; use crate::core; use crate::core::alignment; -use crate::core::{ - Color, Font, Pixels, Point, Rectangle, Size, Transformation, Vector, -}; +use crate::core::{Color, Font, Pixels, Point, Rectangle, Size, Vector}; use crate::graphics; use crate::graphics::color; use crate::graphics::Viewport; @@ -106,7 +104,7 @@ impl<'a> Layer<'a> { for primitive in primitives { Self::process_primitive( &mut layers, - Transformation::IDENTITY, + Vector::new(0.0, 0.0), primitive, 0, ); @@ -117,7 +115,7 @@ impl<'a> Layer<'a> { fn process_primitive( layers: &mut Vec, - transformation: Transformation, + translation: Vector, primitive: &'a Primitive, current_layer: usize, ) { @@ -132,10 +130,9 @@ impl<'a> Layer<'a> { layer.text.push(Text::Paragraph { paragraph: paragraph.clone(), - position: *position, + position: *position + translation, color: *color, - clip_bounds: *clip_bounds, - transformation, + clip_bounds: *clip_bounds + translation, }); } Primitive::Editor { @@ -148,10 +145,9 @@ impl<'a> Layer<'a> { layer.text.push(Text::Editor { editor: editor.clone(), - position: *position, + position: *position + translation, color: *color, - clip_bounds: *clip_bounds, - transformation, + clip_bounds: *clip_bounds + translation, }); } Primitive::Text { @@ -170,24 +166,31 @@ impl<'a> Layer<'a> { layer.text.push(Text::Cached(text::Cached { content, - bounds: *bounds + transformation.translation(), - size: *size * transformation.scale_factor(), + bounds: *bounds + translation, + size: *size, line_height: *line_height, color: *color, font: *font, horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, shaping: *shaping, - clip_bounds: *clip_bounds * transformation, + clip_bounds: *clip_bounds + translation, })); } - graphics::Primitive::RawText(raw) => { + graphics::Primitive::RawText(graphics::text::Raw { + buffer, + position, + color, + clip_bounds, + }) => { let layer = &mut layers[current_layer]; - layer.text.push(Text::Raw { - raw: raw.clone(), - transformation, - }); + layer.text.push(Text::Raw(graphics::text::Raw { + buffer: buffer.clone(), + position: *position + translation, + color: *color, + clip_bounds: *clip_bounds + translation, + })); } Primitive::Quad { bounds, @@ -196,10 +199,12 @@ impl<'a> Layer<'a> { shadow, } => { let layer = &mut layers[current_layer]; - let bounds = *bounds * transformation; let quad = Quad { - position: [bounds.x, bounds.y], + position: [ + bounds.x + translation.x, + bounds.y + translation.y, + ], size: [bounds.width, bounds.height], border_color: color::pack(border.color), border_radius: border.radius.into(), @@ -221,7 +226,7 @@ impl<'a> Layer<'a> { layer.images.push(Image::Raster { handle: handle.clone(), filter_method: *filter_method, - bounds: *bounds * transformation, + bounds: *bounds + translation, }); } Primitive::Svg { @@ -234,7 +239,7 @@ impl<'a> Layer<'a> { layer.images.push(Image::Vector { handle: handle.clone(), color: *color, - bounds: *bounds * transformation, + bounds: *bounds + translation, }); } Primitive::Group { primitives } => { @@ -242,7 +247,7 @@ impl<'a> Layer<'a> { for primitive in primitives { Self::process_primitive( layers, - transformation, + translation, primitive, current_layer, ); @@ -250,7 +255,7 @@ impl<'a> Layer<'a> { } Primitive::Clip { bounds, content } => { let layer = &mut layers[current_layer]; - let translated_bounds = *bounds * transformation; + let translated_bounds = *bounds + translation; // Only draw visible content if let Some(clip_bounds) = @@ -261,19 +266,19 @@ impl<'a> Layer<'a> { Self::process_primitive( layers, - transformation, + translation, content, layers.len() - 1, ); } } - Primitive::Transform { - transformation: new_transformation, + Primitive::Translate { + translation: new_translation, content, } => { Self::process_primitive( layers, - transformation * *new_transformation, + translation + *new_translation, content, current_layer, ); @@ -281,7 +286,7 @@ impl<'a> Layer<'a> { Primitive::Cache { content } => { Self::process_primitive( layers, - transformation, + translation, content, current_layer, ); @@ -291,15 +296,20 @@ impl<'a> Layer<'a> { graphics::Mesh::Solid { buffers, size } => { let layer = &mut layers[current_layer]; - let bounds = - Rectangle::with_size(*size) * transformation; + let bounds = Rectangle::new( + Point::new(translation.x, translation.y), + *size, + ); // Only draw visible content if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { layer.meshes.push(Mesh::Solid { - transformation, + origin: Point::new( + translation.x, + translation.y, + ), buffers, clip_bounds, }); @@ -308,15 +318,20 @@ impl<'a> Layer<'a> { graphics::Mesh::Gradient { buffers, size } => { let layer = &mut layers[current_layer]; - let bounds = - Rectangle::with_size(*size) * transformation; + let bounds = Rectangle::new( + Point::new(translation.x, translation.y), + *size, + ); // Only draw visible content if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { layer.meshes.push(Mesh::Gradient { - transformation, + origin: Point::new( + translation.x, + translation.y, + ), buffers, clip_bounds, }); @@ -325,7 +340,7 @@ impl<'a> Layer<'a> { }, primitive::Custom::Pipeline(pipeline) => { let layer = &mut layers[current_layer]; - let bounds = pipeline.bounds * transformation; + let bounds = pipeline.bounds + translation; if let Some(clip_bounds) = layer.bounds.intersection(&bounds) diff --git a/wgpu/src/layer/mesh.rs b/wgpu/src/layer/mesh.rs index 5ed7c6544c..7c6206cd6d 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::{Rectangle, Transformation}; +use crate::core::{Point, Rectangle}; 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 [`Transformation`] for the vertices of the [`Mesh`]. - transformation: Transformation, + /// The origin of the vertices of the [`Mesh`]. + origin: Point, /// The vertex and index buffers of the [`Mesh`]. buffers: &'a mesh::Indexed, @@ -18,8 +18,8 @@ pub enum Mesh<'a> { }, /// A mesh of triangles with a gradient color. Gradient { - /// The [`Transformation`] for the vertices of the [`Mesh`]. - transformation: Transformation, + /// The origin of the vertices of the [`Mesh`]. + origin: Point, /// The vertex and index buffers of the [`Mesh`]. buffers: &'a mesh::Indexed, @@ -31,10 +31,11 @@ pub enum Mesh<'a> { impl Mesh<'_> { /// Returns the origin of the [`Mesh`]. - pub fn transformation(&self) -> Transformation { + pub fn origin(&self) -> Point { match self { - Self::Solid { transformation, .. } - | Self::Gradient { transformation, .. } => *transformation, + Self::Solid { origin, .. } | Self::Gradient { origin, .. } => { + *origin + } } } diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index b3a00130d5..37ee524728 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, Transformation}; +use crate::core::{Color, Font, Pixels, Point, Rectangle}; use crate::graphics; use crate::graphics::text::editor; use crate::graphics::text::paragraph; @@ -15,7 +15,6 @@ pub enum Text<'a> { position: Point, color: Color, clip_bounds: Rectangle, - transformation: Transformation, }, /// An editor. #[allow(missing_docs)] @@ -24,16 +23,11 @@ pub enum Text<'a> { position: Point, color: Color, clip_bounds: Rectangle, - transformation: Transformation, }, /// Some cached text. Cached(Cached<'a>), /// Some raw text. - #[allow(missing_docs)] - Raw { - raw: graphics::text::Raw, - transformation: Transformation, - }, + Raw(graphics::text::Raw), } #[derive(Debug, Clone)] diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index b932f54f9e..cda1bec974 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, Transformation}; -use crate::graphics; +use crate::core::{Background, Rectangle}; 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 6fa1922d43..dca09cb8a8 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -1,5 +1,5 @@ use crate::core::alignment; -use crate::core::{Rectangle, Size, Transformation}; +use crate::core::{Rectangle, Size}; use crate::graphics::color; use crate::graphics::text::cache::{self, Cache}; use crate::graphics::text::{font_system, to_color, Editor, Paragraph}; @@ -109,9 +109,7 @@ impl Pipeline { Some(Allocation::Cache(key)) } - Text::Raw { raw, .. } => { - raw.buffer.upgrade().map(Allocation::Raw) - } + Text::Raw(text) => text.buffer.upgrade().map(Allocation::Raw), }) .collect(); @@ -126,13 +124,11 @@ impl Pipeline { vertical_alignment, color, clip_bounds, - transformation, ) = match section { Text::Paragraph { position, color, clip_bounds, - transformation, .. } => { use crate::core::text::Paragraph as _; @@ -149,14 +145,12 @@ impl Pipeline { paragraph.vertical_alignment(), *color, *clip_bounds, - *transformation, ) } Text::Editor { position, color, clip_bounds, - transformation, .. } => { use crate::core::text::Editor as _; @@ -173,7 +167,6 @@ impl Pipeline { alignment::Vertical::Top, *color, *clip_bounds, - *transformation, ) } Text::Cached(text) => { @@ -193,13 +186,9 @@ impl Pipeline { text.vertical_alignment, text.color, text.clip_bounds, - Transformation::IDENTITY, ) } - Text::Raw { - raw, - transformation, - } => { + Text::Raw(text) => { let Some(Allocation::Raw(buffer)) = allocation else { return None; }; @@ -209,19 +198,18 @@ impl Pipeline { ( buffer.as_ref(), Rectangle::new( - raw.position, + text.position, Size::new(width, height), ), alignment::Horizontal::Left, alignment::Vertical::Top, - raw.color, - raw.clip_bounds, - *transformation, + text.color, + text.clip_bounds, ) } }; - let bounds = bounds * transformation * scale_factor; + let bounds = bounds * scale_factor; let left = match horizontal_alignment { alignment::Horizontal::Left => bounds.x, @@ -239,15 +227,14 @@ impl Pipeline { alignment::Vertical::Bottom => bounds.y - bounds.height, }; - let clip_bounds = layer_bounds.intersection( - &(clip_bounds * transformation * scale_factor), - )?; + let clip_bounds = + layer_bounds.intersection(&(clip_bounds * scale_factor))?; Some(glyphon::TextArea { buffer, left, top, - scale: scale_factor * transformation.scale_factor(), + scale: 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 2bb6f307fa..69270a7353 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, Transformation}; -use crate::graphics::Antialiasing; +use crate::core::Size; +use crate::graphics::{Antialiasing, Transformation}; use crate::layer::mesh::{self, Mesh}; use crate::Buffer; @@ -98,10 +98,12 @@ impl Layer { let mut index_offset = 0; for mesh in meshes { + let origin = mesh.origin(); let indices = mesh.indices(); - let uniforms = - Uniforms::new(transformation * mesh.transformation()); + let uniforms = Uniforms::new( + transformation * Transformation::translate(origin.x, origin.y), + ); index_offset += self.index_buffer.write(queue, index_offset, indices); diff --git a/widget/src/button.rs b/widget/src/button.rs index d16e8c6787..3b11e8a7aa 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -11,7 +11,7 @@ use crate::core::widget::tree::{self, Tree}; use crate::core::widget::Operation; use crate::core::{ Background, Clipboard, Color, Element, Layout, Length, Padding, Rectangle, - Shell, Size, Vector, Widget, + Shell, Size, Widget, }; pub use crate::style::button::{Appearance, StyleSheet}; @@ -271,13 +271,11 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { self.content.as_widget_mut().overlay( &mut tree.children[0], layout.children().next().unwrap(), renderer, - translation, ) } } diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index 0eda01913d..b95e6206f7 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, Transformation, Widget, + Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget, }; use crate::graphics::geometry; @@ -207,8 +207,8 @@ where let state = tree.state.downcast_ref::(); - renderer.with_transformation( - Transformation::translate(bounds.x, bounds.y), + renderer.with_translation( + Vector::new(bounds.x, bounds.y), |renderer| { renderer.draw( self.program.draw(state, renderer, theme, bounds, cursor), diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 0ff4d58b51..6f559ccc72 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -28,7 +28,7 @@ pub use crate::style::checkbox::{Appearance, StyleSheet}; /// /// let is_checked = true; /// -/// Checkbox::new("Toggle me!", is_checked).on_toggle(Message::CheckboxToggled); +/// Checkbox::new("Toggle me!", is_checked, Message::CheckboxToggled); /// ``` /// /// ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true) @@ -43,7 +43,7 @@ pub struct Checkbox< Renderer: text::Renderer, { is_checked: bool, - on_toggle: Option Message + 'a>>, + on_toggle: Box Message + 'a>, label: String, width: Length, size: f32, @@ -70,12 +70,18 @@ where /// Creates a new [`Checkbox`]. /// /// It expects: - /// * the label of the [`Checkbox`] /// * a boolean describing whether the [`Checkbox`] is checked or not - pub fn new(label: impl Into, is_checked: bool) -> Self { + /// * the label of the [`Checkbox`] + /// * a function that will be called when the [`Checkbox`] is toggled. It + /// will receive the new state of the [`Checkbox`] and must produce a + /// `Message`. + pub fn new(label: impl Into, is_checked: bool, f: F) -> Self + where + F: 'a + Fn(bool) -> Message, + { Checkbox { is_checked, - on_toggle: None, + on_toggle: Box::new(f), label: label.into(), width: Length::Shrink, size: Self::DEFAULT_SIZE, @@ -95,31 +101,6 @@ where } } - /// Sets the function that will be called when the [`Checkbox`] is toggled. - /// It will receive the new state of the [`Checkbox`] and must produce a - /// `Message`. - /// - /// Unless `on_toggle` is called, the [`Checkbox`] will be disabled. - pub fn on_toggle(mut self, f: F) -> Self - where - F: 'a + Fn(bool) -> Message, - { - self.on_toggle = Some(Box::new(f)); - self - } - - /// Sets the function that will be called when the [`Checkbox`] is toggled, - /// if `Some`. - /// - /// If `None`, the checkbox will be disabled. - pub fn on_toggle_maybe(mut self, f: Option) -> Self - where - F: Fn(bool) -> Message + 'a, - { - self.on_toggle = f.map(|f| Box::new(f) as _); - self - } - /// Sets the size of the [`Checkbox`]. pub fn size(mut self, size: impl Into) -> Self { self.size = size.into().0; @@ -254,10 +235,9 @@ where let mouse_over = cursor.is_over(layout.bounds()); if mouse_over { - if let Some(on_toggle) = &self.on_toggle { - shell.publish((on_toggle)(!self.is_checked)); - return event::Status::Captured; - } + shell.publish((self.on_toggle)(!self.is_checked)); + + return event::Status::Captured; } } _ => {} @@ -274,7 +254,7 @@ where _viewport: &Rectangle, _renderer: &Renderer, ) -> mouse::Interaction { - if cursor.is_over(layout.bounds()) && self.on_toggle.is_some() { + if cursor.is_over(layout.bounds()) { mouse::Interaction::Pointer } else { mouse::Interaction::default() @@ -292,13 +272,10 @@ where viewport: &Rectangle, ) { let is_mouse_over = cursor.is_over(layout.bounds()); - let is_disabled = self.on_toggle.is_none(); let mut children = layout.children(); - let custom_style = if is_disabled { - theme.disabled(&self.style, self.is_checked) - } else if is_mouse_over { + let custom_style = if is_mouse_over { theme.hovered(&self.style, self.is_checked) } else { theme.active(&self.style, self.is_checked) diff --git a/widget/src/column.rs b/widget/src/column.rs index 1e9841eee8..faac0e48d8 100644 --- a/widget/src/column.rs +++ b/widget/src/column.rs @@ -7,7 +7,7 @@ use crate::core::renderer; use crate::core::widget::{Operation, Tree}; use crate::core::{ Alignment, Clipboard, Element, Layout, Length, Padding, Pixels, Rectangle, - Shell, Size, Vector, Widget, + Shell, Size, Widget, }; /// A container that distributes its contents vertically. @@ -259,15 +259,8 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { - overlay::from_children( - &mut self.children, - tree, - layout, - renderer, - translation, - ) + overlay::from_children(&mut self.children, tree, layout, renderer) } } diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs index e3862174ad..0103e9cd8c 100644 --- a/widget/src/combo_box.rs +++ b/widget/src/combo_box.rs @@ -10,7 +10,7 @@ use crate::core::text; use crate::core::time::Instant; use crate::core::widget::{self, Widget}; use crate::core::{ - Clipboard, Element, Length, Padding, Rectangle, Shell, Size, Vector, + Clipboard, Element, Length, Padding, Rectangle, Shell, Size, }; use crate::overlay::menu; use crate::text::LineHeight; @@ -657,7 +657,6 @@ where tree: &'b mut widget::Tree, layout: Layout<'_>, _renderer: &Renderer, - translation: Vector, ) -> Option> { let is_focused = { let text_input_state = tree.children[0] @@ -706,7 +705,7 @@ where menu = menu.text_size(size); } - Some(menu.overlay(layout.position() + translation, bounds.height)) + Some(menu.overlay(layout.position(), bounds.height)) } else { None } diff --git a/widget/src/container.rs b/widget/src/container.rs index 4eb4a5d9bb..78ec19788d 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -279,13 +279,11 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { self.content.as_widget_mut().overlay( tree, layout.children().next().unwrap(), renderer, - translation, ) } } diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index e13e900a33..444eb4c2ea 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -158,12 +158,13 @@ where pub fn checkbox<'a, Message, Theme, Renderer>( label: impl Into, is_checked: bool, + f: impl Fn(bool) -> Message + 'a, ) -> Checkbox<'a, Message, Theme, Renderer> where Theme: checkbox::StyleSheet + text::StyleSheet, Renderer: core::text::Renderer, { - Checkbox::new(label, is_checked) + Checkbox::new(label, is_checked, f) } /// Creates a new [`Radio`]. diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index 88a6e503c8..6203d2c587 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -8,7 +8,7 @@ use crate::core::widget::tree::{self, Tree}; use crate::core::widget::Operation; use crate::core::{ Alignment, Clipboard, Element, Layout, Length, Padding, Pixels, Rectangle, - Shell, Size, Vector, Widget, + Shell, Size, Widget, }; /// A container that distributes its contents vertically. @@ -316,15 +316,8 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { - overlay::from_children( - &mut self.children, - tree, - layout, - renderer, - translation, - ) + overlay::from_children(&mut self.children, tree, layout, renderer) } } diff --git a/widget/src/lazy.rs b/widget/src/lazy.rs index eb663ea589..dda6162b27 100644 --- a/widget/src/lazy.rs +++ b/widget/src/lazy.rs @@ -259,7 +259,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let overlay = Overlay(Some( InnerBuilder { @@ -276,14 +275,18 @@ where overlay_builder: |element, tree| { element .as_widget_mut() - .overlay(tree, layout, renderer, translation) + .overlay(tree, layout, renderer) .map(|overlay| RefCell::new(Nested::new(overlay))) }, } .build(), )); - Some(overlay::Element::new(Box::new(overlay))) + let has_overlay = + overlay.with_overlay_maybe(|overlay| overlay.position()); + + has_overlay + .map(|position| overlay::Element::new(position, Box::new(overlay))) } } @@ -336,9 +339,17 @@ impl<'a, Message, Theme, Renderer> overlay::Overlay where Renderer: core::Renderer, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { - self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds)) - .unwrap_or_default() + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + translation: Vector, + ) -> layout::Node { + self.with_overlay_maybe(|overlay| { + overlay.layout(renderer, bounds, position, translation) + }) + .unwrap_or_default() } fn draw( diff --git a/widget/src/lazy/component.rs b/widget/src/lazy/component.rs index edecbdaa6e..30b1efedd3 100644 --- a/widget/src/lazy/component.rs +++ b/widget/src/lazy/component.rs @@ -462,7 +462,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { self.rebuild_element_if_necessary(); let tree = tree @@ -487,7 +486,6 @@ where &mut tree.children[0], layout, renderer, - translation, ) .map(|overlay| { RefCell::new(Nested::new(overlay)) @@ -499,9 +497,18 @@ where .build(), )); - Some(overlay::Element::new(Box::new(OverlayInstance { - overlay: Some(overlay), - }))) + let has_overlay = overlay.0.as_ref().unwrap().with_overlay(|overlay| { + overlay.as_ref().map(|nested| nested.borrow().position()) + }); + + has_overlay.map(|position| { + overlay::Element::new( + position, + Box::new(OverlayInstance { + overlay: Some(overlay), + }), + ) + }) } } @@ -575,9 +582,17 @@ where Renderer: core::Renderer, S: 'static + Default, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { - self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds)) - .unwrap_or_default() + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + translation: Vector, + ) -> layout::Node { + self.with_overlay_maybe(|overlay| { + overlay.layout(renderer, bounds, position, translation) + }) + .unwrap_or_default() } fn draw( diff --git a/widget/src/lazy/responsive.rs b/widget/src/lazy/responsive.rs index 44312a2158..9875b24ef0 100644 --- a/widget/src/lazy/responsive.rs +++ b/widget/src/lazy/responsive.rs @@ -279,7 +279,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { use std::ops::DerefMut; @@ -310,13 +309,17 @@ where element .as_widget_mut() - .overlay(tree, content_layout, renderer, translation) + .overlay(tree, content_layout, renderer) .map(|overlay| RefCell::new(Nested::new(overlay))) }, } .build(); - Some(overlay::Element::new(Box::new(overlay))) + let has_overlay = + overlay.with_overlay_maybe(|overlay| overlay.position()); + + has_overlay + .map(|position| overlay::Element::new(position, Box::new(overlay))) } } @@ -372,9 +375,17 @@ impl<'a, 'b, Message, Theme, Renderer> where Renderer: core::Renderer, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { - self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds)) - .unwrap_or_default() + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + translation: Vector, + ) -> layout::Node { + self.with_overlay_maybe(|overlay| { + overlay.layout(renderer, bounds, position, translation) + }) + .unwrap_or_default() } fn draw( diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index f82a75f406..62bb45d827 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -1,7 +1,5 @@ //! A container for capturing mouse events. -use iced_renderer::core::Point; - use crate::core::event::{self, Event}; use crate::core::layout; use crate::core::mouse; @@ -10,7 +8,7 @@ use crate::core::renderer; use crate::core::touch; use crate::core::widget::{tree, Operation, Tree}; use crate::core::{ - Clipboard, Element, Layout, Length, Rectangle, Shell, Size, Vector, Widget, + Clipboard, Element, Layout, Length, Rectangle, Shell, Size, Widget, }; /// Emit messages on mouse events. @@ -28,9 +26,6 @@ pub struct MouseArea< on_right_release: Option, on_middle_press: Option, on_middle_release: Option, - on_mouse_enter: Option, - on_mouse_move: Option Message>>, - on_mouse_exit: Option, } impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> { @@ -75,36 +70,12 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> { self.on_middle_release = Some(message); self } - - /// The message to emit when the mouse enters the area. - #[must_use] - pub fn on_mouse_enter(mut self, message: Message) -> Self { - self.on_mouse_enter = Some(message); - self - } - - /// The message to emit when the mouse moves in the area. - #[must_use] - pub fn on_mouse_move(mut self, build_message: F) -> Self - where - F: Fn(Point) -> Message + 'static, - { - self.on_mouse_move = Some(Box::new(build_message)); - self - } - - /// The message to emit when the mouse exits the area. - #[must_use] - pub fn on_mouse_exit(mut self, message: Message) -> Self { - self.on_mouse_exit = Some(message); - self - } } /// Local state of the [`MouseArea`]. #[derive(Default)] struct State { - is_hovered: bool, + // TODO: Support on_mouse_enter and on_mouse_exit } impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> { @@ -120,9 +91,6 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> { on_right_release: None, on_middle_press: None, on_middle_release: None, - on_mouse_enter: None, - on_mouse_move: None, - on_mouse_exit: None, } } } @@ -203,7 +171,7 @@ where return event::Status::Captured; } - update(self, tree, event, layout, cursor, shell) + update(self, &event, layout, cursor, shell) } fn mouse_interaction( @@ -249,13 +217,11 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { self.content.as_widget_mut().overlay( &mut tree.children[0], layout, renderer, - translation, ) } } @@ -278,42 +244,11 @@ where /// accordingly. fn update( widget: &mut MouseArea<'_, Message, Theme, Renderer>, - tree: &mut Tree, - event: Event, + event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, shell: &mut Shell<'_, Message>, ) -> event::Status { - if let Event::Mouse(mouse::Event::CursorMoved { .. }) - | Event::Touch(touch::Event::FingerMoved { .. }) = event - { - let state: &mut State = tree.state.downcast_mut(); - - let was_hovered = state.is_hovered; - state.is_hovered = cursor.is_over(layout.bounds()); - - match ( - widget.on_mouse_enter.as_ref(), - widget.on_mouse_move.as_ref(), - widget.on_mouse_exit.as_ref(), - ) { - (Some(on_mouse_enter), _, _) - if state.is_hovered && !was_hovered => - { - shell.publish(on_mouse_enter.clone()); - } - (_, Some(on_mouse_move), _) if state.is_hovered => { - if let Some(position) = cursor.position_in(layout.bounds()) { - shell.publish(on_mouse_move(position)); - } - } - (_, _, Some(on_mouse_exit)) if !state.is_hovered && was_hovered => { - shell.publish(on_mouse_exit.clone()); - } - _ => {} - } - } - if !cursor.is_over(layout.bounds()) { return event::Status::Ignored; } diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs index 8a4d6a98cd..a7b7ec9406 100644 --- a/widget/src/overlay/menu.rs +++ b/widget/src/overlay/menu.rs @@ -134,11 +134,10 @@ where position: Point, target_height: f32, ) -> overlay::Element<'a, Message, Theme, Renderer> { - overlay::Element::new(Box::new(Overlay::new( + overlay::Element::new( position, - self, - target_height, - ))) + Box::new(Overlay::new(self, target_height)), + ) } } @@ -168,7 +167,6 @@ where Theme: StyleSheet + container::StyleSheet, Renderer: crate::core::Renderer, { - position: Point, state: &'a mut Tree, container: Container<'a, Message, Theme, Renderer>, width: f32, @@ -183,7 +181,6 @@ where Renderer: text::Renderer + 'a, { pub fn new( - position: Point, menu: Menu<'a, T, Message, Theme, Renderer>, target_height: f32, ) -> Self @@ -221,7 +218,6 @@ where state.tree.diff(&container as &dyn Widget<_, _, _>); Self { - position, state: &mut state.tree, container, width, @@ -238,15 +234,20 @@ where Theme: StyleSheet + container::StyleSheet, Renderer: text::Renderer, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { - let space_below = - bounds.height - (self.position.y + self.target_height); - let space_above = self.position.y; + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + _translation: Vector, + ) -> layout::Node { + let space_below = bounds.height - (position.y + self.target_height); + let space_above = position.y; let limits = layout::Limits::new( Size::ZERO, Size::new( - bounds.width - self.position.x, + bounds.width - position.x, if space_below > space_above { space_below } else { @@ -260,9 +261,9 @@ where let size = node.size(); node.move_to(if space_below > space_above { - self.position + Vector::new(0.0, self.target_height) + position + Vector::new(0.0, self.target_height) } else { - self.position - Vector::new(0.0, size.height) + position - Vector::new(0.0, size.height) }) } diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index 4f9a265a66..c20d959a98 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -447,7 +447,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let children = self .contents @@ -455,7 +454,7 @@ where .zip(&mut tree.children) .zip(layout.children()) .filter_map(|(((_, content), state), layout)| { - content.overlay(state, layout, renderer, translation) + content.overlay(state, layout, renderer) }) .collect::>(); @@ -962,21 +961,22 @@ pub fn draw( if let Some(cursor_position) = cursor.position() { let bounds = layout.bounds(); - 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, - ); - }); - }); + 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, + ); + }); + }, + ); } } diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index dfe0fdcfbd..415dcc3ef0 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -5,9 +5,7 @@ use crate::core::mouse; use crate::core::overlay; use crate::core::renderer; use crate::core::widget::{self, Tree}; -use crate::core::{ - Clipboard, Element, Layout, Point, Rectangle, Shell, Size, Vector, -}; +use crate::core::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size}; use crate::pane_grid::{Draggable, TitleBar}; /// The content of a [`Pane`]. @@ -332,7 +330,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { if let Some(title_bar) = self.title_bar.as_mut() { let mut children = layout.children(); @@ -342,18 +339,13 @@ where let body_state = states.next().unwrap(); let title_bar_state = states.next().unwrap(); - match title_bar.overlay( - title_bar_state, - title_bar_layout, - renderer, - translation, - ) { + match title_bar.overlay(title_bar_state, title_bar_layout, renderer) + { Some(overlay) => Some(overlay), None => self.body.as_widget_mut().overlay( body_state, children.next()?, renderer, - translation, ), } } else { @@ -361,7 +353,6 @@ where &mut tree.children[0], layout, renderer, - translation, ) } } diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs index 5b57509b35..3cca6b33da 100644 --- a/widget/src/pane_grid/title_bar.rs +++ b/widget/src/pane_grid/title_bar.rs @@ -6,7 +6,7 @@ use crate::core::overlay; use crate::core::renderer; use crate::core::widget::{self, Tree}; use crate::core::{ - Clipboard, Element, Layout, Padding, Point, Rectangle, Shell, Size, Vector, + Clipboard, Element, Layout, Padding, Point, Rectangle, Shell, Size, }; /// The title bar of a [`Pane`]. @@ -405,7 +405,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let mut children = layout.children(); let padded = children.next()?; @@ -423,7 +422,7 @@ where content .as_widget_mut() - .overlay(title_state, title_layout, renderer, translation) + .overlay(title_state, title_layout, renderer) .or_else(move || { controls.as_mut().and_then(|controls| { let controls_layout = children.next()?; @@ -432,7 +431,6 @@ where controls_state, controls_layout, renderer, - translation, ) }) }) diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 475115c2c5..70b1d4c07a 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -12,7 +12,7 @@ use crate::core::touch; use crate::core::widget::tree::{self, Tree}; use crate::core::{ Clipboard, Element, Layout, Length, Padding, Pixels, Point, Rectangle, - Shell, Size, Vector, Widget, + Shell, Size, Widget, }; use crate::overlay::menu::{self, Menu}; use crate::scrollable; @@ -265,13 +265,11 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let state = tree.state.downcast_mut::>(); overlay( layout, - translation, state, self.padding, self.text_size, @@ -575,7 +573,6 @@ pub fn mouse_interaction( /// Returns the current overlay of a [`PickList`]. pub fn overlay<'a, T, Message, Theme, Renderer>( layout: Layout<'_>, - translation: Vector, state: &'a mut State, padding: Padding, text_size: Option, @@ -620,7 +617,7 @@ where menu = menu.text_size(text_size); } - Some(menu.overlay(layout.position() + translation, bounds.height)) + Some(menu.overlay(layout.position(), bounds.height)) } else { None } diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index 6a748e6396..91c0a97bc8 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -119,12 +119,11 @@ impl<'a, Message, Theme> Widget for QRCode<'a> { }); }); - renderer.with_translation( - bounds.position() - Point::ORIGIN, - |renderer| { - renderer.draw(vec![geometry]); - }, - ); + let translation = Vector::new(bounds.x, bounds.y); + + renderer.with_translation(translation, |renderer| { + renderer.draw(vec![geometry]); + }); } } diff --git a/widget/src/row.rs b/widget/src/row.rs index 7f8c335418..89f610c990 100644 --- a/widget/src/row.rs +++ b/widget/src/row.rs @@ -7,7 +7,7 @@ use crate::core::renderer; use crate::core::widget::{Operation, Tree}; use crate::core::{ Alignment, Clipboard, Element, Length, Padding, Pixels, Rectangle, Shell, - Size, Vector, Widget, + Size, Widget, }; /// A container that distributes its contents horizontally. @@ -248,15 +248,8 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { - overlay::from_children( - &mut self.children, - tree, - layout, - renderer, - translation, - ) + overlay::from_children(&mut self.children, tree, layout, renderer) } } diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 207b2539e1..509a6b342e 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -385,24 +385,25 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { - let bounds = layout.bounds(); - let content_layout = layout.children().next().unwrap(); - let content_bounds = content_layout.bounds(); - - let offset = tree.state.downcast_ref::().translation( - self.direction, - bounds, - content_bounds, - ); - - self.content.as_widget_mut().overlay( - &mut tree.children[0], - layout.children().next().unwrap(), - renderer, - translation - offset, - ) + self.content + .as_widget_mut() + .overlay( + &mut tree.children[0], + layout.children().next().unwrap(), + renderer, + ) + .map(|overlay| { + let bounds = layout.bounds(); + let content_layout = layout.children().next().unwrap(); + let content_bounds = content_layout.bounds(); + let translation = tree + .state + .downcast_ref::() + .translation(self.direction, bounds, content_bounds); + + overlay.translate(Vector::new(-translation.x, -translation.y)) + }) } } @@ -524,7 +525,7 @@ pub fn update( let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) = scrollbars.is_mouse_over(cursor); - let mut event_status = { + let event_status = { let cursor = match cursor_over_scrollable { Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => @@ -588,7 +589,7 @@ pub fn update( notify_on_scroll(state, on_scroll, bounds, content_bounds, shell); - event_status = event::Status::Captured; + return event::Status::Captured; } Event::Touch(event) if state.scroll_area_touched_at.is_some() @@ -634,7 +635,7 @@ pub fn update( } } - event_status = event::Status::Captured; + return event::Status::Captured; } _ => {} } @@ -646,7 +647,7 @@ pub fn update( | Event::Touch(touch::Event::FingerLost { .. }) => { state.y_scroller_grabbed_at = None; - event_status = event::Status::Captured; + return event::Status::Captured; } Event::Mouse(mouse::Event::CursorMoved { .. }) | Event::Touch(touch::Event::FingerMoved { .. }) => { @@ -672,7 +673,7 @@ pub fn update( shell, ); - event_status = event::Status::Captured; + return event::Status::Captured; } } _ => {} @@ -708,7 +709,7 @@ pub fn update( ); } - event_status = event::Status::Captured; + return event::Status::Captured; } _ => {} } @@ -721,7 +722,7 @@ pub fn update( | Event::Touch(touch::Event::FingerLost { .. }) => { state.x_scroller_grabbed_at = None; - event_status = event::Status::Captured; + return event::Status::Captured; } Event::Mouse(mouse::Event::CursorMoved { .. }) | Event::Touch(touch::Event::FingerMoved { .. }) => { @@ -748,7 +749,7 @@ pub fn update( ); } - event_status = event::Status::Captured; + return event::Status::Captured; } _ => {} } @@ -782,14 +783,14 @@ pub fn update( shell, ); - event_status = event::Status::Captured; + return event::Status::Captured; } } _ => {} } } - event_status + event::Status::Ignored } /// Computes the current [`mouse::Interaction`] of a [`Scrollable`]. diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 65bc1772eb..5c3b63841e 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -2,8 +2,6 @@ //! //! A [`Slider`] has some local [`State`]. use crate::core::event::{self, Event}; -use crate::core::keyboard; -use crate::core::keyboard::key::{self, Key}; use crate::core::layout; use crate::core::mouse; use crate::core::renderer; @@ -51,9 +49,7 @@ where { range: RangeInclusive, step: T, - shift_step: Option, value: T, - default: Option, on_change: Box Message + 'a>, on_release: Option, width: Length, @@ -63,7 +59,7 @@ where impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> where - T: Copy + From + PartialOrd, + T: Copy + From + std::cmp::PartialOrd, Message: Clone, Theme: StyleSheet, { @@ -96,10 +92,8 @@ where Slider { value, - default: None, range, step: T::from(1), - shift_step: None, on_change: Box::new(on_change), on_release: None, width: Length::Fill, @@ -108,14 +102,6 @@ where } } - /// Sets the optional default value for the [`Slider`]. - /// - /// If set, the [`Slider`] will reset to this value when ctrl-clicked or command-clicked. - pub fn default(mut self, default: impl Into) -> Self { - self.default = Some(default.into()); - self - } - /// Sets the release message of the [`Slider`]. /// This is called when the mouse is released from the slider. /// @@ -150,14 +136,6 @@ where self.step = step.into(); self } - - /// Sets the optional "shift" step for the [`Slider`]. - /// - /// If set, this value is used as the step while the shift key is pressed. - pub fn shift_step(mut self, shift_step: impl Into) -> Self { - self.shift_step = Some(shift_step.into()); - self - } } impl<'a, T, Message, Theme, Renderer> Widget @@ -210,10 +188,8 @@ where shell, tree.state.downcast_mut::(), &mut self.value, - self.default, &self.range, self.step, - self.shift_step, self.on_change.as_ref(), &self.on_release, ) @@ -277,10 +253,8 @@ pub fn update( shell: &mut Shell<'_, Message>, state: &mut State, value: &mut T, - default: Option, range: &RangeInclusive, step: T, - shift_step: Option, on_change: &dyn Fn(T) -> Message, on_release: &Option, ) -> event::Status @@ -289,22 +263,15 @@ where Message: Clone, { let is_dragging = state.is_dragging; - let current_value = *value; - let locate = |cursor_position: Point| -> Option { + let mut change = |cursor_position: Point| { let bounds = layout.bounds(); let new_value = if cursor_position.x <= bounds.x { - Some(*range.start()) + *range.start() } else if cursor_position.x >= bounds.x + bounds.width { - Some(*range.end()) + *range.end() } else { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - + let step = step.into(); let start = (*range.start()).into(); let end = (*range.end()).into(); @@ -314,49 +281,13 @@ where let steps = (percent * (end - start) / step).round(); let value = steps * step + start; - T::from_f64(value) + if let Some(value) = T::from_f64(value) { + value + } else { + return; + } }; - new_value - }; - - let increment = |value: T| -> Option { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - - let steps = (value.into() / step).round(); - let new_value = step * (steps + 1.0); - - if new_value > (*range.end()).into() { - return Some(*range.end()); - } - - T::from_f64(new_value) - }; - - let decrement = |value: T| -> Option { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - - let steps = (value.into() / step).round(); - let new_value = step * (steps - 1.0); - - if new_value < (*range.start()).into() { - return Some(*range.start()); - } - - T::from_f64(new_value) - }; - - let change = |new_value: T| { if ((*value).into() - new_value.into()).abs() > f64::EPSILON { shell.publish((on_change)(new_value)); @@ -369,13 +300,8 @@ where | Event::Touch(touch::Event::FingerPressed { .. }) => { if let Some(cursor_position) = cursor.position_over(layout.bounds()) { - if state.keyboard_modifiers.command() { - let _ = default.map(change); - state.is_dragging = false; - } else { - let _ = locate(cursor_position).map(change); - state.is_dragging = true; - } + change(cursor_position); + state.is_dragging = true; return event::Status::Captured; } @@ -395,29 +321,11 @@ where Event::Mouse(mouse::Event::CursorMoved { .. }) | Event::Touch(touch::Event::FingerMoved { .. }) => { if is_dragging { - let _ = cursor.position().and_then(locate).map(change); - - return event::Status::Captured; - } - } - Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => { - if cursor.position_over(layout.bounds()).is_some() { - match key { - Key::Named(key::Named::ArrowUp) => { - let _ = increment(current_value).map(change); - } - Key::Named(key::Named::ArrowDown) => { - let _ = decrement(current_value).map(change); - } - _ => (), - } + let _ = cursor.position().map(change); return event::Status::Captured; } } - Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { - state.keyboard_modifiers = modifiers; - } _ => {} } @@ -546,7 +454,6 @@ pub fn mouse_interaction( #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct State { is_dragging: bool, - keyboard_modifiers: keyboard::Modifiers, } impl State { diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 8d4319911b..c3a17bd25b 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -289,7 +289,6 @@ struct State { is_focused: bool, last_click: Option, drag_click: Option, - partial_scroll: f32, highlighter: RefCell, highlighter_settings: Highlighter::Settings, highlighter_format_address: usize, @@ -311,7 +310,6 @@ where is_focused: false, last_click: None, drag_click: None, - partial_scroll: 0.0, highlighter: RefCell::new(Highlighter::new( &self.highlighter_settings, )), @@ -406,14 +404,6 @@ where shell.publish(on_edit(action)); } - Update::Scroll(lines) => { - let lines = lines + state.partial_scroll; - state.partial_scroll = lines.fract(); - - shell.publish(on_edit(Action::Scroll { - lines: lines as i32, - })); - } Update::Unfocus => { state.is_focused = false; state.drag_click = None; @@ -429,12 +419,6 @@ where clipboard.write(selection); } } - Update::Cut => { - if let Some(selection) = self.content.selection() { - clipboard.write(selection.clone()); - shell.publish(on_edit(Action::Edit(Edit::Delete))); - } - } Update::Paste => { if let Some(contents) = clipboard.read() { shell.publish(on_edit(Action::Edit(Edit::Paste( @@ -587,12 +571,10 @@ where enum Update { Click(mouse::Click), - Scroll(f32), Unfocus, Release, Action(Action), Copy, - Cut, Paste, } @@ -641,16 +623,21 @@ impl Update { mouse::Event::WheelScrolled { delta } if cursor.is_over(bounds) => { - Some(Update::Scroll(match delta { - mouse::ScrollDelta::Lines { y, .. } => { - if y.abs() > 0.0 { - y.signum() * -(y.abs() * 4.0).max(1.0) - } else { - 0.0 + action(Action::Scroll { + lines: match delta { + mouse::ScrollDelta::Lines { y, .. } => { + if y.abs() > 0.0 { + (y.signum() * -(y.abs() * 4.0).max(1.0)) + as i32 + } else { + 0 + } } - } - mouse::ScrollDelta::Pixels { y, .. } => -y / 4.0, - })) + mouse::ScrollDelta::Pixels { y, .. } => { + (-y / 4.0) as i32 + } + }, + }) } _ => None, }, @@ -697,11 +684,6 @@ impl Update { { Some(Self::Copy) } - keyboard::Key::Character("x") - if modifiers.command() => - { - Some(Self::Cut) - } keyboard::Key::Character("v") if modifiers.command() && !modifiers.alt() => { diff --git a/widget/src/themer.rs b/widget/src/themer.rs index e6ca6cfea2..ee96a49362 100644 --- a/widget/src/themer.rs +++ b/widget/src/themer.rs @@ -141,7 +141,6 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { struct Overlay<'a, Message, Theme, Renderer> { theme: &'a Theme, @@ -158,8 +157,14 @@ where &mut self, renderer: &Renderer, bounds: Size, + position: Point, + translation: Vector, ) -> layout::Node { - self.content.layout(renderer, bounds) + self.content.layout( + renderer, + bounds, + translation + (position - Point::ORIGIN), + ) } fn draw( @@ -228,18 +233,22 @@ where theme: self.theme, content, }) - .map(|overlay| overlay::Element::new(Box::new(overlay))) + .map(|overlay| { + overlay::Element::new(Point::ORIGIN, Box::new(overlay)) + }) } } self.content .as_widget_mut() - .overlay(tree, layout, renderer, translation) + .overlay(tree, layout, renderer) .map(|content| Overlay { theme: &self.theme, content, }) - .map(|overlay| overlay::Element::new(Box::new(overlay))) + .map(|overlay| { + overlay::Element::new(Point::ORIGIN, Box::new(overlay)) + }) } } diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs index 87bec9323d..44cfc4b39e 100644 --- a/widget/src/tooltip.rs +++ b/widget/src/tooltip.rs @@ -231,7 +231,6 @@ where tree: &'b mut widget::Tree, layout: Layout<'_>, renderer: &Renderer, - translation: Vector, ) -> Option> { let state = tree.state.downcast_ref::(); @@ -241,22 +240,23 @@ where children.next().unwrap(), layout, renderer, - translation, ); let tooltip = if let State::Hovered { cursor_position } = *state { - Some(overlay::Element::new(Box::new(Overlay { - position: layout.position() + translation, - tooltip: &self.tooltip, - state: children.next().unwrap(), - cursor_position, - content_bounds: layout.bounds(), - snap_within_viewport: self.snap_within_viewport, - positioning: self.position, - gap: self.gap, - padding: self.padding, - style: &self.style, - }))) + Some(overlay::Element::new( + layout.position(), + Box::new(Overlay { + tooltip: &self.tooltip, + state: children.next().unwrap(), + cursor_position, + content_bounds: layout.bounds(), + snap_within_viewport: self.snap_within_viewport, + position: self.position, + gap: self.gap, + padding: self.padding, + style: &self.style, + }), + )) } else { None }; @@ -317,13 +317,12 @@ where Theme: container::StyleSheet + widget::text::StyleSheet, Renderer: text::Renderer, { - position: Point, tooltip: &'b Text<'a, Theme, Renderer>, state: &'b mut widget::Tree, cursor_position: Point, content_bounds: Rectangle, snap_within_viewport: bool, - positioning: Position, + position: Position, gap: f32, padding: f32, style: &'b ::Style, @@ -336,7 +335,13 @@ where Theme: container::StyleSheet + widget::text::StyleSheet, Renderer: text::Renderer, { - fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + _translation: Vector, + ) -> layout::Node { let viewport = Rectangle::with_size(bounds); let text_layout = Widget::<(), Theme, Renderer>::layout( @@ -353,44 +358,37 @@ where ); let text_bounds = text_layout.bounds(); - let x_center = self.position.x - + (self.content_bounds.width - text_bounds.width) / 2.0; - let y_center = self.position.y + let x_center = + position.x + (self.content_bounds.width - text_bounds.width) / 2.0; + let y_center = position.y + (self.content_bounds.height - text_bounds.height) / 2.0; let mut tooltip_bounds = { - let offset = match self.positioning { + let offset = match self.position { Position::Top => Vector::new( x_center, - self.position.y - - text_bounds.height - - self.gap - - self.padding, + position.y - text_bounds.height - self.gap - self.padding, ), Position::Bottom => Vector::new( x_center, - self.position.y + position.y + self.content_bounds.height + self.gap + self.padding, ), Position::Left => Vector::new( - self.position.x - - text_bounds.width - - self.gap - - self.padding, + position.x - text_bounds.width - self.gap - self.padding, y_center, ), Position::Right => Vector::new( - self.position.x + position.x + self.content_bounds.width + self.gap + self.padding, y_center, ), Position::FollowCursor => { - let translation = - self.position - self.content_bounds.position(); + let translation = position - self.content_bounds.position(); Vector::new( self.cursor_position.x, diff --git a/widget/src/vertical_slider.rs b/widget/src/vertical_slider.rs index 8f7c88da72..d3086a81f5 100644 --- a/widget/src/vertical_slider.rs +++ b/widget/src/vertical_slider.rs @@ -7,8 +7,6 @@ pub use crate::style::slider::{Appearance, Handle, HandleShape, StyleSheet}; use crate::core; use crate::core::event::{self, Event}; -use crate::core::keyboard; -use crate::core::keyboard::key::{self, Key}; use crate::core::layout::{self, Layout}; use crate::core::mouse; use crate::core::renderer; @@ -48,9 +46,7 @@ where { range: RangeInclusive, step: T, - shift_step: Option, value: T, - default: Option, on_change: Box Message + 'a>, on_release: Option, width: f32, @@ -93,10 +89,8 @@ where VerticalSlider { value, - default: None, range, step: T::from(1), - shift_step: None, on_change: Box::new(on_change), on_release: None, width: Self::DEFAULT_WIDTH, @@ -105,14 +99,6 @@ where } } - /// Sets the optional default value for the [`VerticalSlider`]. - /// - /// If set, the [`VerticalSlider`] will reset to this value when ctrl-clicked or command-clicked. - pub fn default(mut self, default: impl Into) -> Self { - self.default = Some(default.into()); - self - } - /// Sets the release message of the [`VerticalSlider`]. /// This is called when the mouse is released from the slider. /// @@ -147,14 +133,6 @@ where self.step = step; self } - - /// Sets the optional "shift" step for the [`VerticalSlider`]. - /// - /// If set, this value is used as the step while the shift key is pressed. - pub fn shift_step(mut self, shift_step: impl Into) -> Self { - self.shift_step = Some(shift_step.into()); - self - } } impl<'a, T, Message, Theme, Renderer> Widget @@ -207,10 +185,8 @@ where shell, tree.state.downcast_mut::(), &mut self.value, - self.default, &self.range, self.step, - self.shift_step, self.on_change.as_ref(), &self.on_release, ) @@ -275,10 +251,8 @@ pub fn update( shell: &mut Shell<'_, Message>, state: &mut State, value: &mut T, - default: Option, range: &RangeInclusive, step: T, - shift_step: Option, on_change: &dyn Fn(T) -> Message, on_release: &Option, ) -> event::Status @@ -287,23 +261,16 @@ where Message: Clone, { let is_dragging = state.is_dragging; - let current_value = *value; - let locate = |cursor_position: Point| -> Option { + let mut change = |cursor_position: Point| { let bounds = layout.bounds(); let new_value = if cursor_position.y >= bounds.y + bounds.height { - Some(*range.start()) + *range.start() } else if cursor_position.y <= bounds.y { - Some(*range.end()) + *range.end() } else { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - + let step = step.into(); let start = (*range.start()).into(); let end = (*range.end()).into(); @@ -314,49 +281,13 @@ where let steps = (percent * (end - start) / step).round(); let value = steps * step + start; - T::from_f64(value) + if let Some(value) = T::from_f64(value) { + value + } else { + return; + } }; - new_value - }; - - let increment = |value: T| -> Option { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - - let steps = (value.into() / step).round(); - let new_value = step * (steps + 1.0); - - if new_value > (*range.end()).into() { - return Some(*range.end()); - } - - T::from_f64(new_value) - }; - - let decrement = |value: T| -> Option { - let step = if state.keyboard_modifiers.shift() { - shift_step.unwrap_or(step) - } else { - step - } - .into(); - - let steps = (value.into() / step).round(); - let new_value = step * (steps - 1.0); - - if new_value < (*range.start()).into() { - return Some(*range.start()); - } - - T::from_f64(new_value) - }; - - let change = |new_value: T| { if ((*value).into() - new_value.into()).abs() > f64::EPSILON { shell.publish((on_change)(new_value)); @@ -369,15 +300,8 @@ where | Event::Touch(touch::Event::FingerPressed { .. }) => { if let Some(cursor_position) = cursor.position_over(layout.bounds()) { - if state.keyboard_modifiers.control() - || state.keyboard_modifiers.command() - { - let _ = default.map(change); - state.is_dragging = false; - } else { - let _ = locate(cursor_position).map(change); - state.is_dragging = true; - } + change(cursor_position); + state.is_dragging = true; return event::Status::Captured; } @@ -397,29 +321,11 @@ where Event::Mouse(mouse::Event::CursorMoved { .. }) | Event::Touch(touch::Event::FingerMoved { .. }) => { if is_dragging { - let _ = cursor.position().and_then(locate).map(change); - - return event::Status::Captured; - } - } - Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => { - if cursor.position_over(layout.bounds()).is_some() { - match key { - Key::Named(key::Named::ArrowUp) => { - let _ = increment(current_value).map(change); - } - Key::Named(key::Named::ArrowDown) => { - let _ = decrement(current_value).map(change); - } - _ => (), - } + let _ = cursor.position().map(change); return event::Status::Captured; } } - Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { - state.keyboard_modifiers = modifiers; - } _ => {} } @@ -548,7 +454,6 @@ pub fn mouse_interaction( #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct State { is_dragging: bool, - keyboard_modifiers: keyboard::Modifiers, } impl State { diff --git a/winit/src/application.rs b/winit/src/application.rs index 5e6f362eb2..ca5d5df9bf 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -935,9 +935,6 @@ pub fn run_command( .send_event(tagger(Ok(()))) .expect("Send message to event loop"); } - command::Action::Custom(_) => { - log::warn!("Unsupported custom action in `iced_winit` shell"); - } } } } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index ef789296e2..eceb160487 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -385,7 +385,6 @@ pub fn mouse_interaction( } Interaction::ResizingVertically => winit::window::CursorIcon::NsResize, Interaction::NotAllowed => winit::window::CursorIcon::NotAllowed, - Interaction::ZoomIn => winit::window::CursorIcon::ZoomIn, } } diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs index 854dfa2eb8..cd2ebfffd2 100644 --- a/winit/src/multi_window.rs +++ b/winit/src/multi_window.rs @@ -1241,9 +1241,6 @@ fn run_command( .send_event(tagger(Ok(()))) .expect("Send message to event loop"); } - command::Action::Custom(_) => { - log::warn!("Unsupported custom action in `iced_winit` shell"); - } } } }