summaryrefslogblamecommitdiffstats
path: root/examples/scrollable/src/main.rs
blob: bbb6497fcc50c0e145c1fd9f2fd209cd0b19592c (plain) (tree)
1
2
3
4
5
6
7
8
9
                                         
                   
                                                                          
                                                         
  
                                                                      
 
                          
 
                                                                               

                               
                  
                            



                                 
          


                       



                                    
                                                      
                                     

 




                                            

 

                       
                               
                                            


                                

                      
                                   

 
                     








                                                                     

     
                                                                
                       
                                                    
                                                                               
                                                      
 



                                               
             








                                                                               

                                                      
 





                                                        
             

                                                     
 

                               
                                           
                                                                               


                                          
                                               
                 
             
                                     
                                                                             
 

                                          
                                               

                 

                                                                        
 
                               
             


         
                                        



                                            
          






                                                                               
 







                                             
                     
 

                                                  




                                                
              




                                                
              




                                                


                     
 

                                                




                                             
              





                                           
         
                     





                                        
                     
 
                                       

                                   
                                               
          
 
                                             

                                         
                                                     
          
 

                                                           
                                                                  
                            
                                               
                                           
                                                      
                                        
                                                      
                                     
                                                     
                     


                                                   






                                                                
                 
                                    
                                     

                                              
                                                                    
                         
                                               
                                           
                                                       
                                        
                                                       
                                     
                                                     
                     
                                


                                                   






                                                                
                 
                                    
                                     

                                              
                                                               



                                                             
                                                         
                          
                                               
                                                        
                                                       


                                                         
                                                   
                                                          
                                                          
                                                       
                                                          
                                                    
                                                         
                                                        
                         
                                     
                                                       
                                                  
                                                     



                                                   











                                                                
                 
                                    
                                     









                                                                               
                                                     
                           


                                                                      

                                                                     



                        
 

                                                                       



                                               
                                             
     
 
                              
                   
     

 





                                 

                                                                    

                                                                            
                                  
     
 
use iced::widget::scrollable::Properties;
use iced::widget::{
    button, column, container, horizontal_space, progress_bar, radio, row,
    scrollable, slider, text, vertical_space, Scrollable,
};
use iced::{Alignment, Border, Color, Command, Element, Length, Theme};

use once_cell::sync::Lazy;

static SCROLLABLE_ID: Lazy<scrollable::Id> = Lazy::new(scrollable::Id::unique);

pub fn main() -> iced::Result {
    iced::program(
        "Scrollable - Iced",
        ScrollableDemo::update,
        ScrollableDemo::view,
    )
    .theme(ScrollableDemo::theme)
    .run()
}

struct ScrollableDemo {
    scrollable_direction: Direction,
    scrollbar_width: u16,
    scrollbar_margin: u16,
    scroller_width: u16,
    current_scroll_offset: scrollable::RelativeOffset,
    alignment: scrollable::Alignment,
}

#[derive(Debug, Clone, Eq, PartialEq, Copy)]
enum Direction {
    Vertical,
    Horizontal,
    Multi,
}

#[derive(Debug, Clone)]
enum Message {
    SwitchDirection(Direction),
    AlignmentChanged(scrollable::Alignment),
    ScrollbarWidthChanged(u16),
    ScrollbarMarginChanged(u16),
    ScrollerWidthChanged(u16),
    ScrollToBeginning,
    ScrollToEnd,
    Scrolled(scrollable::Viewport),
}

impl ScrollableDemo {
    fn new() -> Self {
        ScrollableDemo {
            scrollable_direction: Direction::Vertical,
            scrollbar_width: 10,
            scrollbar_margin: 0,
            scroller_width: 10,
            current_scroll_offset: scrollable::RelativeOffset::START,
            alignment: scrollable::Alignment::Start,
        }
    }

