From 05b84780b7ad4cd269b1fec5a1355e9d1c34291a Mon Sep 17 00:00:00 2001 From: David Weis Date: Sun, 23 Aug 2020 22:48:41 +0100 Subject: [PATCH] Add dark style --- src/main.rs | 21 +++-- src/style.rs | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 src/style.rs diff --git a/src/main.rs b/src/main.rs index a59d668..69f034d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,7 @@ mod i3_config; +mod style; + +use style::Theme; use iced::{ scrollable, text_input, Align, Application, Color, Column, Command, Container, Element, Font, @@ -11,10 +14,10 @@ pub fn main() { #[derive(Debug)] struct State { - scroll: scrollable::State, - search_string: String, - text_input_state: text_input::State, - shortcuts: i3_config::ConfigMetadata, + scroll: scrollable::State, + search_string: String, + text_input_state: text_input::State, + shortcuts: i3_config::ConfigMetadata, } impl State { @@ -93,6 +96,7 @@ impl Application for Searcher { .height(Length::Fill) .center_x() .center_y() + .style(Theme::Dark) .into(), Searcher::Error => Container::new( Text::new("Error loading i3 config") @@ -103,6 +107,7 @@ impl Application for Searcher { .height(Length::Fill) .center_x() .center_y() + .style(Theme::Dark) .into(), Searcher::Searching(state) => { let input = TextInput::new( @@ -112,6 +117,7 @@ impl Application for Searcher { Message::InputChanged, ) .width(Length::Fill) + .style(Theme::Dark) .size(40); let entries = state.shortcuts @@ -121,15 +127,16 @@ impl Application for Searcher { column.push(config_entry.view()) }); - let scrollable_entries = Scrollable::new(&mut state.scroll).push(entries); + let scrollable_entries = Scrollable::new(&mut state.scroll).push(entries).style(Theme::Dark); let content = Column::new() .push(input) .push(scrollable_entries) .spacing(20) - .padding(50); + .padding(20); Container::new(content) + .style(Theme::Dark) .width(Length::Fill) .height(Length::Fill) .center_x() @@ -149,7 +156,7 @@ impl ViewModel for i3_config::ConfigEntry { Row::new() .width(Length::Fill) .align_items(Align::Center) - .padding(10) + .padding(30) .push(Text::new(self.description().to_owned()).font(FONT).size(20)) .push(Space::new(Length::Fill, Length::Shrink)) .push(Text::new(self.keys().to_owned()).font(FONT).size(20)) diff --git a/src/style.rs b/src/style.rs new file mode 100644 index 0000000..d492479 --- /dev/null +++ b/src/style.rs @@ -0,0 +1,237 @@ + +use iced::{button, container, scrollable, text_input}; + +#[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::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(), + } + } +} + +mod light { + use iced::{button, Background, Color, Vector}; + + pub struct Button; + + impl button::StyleSheet for Button { + fn active(&self) -> button::Style { + button::Style { + background: Some(Background::Color(Color::from_rgb(0.11, 0.42, 0.87))), + border_radius: 12, + 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, container, scrollable, text_input, + Background, 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: Some(Background::Color(Color::from_rgb8(0x36, 0x39, 0x3F))), + text_color: Some(Color::WHITE), + ..container::Style::default() + } + } + } + + pub struct TextInput; + + impl text_input::StyleSheet for TextInput { + fn active(&self) -> text_input::Style { + text_input::Style { + background: Background::Color(SURFACE), + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + } + } + + fn focused(&self) -> text_input::Style { + text_input::Style { + border_width: 1, + border_color: ACCENT, + ..self.active() + } + } + + fn hovered(&self) -> text_input::Style { + text_input::Style { + border_width: 1, + 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: Some(Background::Color(ACTIVE)), + border_radius: 3, + text_color: Color::WHITE, + ..button::Style::default() + } + } + + fn hovered(&self) -> button::Style { + button::Style { + background: Some(Background::Color(HOVERED)), + text_color: Color::WHITE, + ..self.active() + } + } + + fn pressed(&self) -> button::Style { + button::Style { + border_width: 1, + border_color: Color::WHITE, + ..self.hovered() + } + } + } + + pub struct Scrollable; + + impl scrollable::StyleSheet for Scrollable { + fn active(&self) -> scrollable::Scrollbar { + scrollable::Scrollbar { + background: Some(Background::Color(SURFACE)), + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + scroller: scrollable::Scroller { + color: ACTIVE, + border_radius: 2, + border_width: 0, + border_color: Color::TRANSPARENT, + }, + } + } + + fn hovered(&self) -> scrollable::Scrollbar { + let active = self.active(); + + scrollable::Scrollbar { + background: Some(Background::Color(Color { a: 0.5, ..SURFACE })), + 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 + } + } + } +}