diff options
Diffstat (limited to 'examples/scrollable/src')
| -rw-r--r-- | examples/scrollable/src/main.rs | 498 | 
1 files changed, 307 insertions, 191 deletions
diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index 6eba34e2..128d98b2 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -1,44 +1,58 @@ -use iced::executor; +use iced::widget::scrollable::{Properties, Scrollbar, Scroller};  use iced::widget::{ -    button, column, container, horizontal_rule, progress_bar, radio, -    scrollable, text, vertical_space, Row, +    button, column, container, horizontal_space, progress_bar, radio, row, +    scrollable, slider, text, vertical_space,  }; +use iced::{executor, theme, Alignment, Color};  use iced::{Application, Command, Element, Length, Settings, Theme}; +use once_cell::sync::Lazy; + +static SCROLLABLE_ID: Lazy<scrollable::Id> = Lazy::new(scrollable::Id::unique);  pub fn main() -> iced::Result {      ScrollableDemo::run(Settings::default())  }  struct ScrollableDemo { -    theme: Theme, -    variants: Vec<Variant>, +    scrollable_direction: Direction, +    scrollbar_width: u16, +    scrollbar_margin: u16, +    scroller_width: u16, +    current_scroll_offset: scrollable::RelativeOffset,  } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -enum ThemeType { -    Light, -    Dark, +#[derive(Debug, Clone, Eq, PartialEq, Copy)] +enum Direction { +    Vertical, +    Horizontal, +    Multi,  }  #[derive(Debug, Clone)]  enum Message { -    ThemeChanged(ThemeType), -    ScrollToTop(usize), -    ScrollToBottom(usize), -    Scrolled(usize, f32), +    SwitchDirection(Direction), +    ScrollbarWidthChanged(u16), +    ScrollbarMarginChanged(u16), +    ScrollerWidthChanged(u16), +    ScrollToBeginning, +    ScrollToEnd, +    Scrolled(scrollable::RelativeOffset),  }  impl Application for ScrollableDemo { +    type Executor = executor::Default;      type Message = Message;      type Theme = Theme; -    type Executor = executor::Default;      type Flags = ();      fn new(_flags: Self::Flags) -> (Self, Command<Message>) {          (              ScrollableDemo { -                theme: Default::default(), -                variants: Variant::all(), +                scrollable_direction: Direction::Vertical, +                scrollbar_width: 10, +                scrollbar_margin: 0, +                scroller_width: 10, +                current_scroll_offset: scrollable::RelativeOffset::START,              },              Command::none(),          ) @@ -50,36 +64,48 @@ impl Application for ScrollableDemo {      fn update(&mut self, message: Message) -> Command<Message> {          match message { -            Message::ThemeChanged(theme) => { -                self.theme = match theme { -                    ThemeType::Light => Theme::Light, -                    ThemeType::Dark => Theme::Dark, -                }; +            Message::SwitchDirection(direction) => { +                self.current_scroll_offset = scrollable::RelativeOffset::START; +                self.scrollable_direction = direction; + +                scrollable::snap_to( +                    SCROLLABLE_ID.clone(), +                    self.current_scroll_offset, +                ) +            } +            Message::ScrollbarWidthChanged(width) => { +                self.scrollbar_width = width; + +                Command::none() +            } +            Message::ScrollbarMarginChanged(margin) => { +                self.scrollbar_margin = margin;                  Command::none()              } -            Message::ScrollToTop(i) => { -                if let Some(variant) = self.variants.get_mut(i) { -                    variant.latest_offset = 0.0; - -                    scrollable::snap_to(Variant::id(i), 0.0) -                } else { -                    Command::none() -                } +            Message::ScrollerWidthChanged(width) => { +                self.scroller_width = width; + +                Command::none()              } -            Message::ScrollToBottom(i) => { -                if let Some(variant) = self.variants.get_mut(i) { -                    variant.latest_offset = 1.0; - -                    scrollable::snap_to(Variant::id(i), 1.0) -                } else { -                    Command::none() -                } +            Message::ScrollToBeginning => { +                self.current_scroll_offset = scrollable::RelativeOffset::START; + +                scrollable::snap_to( +                    SCROLLABLE_ID.clone(), +                    self.current_scroll_offset, +                )              } -            Message::Scrolled(i, offset) => { -                if let Some(variant) = self.variants.get_mut(i) { -                    variant.latest_offset = offset; -                } +            Message::ScrollToEnd => { +                self.current_scroll_offset = scrollable::RelativeOffset::END; + +                scrollable::snap_to( +                    SCROLLABLE_ID.clone(), +                    self.current_scroll_offset, +                ) +            } +            Message::Scrolled(offset) => { +                self.current_scroll_offset = offset;                  Command::none()              } @@ -87,172 +113,262 @@ impl Application for ScrollableDemo {      }      fn view(&self) -> Element<Message> { -        let ScrollableDemo { variants, .. } = self; - -        let choose_theme = [ThemeType::Light, ThemeType::Dark].iter().fold( -            column!["Choose a theme:"].spacing(10), -            |column, option| { -                column.push(radio( -                    format!("{:?}", option), -                    *option, -                    Some(*option), -                    Message::ThemeChanged, -                )) -            }, +        let scrollbar_width_slider = slider( +            0..=15, +            self.scrollbar_width, +            Message::ScrollbarWidthChanged, +        ); +        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( -            variants -                .iter() -                .enumerate() -                .map(|(i, variant)| { -                    let mut contents = column![ -                        variant.title, -                        button("Scroll to bottom",) -                            .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 { -                        contents = contents.push(text(format!( -                            "scrollbar_width: {:?}", -                            scrollbar_width -                        ))); -                    } - -                    if let Some(scrollbar_margin) = variant.scrollbar_margin { -                        contents = contents.push(text(format!( -                            "scrollbar_margin: {:?}", -                            scrollbar_margin -                        ))); -                    } - -                    if let Some(scroller_width) = variant.scroller_width { -                        contents = contents.push(text(format!( -                            "scroller_width: {:?}", -                            scroller_width -                        ))); -                    } - -                    contents = contents -                        .push(vertical_space(Length::Units(100))) -                        .push( -                            "Some content that should wrap within the \ -                            scrollable. Let's output a lot of short words, so \ -                            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 scroll_slider_controls = column![ +            text("Scrollbar width:"), +            scrollbar_width_slider, +            text("Scrollbar margin:"), +            scrollbar_margin_slider, +            text("Scroller width:"), +            scroller_width_slider, +        ] +        .spacing(10) +        .width(Length::Fill); + +        let scroll_orientation_controls = column(vec![ +            text("Scrollbar direction:").into(), +            radio( +                "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(), +        ]) +        .spacing(10) +        .width(Length::Fill); +        let scroll_controls = +            row![scroll_slider_controls, scroll_orientation_controls] +                .spacing(20) +                .width(Length::Fill); + +        let scroll_to_end_button = || { +            button("Scroll to end") +                .padding(10) +                .on_press(Message::ScrollToEnd) +        }; + +        let scroll_to_beginning_button = || { +            button("Scroll to beginning") +                .padding(10) +                .on_press(Message::ScrollToBeginning) +        }; + +        let scrollable_content: Element<Message> = +            Element::from(match self.scrollable_direction { +                Direction::Vertical => scrollable(                      column![ -                        scrollable, -                        progress_bar(0.0..=1.0, variant.latest_offset,) +                        scroll_to_end_button(), +                        text("Beginning!"), +                        vertical_space(Length::Units(1200)), +                        text("Middle!"), +                        vertical_space(Length::Units(1200)), +                        text("End!"), +                        scroll_to_beginning_button(),                      ]                      .width(Length::Fill) -                    .height(Length::Fill) -                    .spacing(10) +                    .align_items(Alignment::Center) +                    .padding([40, 0, 40, 0]) +                    .spacing(40), +                ) +                .height(Length::Fill) +                .vertical_scroll( +                    Properties::new() +                        .width(self.scrollbar_width) +                        .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(), +                        text("Beginning!"), +                        horizontal_space(Length::Units(1200)), +                        text("Middle!"), +                        horizontal_space(Length::Units(1200)), +                        text("End!"), +                        scroll_to_beginning_button(), +                    ] +                    .height(Length::Units(450)) +                    .align_items(Alignment::Center) +                    .padding([0, 40, 0, 40]) +                    .spacing(40), +                ) +                .height(Length::Fill) +                .horizontal_scroll( +                    Properties::new() +                        .width(self.scrollbar_width) +                        .margin(self.scrollbar_margin) +                        .scroller_width(self.scroller_width), +                ) +                .style(theme::Scrollable::custom(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(), +                        text("Horizontal - Beginning!"), +                        horizontal_space(Length::Units(1200)), +                        //vertical content +                        column![ +                            text("Horizontal - Middle!"), +                            scroll_to_end_button(), +                            text("Vertical - Beginning!"), +                            vertical_space(Length::Units(1200)), +                            text("Vertical - Middle!"), +                            vertical_space(Length::Units(1200)), +                            text("Vertical - End!"), +                            scroll_to_beginning_button(), +                            vertical_space(Length::Units(40)), +                        ] +                        .align_items(Alignment::Fill) +                        .spacing(40), +                        horizontal_space(Length::Units(1200)), +                        text("Horizontal - End!"), +                        scroll_to_beginning_button(), +                    ] +                    .align_items(Alignment::Center) +                    .padding([0, 40, 0, 40]) +                    .spacing(40), +                ) +                .height(Length::Fill) +                .vertical_scroll( +                    Properties::new() +                        .width(self.scrollbar_width) +                        .margin(self.scrollbar_margin) +                        .scroller_width(self.scroller_width), +                ) +                .horizontal_scroll( +                    Properties::new() +                        .width(self.scrollbar_width) +                        .margin(self.scrollbar_margin) +                        .scroller_width(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() -                }) -                .collect(), -        ) -        .spacing(20) -        .width(Length::Fill) -        .height(Length::Fill); +            } +            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 = -            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() +        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(), +        )      } -    fn theme(&self) -> Theme { -        self.theme.clone() +    fn theme(&self) -> Self::Theme { +        Theme::Dark      }  } -/// A version of a scrollable -struct Variant { -    title: &'static str, -    scrollbar_width: Option<u16>, -    scrollbar_margin: Option<u16>, -    scroller_width: Option<u16>, -    latest_offset: f32, -} +struct ScrollbarCustomStyle; -impl Variant { -    pub fn all() -> Vec<Self> { -        vec![ -            Self { -                title: "Default Scrollbar", -                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, +impl scrollable::StyleSheet for ScrollbarCustomStyle { +    type Style = Theme; + +    fn active(&self, style: &Self::Style) -> Scrollbar { +        style.active(&theme::Scrollable::Default) +    } + +    fn hovered(&self, style: &Self::Style) -> Scrollbar { +        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; -    pub fn id(i: usize) -> scrollable::Id { -        scrollable::Id::new(format!("scrollable-{}", i)) +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, +        }      }  }  | 
