use iced::{ button, scrollable, slider, text_input, Align, Button, Checkbox, Column, Container, Element, Length, ProgressBar, Radio, Row, Rule, Sandbox, Scrollable, Settings, Slider, Space, Text, TextInput, Toggler, }; pub fn main() -> iced::Result { Styling::run(Settings::default()) } #[derive(Default)] struct Styling { theme: style::Theme, scroll: scrollable::State, input: text_input::State, input_value: String, button: button::State, slider: slider::State, slider_value: f32, checkbox_value: bool, toggler_value: bool, } #[derive(Debug, Clone)] enum Message { ThemeChanged(style::Theme), InputChanged(String), ButtonPressed, SliderChanged(f32), CheckboxToggled(bool), TogglerToggled(bool), } impl Sandbox for Styling { type Message = Message; fn new() -> Self { Styling::default() } fn title(&self) -> String { String::from("Styling - Iced") } fn update(&mut self, message: Message) { match message { Message::ThemeChanged(theme) => self.theme = theme, Message::InputChanged(value) => self.input_value = value, Message::ButtonPressed => {} Message::SliderChanged(value) => self.slider_value = value, Message::CheckboxToggled(value) => self.checkbox_value = value, Message::TogglerToggled(value) => self.toggler_value = value, } } fn view(&mut self) -> Element { let choose_theme = style::Theme::ALL.iter().fold( Column::new().spacing(10).push(Text::new("Choose a theme:")), |column, theme| { column.push( Radio::new( *theme, &format!("{:?}", theme), Some(self.theme), Message::ThemeChanged, ) .style(self.theme), ) }, ); let text_input = TextInput::new( &mut self.input, "Type something...", &self.input_value, Message::InputChanged, ) .padding(10) .size(20) .style(self.theme); let button = Button::new(&mut self.button, Text::new("Submit")) .padding(10) .on_press(Message::ButtonPressed) .style(self.theme); let slider = Slider::new( &mut self.slider, 0.0..=100.0, self.slider_value, Message::SliderChanged, ) .style(self.theme); let progress_bar = ProgressBar::new(0.0..=100.0, self.slider_value).style(self.theme); let scrollable = Scrollable::new(&mut self.scroll) .width(Length::Fill) .height(Length::Units(100)) .style(self.theme) .push(Text::new("Scroll me!")) .push(Space::with_height(Length::Units(800))) .push(Text::new("You did it!")); let checkbox = Checkbox::new( self.checkbox_value, "Check me!", Message::CheckboxToggled, ) .style(self.theme); let toggler = Toggler::new( self.toggler_value, String::from("Toggle me!"), Message::TogglerToggled, ) .width(Length::Shrink) .spacing(10) .style(self.theme); let content = Column::new() .spacing(20) .padding(20) .max_width(600) .push(choose_theme) .push(Rule::horizontal(38).style(self.theme)) .push(Row::new().spacing(10).push(text_input).push(button)) .push(slider) .push(progress_bar) .push( Row::new() .spacing(10) .height(Length::Units(100)) .align_items(Align::Center) .push(scrollable) .push(Rule::vertical(38).style(self.theme)) .push( Column::new() .width(Length::Shrink) .spacing(20) .push(checkbox) .push(toggler), ), ); Container::new(content) .width(Length::Fill) .height(Length::Fill) .center_x() .center_y() .style(self.theme) .into() } } mod style { use iced::{ button, checkbox, container, progress_bar, radio, rule, scrollable, slider, text_input, toggler, }; #[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::TextInput.into(), } } } impl From for Box { fn from(theme: Theme) -> Self { match theme { Theme::Light => light::Button.into(), Theme::Dark => dark::Button.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::Slider.into(), } } } impl From for Box { fn from(theme: Theme) -> Self { match theme { Theme::Light => Default::default(), Theme::Dark => dark::ProgressBar.into(), } } } impl From for Box { fn from(theme: Theme) -> Self { match theme { Theme::Light => Default::default(), Theme::Dark => dark::Checkbox.into(), } } } impl From for Box { fn from(theme: Theme) -> Self { match theme { Theme::Light => Default::default(), Theme::Dark => dark::Toggler.into(), } } } impl From for Box { fn from(theme: Theme) -> Self { match theme { Theme::Light => Default::default(), Theme::Dark => dark::Rule.into(), } } } mod light { use iced::{button, Color, Vector}; pub struct Button; impl button::StyleSheet for Button { fn active(&self) -> button::Style { button::Style { background: Color::from_rgb(0.11, 0.42, 0.87).into(), border_radius: 12.0, shadow_offset: Vector::new(1.0, 1.0), text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE), ..button::Style::default() } } fn hovered(&self) -> button::Style { button::Style { text_color: Color::WHITE, shadow_offset: Vector::new(1.0, 2.0), ..self.active() } } } } mod dark { use iced::{ button, checkbox, container, progress_bar, radio, rule, scrollable, slider, text_input, toggler, Color, }; const SURFACE: Color = Color::from_rgb( 0x40 as f32 / 255.0, 0x44 as f32 / 255.0, 0x4B as f32 / 255.0, ); const ACCENT: Color = Color::from_rgb( 0x6F as f32 / 255.0, 0xFF as f32 / 255.0, 0xE9 as f32 / 255.0, ); const ACTIVE: Color = Color::from_rgb( 0x72 as f32 / 255.0, 0x89 as f32 / 255.0, 0xDA as f32 / 255.0, ); const HOVERED: Color = Color::from_rgb( 0x67 as f32 / 255.0, 0x7B as f32 / 255.0, 0xC4 as f32 / 255.0, ); pub struct Container; impl container::StyleSheet for Container { fn style(&self) -> container::Style { container::Style { background: Color::from_rgb8(0x36, 0x39, 0x3F).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: SURFACE.into(), dot_color: ACTIVE, border_width: 1.0, border_color: ACTIVE, } } fn hovered(&self) -> radio::Style { radio::Style { background: Color { a: 0.5, ..SURFACE }.into(), ..self.active() } } } pub struct TextInput; impl text_input::StyleSheet for TextInput { fn active(&self) -> text_input::Style { text_input::Style { background: SURFACE.into(), border_radius: 2.0, border_width: 0.0, border_color: Color::TRANSPARENT, } } fn focused(&self) -> text_input::Style { text_input::Style { border_width: 1.0, border_color: ACCENT, ..self.active() } } fn hovered(&self) -> text_input::Style { text_input::Style { border_width: 1.0, border_color: Color { a: 0.3, ..ACCENT }, ..self.focused() } } fn placeholder_color(&self) -> Color { Color::from_rgb(0.4, 0.4, 0.4) } fn value_color(&self) -> Color { Color::WHITE } fn selection_color(&self) -> Color { ACTIVE } } pub struct Button; impl button::StyleSheet for Button { fn active(&self) -> button::Style { button::Style { background: ACTIVE.into(), border_radius: 3.0, text_color: Color::WHITE, ..button::Style::default() } } fn hovered(&self) -> button::Style { button::Style { background: HOVERED.into(), text_color: Color::WHITE, ..self.active() } } fn pressed(&self) -> button::Style { button::Style { border_width: 1.0, border_color: Color::WHITE, ..self.hovered() } } } pub struct Scrollable; impl scrollable::StyleSheet for Scrollable { fn active(&self) -> scrollable::Scrollbar { scrollable::Scrollbar { background: SURFACE.into(), border_radius: 2.0, border_width: 0.0, border_color: Color::TRANSPARENT, scroller: scrollable::Scroller { color: ACTIVE, border_radius: 2.0, border_width: 0.0, border_color: Color::TRANSPARENT, }, } } fn hovered(&self) -> scrollable::Scrollbar { let active = self.active(); scrollable::Scrollbar { background: Color { a: 0.5, ..SURFACE }.into(), scroller: scrollable::Scroller { color: HOVERED, ..active.scroller }, ..active } } fn dragging(&self) -> scrollable::Scrollbar { let hovered = self.hovered(); scrollable::Scrollbar { scroller: scrollable::Scroller { color: Color::from_rgb(0.85, 0.85, 0.85), ..hovered.scroller }, ..hovered } } } pub struct Slider; impl slider::StyleSheet for Slider { fn active(&self) -> slider::Style { slider::Style { rail_colors: (ACTIVE, Color { a: 0.1, ..ACTIVE }), handle: slider::Handle { shape: slider::HandleShape::Circle { radius: 9.0 }, color: ACTIVE, border_width: 0.0, border_color: Color::TRANSPARENT, }, } } fn hovered(&self) -> slider::Style { let active = self.active(); slider::Style { handle: slider::Handle { color: HOVERED, ..active.handle }, ..active } } fn dragging(&self) -> slider::Style { let active = self.active(); slider::Style { handle: slider::Handle { color: Color::from_rgb(0.85, 0.85, 0.85), ..active.handle }, ..active } } } pub struct ProgressBar; impl progress_bar::StyleSheet for ProgressBar { fn style(&self) -> progress_bar::Style { progress_bar::Style { background: SURFACE.into(), bar: ACTIVE.into(), border_radius: 10.0, } } } pub struct Checkbox; impl checkbox::StyleSheet for Checkbox { fn active(&self, is_checked: bool) -> checkbox::Style { checkbox::Style { background: if is_checked { ACTIVE } else { SURFACE } .into(), checkmark_color: Color::WHITE, border_radius: 2.0, border_width: 1.0, border_color: ACTIVE, } } fn hovered(&self, is_checked: bool) -> checkbox::Style { checkbox::Style { background: Color { a: 0.8, ..if is_checked { ACTIVE } else { SURFACE } } .into(), ..self.active(is_checked) } } } pub struct Toggler; impl toggler::StyleSheet for Toggler { fn active(&self, is_active: bool) -> toggler::Style { toggler::Style { background: if is_active { ACTIVE } else { SURFACE }, background_border: None, foreground: if is_active { Color::WHITE } else { ACTIVE }, foreground_border: None, } } fn hovered(&self, is_active: bool) -> toggler::Style { toggler::Style { background: if is_active { ACTIVE } else { SURFACE }, background_border: None, foreground: if is_active { Color { a: 0.5, ..Color::WHITE } } else { Color { a: 0.5, ..ACTIVE } }, foreground_border: None, } } } pub struct Rule; impl rule::StyleSheet for Rule { fn style(&self) -> rule::Style { rule::Style { color: SURFACE, width: 2, radius: 1.0, fill_mode: rule::FillMode::Padded(15), } } } } }