Add multidirectional scrolling capabilities to the existing Scrollable.
This commit is contained in:
parent
a6d0d5773f
commit
d91f4f6aa7
12 changed files with 1148 additions and 576 deletions
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::{Padding, Vector};
|
use crate::{Padding, Vector};
|
||||||
use std::f32;
|
|
||||||
|
|
||||||
/// An amount of space in 2 dimensions.
|
/// An amount of space in 2 dimensions.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ A bunch of simpler examples exist:
|
||||||
- [`pick_list`](pick_list), a dropdown list of selectable options.
|
- [`pick_list`](pick_list), a dropdown list of selectable options.
|
||||||
- [`pokedex`](pokedex), an application that displays a random Pokédex entry (sprite included!) by using the [PokéAPI].
|
- [`pokedex`](pokedex), an application that displays a random Pokédex entry (sprite included!) by using the [PokéAPI].
|
||||||
- [`progress_bar`](progress_bar), a simple progress bar that can be filled by using a slider.
|
- [`progress_bar`](progress_bar), a simple progress bar that can be filled by using a slider.
|
||||||
- [`scrollable`](scrollable), a showcase of the various scrollbar width options.
|
- [`scrollable`](scrollable), a showcase of various scrollable content configurations.
|
||||||
- [`sierpinski_triangle`](sierpinski_triangle), a [sierpiński triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle) Emulator, use `Canvas` and `Slider`.
|
- [`sierpinski_triangle`](sierpinski_triangle), a [sierpiński triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle) Emulator, use `Canvas` and `Slider`.
|
||||||
- [`solar_system`](solar_system), an animated solar system drawn using the `Canvas` widget and showcasing how to compose different transforms.
|
- [`solar_system`](solar_system), an animated solar system drawn using the `Canvas` widget and showcasing how to compose different transforms.
|
||||||
- [`stopwatch`](stopwatch), a watch with start/stop and reset buttons showcasing how to listen to time.
|
- [`stopwatch`](stopwatch), a watch with start/stop and reset buttons showcasing how to listen to time.
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,4 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced = { path = "../..", features = ["debug"] }
|
iced = { path = "../..", features = ["debug"] }
|
||||||
|
lazy_static = "1.4"
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 509 KiB |
|
|
@ -1,44 +1,60 @@
|
||||||
use iced::executor;
|
use iced::widget::scrollable::{Scrollbar, Scroller};
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
button, column, container, horizontal_rule, progress_bar, radio,
|
button, column, container, horizontal_space, progress_bar, radio, row,
|
||||||
scrollable, text, vertical_space, Row,
|
scrollable, slider, text, vertical_space,
|
||||||
};
|
};
|
||||||
|
use iced::{executor, theme, Alignment, Color, Vector};
|
||||||
use iced::{Application, Command, Element, Length, Settings, Theme};
|
use iced::{Application, Command, Element, Length, Settings, Theme};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SCROLLABLE_ID: scrollable::Id = scrollable::Id::unique();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
pub fn main() -> iced::Result {
|
||||||
ScrollableDemo::run(Settings::default())
|
ScrollableDemo::run(Settings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScrollableDemo {
|
struct ScrollableDemo {
|
||||||
theme: Theme,
|
scrollable_direction: Direction,
|
||||||
variants: Vec<Variant>,
|
scrollbar_width: u16,
|
||||||
|
scrollbar_margin: u16,
|
||||||
|
scroller_width: u16,
|
||||||
|
current_scroll_offset: Vector<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, Clone, Eq, PartialEq, Copy)]
|
||||||
enum ThemeType {
|
enum Direction {
|
||||||
Light,
|
Vertical,
|
||||||
Dark,
|
Horizontal,
|
||||||
|
Multi,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
ThemeChanged(ThemeType),
|
SwitchDirection(Direction),
|
||||||
ScrollToTop(usize),
|
ScrollbarWidthChanged(u16),
|
||||||
ScrollToBottom(usize),
|
ScrollbarMarginChanged(u16),
|
||||||
Scrolled(usize, f32),
|
ScrollerWidthChanged(u16),
|
||||||
|
ScrollToBeginning(scrollable::Direction),
|
||||||
|
ScrollToEnd(scrollable::Direction),
|
||||||
|
Scrolled(Vector<f32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application for ScrollableDemo {
|
impl Application for ScrollableDemo {
|
||||||
|
type Executor = executor::Default;
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
type Theme = Theme;
|
type Theme = Theme;
|
||||||
type Executor = executor::Default;
|
|
||||||
type Flags = ();
|
type Flags = ();
|
||||||
|
|
||||||
fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
|
fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
|
||||||
(
|
(
|
||||||
ScrollableDemo {
|
ScrollableDemo {
|
||||||
theme: Default::default(),
|
scrollable_direction: Direction::Vertical,
|
||||||
variants: Variant::all(),
|
scrollbar_width: 10,
|
||||||
|
scrollbar_margin: 0,
|
||||||
|
scroller_width: 10,
|
||||||
|
current_scroll_offset: Vector::new(0.0, 0.0),
|
||||||
},
|
},
|
||||||
Command::none(),
|
Command::none(),
|
||||||
)
|
)
|
||||||
|
|
@ -50,209 +66,333 @@ impl Application for ScrollableDemo {
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Command<Message> {
|
fn update(&mut self, message: Message) -> Command<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::ThemeChanged(theme) => {
|
Message::SwitchDirection(direction) => {
|
||||||
self.theme = match theme {
|
self.current_scroll_offset = Vector::new(0.0, 0.0);
|
||||||
ThemeType::Light => Theme::Light,
|
self.scrollable_direction = direction;
|
||||||
ThemeType::Dark => Theme::Dark,
|
|
||||||
};
|
|
||||||
|
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
Message::ScrollToTop(i) => {
|
Message::ScrollbarWidthChanged(width) => {
|
||||||
if let Some(variant) = self.variants.get_mut(i) {
|
self.scrollbar_width = width;
|
||||||
variant.latest_offset = 0.0;
|
|
||||||
|
|
||||||
scrollable::snap_to(Variant::id(i), 0.0)
|
Command::none()
|
||||||
} else {
|
|
||||||
Command::none()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Message::ScrollToBottom(i) => {
|
Message::ScrollbarMarginChanged(margin) => {
|
||||||
if let Some(variant) = self.variants.get_mut(i) {
|
self.scrollbar_margin = margin;
|
||||||
variant.latest_offset = 1.0;
|
|
||||||
|
|
||||||
scrollable::snap_to(Variant::id(i), 1.0)
|
Command::none()
|
||||||
} else {
|
|
||||||
Command::none()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Message::Scrolled(i, offset) => {
|
Message::ScrollerWidthChanged(width) => {
|
||||||
if let Some(variant) = self.variants.get_mut(i) {
|
self.scroller_width = width;
|
||||||
variant.latest_offset = offset;
|
|
||||||
|
Command::none()
|
||||||
|
}
|
||||||
|
Message::ScrollToBeginning(direction) => {
|
||||||
|
match direction {
|
||||||
|
scrollable::Direction::Horizontal => {
|
||||||
|
self.current_scroll_offset.x = 0.0;
|
||||||
|
}
|
||||||
|
scrollable::Direction::Vertical => {
|
||||||
|
self.current_scroll_offset.y = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrollable::snap_to(
|
||||||
|
SCROLLABLE_ID.clone(),
|
||||||
|
Vector::new(
|
||||||
|
self.current_scroll_offset.x,
|
||||||
|
self.current_scroll_offset.y,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Message::ScrollToEnd(direction) => {
|
||||||
|
match direction {
|
||||||
|
scrollable::Direction::Horizontal => {
|
||||||
|
self.current_scroll_offset.x = 1.0;
|
||||||
|
}
|
||||||
|
scrollable::Direction::Vertical => {
|
||||||
|
self.current_scroll_offset.y = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollable::snap_to(
|
||||||
|
SCROLLABLE_ID.clone(),
|
||||||
|
Vector::new(
|
||||||
|
self.current_scroll_offset.x,
|
||||||
|
self.current_scroll_offset.y,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Message::Scrolled(offset) => {
|
||||||
|
self.current_scroll_offset = offset;
|
||||||
|
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let ScrollableDemo { variants, .. } = self;
|
let scrollbar_width_slider = slider(
|
||||||
|
0..=15,
|
||||||
let choose_theme = [ThemeType::Light, ThemeType::Dark].iter().fold(
|
self.scrollbar_width,
|
||||||
column!["Choose a theme:"].spacing(10),
|
Message::ScrollbarWidthChanged,
|
||||||
|column, option| {
|
|
||||||
column.push(radio(
|
|
||||||
format!("{:?}", option),
|
|
||||||
*option,
|
|
||||||
Some(*option),
|
|
||||||
Message::ThemeChanged,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
let scrollbar_margin_slider = slider(
|
||||||
|
0..=15,
|
||||||
|
self.scrollbar_margin,
|
||||||
|
Message::ScrollbarMarginChanged,
|
||||||
|
);
|
||||||
|
let scroller_width_slider =
|
||||||
|
slider(0..=15, self.scroller_width, Message::ScrollerWidthChanged);
|
||||||
|
|
||||||
let scrollable_row = Row::with_children(
|
let scroll_slider_controls = column![
|
||||||
variants
|
text("Scrollbar width:"),
|
||||||
.iter()
|
scrollbar_width_slider,
|
||||||
.enumerate()
|
text("Scrollbar margin:"),
|
||||||
.map(|(i, variant)| {
|
scrollbar_margin_slider,
|
||||||
let mut contents = column![
|
text("Scroller width:"),
|
||||||
variant.title,
|
scroller_width_slider,
|
||||||
button("Scroll to bottom",)
|
]
|
||||||
.width(Length::Fill)
|
.width(Length::Fill);
|
||||||
.padding(10)
|
|
||||||
.on_press(Message::ScrollToBottom(i)),
|
|
||||||
]
|
|
||||||
.padding(10)
|
|
||||||
.spacing(10)
|
|
||||||
.width(Length::Fill);
|
|
||||||
|
|
||||||
if let Some(scrollbar_width) = variant.scrollbar_width {
|
let scroll_orientation_controls = column(vec![
|
||||||
contents = contents.push(text(format!(
|
text("Scrollbar direction:").into(),
|
||||||
"scrollbar_width: {:?}",
|
radio(
|
||||||
scrollbar_width
|
"Vertical",
|
||||||
)));
|
Direction::Vertical,
|
||||||
}
|
Some(self.scrollable_direction),
|
||||||
|
Message::SwitchDirection,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
radio(
|
||||||
|
"Horizontal",
|
||||||
|
Direction::Horizontal,
|
||||||
|
Some(self.scrollable_direction),
|
||||||
|
Message::SwitchDirection,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
radio(
|
||||||
|
"Both!",
|
||||||
|
Direction::Multi,
|
||||||
|
Some(self.scrollable_direction),
|
||||||
|
Message::SwitchDirection,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.width(Length::Fill);
|
||||||
|
|
||||||
if let Some(scrollbar_margin) = variant.scrollbar_margin {
|
let scroll_controls =
|
||||||
contents = contents.push(text(format!(
|
row![scroll_slider_controls, scroll_orientation_controls]
|
||||||
"scrollbar_margin: {:?}",
|
.spacing(20)
|
||||||
scrollbar_margin
|
.width(Length::Fill);
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(scroller_width) = variant.scroller_width {
|
let scroll_to_end_button = |direction: scrollable::Direction| {
|
||||||
contents = contents.push(text(format!(
|
button("Scroll to end")
|
||||||
"scroller_width: {:?}",
|
.padding(10)
|
||||||
scroller_width
|
.width(Length::Units(120))
|
||||||
)));
|
.on_press(Message::ScrollToEnd(direction))
|
||||||
}
|
};
|
||||||
|
|
||||||
contents = contents
|
let scroll_to_beginning_button = |direction: scrollable::Direction| {
|
||||||
.push(vertical_space(Length::Units(100)))
|
button("Scroll to beginning")
|
||||||
.push(
|
.padding(10)
|
||||||
"Some content that should wrap within the \
|
.width(Length::Units(120))
|
||||||
scrollable. Let's output a lot of short words, so \
|
.on_press(Message::ScrollToBeginning(direction))
|
||||||
that we'll make sure to see how wrapping works \
|
};
|
||||||
with these scrollbars.",
|
|
||||||
)
|
|
||||||
.push(vertical_space(Length::Units(1200)))
|
|
||||||
.push("Middle")
|
|
||||||
.push(vertical_space(Length::Units(1200)))
|
|
||||||
.push("The End.")
|
|
||||||
.push(
|
|
||||||
button("Scroll to top")
|
|
||||||
.width(Length::Fill)
|
|
||||||
.padding(10)
|
|
||||||
.on_press(Message::ScrollToTop(i)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut scrollable = scrollable(contents)
|
|
||||||
.id(Variant::id(i))
|
|
||||||
.height(Length::Fill)
|
|
||||||
.on_scroll(move |offset| Message::Scrolled(i, offset));
|
|
||||||
|
|
||||||
if let Some(scrollbar_width) = variant.scrollbar_width {
|
|
||||||
scrollable =
|
|
||||||
scrollable.scrollbar_width(scrollbar_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(scrollbar_margin) = variant.scrollbar_margin {
|
|
||||||
scrollable =
|
|
||||||
scrollable.scrollbar_margin(scrollbar_margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(scroller_width) = variant.scroller_width {
|
|
||||||
scrollable = scrollable.scroller_width(scroller_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let scrollable_content: Element<Message> =
|
||||||
|
Element::from(match self.scrollable_direction {
|
||||||
|
Direction::Vertical => scrollable(
|
||||||
column![
|
column![
|
||||||
scrollable,
|
scroll_to_end_button(scrollable::Direction::Vertical),
|
||||||
progress_bar(0.0..=1.0, variant.latest_offset,)
|
text("Beginning!"),
|
||||||
|
vertical_space(Length::Units(1200)),
|
||||||
|
text("Middle!"),
|
||||||
|
vertical_space(Length::Units(1200)),
|
||||||
|
text("End!"),
|
||||||
|
scroll_to_beginning_button(
|
||||||
|
scrollable::Direction::Vertical
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.height(Length::Fill)
|
.align_items(Alignment::Center)
|
||||||
.spacing(10)
|
.padding([40, 0, 40, 0])
|
||||||
|
.spacing(40),
|
||||||
|
)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.scrollbar_width(self.scrollbar_width)
|
||||||
|
.scrollbar_margin(self.scrollbar_margin)
|
||||||
|
.scroller_width(self.scroller_width)
|
||||||
|
.id(SCROLLABLE_ID.clone())
|
||||||
|
.on_scroll(Message::Scrolled),
|
||||||
|
Direction::Horizontal => scrollable(
|
||||||
|
row![
|
||||||
|
scroll_to_end_button(scrollable::Direction::Horizontal),
|
||||||
|
text("Beginning!"),
|
||||||
|
horizontal_space(Length::Units(1200)),
|
||||||
|
text("Middle!"),
|
||||||
|
horizontal_space(Length::Units(1200)),
|
||||||
|
text("End!"),
|
||||||
|
scroll_to_beginning_button(
|
||||||
|
scrollable::Direction::Horizontal
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.height(Length::Units(450))
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.padding([0, 40, 0, 40])
|
||||||
|
.spacing(40),
|
||||||
|
)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.horizontal_scroll(
|
||||||
|
scrollable::Horizontal::new()
|
||||||
|
.scrollbar_height(self.scrollbar_width)
|
||||||
|
.scrollbar_margin(self.scrollbar_margin)
|
||||||
|
.scroller_height(self.scroller_width),
|
||||||
|
)
|
||||||
|
.style(theme::Scrollable::Custom(Box::new(
|
||||||
|
ScrollbarCustomStyle,
|
||||||
|
)))
|
||||||
|
.id(SCROLLABLE_ID.clone())
|
||||||
|
.on_scroll(Message::Scrolled),
|
||||||
|
Direction::Multi => scrollable(
|
||||||
|
//horizontal content
|
||||||
|
row![
|
||||||
|
column![
|
||||||
|
text("Let's do some scrolling!"),
|
||||||
|
vertical_space(Length::Units(2400))
|
||||||
|
],
|
||||||
|
scroll_to_end_button(scrollable::Direction::Horizontal),
|
||||||
|
text("Horizontal - Beginning!"),
|
||||||
|
horizontal_space(Length::Units(1200)),
|
||||||
|
//vertical content
|
||||||
|
column![
|
||||||
|
text("Horizontal - Middle!"),
|
||||||
|
scroll_to_end_button(
|
||||||
|
scrollable::Direction::Vertical
|
||||||
|
),
|
||||||
|
text("Vertical - Beginning!"),
|
||||||
|
vertical_space(Length::Units(1200)),
|
||||||
|
text("Vertical - Middle!"),
|
||||||
|
vertical_space(Length::Units(1200)),
|
||||||
|
text("Vertical - End!"),
|
||||||
|
scroll_to_beginning_button(
|
||||||
|
scrollable::Direction::Vertical
|
||||||
|
)
|
||||||
|
]
|
||||||
|
.align_items(Alignment::Fill)
|
||||||
|
.spacing(40),
|
||||||
|
horizontal_space(Length::Units(1200)),
|
||||||
|
text("Horizontal - End!"),
|
||||||
|
scroll_to_beginning_button(
|
||||||
|
scrollable::Direction::Horizontal
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.padding([0, 40, 0, 40])
|
||||||
|
.spacing(40),
|
||||||
|
)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.scrollbar_width(self.scrollbar_width)
|
||||||
|
.scrollbar_margin(self.scrollbar_margin)
|
||||||
|
.scroller_width(self.scroller_width)
|
||||||
|
.horizontal_scroll(
|
||||||
|
scrollable::Horizontal::new()
|
||||||
|
.scrollbar_height(self.scrollbar_width)
|
||||||
|
.scrollbar_margin(self.scrollbar_margin)
|
||||||
|
.scroller_height(self.scroller_width),
|
||||||
|
)
|
||||||
|
.style(theme::Scrollable::Custom(Box::new(
|
||||||
|
ScrollbarCustomStyle,
|
||||||
|
)))
|
||||||
|
.id(SCROLLABLE_ID.clone())
|
||||||
|
.on_scroll(Message::Scrolled),
|
||||||
|
});
|
||||||
|
|
||||||
|
let progress_bars: Element<Message> = match self.scrollable_direction {
|
||||||
|
Direction::Vertical => {
|
||||||
|
progress_bar(0.0..=1.0, self.current_scroll_offset.y).into()
|
||||||
|
}
|
||||||
|
Direction::Horizontal => {
|
||||||
|
progress_bar(0.0..=1.0, self.current_scroll_offset.x)
|
||||||
|
.style(theme::ProgressBar::Custom(Box::new(
|
||||||
|
ProgressBarCustomStyle,
|
||||||
|
)))
|
||||||
.into()
|
.into()
|
||||||
})
|
}
|
||||||
.collect(),
|
Direction::Multi => column![
|
||||||
|
progress_bar(0.0..=1.0, self.current_scroll_offset.y),
|
||||||
|
progress_bar(0.0..=1.0, self.current_scroll_offset.x).style(
|
||||||
|
theme::ProgressBar::Custom(Box::new(
|
||||||
|
ProgressBarCustomStyle,
|
||||||
|
))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
.spacing(10)
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let content: Element<Message> =
|
||||||
|
column![scroll_controls, scrollable_content, progress_bars]
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.spacing(10)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Element::from(
|
||||||
|
container(content)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.padding(40)
|
||||||
|
.center_x()
|
||||||
|
.center_y(),
|
||||||
)
|
)
|
||||||
.spacing(20)
|
|
||||||
.width(Length::Fill)
|
|
||||||
.height(Length::Fill);
|
|
||||||
|
|
||||||
let content =
|
|
||||||
column![choose_theme, horizontal_rule(20), scrollable_row]
|
|
||||||
.spacing(20)
|
|
||||||
.padding(20);
|
|
||||||
|
|
||||||
container(content)
|
|
||||||
.width(Length::Fill)
|
|
||||||
.height(Length::Fill)
|
|
||||||
.center_x()
|
|
||||||
.center_y()
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn theme(&self) -> Theme {
|
fn theme(&self) -> Self::Theme {
|
||||||
self.theme.clone()
|
Theme::Dark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A version of a scrollable
|
struct ScrollbarCustomStyle;
|
||||||
struct Variant {
|
|
||||||
title: &'static str,
|
|
||||||
scrollbar_width: Option<u16>,
|
|
||||||
scrollbar_margin: Option<u16>,
|
|
||||||
scroller_width: Option<u16>,
|
|
||||||
latest_offset: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Variant {
|
impl scrollable::StyleSheet for ScrollbarCustomStyle {
|
||||||
pub fn all() -> Vec<Self> {
|
type Style = Theme;
|
||||||
vec![
|
|
||||||
Self {
|
fn active(&self, style: &Self::Style) -> Scrollbar {
|
||||||
title: "Default Scrollbar",
|
style.active(&theme::Scrollable::Default)
|
||||||
scrollbar_width: None,
|
|
||||||
scrollbar_margin: None,
|
|
||||||
scroller_width: None,
|
|
||||||
latest_offset: 0.0,
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
title: "Slimmed & Margin",
|
|
||||||
scrollbar_width: Some(4),
|
|
||||||
scrollbar_margin: Some(3),
|
|
||||||
scroller_width: Some(4),
|
|
||||||
latest_offset: 0.0,
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
title: "Wide Scroller",
|
|
||||||
scrollbar_width: Some(4),
|
|
||||||
scrollbar_margin: None,
|
|
||||||
scroller_width: Some(10),
|
|
||||||
latest_offset: 0.0,
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
title: "Narrow Scroller",
|
|
||||||
scrollbar_width: Some(10),
|
|
||||||
scrollbar_margin: None,
|
|
||||||
scroller_width: Some(4),
|
|
||||||
latest_offset: 0.0,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(i: usize) -> scrollable::Id {
|
fn hovered(&self, style: &Self::Style) -> Scrollbar {
|
||||||
scrollable::Id::new(format!("scrollable-{}", i))
|
style.hovered(&theme::Scrollable::Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered_horizontal(&self, style: &Self::Style) -> Scrollbar {
|
||||||
|
Scrollbar {
|
||||||
|
background: style.active(&theme::Scrollable::default()).background,
|
||||||
|
border_radius: 0.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Default::default(),
|
||||||
|
scroller: Scroller {
|
||||||
|
color: Color::from_rgb8(250, 85, 134),
|
||||||
|
border_radius: 0.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Default::default(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProgressBarCustomStyle;
|
||||||
|
|
||||||
|
impl progress_bar::StyleSheet for ProgressBarCustomStyle {
|
||||||
|
type Style = Theme;
|
||||||
|
|
||||||
|
fn appearance(&self, style: &Self::Style) -> progress_bar::Appearance {
|
||||||
|
progress_bar::Appearance {
|
||||||
|
background: style.extended_palette().background.strong.color.into(),
|
||||||
|
bar: Color::from_rgb8(250, 85, 134).into(),
|
||||||
|
border_radius: 0.0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
mod echo;
|
mod echo;
|
||||||
|
|
||||||
use iced::alignment::{self, Alignment};
|
use iced::alignment::{self, Alignment};
|
||||||
use iced::executor;
|
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
button, column, container, row, scrollable, text, text_input, Column,
|
button, column, container, row, scrollable, text, text_input, Column,
|
||||||
};
|
};
|
||||||
|
use iced::{executor, Vector};
|
||||||
use iced::{
|
use iced::{
|
||||||
Application, Color, Command, Element, Length, Settings, Subscription, Theme,
|
Application, Color, Command, Element, Length, Settings, Subscription, Theme,
|
||||||
};
|
};
|
||||||
|
|
@ -81,7 +81,10 @@ impl Application for WebSocket {
|
||||||
echo::Event::MessageReceived(message) => {
|
echo::Event::MessageReceived(message) => {
|
||||||
self.messages.push(message);
|
self.messages.push(message);
|
||||||
|
|
||||||
scrollable::snap_to(MESSAGE_LOG.clone(), 1.0)
|
scrollable::snap_to(
|
||||||
|
MESSAGE_LOG.clone(),
|
||||||
|
Vector::new(0.0, 1.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::Server => Command::none(),
|
Message::Server => Command::none(),
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,6 @@ use crate::{
|
||||||
Shell, Widget,
|
Shell, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::u32;
|
|
||||||
|
|
||||||
/// A container that distributes its contents vertically.
|
/// A container that distributes its contents vertically.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Column<'a, Message, Renderer> {
|
pub struct Column<'a, Message, Renderer> {
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,22 @@
|
||||||
//! Operate on widgets that can be scrolled.
|
//! Operate on widgets that can be scrolled.
|
||||||
use crate::widget::{Id, Operation};
|
use crate::widget::{Id, Operation};
|
||||||
|
use iced_core::Vector;
|
||||||
|
|
||||||
/// The internal state of a widget that can be scrolled.
|
/// The internal state of a widget that can be scrolled.
|
||||||
pub trait Scrollable {
|
pub trait Scrollable {
|
||||||
/// Snaps the scroll of the widget to the given `percentage`.
|
/// Snaps the scroll of the widget to the given `percentage`.
|
||||||
fn snap_to(&mut self, percentage: f32);
|
fn snap_to(&mut self, percentage: Vector<f32>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produces an [`Operation`] that snaps the widget with the given [`Id`] to
|
/// Produces an [`Operation`] that snaps the widget with the given [`Id`] to
|
||||||
/// the provided `percentage`.
|
/// the provided `percentage`.
|
||||||
pub fn snap_to<T>(target: Id, percentage: f32) -> impl Operation<T> {
|
pub fn snap_to<T>(target: Id, percentage: Vector<f32>) -> impl Operation<T> {
|
||||||
struct SnapTo {
|
struct SnapTo {
|
||||||
target: Id,
|
target: Id,
|
||||||
percentage: f32,
|
percentage: Vector<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for SnapTo {
|
impl<T> Operation<T> for SnapTo {
|
||||||
fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) {
|
|
||||||
if Some(&self.target) == id {
|
|
||||||
state.snap_to(self.percentage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn container(
|
fn container(
|
||||||
&mut self,
|
&mut self,
|
||||||
_id: Option<&Id>,
|
_id: Option<&Id>,
|
||||||
|
|
@ -29,6 +24,12 @@ pub fn snap_to<T>(target: Id, percentage: f32) -> impl Operation<T> {
|
||||||
) {
|
) {
|
||||||
operate_on_children(self)
|
operate_on_children(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) {
|
||||||
|
if Some(&self.target) == id {
|
||||||
|
state.snap_to(self.percentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SnapTo { target, percentage }
|
SnapTo { target, percentage }
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -99,7 +99,8 @@ pub mod radio {
|
||||||
pub mod scrollable {
|
pub mod scrollable {
|
||||||
//! Navigate an endless amount of content with a scrollbar.
|
//! Navigate an endless amount of content with a scrollbar.
|
||||||
pub use iced_native::widget::scrollable::{
|
pub use iced_native::widget::scrollable::{
|
||||||
snap_to, style::Scrollbar, style::Scroller, Id, StyleSheet,
|
snap_to, style::Scrollbar, style::Scroller, Direction, Horizontal, Id,
|
||||||
|
StyleSheet,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A widget that can vertically display an infinite amount of content
|
/// A widget that can vertically display an infinite amount of content
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,26 @@ pub trait StyleSheet {
|
||||||
/// Produces the style of an active scrollbar.
|
/// Produces the style of an active scrollbar.
|
||||||
fn active(&self, style: &Self::Style) -> Scrollbar;
|
fn active(&self, style: &Self::Style) -> Scrollbar;
|
||||||
|
|
||||||
/// Produces the style of an hovered scrollbar.
|
/// Produces the style of a hovered scrollbar.
|
||||||
fn hovered(&self, style: &Self::Style) -> Scrollbar;
|
fn hovered(&self, style: &Self::Style) -> Scrollbar;
|
||||||
|
|
||||||
/// Produces the style of a scrollbar that is being dragged.
|
/// Produces the style of a scrollbar that is being dragged.
|
||||||
fn dragging(&self, style: &Self::Style) -> Scrollbar {
|
fn dragging(&self, style: &Self::Style) -> Scrollbar {
|
||||||
self.hovered(style)
|
self.hovered(style)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces the style of an active horizontal scrollbar.
|
||||||
|
fn active_horizontal(&self, style: &Self::Style) -> Scrollbar {
|
||||||
|
self.active(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produces the style of a hovered horizontal scrollbar.
|
||||||
|
fn hovered_horizontal(&self, style: &Self::Style) -> Scrollbar {
|
||||||
|
self.hovered(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produces the style of a horizontal scrollbar that is being dragged.
|
||||||
|
fn dragging_horizontal(&self, style: &Self::Style) -> Scrollbar {
|
||||||
|
self.hovered_horizontal(style)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -925,6 +925,30 @@ impl scrollable::StyleSheet for Theme {
|
||||||
Scrollable::Custom(custom) => custom.dragging(self),
|
Scrollable::Custom(custom) => custom.dragging(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn active_horizontal(&self, style: &Self::Style) -> scrollable::Scrollbar {
|
||||||
|
match style {
|
||||||
|
Scrollable::Default => self.active(style),
|
||||||
|
Scrollable::Custom(custom) => custom.active_horizontal(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered_horizontal(&self, style: &Self::Style) -> scrollable::Scrollbar {
|
||||||
|
match style {
|
||||||
|
Scrollable::Default => self.hovered(style),
|
||||||
|
Scrollable::Custom(custom) => custom.hovered_horizontal(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dragging_horizontal(
|
||||||
|
&self,
|
||||||
|
style: &Self::Style,
|
||||||
|
) -> scrollable::Scrollbar {
|
||||||
|
match style {
|
||||||
|
Scrollable::Default => self.hovered_horizontal(style),
|
||||||
|
Scrollable::Custom(custom) => custom.dragging_horizontal(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The style of text.
|
/// The style of text.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue