summaryrefslogtreecommitdiffstats
path: root/native
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 /native
parenta4f4d831615899046d36c96e6a580d5386aa25bf (diff)
downloadiced-54a9a232f8110364972a8eef966b7b7477573f4f.tar.gz
iced-54a9a232f8110364972a8eef966b7b7477573f4f.tar.bz2
iced-54a9a232f8110364972a8eef966b7b7477573f4f.zip
Draw scrollbar in `Widget::draw` for `Scrollable`
Diffstat (limited to '')
-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
5 files changed, 119 insertions, 115 deletions
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(