diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index da38cd7d..8dd2e20c 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -1,3 +1,5 @@ +mod style; + use iced::{ scrollable, Column, Container, Element, Length, Radio, Row, Rule, Sandbox, Scrollable, Settings, Space, Text, @@ -9,8 +11,7 @@ pub fn main() -> iced::Result { struct ScrollableDemo { theme: style::Theme, - scroll: Vec, - config: Vec, + variants: Vec, } #[derive(Debug, Clone)] @@ -18,52 +19,13 @@ enum Message { ThemeChanged(style::Theme), } -/// Contains configuration for a single scrollbar -struct Config { - top_content: String, - scrollbar_width: Option, - scrollbar_margin: Option, - scroller_width: Option, -} - -fn get_configs() -> Vec { - vec![ - Config { - top_content: "Default Scrollbar".into(), - scrollbar_width: None, - scrollbar_margin: None, - scroller_width: None, - }, - Config { - top_content: "Slimmed & Margin".into(), - scrollbar_width: Some(4), - scrollbar_margin: Some(3), - scroller_width: Some(4), - }, - Config { - top_content: "Wide Scroller".into(), - scrollbar_width: Some(4), - scrollbar_margin: None, - scroller_width: Some(10), - }, - Config { - top_content: "Narrow Scroller".into(), - scrollbar_width: Some(10), - scrollbar_margin: None, - scroller_width: Some(4), - }, - ] -} - impl Sandbox for ScrollableDemo { type Message = Message; fn new() -> Self { - let config = get_configs(); ScrollableDemo { theme: Default::default(), - scroll: vec![scrollable::State::default(); config.len()], - config, + variants: Variant::all(), } } @@ -78,36 +40,37 @@ impl Sandbox for ScrollableDemo { } fn view(&mut self) -> Element { + let ScrollableDemo { + theme, variants, .. + } = self; + let choose_theme = style::Theme::ALL.iter().fold( Column::new().spacing(10).push(Text::new("Choose a theme:")), - |column, theme| { + |column, option| { column.push( Radio::new( - *theme, - &format!("{:?}", theme), - Some(self.theme), + *option, + &format!("{:?}", option), + Some(*theme), Message::ThemeChanged, ) - .style(self.theme), + .style(*theme), ) }, ); - let ScrollableDemo { scroll, theme, .. } = self; - let scrollable_row = Row::with_children( - scroll + variants .iter_mut() - .zip(self.config.iter()) - .map(|(state, config)| { - let mut scrollable = Scrollable::new(state) + .map(|variant| { + let mut scrollable = Scrollable::new(&mut variant.state) .padding(10) .width(Length::Fill) .height(Length::Fill) .style(*theme) - .push(Text::new(config.top_content.clone())); + .push(Text::new(variant.title)); - if let Some(scrollbar_width) = config.scrollbar_width { + if let Some(scrollbar_width) = variant.scrollbar_width { scrollable = scrollable .scrollbar_width(scrollbar_width) .push(Text::new(format!( @@ -115,7 +78,8 @@ impl Sandbox for ScrollableDemo { scrollbar_width ))); } - if let Some(scrollbar_margin) = config.scrollbar_margin { + + if let Some(scrollbar_margin) = variant.scrollbar_margin { scrollable = scrollable .scrollbar_margin(scrollbar_margin) .push(Text::new(format!( @@ -123,7 +87,8 @@ impl Sandbox for ScrollableDemo { scrollbar_margin ))); } - if let Some(scroller_width) = config.scroller_width { + + if let Some(scroller_width) = variant.scroller_width { scrollable = scrollable .scroller_width(scroller_width) .push(Text::new(format!( @@ -134,7 +99,12 @@ impl Sandbox for ScrollableDemo { scrollable = scrollable .push(Space::with_height(Length::Units(100))) - .push(Text::new("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(Text::new( + "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(Space::with_height(Length::Units(1200))) .push(Text::new("Middle")) .push(Space::with_height(Length::Units(1200))) @@ -169,197 +139,46 @@ impl Sandbox for ScrollableDemo { } } -mod style { - use iced::{container, radio, rule, scrollable}; +/// A version of a scrollable +struct Variant { + title: &'static str, + state: scrollable::State, + scrollbar_width: Option, + scrollbar_margin: Option, + scroller_width: Option, +} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum Theme { - Light, - Dark, - } - - impl Theme { - pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark]; - } - - impl Default for Theme { - fn default() -> Theme { - Theme::Light - } - } - - impl From for Box { - fn from(theme: Theme) -> Self { - match theme { - Theme::Light => Default::default(), - Theme::Dark => dark::Container.into(), - } - } - } - - impl From for Box { - fn from(theme: Theme) -> Self { - match theme { - Theme::Light => Default::default(), - Theme::Dark => dark::Radio.into(), - } - } - } - - impl From for Box { - fn from(theme: Theme) -> Self { - match theme { - Theme::Light => Default::default(), - Theme::Dark => dark::Scrollable.into(), - } - } - } - - impl From for Box { - fn from(theme: Theme) -> Self { - match theme { - Theme::Light => Default::default(), - Theme::Dark => dark::Rule.into(), - } - } - } - - mod dark { - use iced::{container, radio, rule, scrollable, Color}; - - const BACKGROUND: Color = Color::from_rgb( - 0x0f as f32 / 255.0, - 0x14 as f32 / 255.0, - 0x19 as f32 / 255.0, - ); - - const LIGHTER_BACKGROUND: Color = Color::from_rgb( - 0x14 as f32 / 255.0, - 0x19 as f32 / 255.0, - 0x1f as f32 / 255.0, - ); - - const YELLOW: Color = Color::from_rgb( - 0xff as f32 / 255.0, - 0xb4 as f32 / 255.0, - 0x54 as f32 / 255.0, - ); - - const CYAN: Color = Color::from_rgb( - 0x39 as f32 / 255.0, - 0xaf as f32 / 255.0, - 0xd7 as f32 / 255.0, - ); - - const CYAN_LIGHT: Color = Color::from_rgb( - 0x5d as f32 / 255.0, - 0xb7 as f32 / 255.0, - 0xd5 as f32 / 255.0, - ); - - const ORANGE: Color = Color::from_rgb( - 0xff as f32 / 255.0, - 0x77 as f32 / 255.0, - 0x33 as f32 / 255.0, - ); - - const ORANGE_DARK: Color = Color::from_rgb( - 0xe6 as f32 / 255.0, - 0x5b as f32 / 255.0, - 0x16 as f32 / 255.0, - ); - - pub struct Container; - - impl container::StyleSheet for Container { - fn style(&self) -> container::Style { - container::Style { - background: Color { - a: 0.99, - ..BACKGROUND - } - .into(), - text_color: Color::WHITE.into(), - ..container::Style::default() - } - } - } - - pub struct Radio; - - impl radio::StyleSheet for Radio { - fn active(&self) -> radio::Style { - radio::Style { - background: BACKGROUND.into(), - dot_color: CYAN, - border_width: 1, - border_color: CYAN, - } - } - - fn hovered(&self) -> radio::Style { - radio::Style { - background: LIGHTER_BACKGROUND.into(), - ..self.active() - } - } - } - - pub struct Scrollable; - - impl scrollable::StyleSheet for Scrollable { - fn active(&self) -> scrollable::Scrollbar { - scrollable::Scrollbar { - background: CYAN.into(), - border_radius: 2, - border_width: 0, - border_color: Color::TRANSPARENT, - scroller: scrollable::Scroller { - color: YELLOW, - border_radius: 2, - border_width: 0, - border_color: Color::TRANSPARENT, - }, - } - } - - fn hovered(&self) -> scrollable::Scrollbar { - let active = self.active(); - - scrollable::Scrollbar { - background: CYAN_LIGHT.into(), - scroller: scrollable::Scroller { - color: ORANGE, - ..active.scroller - }, - ..active - } - } - - fn dragging(&self) -> scrollable::Scrollbar { - let hovered = self.hovered(); - - scrollable::Scrollbar { - scroller: scrollable::Scroller { - color: ORANGE_DARK, - ..hovered.scroller - }, - ..hovered - } - } - } - - pub struct Rule; - - impl rule::StyleSheet for Rule { - fn style(&self) -> rule::Style { - rule::Style { - color: CYAN, - width: 2, - radius: 1, - fill_mode: rule::FillMode::Percent(15.0), - } - } - } +impl Variant { + pub fn all() -> Vec { + vec![ + Self { + title: "Default Scrollbar", + state: scrollable::State::new(), + scrollbar_width: None, + scrollbar_margin: None, + scroller_width: None, + }, + Self { + title: "Slimmed & Margin", + state: scrollable::State::new(), + scrollbar_width: Some(4), + scrollbar_margin: Some(3), + scroller_width: Some(4), + }, + Self { + title: "Wide Scroller", + state: scrollable::State::new(), + scrollbar_width: Some(4), + scrollbar_margin: None, + scroller_width: Some(10), + }, + Self { + title: "Narrow Scroller", + state: scrollable::State::new(), + scrollbar_width: Some(10), + scrollbar_margin: None, + scroller_width: Some(4), + }, + ] } } diff --git a/examples/scrollable/src/style.rs b/examples/scrollable/src/style.rs new file mode 100644 index 00000000..c6a33192 --- /dev/null +++ b/examples/scrollable/src/style.rs @@ -0,0 +1,192 @@ +use iced::{container, radio, rule, scrollable}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Theme { + Light, + Dark, +} + +impl Theme { + pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark]; +} + +impl Default for Theme { + fn default() -> Theme { + Theme::Light + } +} + +impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Container.into(), + } + } +} + +impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Radio.into(), + } + } +} + +impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Scrollable.into(), + } + } +} + +impl From for Box { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Rule.into(), + } + } +} + +mod dark { + use iced::{container, radio, rule, scrollable, Color}; + + const BACKGROUND: Color = Color::from_rgb( + 0x0f as f32 / 255.0, + 0x14 as f32 / 255.0, + 0x19 as f32 / 255.0, + ); + + const LIGHTER_BACKGROUND: Color = Color::from_rgb( + 0x14 as f32 / 255.0, + 0x19 as f32 / 255.0, + 0x1f as f32 / 255.0, + ); + + const YELLOW: Color = Color::from_rgb( + 0xff as f32 / 255.0, + 0xb4 as f32 / 255.0, + 0x54 as f32 / 255.0, + ); + + const CYAN: Color = Color::from_rgb( + 0x39 as f32 / 255.0, + 0xaf as f32 / 255.0, + 0xd7 as f32 / 255.0, + ); + + const CYAN_LIGHT: Color = Color::from_rgb( + 0x5d as f32 / 255.0, + 0xb7 as f32 / 255.0, + 0xd5 as f32 / 255.0, + ); + + const ORANGE: Color = Color::from_rgb( + 0xff as f32 / 255.0, + 0x77 as f32 / 255.0, + 0x33 as f32 / 255.0, + ); + + const ORANGE_DARK: Color = Color::from_rgb( + 0xe6 as f32 / 255.0, + 0x5b as f32 / 255.0, + 0x16 as f32 / 255.0, + ); + + pub struct Container; + + impl container::StyleSheet for Container { + fn style(&self) -> container::Style { + container::Style { + background: Color { + a: 0.99, + ..BACKGROUND + } + .into(), + text_color: Color::WHITE.into(), + ..container::Style::default() + } + } + } + + pub struct Radio; + + impl radio::StyleSheet for Radio { + fn active(&self) -> radio::Style { + radio::Style { + background: BACKGROUND.into(), + dot_color: CYAN, + border_width: 1, + border_color: CYAN, + } + } + + fn hovered(&self) -> radio::Style { + radio::Style { + background: LIGHTER_BACKGROUND.into(), + ..self.active() + } + } + } + + pub struct Scrollable; + + impl scrollable::StyleSheet for Scrollable { + fn active(&self) -> scrollable::Scrollbar { + scrollable::Scrollbar { + background: CYAN.into(), + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + scroller: scrollable::Scroller { + color: YELLOW, + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + }, + } + } + + fn hovered(&self) -> scrollable::Scrollbar { + let active = self.active(); + + scrollable::Scrollbar { + background: CYAN_LIGHT.into(), + scroller: scrollable::Scroller { + color: ORANGE, + ..active.scroller + }, + ..active + } + } + + fn dragging(&self) -> scrollable::Scrollbar { + let hovered = self.hovered(); + + scrollable::Scrollbar { + scroller: scrollable::Scroller { + color: ORANGE_DARK, + ..hovered.scroller + }, + ..hovered + } + } + } + + pub struct Rule; + + impl rule::StyleSheet for Rule { + fn style(&self) -> rule::Style { + rule::Style { + color: CYAN, + width: 2, + radius: 1, + fill_mode: rule::FillMode::Percent(15.0), + } + } + } +}