use crate::{
style::{Background, CursorStyle, Foreground, Style, Transition},
unit::{DurationUnitExt, UnitExt},
views::{
dropdown::{self},
scroll,
slider::{self, SliderClass},
ButtonClass, CheckboxClass, LabelClass, LabelCustomStyle, LabeledCheckboxClass,
LabeledRadioButtonClass, ListClass, ListItemClass, PlaceholderTextClass, RadioButtonClass,
RadioButtonDotClass, TextInputClass, ToggleButtonCircleRad, ToggleButtonClass,
ToggleButtonInset, TooltipClass,
},
};
use peniko::{Brush, Color};
use std::rc::Rc;
use taffy::style::AlignItems;
pub(crate) struct Theme {
pub(crate) background: Color,
pub(crate) style: Rc<Style>,
}
pub(crate) fn default_theme() -> Theme {
let border = Color::rgb8(140, 140, 140);
let padding = 5.0;
let border_radius = 5.0;
let hover_bg_color = Color::rgba8(228, 237, 216, 160);
let focus_hover_bg_color = Color::rgb8(234, 230, 236);
let active_bg_color = Color::rgb8(160, 160, 160);
let selected_bg_color = Color::rgb8(213, 208, 216);
let selected_hover_bg_color = Color::rgb8(186, 180, 216);
let selected_unfocused_bg_color = Color::rgb8(212, 212, 212);
let selected_unfocused_hover_bg_color = Color::rgb8(197, 197, 197);
let light_hover_bg_color = Color::rgb8(250, 252, 248);
let light_focus_hover_bg_color = Color::rgb8(250, 249, 251);
let focus_applied_style = Style::new().border_color(Color::rgb8(114, 74, 140));
let focus_visible_applied_style = Style::new().outline(3.0);
let focus_style = Style::new()
.outline_color(Color::rgba8(213, 208, 216, 150))
.focus(|_| focus_applied_style.clone())
.focus_visible(|_| focus_visible_applied_style.clone());
let border_style = Style::new()
.disabled(|s| s.border_color(Color::rgb8(131, 145, 123).multiply_alpha(0.3)))
.border(1.0)
.border_color(border)
.padding(padding)
.border_radius(border_radius)
.apply(focus_style.clone());
let button_style = Style::new()
.apply(LabelCustomStyle::new().selectable(false).style())
.class(LabelClass, |s| {
s.apply(LabelCustomStyle::new().selectable(false).style())
})
.background(Color::rgb8(240, 240, 240))
.disabled(|s| {
s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3))
.border_color(Color::rgb8(131, 145, 123).multiply_alpha(0.3))
.color(Color::GRAY)
})
.active(|s| {
s.background(active_bg_color)
.color(Color::WHITE.multiply_alpha(0.9))
})
.transition(Background, Transition::linear(100.millis()))
.focus(|s| s.hover(|s| s.background(focus_hover_bg_color)))
.hover(|s| s.background(hover_bg_color))
.padding(padding)
.justify_center()
.items_center()
.apply(focus_style.clone())
.apply(border_style.clone())
.color(Color::rgb8(40, 40, 40));
let checkbox_style = Style::new()
.width(20.)
.height(20.)
.background(Color::WHITE)
.active(|s| s.background(active_bg_color))
.transition(Background, Transition::linear(100.millis()))
.hover(|s| s.background(hover_bg_color))
.focus(|s| s.hover(|s| s.background(focus_hover_bg_color)))
.apply(border_style.clone())
.apply(focus_style.clone())
.disabled(|s| {
s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3))
.color(Color::GRAY)
});
let labeled_checkbox_style = Style::new()
.row_gap(padding)
.hover(|s| s.background(hover_bg_color))
.padding(padding)
.transition(Background, Transition::linear(100.millis()))
.border_radius(border_radius)
.active(|s| s.class(CheckboxClass, |s| s.background(active_bg_color)))
.focus(|s| {
s.class(CheckboxClass, |_| focus_applied_style.clone())
.hover(|s| s.background(focus_hover_bg_color))
})
.disabled(|s| {
s.color(Color::GRAY).class(CheckboxClass, |s| {
s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3))
.color(Color::GRAY)
.hover(|s| s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3)))
})
})
.apply(focus_style.clone());
let radio_button_style = Style::new()
.width(20.)
.height(20.)
.align_items(AlignItems::Center)
.justify_center()
.background(Color::WHITE)
.active(|s| s.background(active_bg_color))
.transition(Background, Transition::linear(100.millis()))
.hover(|s| s.background(hover_bg_color))
.focus(|s| s.hover(|s| s.background(focus_hover_bg_color)))
.apply(border_style.clone())
.padding(0.)
.border_radius(100.0)
.apply(focus_style.clone())
.disabled(|s| {
s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3))
.color(Color::GRAY)
});
let radio_button_dot_style = Style::new()
.width(8.)
.height(8.)
.border_radius(100.0)
.background(Color::BLACK)
.disabled(|s| {
s.background(Color::rgb(0.5, 0.5, 0.5))
.hover(|s| s.background(Color::rgb(0.5, 0.5, 0.5)))
});
let labeled_radio_button_style = Style::new()
.row_gap(padding)
.hover(|s| s.background(hover_bg_color))
.padding(padding)
.transition(Background, Transition::linear(100.millis()))
.border_radius(border_radius)
.active(|s| s.class(RadioButtonClass, |s| s.background(active_bg_color)))
.focus(|s| {
s.class(RadioButtonClass, |_| focus_applied_style.clone())
.hover(|s| s.background(focus_hover_bg_color))
})
.disabled(|s| {
s.color(Color::GRAY).class(RadioButtonClass, |s| {
s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3))
.color(Color::GRAY)
.hover(|s| s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3)))
})
})
.apply(focus_style.clone());
let toggle_button_style = Style::new()
.active(|s| {
s.background(active_bg_color)
.color(Color::WHITE.multiply_alpha(0.9))
.set(Foreground, Brush::Solid(Color::WHITE.multiply_alpha(0.9)))
})
.aspect_ratio(2.)
.background(Color::rgb8(240, 240, 240))
.border_radius(50.pct())
.border(1.)
.focus(|s| s.hover(|s| s.background(focus_hover_bg_color)))
.height(FONT_SIZE * 1.75)
.hover(|s| s.background(hover_bg_color))
.padding(padding)
.set(Foreground, Brush::Solid(Color::DARK_GRAY))
.set(ToggleButtonCircleRad, 75.pct())
.set(ToggleButtonInset, 10.pct())
.apply(border_style.clone())
.apply(focus_style.clone());
const FONT_SIZE: f32 = 12.0;
let input_style = Style::new()
.background(Color::WHITE)
.hover(|s| s.background(light_hover_bg_color))
.focus(|s| s.hover(|s| s.background(light_focus_hover_bg_color)))
.apply(border_style.clone())
.apply(focus_style.clone())
.cursor(CursorStyle::Text)
.padding(padding)
.disabled(|s| {
s.background(Color::rgb8(180, 188, 175).multiply_alpha(0.3))
.color(Color::GRAY)
});
let item_focused_style = Style::new().selected(|s| {
s.background(selected_bg_color)
.hover(|s| s.background(selected_hover_bg_color))
});
let item_unfocused_style = Style::new()
.hover(|s| s.background(hover_bg_color))
.selected(|s| {
s.background(selected_unfocused_bg_color)
.hover(|s| s.background(selected_unfocused_hover_bg_color))
});
let theme = Style::new()
.class(ListClass, |s| {
s.apply(focus_style)
.focus(|s| s.class(ListItemClass, |_| item_focused_style))
.class(ListItemClass, |_| item_unfocused_style)
})
.class(LabeledCheckboxClass, |_| labeled_checkbox_style)
.class(CheckboxClass, |_| checkbox_style)
.class(RadioButtonClass, |_| radio_button_style)
.class(RadioButtonDotClass, |_| radio_button_dot_style)
.class(LabeledRadioButtonClass, |_| labeled_radio_button_style)
.class(TextInputClass, |_| input_style)
.class(ButtonClass, |_| button_style)
.apply_custom(
scroll::ScrollCustomStyle::new()
.handle_border_radius(4.0)
.handle_background(Color::rgba8(166, 166, 166, 140))
.handle_thickness(16.0)
.handle_rounded(false),
)
.class(scroll::Handle, |s| {
s.active(|s| s.background(Color::rgb8(166, 166, 166)))
.hover(|s| s.background(Color::rgb8(184, 184, 184)))
})
.class(scroll::Track, |s| {
s.hover(|s| s.background(Color::rgba8(166, 166, 166, 30)))
})
.class(ToggleButtonClass, |_| toggle_button_style)
.class(SliderClass, |s| {
s.apply_custom(
slider::SliderCustomStyle::new()
.bar_color(Color::BLACK)
.bar_radius(100.pct())
.accent_bar_color(Color::GREEN)
.accent_bar_radius(100.pct())
.handle_color(Brush::Solid(Color::DARK_GRAY))
.handle_radius(100.pct())
.edge_align(true),
)
.height(15)
.width(100)
})
.class(PlaceholderTextClass, |s| {
s.color(Color::rgba8(158, 158, 158, 30))
.font_size(FONT_SIZE)
})
.class(TooltipClass, |s| {
s.border(0.5)
.border_color(Color::rgb8(140, 140, 140))
.color(Color::rgb8(80, 80, 80))
.border_radius(2.0)
.padding(padding)
.margin(10.0)
.background(Color::WHITE_SMOKE)
.box_shadow_blur(2.0)
.box_shadow_h_offset(2.0)
.box_shadow_v_offset(2.0)
.box_shadow_color(Color::BLACK.multiply_alpha(0.2))
})
.class(dropdown::DropdownClass, |s| {
s.width(75)
.padding(3)
.apply(border_style)
.class(scroll::ScrollClass, |s| {
s.width_full()
.margin_top(3)
.padding_vert(3)
.background(Color::WHITE_SMOKE)
.box_shadow_blur(2.0)
.box_shadow_h_offset(2.0)
.box_shadow_v_offset(2.0)
.box_shadow_color(Color::BLACK.multiply_alpha(0.4))
.border_radius(5.pct())
.items_center()
.class(ListItemClass, |s| {
s.margin_horiz(3).padding(3).items_center()
})
})
})
.font_size(FONT_SIZE)
.color(Color::BLACK);
Theme {
background: Color::rgb8(248, 248, 248),
style: Rc::new(theme),
}
}