From 719c073fc67c87d6b2da1bc01b74751d3f5e59f0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 25 Oct 2019 03:47:34 +0200 Subject: Draft `Scrollable` widget (no clipping yet!) --- core/src/widget.rs | 4 ++ core/src/widget/scrollable.rs | 122 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 core/src/widget/scrollable.rs (limited to 'core/src') diff --git a/core/src/widget.rs b/core/src/widget.rs index f9d4bf2a..3ee8e347 100644 --- a/core/src/widget.rs +++ b/core/src/widget.rs @@ -14,6 +14,7 @@ mod radio; mod row; pub mod button; +pub mod scrollable; pub mod slider; pub mod text; @@ -26,6 +27,9 @@ pub use slider::Slider; #[doc(no_inline)] pub use text::Text; +#[doc(no_inline)] +pub use scrollable::Scrollable; + pub use checkbox::Checkbox; pub use column::Column; pub use image::Image; diff --git a/core/src/widget/scrollable.rs b/core/src/widget/scrollable.rs new file mode 100644 index 00000000..dd62b658 --- /dev/null +++ b/core/src/widget/scrollable.rs @@ -0,0 +1,122 @@ +use crate::{Align, Column, Justify, Length}; + +#[derive(Debug)] +pub struct Scrollable<'a, Element> { + pub state: &'a mut State, + pub height: Length, + pub align_self: Option, + pub align_items: Align, + pub content: Column, +} + +impl<'a, Element> Scrollable<'a, Element> { + pub fn new(state: &'a mut State) -> Self { + Scrollable { + state, + height: Length::Shrink, + align_self: None, + align_items: Align::Start, + content: Column::new(), + } + } + + /// Sets the vertical spacing _between_ elements. + /// + /// Custom margins per element do not exist in Iced. You should use this + /// method instead! While less flexible, it helps you keep spacing between + /// elements consistent. + pub fn spacing(mut self, units: u16) -> Self { + self.content = self.content.spacing(units); + self + } + + /// Sets the padding of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn padding(mut self, units: u16) -> Self { + self.content = self.content.padding(units); + self + } + + /// Sets the width of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn width(mut self, width: Length) -> Self { + self.content = self.content.width(width); + self + } + + /// Sets the height of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + /// Sets the maximum width of the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn max_width(mut self, max_width: Length) -> Self { + self.content = self.content.max_width(max_width); + self + } + + /// Sets the maximum height of the [`Column`] in pixels. + /// + /// [`Column`]: struct.Column.html + pub fn max_height(mut self, max_height: Length) -> Self { + self.content = self.content.max_height(max_height); + self + } + + /// Sets the alignment of the [`Column`] itself. + /// + /// This is useful if you want to override the default alignment given by + /// the parent container. + /// + /// [`Column`]: struct.Column.html + pub fn align_self(mut self, align: Align) -> Self { + self.align_self = Some(align); + self + } + + /// Sets the horizontal alignment of the contents of the [`Column`] . + /// + /// [`Column`]: struct.Column.html + pub fn align_items(mut self, align_items: Align) -> Self { + self.align_items = align_items; + self + } + + /// Sets the vertical distribution strategy for the contents of the + /// [`Column`] . + /// + /// [`Column`]: struct.Column.html + pub fn justify_content(mut self, justify: Justify) -> Self { + self.content = self.content.justify_content(justify); + self + } + + /// Adds an element to the [`Column`]. + /// + /// [`Column`]: struct.Column.html + pub fn push(mut self, child: E) -> Scrollable<'a, Element> + where + E: Into, + { + self.content = self.content.push(child); + self + } +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct State { + pub offset: u32, +} + +impl State { + pub fn new() -> Self { + State::default() + } +} -- cgit From 09bd2c46c06eba72da40852d82a52e7353cc9e9b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 27 Oct 2019 01:24:08 +0200 Subject: Expose scrollable offset properly --- core/src/widget/scrollable.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'core/src') diff --git a/core/src/widget/scrollable.rs b/core/src/widget/scrollable.rs index dd62b658..4e5c4ad0 100644 --- a/core/src/widget/scrollable.rs +++ b/core/src/widget/scrollable.rs @@ -1,4 +1,4 @@ -use crate::{Align, Column, Justify, Length}; +use crate::{Align, Column, Justify, Length, Rectangle}; #[derive(Debug)] pub struct Scrollable<'a, Element> { @@ -112,11 +112,35 @@ impl<'a, Element> Scrollable<'a, Element> { #[derive(Debug, Clone, Copy, Default)] pub struct State { - pub offset: u32, + offset: u32, } impl State { pub fn new() -> Self { State::default() } + + pub fn scroll( + &mut self, + delta_y: f32, + bounds: Rectangle, + content_bounds: Rectangle, + ) { + if bounds.height >= content_bounds.height { + return; + } + + // TODO: Configurable speed (?) + self.offset = (self.offset as i32 - delta_y.round() as i32 * 15) + .max(0) + .min((content_bounds.height - bounds.height) as i32) + as u32; + } + + pub fn offset(&self, bounds: Rectangle, content_bounds: Rectangle) -> u32 { + let hidden_content = + (content_bounds.height - bounds.height).round() as u32; + + self.offset.min(hidden_content).max(0) + } } -- cgit From 63c10b67ab213c5971313743fde566bd5c0f0c15 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 27 Oct 2019 01:37:40 +0200 Subject: Remove `Scrollable::justify_content` method --- core/src/widget/scrollable.rs | 47 ++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) (limited to 'core/src') diff --git a/core/src/widget/scrollable.rs b/core/src/widget/scrollable.rs index 4e5c4ad0..ef3bc1db 100644 --- a/core/src/widget/scrollable.rs +++ b/core/src/widget/scrollable.rs @@ -1,9 +1,10 @@ -use crate::{Align, Column, Justify, Length, Rectangle}; +use crate::{Align, Column, Length, Rectangle}; #[derive(Debug)] pub struct Scrollable<'a, Element> { pub state: &'a mut State, pub height: Length, + pub max_height: Length, pub align_self: Option, pub align_items: Align, pub content: Column, @@ -14,6 +15,7 @@ impl<'a, Element> Scrollable<'a, Element> { Scrollable { state, height: Length::Shrink, + max_height: Length::Shrink, align_self: None, align_items: Align::Start, content: Column::new(), @@ -30,77 +32,68 @@ impl<'a, Element> Scrollable<'a, Element> { self } - /// Sets the padding of the [`Column`]. + /// Sets the padding of the [`Scrollable`]. /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn padding(mut self, units: u16) -> Self { self.content = self.content.padding(units); self } - /// Sets the width of the [`Column`]. + /// Sets the width of the [`Scrollable`]. /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn width(mut self, width: Length) -> Self { self.content = self.content.width(width); self } - /// Sets the height of the [`Column`]. + /// Sets the height of the [`Scrollable`]. /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn height(mut self, height: Length) -> Self { self.height = height; self } - /// Sets the maximum width of the [`Column`]. + /// Sets the maximum width of the [`Scrollable`]. /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn max_width(mut self, max_width: Length) -> Self { self.content = self.content.max_width(max_width); self } - /// Sets the maximum height of the [`Column`] in pixels. + /// Sets the maximum height of the [`Scrollable`] in pixels. /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn max_height(mut self, max_height: Length) -> Self { - self.content = self.content.max_height(max_height); + self.max_height = max_height; self } - /// Sets the alignment of the [`Column`] itself. + /// Sets the alignment of the [`Scrollable`] itself. /// /// This is useful if you want to override the default alignment given by /// the parent container. /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn align_self(mut self, align: Align) -> Self { self.align_self = Some(align); self } - /// Sets the horizontal alignment of the contents of the [`Column`] . + /// Sets the horizontal alignment of the contents of the [`Scrollable`] . /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn align_items(mut self, align_items: Align) -> Self { self.align_items = align_items; self } - /// Sets the vertical distribution strategy for the contents of the - /// [`Column`] . + /// Adds an element to the [`Scrollable`]. /// - /// [`Column`]: struct.Column.html - pub fn justify_content(mut self, justify: Justify) -> Self { - self.content = self.content.justify_content(justify); - self - } - - /// Adds an element to the [`Column`]. - /// - /// [`Column`]: struct.Column.html + /// [`Scrollable`]: struct.Scrollable.html pub fn push(mut self, child: E) -> Scrollable<'a, Element> where E: Into, -- cgit From 82c2aa6bfd1ed90b32b303a900e13b2c07bc69ba Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 27 Oct 2019 02:59:25 +0100 Subject: Align items properly inside a `Scrollable` --- core/src/widget/scrollable.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'core/src') diff --git a/core/src/widget/scrollable.rs b/core/src/widget/scrollable.rs index ef3bc1db..1bad8555 100644 --- a/core/src/widget/scrollable.rs +++ b/core/src/widget/scrollable.rs @@ -6,7 +6,6 @@ pub struct Scrollable<'a, Element> { pub height: Length, pub max_height: Length, pub align_self: Option, - pub align_items: Align, pub content: Column, } @@ -17,7 +16,6 @@ impl<'a, Element> Scrollable<'a, Element> { height: Length::Shrink, max_height: Length::Shrink, align_self: None, - align_items: Align::Start, content: Column::new(), } } @@ -87,7 +85,7 @@ impl<'a, Element> Scrollable<'a, Element> { /// /// [`Scrollable`]: struct.Scrollable.html pub fn align_items(mut self, align_items: Align) -> Self { - self.align_items = align_items; + self.content = self.content.align_items(align_items); self } -- cgit From 29588f604af66fb4911f791c0c402fccd30ba64b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 29 Oct 2019 05:09:54 +0100 Subject: Implement scrollbar interactions! :tada: --- core/src/widget/scrollable.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'core/src') diff --git a/core/src/widget/scrollable.rs b/core/src/widget/scrollable.rs index 1bad8555..31a5abed 100644 --- a/core/src/widget/scrollable.rs +++ b/core/src/widget/scrollable.rs @@ -1,4 +1,4 @@ -use crate::{Align, Column, Length, Rectangle}; +use crate::{Align, Column, Length, Point, Rectangle}; #[derive(Debug)] pub struct Scrollable<'a, Element> { @@ -103,6 +103,7 @@ impl<'a, Element> Scrollable<'a, Element> { #[derive(Debug, Clone, Copy, Default)] pub struct State { + pub scrollbar_grabbed_at: Option, offset: u32, } @@ -121,17 +122,30 @@ impl State { return; } - // TODO: Configurable speed (?) - self.offset = (self.offset as i32 - delta_y.round() as i32 * 15) + self.offset = (self.offset as i32 - delta_y.round() as i32) .max(0) .min((content_bounds.height - bounds.height) as i32) as u32; } + pub fn scroll_to( + &mut self, + percentage: f32, + bounds: Rectangle, + content_bounds: Rectangle, + ) { + self.offset = ((content_bounds.height - bounds.height) * percentage) + .max(0.0) as u32; + } + pub fn offset(&self, bounds: Rectangle, content_bounds: Rectangle) -> u32 { let hidden_content = (content_bounds.height - bounds.height).round() as u32; self.offset.min(hidden_content).max(0) } + + pub fn is_scrollbar_grabbed(&self) -> bool { + self.scrollbar_grabbed_at.is_some() + } } -- cgit