summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-10-18 14:48:33 +0700
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-10-18 14:48:33 +0700
commit54a9a232f8110364972a8eef966b7b7477573f4f (patch)
treea6abebbcfefbd53d4c4d006d6911353801ea3284
parenta4f4d831615899046d36c96e6a580d5386aa25bf (diff)
downloadiced-54a9a232f8110364972a8eef966b7b7477573f4f.tar.gz
iced-54a9a232f8110364972a8eef966b7b7477573f4f.tar.bz2
iced-54a9a232f8110364972a8eef966b7b7477573f4f.zip
Draw scrollbar in `Widget::draw` for `Scrollable`
-rw-r--r--examples/scrollable/src/main.rs2
-rw-r--r--examples/scrollable/src/style.rs4
-rw-r--r--examples/styling/src/main.rs6
-rw-r--r--graphics/src/widget/scrollable.rs64
-rw-r--r--native/Cargo.toml4
-rw-r--r--native/src/overlay/menu.rs4
-rw-r--r--native/src/renderer/null.rs16
-rw-r--r--native/src/widget/pick_list.rs3
-rw-r--r--native/src/widget/scrollable.rs207
-rw-r--r--style/src/scrollable.rs13
-rw-r--r--web/src/widget/scrollable.rs11
11 files changed, 135 insertions, 199 deletions
diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs
index 3416b83d..272f0ce2 100644
--- a/examples/scrollable/src/main.rs
+++ b/examples/scrollable/src/main.rs
@@ -95,7 +95,7 @@ impl Sandbox for ScrollableDemo {
.on_scroll(move |offset| {
Message::Scrolled(i, offset)
})
- .style(*theme)
+ .style(theme.clone().into())
.push(Text::new(variant.title))
.push(
Button::new(
diff --git a/examples/scrollable/src/style.rs b/examples/scrollable/src/style.rs
index ae449141..d955f52d 100644
--- a/examples/scrollable/src/style.rs
+++ b/examples/scrollable/src/style.rs
@@ -34,11 +34,11 @@ impl From<Theme> for Box<dyn radio::StyleSheet> {
}
}
-impl From<Theme> for Box<dyn scrollable::StyleSheet> {
+impl From<Theme> for &'static dyn scrollable::StyleSheet {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
- Theme::Dark => dark::Scrollable.into(),
+ Theme::Dark => &dark::Scrollable,
}
}
}
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index 81d33ad3..1746d7b4 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -98,7 +98,7 @@ impl Sandbox for Styling {
let scrollable = Scrollable::new(&mut self.scroll)
.width(Length::Fill)
.height(Length::Units(100))
- .style(self.theme)
+ .style(self.theme.into())
.push(Text::new("Scroll me!"))
.push(Space::with_height(Length::Units(800)))
.push(Text::new("You did it!"));
@@ -212,11 +212,11 @@ mod style {
}
}
- impl From<Theme> for Box<dyn scrollable::StyleSheet> {
+ impl From<Theme> for &'static dyn scrollable::StyleSheet {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
- Theme::Dark => dark::Scrollable.into(),
+ Theme::Dark => &dark::Scrollable,
}
}
}
diff --git a/graphics/src/widget/scrollable.rs b/graphics/src/widget/scrollable.rs
index f1fe0d2d..61eae587 100644
--- a/graphics/src/widget/scrollable.rs
+++ b/graphics/src/widget/scrollable.rs
@@ -1,7 +1,5 @@
//! Navigate an endless amount of content with a scrollbar.
-use crate::{Backend, Renderer};
-use iced_native::scrollable;
-use iced_native::Rectangle;
+use crate::Renderer;
pub use iced_native::scrollable::State;
pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet};
@@ -13,63 +11,3 @@ pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet};
/// `Renderer`.
pub type Scrollable<'a, Message, Backend> =
iced_native::Scrollable<'a, Message, Renderer<Backend>>;
-
-impl<B> scrollable::Renderer for Renderer<B>
-where
- B: Backend,
-{
- type Style = Box<dyn iced_style::scrollable::StyleSheet>;
-
- fn scrollbar(
- &self,
- bounds: Rectangle,
- content_bounds: Rectangle,
- offset: u32,
- scrollbar_width: u16,
- scrollbar_margin: u16,
- scroller_width: u16,
- ) -> Option<scrollable::Scrollbar> {
- if content_bounds.height > bounds.height {
- let outer_width =
- scrollbar_width.max(scroller_width) + 2 * scrollbar_margin;
-
- let outer_bounds = Rectangle {
- x: bounds.x + bounds.width - outer_width as f32,
- y: bounds.y,
- width: outer_width as f32,
- height: bounds.height,
- };
-
- let scrollbar_bounds = Rectangle {
- x: bounds.x + bounds.width
- - f32::from(outer_width / 2 + scrollbar_width / 2),
- y: bounds.y,
- width: scrollbar_width as f32,
- height: bounds.height,
- };
-
- let ratio = bounds.height / content_bounds.height;
- let scroller_height = bounds.height * ratio;
- let y_offset = offset as f32 * ratio;
-
- let scroller_bounds = Rectangle {
- x: bounds.x + bounds.width
- - f32::from(outer_width / 2 + scroller_width / 2),
- y: scrollbar_bounds.y + y_offset,
- width: scroller_width as f32,
- height: scroller_height,
- };
-
- Some(scrollable::Scrollbar {
- outer_bounds,
- bounds: scrollbar_bounds,
- margin: scrollbar_margin,
- scroller: scrollable::Scroller {
- bounds: scroller_bounds,
- },
- })
- } else {
- None
- }
- }
-}
diff --git a/native/Cargo.toml b/native/Cargo.toml
index a3134ef4..5de99b2e 100644
--- a/native/Cargo.toml
+++ b/native/Cargo.toml
@@ -23,3 +23,7 @@ path = "../core"
version = "0.3"
path = "../futures"
features = ["thread-pool"]
+
+[dependencies.iced_style]
+version = "0.3"
+path = "../style"
diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index f90a9f7b..c4f64f85 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -395,9 +395,7 @@ where
/// able to use a [`Menu`] in your user interface.
///
/// [renderer]: crate::renderer
-pub trait Renderer:
- scrollable::Renderer + container::Renderer + text::Renderer
-{
+pub trait Renderer: container::Renderer + text::Renderer {
/// The [`Menu`] style supported by this renderer.
type Style: Default + Clone;
}
diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs
index 1c026fde..960a5727 100644
--- a/native/src/renderer/null.rs
+++ b/native/src/renderer/null.rs
@@ -75,22 +75,6 @@ impl text::Renderer for Null {
}
}
-impl scrollable::Renderer for Null {
- type Style = ();
-
- fn scrollbar(
- &self,
- _bounds: Rectangle,
- _content_bounds: Rectangle,
- _offset: u32,
- _scrollbar_width: u16,
- _scrollbar_margin: u16,
- _scroller_width: u16,
- ) -> Option<scrollable::Scrollbar> {
- None
- }
-}
-
impl text_input::Renderer for Null {
type Style = ();
diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs
index 7154a572..73b01b01 100644
--- a/native/src/widget/pick_list.rs
+++ b/native/src/widget/pick_list.rs
@@ -5,7 +5,6 @@ use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::overlay::menu::{self, Menu};
-use crate::scrollable;
use crate::text;
use crate::touch;
use crate::{
@@ -145,7 +144,7 @@ where
T: Clone + ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>,
Message: 'static,
- Renderer: self::Renderer + scrollable::Renderer + 'a,
+ Renderer: self::Renderer + 'a,
{
fn width(&self) -> Length {
self.width
diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs
index ba3d3dd6..98357928 100644
--- a/native/src/widget/scrollable.rs
+++ b/native/src/widget/scrollable.rs
@@ -3,18 +3,21 @@ use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
use crate::overlay;
+use crate::renderer;
use crate::touch;
use crate::{
- Alignment, Clipboard, Column, Element, Hasher, Layout, Length, Padding,
- Point, Rectangle, Size, Vector, Widget,
+ Alignment, Background, Clipboard, Color, Column, Element, Hasher, Layout,
+ Length, Padding, Point, Rectangle, Size, Vector, Widget,
};
use std::{f32, hash::Hash, u32};
+pub use iced_style::scrollable::StyleSheet;
+
/// A widget that can vertically display an infinite amount of content with a
/// scrollbar.
#[allow(missing_debug_implementations)]
-pub struct Scrollable<'a, Message, Renderer: self::Renderer> {
+pub struct Scrollable<'a, Message, Renderer> {
state: &'a mut State,
height: Length,
max_height: u32,
@@ -23,10 +26,10 @@ pub struct Scrollable<'a, Message, Renderer: self::Renderer> {
scroller_width: u16,
content: Column<'a, Message, Renderer>,
on_scroll: Option<Box<dyn Fn(f32) -> Message>>,
- style: Renderer::Style,
+ style_sheet: &'a dyn StyleSheet,
}
-impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
+impl<'a, Message, Renderer: crate::Renderer> Scrollable<'a, Message, Renderer> {
/// Creates a new [`Scrollable`] with the given [`State`].
pub fn new(state: &'a mut State) -> Self {
Scrollable {
@@ -38,7 +41,7 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
scroller_width: 10,
content: Column::new(),
on_scroll: None,
- style: Renderer::Style::default(),
+ style_sheet: Default::default(),
}
}
@@ -119,8 +122,11 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
}
/// Sets the style of the [`Scrollable`] .
- pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
- self.style = style.into();
+ pub fn style<'b>(mut self, style_sheet: &'b dyn StyleSheet) -> Self
+ where
+ 'b: 'a,
+ {
+ self.style_sheet = style_sheet;
self
}
@@ -150,12 +156,63 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
));
}
}
+
+ fn scrollbar(
+ &self,
+ bounds: Rectangle,
+ content_bounds: Rectangle,
+ ) -> Option<Scrollbar> {
+ let offset = self.state.offset(bounds, content_bounds);
+
+ if content_bounds.height > bounds.height {
+ let outer_width = self.scrollbar_width.max(self.scroller_width)
+ + 2 * self.scrollbar_margin;
+
+ let outer_bounds = Rectangle {
+ x: bounds.x + bounds.width - outer_width as f32,
+ y: bounds.y,
+ width: outer_width as f32,
+ height: bounds.height,
+ };
+
+ let scrollbar_bounds = Rectangle {
+ x: bounds.x + bounds.width
+ - f32::from(outer_width / 2 + self.scrollbar_width / 2),
+ y: bounds.y,
+ width: self.scrollbar_width as f32,
+ height: bounds.height,
+ };
+
+ let ratio = bounds.height / content_bounds.height;
+ let scroller_height = bounds.height * ratio;
+ let y_offset = offset as f32 * ratio;
+
+ let scroller_bounds = Rectangle {
+ x: bounds.x + bounds.width
+ - f32::from(outer_width / 2 + self.scroller_width / 2),
+ y: scrollbar_bounds.y + y_offset,
+ width: self.scroller_width as f32,
+ height: scroller_height,
+ };
+
+ Some(Scrollbar {
+ outer_bounds,
+ bounds: scrollbar_bounds,
+ margin: self.scrollbar_margin,
+ scroller: Scroller {
+ bounds: scroller_bounds,
+ },
+ })
+ } else {
+ None
+ }
+ }
}
impl<'a, Message, Renderer> Widget<Message, Renderer>
for Scrollable<'a, Message, Renderer>
where
- Renderer: self::Renderer,
+ Renderer: crate::Renderer,
{
fn width(&self) -> Length {
Widget::<Message, Renderer>::width(&self.content)
@@ -201,15 +258,7 @@ where
let content = layout.children().next().unwrap();
let content_bounds = content.bounds();
- let offset = self.state.offset(bounds, content_bounds);
- let scrollbar = renderer.scrollbar(
- bounds,
- content_bounds,
- offset,
- self.scrollbar_width,
- self.scrollbar_margin,
- self.scroller_width,
- );
+ let scrollbar = self.scrollbar(bounds, content_bounds);
let is_mouse_over_scrollbar = scrollbar
.as_ref()
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
@@ -385,14 +434,7 @@ where
let content_layout = layout.children().next().unwrap();
let content_bounds = content_layout.bounds();
let offset = self.state.offset(bounds, content_bounds);
- let scrollbar = renderer.scrollbar(
- bounds,
- content_bounds,
- offset,
- self.scrollbar_width,
- self.scrollbar_margin,
- self.scroller_width,
- );
+ let scrollbar = self.scrollbar(bounds, content_bounds);
let is_mouse_over = bounds.contains(cursor_position);
let is_mouse_over_scrollbar = scrollbar
@@ -420,43 +462,43 @@ where
);
});
- // TODO: Draw scroller
- // let style = if self.state.is_scroller_grabbed() {
- // style_sheet.dragging()
- // } else if is_mouse_over_scrollbar {
- // style_sheet.hovered()
- // } else {
- // style_sheet.active()
- // };
-
- // let is_scrollbar_visible =
- // style.background.is_some() || style.border_width > 0.0;
-
- // if is_mouse_over
- // || self.state.is_scroller_grabbed()
- // || is_scrollbar_visible
- // {
- // // Primitive::Quad {
- // // bounds: scrollbar.scroller.bounds,
- // // background: Background::Color(style.scroller.color),
- // // border_radius: style.scroller.border_radius,
- // // border_width: style.scroller.border_width,
- // // border_color: style.scroller.border_color,
- // // }
- // };
-
- // TODO: Draw scrollbar
- // if is_scrollbar_visible {
- // Primitive::Quad {
- // bounds: scrollbar.bounds,
- // background: style
- // .background
- // .unwrap_or(Background::Color(Color::TRANSPARENT)),
- // border_radius: style.border_radius,
- // border_width: style.border_width,
- // border_color: style.border_color,
- // }
- //}
+ let style = if self.state.is_scroller_grabbed() {
+ self.style_sheet.dragging()
+ } else if is_mouse_over_scrollbar {
+ self.style_sheet.hovered()
+ } else {
+ self.style_sheet.active()
+ };
+
+ let is_scrollbar_visible =
+ style.background.is_some() || style.border_width > 0.0;
+
+ renderer.with_layer(bounds, Vector::new(0, 0), |renderer| {
+ if is_scrollbar_visible {
+ renderer.fill_rectangle(renderer::Quad {
+ bounds: scrollbar.bounds,
+ background: style
+ .background
+ .unwrap_or(Background::Color(Color::TRANSPARENT)),
+ border_radius: style.border_radius,
+ border_width: style.border_width,
+ border_color: style.border_color,
+ });
+ }
+
+ if is_mouse_over
+ || self.state.is_scroller_grabbed()
+ || is_scrollbar_visible
+ {
+ renderer.fill_rectangle(renderer::Quad {
+ bounds: scrollbar.scroller.bounds,
+ background: Background::Color(style.scroller.color),
+ border_radius: style.scroller.border_radius,
+ border_width: style.scroller.border_width,
+ border_color: style.scroller.border_color,
+ });
+ }
+ });
} else {
self.content.draw(
renderer,
@@ -614,19 +656,19 @@ impl State {
/// The scrollbar of a [`Scrollable`].
#[derive(Debug)]
-pub struct Scrollbar {
+struct Scrollbar {
/// The outer bounds of the scrollable, including the [`Scrollbar`] and
/// [`Scroller`].
- pub outer_bounds: Rectangle,
+ outer_bounds: Rectangle,
/// The bounds of the [`Scrollbar`].
- pub bounds: Rectangle,
+ bounds: Rectangle,
/// The margin within the [`Scrollbar`].
- pub margin: u16,
+ margin: u16,
/// The bounds of the [`Scroller`].
- pub scroller: Scroller,
+ scroller: Scroller,
}
impl Scrollbar {
@@ -661,38 +703,15 @@ impl Scrollbar {
/// The handle of a [`Scrollbar`].
#[derive(Debug, Clone, Copy)]
-pub struct Scroller {
+struct Scroller {
/// The bounds of the [`Scroller`].
- pub bounds: Rectangle,
-}
-
-/// The renderer of a [`Scrollable`].
-///
-/// Your [renderer] will need to implement this trait before being
-/// able to use a [`Scrollable`] in your user interface.
-///
-/// [renderer]: crate::renderer
-pub trait Renderer: crate::Renderer + Sized {
- /// The style supported by this renderer.
- type Style: Default;
-
- /// Returns the [`Scrollbar`] given the bounds and content bounds of a
- /// [`Scrollable`].
- fn scrollbar(
- &self,
- bounds: Rectangle,
- content_bounds: Rectangle,
- offset: u32,
- scrollbar_width: u16,
- scrollbar_margin: u16,
- scroller_width: u16,
- ) -> Option<Scrollbar>;
+ bounds: Rectangle,
}
impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
- Renderer: 'a + self::Renderer,
+ Renderer: 'a + crate::Renderer,
Message: 'a,
{
fn from(
diff --git a/style/src/scrollable.rs b/style/src/scrollable.rs
index 65da9803..741d9d39 100644
--- a/style/src/scrollable.rs
+++ b/style/src/scrollable.rs
@@ -60,17 +60,8 @@ impl StyleSheet for Default {
}
}
-impl std::default::Default for Box<dyn StyleSheet> {
+impl std::default::Default for &'static dyn StyleSheet {
fn default() -> Self {
- Box::new(Default)
- }
-}
-
-impl<T> From<T> for Box<dyn StyleSheet>
-where
- T: 'static + StyleSheet,
-{
- fn from(style: T) -> Self {
- Box::new(style)
+ &Default
}
}
diff --git a/web/src/widget/scrollable.rs b/web/src/widget/scrollable.rs
index 847bf5a0..595eb26e 100644
--- a/web/src/widget/scrollable.rs
+++ b/web/src/widget/scrollable.rs
@@ -14,7 +14,7 @@ pub struct Scrollable<'a, Message> {
max_height: u32,
content: Column<'a, Message>,
#[allow(dead_code)]
- style: Box<dyn StyleSheet>,
+ style_sheet: &'a dyn StyleSheet,
}
impl<'a, Message> Scrollable<'a, Message> {
@@ -27,7 +27,7 @@ impl<'a, Message> Scrollable<'a, Message> {
height: Length::Shrink,
max_height: u32::MAX,
content: Column::new(),
- style: Default::default(),
+ style_sheet: Default::default(),
}
}
@@ -78,8 +78,11 @@ impl<'a, Message> Scrollable<'a, Message> {
}
/// Sets the style of the [`Scrollable`] .
- pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self {
- self.style = style.into();
+ pub fn style<'b>(mut self, style_sheet: &'b dyn StyleSheet) -> Self
+ where
+ 'b: 'a,
+ {
+ self.style_sheet = style_sheet;
self
}