diff options
Diffstat (limited to '')
-rw-r--r-- | examples/tour.rs | 2 | ||||
-rw-r--r-- | native/src/renderer/null.rs | 9 | ||||
-rw-r--r-- | native/src/widget.rs | 2 | ||||
-rw-r--r-- | native/src/widget/scrollable.rs | 73 | ||||
-rw-r--r-- | wgpu/src/renderer/widget/scrollable.rs | 84 |
5 files changed, 119 insertions, 51 deletions
diff --git a/examples/tour.rs b/examples/tour.rs index 0121c3bd..6b366957 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -145,7 +145,7 @@ impl Steps { Step::Debugger, Step::End, ], - current: 0, + current: 6, } } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 182f033a..c8852ad1 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -1,7 +1,7 @@ use crate::{ button, checkbox, column, radio, row, scrollable, text, text_input, Background, Color, Element, Font, HorizontalAlignment, Layout, Point, - Rectangle, Renderer, Size, VerticalAlignment, + Rectangle, Renderer, ScrollbarGrab, Size, VerticalAlignment, }; /// A renderer that does nothing. @@ -61,13 +61,14 @@ impl text::Renderer for Null { } impl scrollable::Renderer for Null { - fn is_mouse_over_scrollbar( + fn scrollbar_grab( &self, _bounds: Rectangle, _content_bounds: Rectangle, + _offset: u32, _cursor_position: Point, - ) -> bool { - false + ) -> Option<ScrollbarGrab> { + None } fn draw( diff --git a/native/src/widget.rs b/native/src/widget.rs index 71dcdc0d..a2d3aa12 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -47,7 +47,7 @@ pub use radio::Radio; #[doc(no_inline)] pub use row::Row; #[doc(no_inline)] -pub use scrollable::Scrollable; +pub use scrollable::{Scrollable, ScrollbarGrab}; #[doc(no_inline)] pub use slider::Slider; #[doc(no_inline)] diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 678d837a..fed7f54e 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -150,9 +150,11 @@ where let content = layout.children().next().unwrap(); let content_bounds = content.bounds(); - let is_mouse_over_scrollbar = renderer.is_mouse_over_scrollbar( + let offset = self.state.offset(bounds, content_bounds); + let scrollbar_grab = renderer.scrollbar_grab( bounds, content_bounds, + offset, cursor_position, ); @@ -174,25 +176,45 @@ where } } - if self.state.is_scrollbar_grabbed() || is_mouse_over_scrollbar { + if self.state.currently_grabbed() || scrollbar_grab.is_some() { match event { Event::Mouse(mouse::Event::Input { button: mouse::Button::Left, state, }) => match state { ButtonState::Pressed => { - self.state.scroll_to( - cursor_position.y / (bounds.y + bounds.height), + let (scrollbar_grab, scroller_bounds) = + scrollbar_grab.unwrap(); + + let scroller_grabbed_at = match scrollbar_grab { + ScrollbarGrab::Background => 0.5, + ScrollbarGrab::Scroller => { + (cursor_position.y - scroller_bounds.y) + / scroller_bounds.height + } + }; + + let scroll_percentage = (cursor_position.y + - (scroller_bounds.height * scroller_grabbed_at)) + / (bounds.height + - (scroller_bounds.height + * scroller_grabbed_at)); + + dbg!((scroll_percentage, scroller_grabbed_at)); + /*self.state.scroll_to( + scroll_percentage, bounds, content_bounds, - ); + );*/ - self.state.scrollbar_grabbed_at = Some(cursor_position); + self.state.scroller_grabbed_at = + Some(scroller_grabbed_at); } ButtonState::Released => { - self.state.scrollbar_grabbed_at = None; + self.state.scroller_grabbed_at = None; } }, + /* TODO: Implement dragging to scroll Event::Mouse(mouse::Event::CursorMoved { .. }) => { if let Some(scrollbar_grabbed_at) = self.state.scrollbar_grabbed_at @@ -209,13 +231,13 @@ where self.state.scrollbar_grabbed_at = Some(cursor_position); } } + */ _ => {} } } let cursor_position = if is_mouse_over - && !(is_mouse_over_scrollbar - || self.state.scrollbar_grabbed_at.is_some()) + && !(scrollbar_grab.is_some() || self.state.currently_grabbed()) { Point::new( cursor_position.x, @@ -251,11 +273,9 @@ where let offset = self.state.offset(bounds, content_bounds); let is_mouse_over = bounds.contains(cursor_position); - let is_mouse_over_scrollbar = renderer.is_mouse_over_scrollbar( - bounds, - content_bounds, - cursor_position, - ); + let is_mouse_over_scrollbar = renderer + .scrollbar_grab(bounds, content_bounds, offset, cursor_position) + .is_some(); let content = { let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar { @@ -294,7 +314,7 @@ where /// [`Scrollable`]: struct.Scrollable.html #[derive(Debug, Clone, Copy, Default)] pub struct State { - scrollbar_grabbed_at: Option<Point>, + scroller_grabbed_at: Option<f32>, offset: f32, } @@ -357,11 +377,20 @@ impl State { } /// Returns whether the scrollbar is currently grabbed or not. - pub fn is_scrollbar_grabbed(&self) -> bool { - self.scrollbar_grabbed_at.is_some() + pub fn currently_grabbed(&self) -> bool { + self.scroller_grabbed_at.is_some() } } +#[derive(Debug, Clone, Copy)] +/// What the mouse is grabbing on the scrollbar +pub enum ScrollbarGrab { + /// The mouse is grabbing the background + Background, + /// The mouse is grabbing the scroller + Scroller, +} + /// The renderer of a [`Scrollable`]. /// /// Your [renderer] will need to implement this trait before being @@ -370,16 +399,18 @@ impl State { /// [`Scrollable`]: struct.Scrollable.html /// [renderer]: ../../renderer/index.html pub trait Renderer: crate::Renderer + Sized { - /// Returns whether the mouse is over the scrollbar given the bounds of - /// the [`Scrollable`] and its contents. + /// Returns what part of the scrollbar is being grabbed by the mouse + /// given the bounds of the [`Scrollable`] and its contents together + /// with the current scroller bounds. /// /// [`Scrollable`]: struct.Scrollable.html - fn is_mouse_over_scrollbar( + fn scrollbar_grab( &self, bounds: Rectangle, content_bounds: Rectangle, + offset: u32, cursor_position: Point, - ) -> bool; + ) -> Option<(ScrollbarGrab, Rectangle)>; /// Draws the [`Scrollable`]. /// diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs index 58dc3df9..d069b799 100644 --- a/wgpu/src/renderer/widget/scrollable.rs +++ b/wgpu/src/renderer/widget/scrollable.rs @@ -1,12 +1,13 @@ use crate::{Primitive, Renderer}; use iced_native::{ - scrollable, Background, MouseCursor, Point, Rectangle, Vector, + scrollable, Background, MouseCursor, Point, Rectangle, ScrollbarGrab, + Vector, }; const SCROLLBAR_WIDTH: u16 = 10; const SCROLLBAR_MARGIN: u16 = 2; -fn scrollbar_bounds(bounds: Rectangle) -> Rectangle { +fn background_bounds(bounds: Rectangle) -> Rectangle { Rectangle { x: bounds.x + bounds.width - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN), @@ -16,15 +17,53 @@ fn scrollbar_bounds(bounds: Rectangle) -> Rectangle { } } +fn scroller_bounds( + bounds: Rectangle, + content_bounds: Rectangle, + background_bounds: Rectangle, + offset: u32, +) -> Rectangle { + let ratio = bounds.height / content_bounds.height; + let scrollbar_height = bounds.height * ratio; + let y_offset = offset as f32 * ratio; + + Rectangle { + x: background_bounds.x + f32::from(SCROLLBAR_MARGIN), + y: background_bounds.y + y_offset, + width: background_bounds.width - f32::from(2 * SCROLLBAR_MARGIN), + height: scrollbar_height, + } +} + impl scrollable::Renderer for Renderer { - fn is_mouse_over_scrollbar( + fn scrollbar_grab( &self, bounds: Rectangle, content_bounds: Rectangle, + offset: u32, cursor_position: Point, - ) -> bool { - content_bounds.height > bounds.height - && scrollbar_bounds(bounds).contains(cursor_position) + ) -> Option<(ScrollbarGrab, Rectangle)> { + let background_bounds = background_bounds(bounds); + if content_bounds.height > bounds.height + && background_bounds.contains(cursor_position) + { + let scroller_bounds = scroller_bounds( + bounds, + content_bounds, + background_bounds, + offset, + ); + + let scrollbar_grab = if scroller_bounds.contains(cursor_position) { + ScrollbarGrab::Scroller + } else { + ScrollbarGrab::Background + }; + + Some((scrollbar_grab, scroller_bounds)) + } else { + None + } } fn draw( @@ -38,7 +77,7 @@ impl scrollable::Renderer for Renderer { (content, mouse_cursor): Self::Output, ) -> Self::Output { let is_content_overflowing = content_bounds.height > bounds.height; - let scrollbar_bounds = scrollbar_bounds(bounds); + let background_bounds = background_bounds(bounds); let clip = Primitive::Clip { bounds, @@ -48,31 +87,28 @@ impl scrollable::Renderer for Renderer { ( if is_content_overflowing - && (is_mouse_over || state.is_scrollbar_grabbed()) + && (is_mouse_over || state.currently_grabbed()) { - let ratio = bounds.height / content_bounds.height; - let scrollbar_height = bounds.height * ratio; - let y_offset = offset as f32 * ratio; - + let scroller_bounds = scroller_bounds( + bounds, + content_bounds, + background_bounds, + offset, + ); let scrollbar = Primitive::Quad { - bounds: Rectangle { - x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN), - y: scrollbar_bounds.y + y_offset, - width: scrollbar_bounds.width - - f32::from(2 * SCROLLBAR_MARGIN), - height: scrollbar_height, - }, + bounds: scroller_bounds, background: Background::Color([0.0, 0.0, 0.0, 0.7].into()), border_radius: 5, }; - if is_mouse_over_scrollbar || state.is_scrollbar_grabbed() { + if is_mouse_over_scrollbar || state.currently_grabbed() { let scrollbar_background = Primitive::Quad { bounds: Rectangle { - x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN), - width: scrollbar_bounds.width + x: background_bounds.x + + f32::from(SCROLLBAR_MARGIN), + width: background_bounds.width - f32::from(2 * SCROLLBAR_MARGIN), - ..scrollbar_bounds + ..background_bounds }, background: Background::Color( [0.0, 0.0, 0.0, 0.3].into(), @@ -91,7 +127,7 @@ impl scrollable::Renderer for Renderer { } else { clip }, - if is_mouse_over_scrollbar || state.is_scrollbar_grabbed() { + if is_mouse_over_scrollbar || state.currently_grabbed() { MouseCursor::Idle } else { mouse_cursor |