    fn update(&mut self, message: Message) -> Command<Message> {
        match message {
            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::AlignmentChanged(alignment) => {
                self.current_scroll_offset = scrollable::RelativeOffset::START;
                self.alignment = alignment;

                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::ScrollerWidthChanged(width) => {
                self.scroller_width = width;

                Command::none()
            }
            Message::ScrollToBeginning => {
                self.current_scroll_offset = scrollable::RelativeOffset::START;

                scrollable::snap_to(
                    SCROLLABLE_ID.clone(),
                    self.current_scroll_offset,
                )
            }
            Message::ScrollToEnd => {
                self.current_scroll_offset = scrollable::RelativeOffset::END;

                scrollable::snap_to(
                    SCROLLABLE_ID.clone(),
                    self.current_scroll_offset,
                )
            }
            Message::Scrolled(viewport) => {
                self.current_scroll_offset = viewport.relative_offset();

                Command::none()
            }
        }
    }

    fn view(&self) -> Element<Message> {
        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 scroll_slider_controls = column![
            text("Scrollbar width:"),
            scrollbar_width_slider,
            text("Scrollbar margin:"),
            scrollbar_margin_slider,
            text("Scroller width:"),
            scroller_width_slider,
        ]
        .spacing(10);

        let scroll_orientation_controls = column![
            text("Scrollbar direction:"),
            radio(
                "Vertical",
                Direction::Vertical,
                Some(self.scrollable_direction),
                Message::SwitchDirection,
            ),
            radio(
                "Horizontal",
                Direction::Horizontal,
                Some(self.scrollable_direction),
                Message::SwitchDirection,
            ),
            radio(
                "Both!",
                Direction::Multi,
                Some(self.scrollable_direction),
                Message::SwitchDirection,
            ),
        ]
        .spacing(10);

        let scroll_alignment_controls = column![
            text("Scrollable alignment:"),
            radio(
                "Start",
                scrollable::Alignment::Start,
                Some(self.alignment),
                Message::AlignmentChanged,
            ),
            radio(
                "End",
                scrollable::Alignment::End,
                Some(self.alignment),
                Message::AlignmentChanged,
            )
        ]
        .spacing(10);

        let scroll_controls = row![
            scroll_slider_controls,
            scroll_orientation_controls,
            scroll_alignment_controls
        ]
        .spacing(20);

        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::with_direction(
                    column![
                        scroll_to_end_button(),
                        text("Beginning!"),
                        vertical_space().height(1200),
                        text("Middle!"),
                        vertical_space().height(1200),
                        text("End!"),
                        scroll_to_beginning_button(),
                    ]
                    .align_items(Alignment::Center)
                    .padding([40, 0, 40, 0])
                    .spacing(40),
                    scrollable::Direction::Vertical(
                        Properties::new()
                            .width(self.scrollbar_width)
                            .margin(self.scrollbar_margin)
                            .scroller_width(self.scroller_width)
                            .alignment(self.alignment),
                    ),
                )
                .width(Length::Fill)
                .height(Length::Fill)
                .id(SCROLLABLE_ID.clone())
                .on_scroll(Message::Scrolled),
                Direction::Horizontal => Scrollable::with_direction(
                    row![
                        scroll_to_end_button(),
                        text("Beginning!"),
                        horizontal_space().width(1200),
                        text("Middle!"),
                        horizontal_space().width(1200),
                        text("End!"),
                        scroll_to_beginning_button(),
                    ]
                    .height(450)
                    .align_items(Alignment::Center)
                    .padding([0, 40, 0, 40])
                    .spacing(40),
                    scrollable::Direction::Horizontal(
                        Properties::new()
                            .width(self.scrollbar_width)
                            .margin(self.scrollbar_margin)
                            .scroller_width(self.scroller_width)
                            .alignment(self.alignment),
                    ),
                )
                .width(Length::Fill)
                .height(Length::Fill)
                .id(SCROLLABLE_ID.clone())
                .on_scroll(Message::Scrolled),
                Direction::Multi => Scrollable::with_direction(
                    //horizontal content
                    row![
                        column![
                            text("Let's do some scrolling!"),
                            vertical_space().height(2400)
                        ],
                        scroll_to_end_button(),
                        text("Horizontal - Beginning!"),
                        horizontal_space().width(1200),
                        //vertical content
                        column![
                            text("Horizontal - Middle!"),
                            scroll_to_end_button(),
                            text("Vertical - Beginning!"),
                            vertical_space().height(1200),
                            text("Vertical - Middle!"),
                            vertical_space().height(1200),
                            text("Vertical - End!"),
                            scroll_to_beginning_button(),
                            vertical_space().height(40),
                        ]
                        .spacing(40),
                        horizontal_space().width(1200),
                        text("Horizontal - End!"),
                        scroll_to_beginning_button(),
                    ]
                    .align_items(Alignment::Center)
                    .padding([0, 40, 0, 40])
                    .spacing(40),
                    {
                        let properties = Properties::new()
                            .width(self.scrollbar_width)
                            .margin(self.scrollbar_margin)
                            .scroller_width(self.scroller_width)
                            .alignment(self.alignment);

                        scrollable::Direction::Both {
                            horizontal: properties,
                            vertical: properties,
                        }
                    },
                )
                .width(Length::Fill)
                .height(Length::Fill)
                .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(progress_bar_custom_style)
                    .into()
            }
            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(progress_bar_custom_style)
            ]
            .spacing(10)
            .into(),
        };

        let content: Element<Message> =
            column![scroll_controls, scrollable_content, progress_bars]
                .align_items(Alignment::Center)
                .spacing(10)
                .into();

        container(content).padding(20).into()
    }

    fn theme(&self) -> Theme {
        Theme::Dark
    }
}

impl Default for ScrollableDemo {
    fn default() -> Self {
        Self::new()
    }
}

fn progress_bar_custom_style(theme: &Theme) -> progress_bar::Style {
    progress_bar::Style {
        background: theme.extended_palette().background.strong.color.into(),
        bar: Color::from_rgb8(250, 85, 134).into(),
        border: Border::default(),
    }
}