diff options
author | 2023-01-08 20:07:11 +0100 | |
---|---|---|
committer | 2023-01-08 20:07:11 +0100 | |
commit | 624a4ada7981eb05c0b50cafa7e9545ad8347cb5 (patch) | |
tree | 4ef01bfbe31333aff06d738ae51272a570c6f11b | |
parent | 9f85e0c721927f1e3bd195a998ec7a80ec0e7455 (diff) | |
download | iced-624a4ada7981eb05c0b50cafa7e9545ad8347cb5.tar.gz iced-624a4ada7981eb05c0b50cafa7e9545ad8347cb5.tar.bz2 iced-624a4ada7981eb05c0b50cafa7e9545ad8347cb5.zip |
Introduce `RelativeOffset` type in `scrollable`
-rw-r--r-- | core/src/point.rs | 8 | ||||
-rw-r--r-- | examples/scrollable/src/main.rs | 14 | ||||
-rw-r--r-- | examples/websocket/src/main.rs | 4 | ||||
-rw-r--r-- | native/src/widget/operation/scrollable.rs | 30 | ||||
-rw-r--r-- | native/src/widget/scrollable.rs | 85 | ||||
-rw-r--r-- | src/widget.rs | 3 |
6 files changed, 75 insertions, 69 deletions
diff --git a/core/src/point.rs b/core/src/point.rs index d351befd..9bf7726b 100644 --- a/core/src/point.rs +++ b/core/src/point.rs @@ -75,11 +75,3 @@ impl std::ops::Sub<Point> for Point { Vector::new(self.x - point.x, self.y - point.y) } } - -impl std::ops::Add<Point> for Point { - type Output = Point; - - fn add(self, point: Point) -> Point { - Point::new(self.x + point.x, self.y + point.y) - } -} diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index 43c863cb..702ade35 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -3,7 +3,7 @@ use iced::widget::{ button, column, container, horizontal_space, progress_bar, radio, row, scrollable, slider, text, vertical_space, }; -use iced::{executor, theme, Alignment, Color, Point}; +use iced::{executor, theme, Alignment, Color}; use iced::{Application, Command, Element, Length, Settings, Theme}; use once_cell::sync::Lazy; @@ -18,7 +18,7 @@ struct ScrollableDemo { scrollbar_width: u16, scrollbar_margin: u16, scroller_width: u16, - current_scroll_offset: Point, + current_scroll_offset: scrollable::RelativeOffset, } #[derive(Debug, Clone, Eq, PartialEq, Copy)] @@ -36,7 +36,7 @@ enum Message { ScrollerWidthChanged(u16), ScrollToBeginning, ScrollToEnd, - Scrolled(Point), + Scrolled(scrollable::RelativeOffset), } impl Application for ScrollableDemo { @@ -52,7 +52,7 @@ impl Application for ScrollableDemo { scrollbar_width: 10, scrollbar_margin: 0, scroller_width: 10, - current_scroll_offset: Point::ORIGIN, + current_scroll_offset: scrollable::RelativeOffset::START, }, Command::none(), ) @@ -65,7 +65,7 @@ impl Application for ScrollableDemo { fn update(&mut self, message: Message) -> Command<Message> { match message { Message::SwitchDirection(direction) => { - self.current_scroll_offset = Point::ORIGIN; + self.current_scroll_offset = scrollable::RelativeOffset::START; self.scrollable_direction = direction; scrollable::snap_to( @@ -89,7 +89,7 @@ impl Application for ScrollableDemo { Command::none() } Message::ScrollToBeginning => { - self.current_scroll_offset = Point::ORIGIN; + self.current_scroll_offset = scrollable::RelativeOffset::START; scrollable::snap_to( SCROLLABLE_ID.clone(), @@ -97,7 +97,7 @@ impl Application for ScrollableDemo { ) } Message::ScrollToEnd => { - self.current_scroll_offset = Point::new(1.0, 1.0); + self.current_scroll_offset = scrollable::RelativeOffset::END; scrollable::snap_to( SCROLLABLE_ID.clone(), diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs index d1e45571..ccd9c815 100644 --- a/examples/websocket/src/main.rs +++ b/examples/websocket/src/main.rs @@ -1,10 +1,10 @@ mod echo; use iced::alignment::{self, Alignment}; +use iced::executor; use iced::widget::{ button, column, container, row, scrollable, text, text_input, Column, }; -use iced::{executor, Point}; use iced::{ Application, Color, Command, Element, Length, Settings, Subscription, Theme, }; @@ -83,7 +83,7 @@ impl Application for WebSocket { scrollable::snap_to( MESSAGE_LOG.clone(), - Point::new(0.0, 1.0), + scrollable::RelativeOffset::END, ) } }, diff --git a/native/src/widget/operation/scrollable.rs b/native/src/widget/operation/scrollable.rs index 6981b1f4..3b20631f 100644 --- a/native/src/widget/operation/scrollable.rs +++ b/native/src/widget/operation/scrollable.rs @@ -1,19 +1,18 @@ //! Operate on widgets that can be scrolled. use crate::widget::{Id, Operation}; -use iced_core::Point; /// The internal state of a widget that can be scrolled. pub trait Scrollable { /// Snaps the scroll of the widget to the given `percentage` along the horizontal & vertical axis. - fn snap_to(&mut self, percentage: Point); + fn snap_to(&mut self, offset: RelativeOffset); } /// Produces an [`Operation`] that snaps the widget with the given [`Id`] to /// the provided `percentage`. -pub fn snap_to<T>(target: Id, percentage: Point) -> impl Operation<T> { +pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> { struct SnapTo { target: Id, - percentage: Point, + offset: RelativeOffset, } impl<T> Operation<T> for SnapTo { @@ -27,10 +26,29 @@ pub fn snap_to<T>(target: Id, percentage: Point) -> impl Operation<T> { fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) { if Some(&self.target) == id { - state.snap_to(self.percentage); + state.snap_to(self.offset); } } } - SnapTo { target, percentage } + SnapTo { target, offset } +} + +/// The amount of offset in each direction of a [`Scrollable`]. +/// +/// A value of `0.0` means start, while `1.0` means end. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct RelativeOffset { + /// The amount of horizontal offset + pub x: f32, + /// The amount of vertical offset + pub y: f32, +} + +impl RelativeOffset { + /// A relative offset that points to the top-left of a [`Scrollable`]. + pub const START: Self = Self { x: 0.0, y: 0.0 }; + + /// A relative offset that points to the bottom-right of a [`Scrollable`]. + pub const END: Self = Self { x: 1.0, y: 1.0 }; } diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 39f970d7..63e7312f 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -14,6 +14,7 @@ use crate::{ }; pub use iced_style::scrollable::StyleSheet; +pub use operation::scrollable::RelativeOffset; pub mod style { //! The styles of a [`Scrollable`]. @@ -35,7 +36,7 @@ where vertical: Properties, horizontal: Option<Properties>, content: Element<'a, Message, Renderer>, - on_scroll: Option<Box<dyn Fn(Point) -> Message + 'a>>, + on_scroll: Option<Box<dyn Fn(RelativeOffset) -> Message + 'a>>, style: <Renderer::Theme as StyleSheet>::Style, } @@ -85,7 +86,10 @@ where /// /// The function takes the new relative x & y offset of the [`Scrollable`] /// (e.g. `0` means beginning, while `1` means end). - pub fn on_scroll(mut self, f: impl Fn(Point) -> Message + 'a) -> Self { + pub fn on_scroll( + mut self, + f: impl Fn(RelativeOffset) -> Message + 'a, + ) -> Self { self.on_scroll = Some(Box::new(f)); self } @@ -375,9 +379,9 @@ impl From<Id> for widget::Id { /// to the provided `percentage` along the x & y axis. pub fn snap_to<Message: 'static>( id: Id, - percentage: Point, + offset: RelativeOffset, ) -> Command<Message> { - Command::widget(operation::scrollable::snap_to(id.0, percentage)) + Command::widget(operation::scrollable::snap_to(id.0, offset)) } /// Computes the layout of a [`Scrollable`]. @@ -428,7 +432,7 @@ pub fn update<Message>( shell: &mut Shell<'_, Message>, vertical: &Properties, horizontal: Option<&Properties>, - on_scroll: &Option<Box<dyn Fn(Point) -> Message + '_>>, + on_scroll: &Option<Box<dyn Fn(RelativeOffset) -> Message + '_>>, update_content: impl FnOnce( Event, Layout<'_>, @@ -872,7 +876,7 @@ pub fn draw<Renderer>( fn notify_on_scroll<Message>( state: &State, - on_scroll: &Option<Box<dyn Fn(Point) -> Message + '_>>, + on_scroll: &Option<Box<dyn Fn(RelativeOffset) -> Message + '_>>, bounds: Rectangle, content_bounds: Rectangle, shell: &mut Shell<'_, Message>, @@ -882,13 +886,15 @@ fn notify_on_scroll<Message>( return; } - let x_offset = state.offset_x.absolute_x(bounds, content_bounds) + let x = state.offset_x.absolute(bounds.width, content_bounds.width) / (content_bounds.width - bounds.width); - let y_offset = state.offset_y.absolute_y(bounds, content_bounds) + let y = state + .offset_y + .absolute(bounds.height, content_bounds.height) / (content_bounds.height - bounds.height); - shell.publish(on_scroll(Point::new(x_offset, y_offset))) + shell.publish(on_scroll(RelativeOffset { x, y })) } } @@ -915,12 +921,11 @@ impl Default for State { } impl operation::Scrollable for State { - fn snap_to(&mut self, percentage: Point) { - State::snap_to(self, percentage); + fn snap_to(&mut self, offset: RelativeOffset) { + State::snap_to(self, offset); } } -/// The offset of a [`Scrollable`]. #[derive(Debug, Clone, Copy)] enum Offset { Absolute(f32), @@ -928,24 +933,13 @@ enum Offset { } impl Offset { - fn absolute_x(self, bounds: Rectangle, content_bounds: Rectangle) -> f32 { - match self { - Offset::Absolute(absolute) => { - absolute.min((content_bounds.width - bounds.width).max(0.0)) - } - Offset::Relative(percentage) => { - ((content_bounds.width - bounds.width) * percentage).max(0.0) - } - } - } - - fn absolute_y(self, bounds: Rectangle, content_bounds: Rectangle) -> f32 { + fn absolute(self, window: f32, content: f32) -> f32 { match self { Offset::Absolute(absolute) => { - absolute.min((content_bounds.height - bounds.height).max(0.0)) + absolute.min((content - window).max(0.0)) } Offset::Relative(percentage) => { - ((content_bounds.height - bounds.height) * percentage).max(0.0) + ((content - window) * percentage).max(0.0) } } } @@ -967,14 +961,16 @@ impl State { ) { if bounds.height < content_bounds.height { self.offset_y = Offset::Absolute( - (self.offset_y.absolute_y(bounds, content_bounds) - delta.y) + (self.offset_y.absolute(bounds.height, content_bounds.height) + - delta.y) .clamp(0.0, content_bounds.height - bounds.height), ) } if bounds.width < content_bounds.width { self.offset_x = Offset::Absolute( - (self.offset_x.absolute_x(bounds, content_bounds) - delta.x) + (self.offset_x.absolute(bounds.width, content_bounds.width) + - delta.x) .clamp(0.0, content_bounds.width - bounds.width), ); } @@ -1008,34 +1004,33 @@ impl State { self.unsnap(bounds, content_bounds); } - /// Snaps the scroll position to a relative amount. - /// - /// `0` represents scrollbar at the beginning, while `1` represents scrollbar at - /// the end. - pub fn snap_to(&mut self, percentage: Point) { - self.offset_x = Offset::Relative(percentage.x.clamp(0.0, 1.0)); - self.offset_y = Offset::Relative(percentage.y.clamp(0.0, 1.0)); + /// Snaps the scroll position to a [`RelativeOffset`]. + pub fn snap_to(&mut self, offset: RelativeOffset) { + self.offset_x = Offset::Relative(offset.x.clamp(0.0, 1.0)); + self.offset_y = Offset::Relative(offset.y.clamp(0.0, 1.0)); } /// Unsnaps the current scroll position, if snapped, given the bounds of the /// [`Scrollable`] and its contents. pub fn unsnap(&mut self, bounds: Rectangle, content_bounds: Rectangle) { - self.offset_x = - Offset::Absolute(self.offset_x.absolute_x(bounds, content_bounds)); - self.offset_y = - Offset::Absolute(self.offset_y.absolute_y(bounds, content_bounds)); + self.offset_x = Offset::Absolute( + self.offset_x.absolute(bounds.width, content_bounds.width), + ); + self.offset_y = Offset::Absolute( + self.offset_y.absolute(bounds.height, content_bounds.height), + ); } - /// Returns the current x & y scrolling offset of the [`State`], given the bounds - /// of the [`Scrollable`] and its contents. + /// Returns the scrolling offset of the [`State`], given the bounds of the + /// [`Scrollable`] and its contents. pub fn offset( &self, bounds: Rectangle, content_bounds: Rectangle, - ) -> Point { - Point::new( - self.offset_x.absolute_x(bounds, content_bounds), - self.offset_y.absolute_y(bounds, content_bounds), + ) -> Vector { + Vector::new( + self.offset_x.absolute(bounds.width, content_bounds.width), + self.offset_y.absolute(bounds.height, content_bounds.height), ) } diff --git a/src/widget.rs b/src/widget.rs index d034200c..f87782d0 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -99,7 +99,8 @@ pub mod radio { pub mod scrollable { //! Navigate an endless amount of content with a scrollbar. pub use iced_native::widget::scrollable::{ - snap_to, style::Scrollbar, style::Scroller, Id, Properties, StyleSheet, + snap_to, style::Scrollbar, style::Scroller, Id, Properties, + RelativeOffset, StyleSheet, }; /// A widget that can vertically display an infinite amount of content |