Include Cosmic theme in libcosmic, instead of in Iced fork
I think it's best to only include things in the Iced fork that can't be done without forking Iced, and/or are expected to be merged upstream. The theme doesn't seem to be either, so it fits more appropriately in libcosmic. That should make it easier to keep up with upstream, and it may help to have all the Cosmic parts in one place. Based on https://github.com/pop-os/iced commit ad9026e.
This commit is contained in:
parent
a6d93de47f
commit
947532413a
13 changed files with 1145 additions and 19 deletions
19
Cargo.toml
19
Cargo.toml
|
|
@ -14,12 +14,22 @@ debug = ["iced/debug"]
|
||||||
freedesktop-icons = "0.2.1"
|
freedesktop-icons = "0.2.1"
|
||||||
apply = "0.3.0"
|
apply = "0.3.0"
|
||||||
derive_setters = "0.1.5"
|
derive_setters = "0.1.5"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
palette = "0.6.1"
|
||||||
|
|
||||||
|
[dependencies.cosmic-theme]
|
||||||
|
git = "https://github.com/pop-os/cosmic-theme.git"
|
||||||
|
|
||||||
[dependencies.iced]
|
[dependencies.iced]
|
||||||
git = "https://github.com/pop-os/iced.git"
|
git = "https://github.com/pop-os/iced.git"
|
||||||
branch = "cosmic-design-system"
|
branch = "cosmic-design-system"
|
||||||
# path = "../iced"
|
# path = "../iced"
|
||||||
features = ["cosmic-theme", "image", "svg"]
|
features = ["image", "svg"]
|
||||||
|
|
||||||
|
[dependencies.iced_core]
|
||||||
|
git = "https://github.com/pop-os/iced.git"
|
||||||
|
branch = "cosmic-design-system"
|
||||||
|
# path = "../iced/core"
|
||||||
|
|
||||||
[dependencies.iced_lazy]
|
[dependencies.iced_lazy]
|
||||||
git = "https://github.com/pop-os/iced.git"
|
git = "https://github.com/pop-os/iced.git"
|
||||||
|
|
@ -30,19 +40,22 @@ branch = "cosmic-design-system"
|
||||||
git = "https://github.com/pop-os/iced.git"
|
git = "https://github.com/pop-os/iced.git"
|
||||||
branch = "cosmic-design-system"
|
branch = "cosmic-design-system"
|
||||||
# path = "../iced/native"
|
# path = "../iced/native"
|
||||||
features = ["cosmic-theme"]
|
|
||||||
|
|
||||||
[dependencies.iced_style]
|
[dependencies.iced_style]
|
||||||
git = "https://github.com/pop-os/iced.git"
|
git = "https://github.com/pop-os/iced.git"
|
||||||
branch = "cosmic-design-system"
|
branch = "cosmic-design-system"
|
||||||
# path = "../iced/style"
|
# path = "../iced/style"
|
||||||
features = ["cosmic-theme"]
|
|
||||||
|
|
||||||
[dependencies.iced_winit]
|
[dependencies.iced_winit]
|
||||||
git = "https://github.com/pop-os/iced.git"
|
git = "https://github.com/pop-os/iced.git"
|
||||||
branch = "cosmic-design-system"
|
branch = "cosmic-design-system"
|
||||||
# path = "../iced/winit"
|
# path = "../iced/winit"
|
||||||
|
|
||||||
|
[dependencies.iced_wgpu]
|
||||||
|
git = "https://github.com/pop-os/iced.git"
|
||||||
|
branch = "cosmic-design-system"
|
||||||
|
# path = "../iced/wgpu"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"examples/*",
|
"examples/*",
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@ use cosmic::{
|
||||||
checkbox, column, container, horizontal_space, pick_list, progress_bar, radio, row, slider,
|
checkbox, column, container, horizontal_space, pick_list, progress_bar, radio, row, slider,
|
||||||
text,
|
text,
|
||||||
},
|
},
|
||||||
iced::{self, theme, Alignment, Application, Color, Command, Element, Length, Theme},
|
iced::{self, Alignment, Application, Color, Command, Length},
|
||||||
iced_lazy::responsive,
|
iced_lazy::responsive,
|
||||||
iced_winit::window::{drag, maximize, minimize},
|
iced_winit::window::{drag, maximize, minimize},
|
||||||
list_view, list_view_item, list_view_row, list_view_section, scrollable,
|
list_view, list_view_item, list_view_row, list_view_section, scrollable,
|
||||||
|
theme::{self, Theme},
|
||||||
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
|
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
|
||||||
|
Element,
|
||||||
};
|
};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
|
@ -106,7 +108,7 @@ impl Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let mut header: Element<Message, _> = header_bar()
|
let mut header: Element<Message> = header_bar()
|
||||||
.title(self.title())
|
.title(self.title())
|
||||||
.nav_title(String::from("Settings"))
|
.nav_title(String::from("Settings"))
|
||||||
.sidebar_active(self.sidebar_toggled)
|
.sidebar_active(self.sidebar_toggled)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,13 @@ pub use iced_style;
|
||||||
pub use iced_winit;
|
pub use iced_winit;
|
||||||
|
|
||||||
pub mod font;
|
pub mod font;
|
||||||
|
pub mod theme;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
|
|
||||||
|
pub use theme::Theme;
|
||||||
|
pub type Renderer = iced::Renderer<Theme>;
|
||||||
|
pub type Element<'a, Message> = iced::Element<'a, Message, Renderer>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum WindowMsg {
|
pub enum WindowMsg {
|
||||||
Close,
|
Close,
|
||||||
|
|
|
||||||
0
src/theme/cosmic.rs
Normal file
0
src/theme/cosmic.rs
Normal file
56
src/theme/expander.rs
Normal file
56
src/theme/expander.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use iced_core::{Background, Color};
|
||||||
|
|
||||||
|
/// The appearance of a [`Expander`](crate::native::expander::Expander).
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Appearance {
|
||||||
|
/// The background of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub background: Background,
|
||||||
|
|
||||||
|
/// The border radius of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub border_radius: f32,
|
||||||
|
|
||||||
|
/// The border width of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub border_width: f32,
|
||||||
|
|
||||||
|
/// The border color of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub border_color: Color,
|
||||||
|
|
||||||
|
/// The background of the head of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub head_background: Background,
|
||||||
|
|
||||||
|
/// The text color of the head of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub head_text_color: Color,
|
||||||
|
|
||||||
|
/// The background of the body of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub body_background: Background,
|
||||||
|
|
||||||
|
/// The text color of the body of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub body_text_color: Color,
|
||||||
|
|
||||||
|
/// The color of the close icon of the [`Expander`](crate::native::expander::Expander).
|
||||||
|
pub toggle_color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::default::Default for Appearance {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
background: Color::WHITE.into(),
|
||||||
|
border_radius: 10.0, //32.0,
|
||||||
|
border_width: 1.0,
|
||||||
|
border_color: [0.87, 0.87, 0.87].into(), //Color::BLACK.into(),
|
||||||
|
head_background: Background::Color([0.87, 0.87, 0.87].into()),
|
||||||
|
head_text_color: Color::BLACK,
|
||||||
|
body_background: Color::TRANSPARENT.into(),
|
||||||
|
body_text_color: Color::BLACK,
|
||||||
|
toggle_color: Color::BLACK,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A set of rules that dictate the [`Appearance`] of a container.
|
||||||
|
pub trait StyleSheet {
|
||||||
|
type Style: Default + Copy;
|
||||||
|
|
||||||
|
/// Produces the [`Appearance`] of a container.
|
||||||
|
fn appearance(&self, style: Self::Style) -> Appearance;
|
||||||
|
}
|
||||||
758
src/theme/mod.rs
Normal file
758
src/theme/mod.rs
Normal file
|
|
@ -0,0 +1,758 @@
|
||||||
|
pub mod expander;
|
||||||
|
pub mod palette;
|
||||||
|
|
||||||
|
pub use self::palette::Palette;
|
||||||
|
|
||||||
|
use iced_style::application;
|
||||||
|
use iced_style::button;
|
||||||
|
use iced_style::checkbox;
|
||||||
|
use iced_style::container;
|
||||||
|
use iced_style::menu;
|
||||||
|
use iced_style::pane_grid;
|
||||||
|
use iced_style::pick_list;
|
||||||
|
use iced_style::progress_bar;
|
||||||
|
use iced_style::radio;
|
||||||
|
use iced_style::rule;
|
||||||
|
use iced_style::scrollable;
|
||||||
|
use iced_style::slider;
|
||||||
|
use iced_style::text;
|
||||||
|
use iced_style::text_input;
|
||||||
|
use iced_style::toggler;
|
||||||
|
|
||||||
|
use iced_core::{Background, Color};
|
||||||
|
|
||||||
|
type CosmicColor = ::palette::rgb::Srgba;
|
||||||
|
type CosmicComponent = cosmic_theme::Component<CosmicColor>;
|
||||||
|
type CosmicTheme = cosmic_theme::Theme<CosmicColor>;
|
||||||
|
type CosmicThemeCss = cosmic_theme::Theme<cosmic_theme::util::CssColor>;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub static ref COSMIC_DARK: CosmicTheme = CosmicThemeCss::dark_default().into_srgba();
|
||||||
|
pub static ref COSMIC_LIGHT: CosmicTheme = CosmicThemeCss::light_default().into_srgba();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Theme {
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Theme {
|
||||||
|
pub fn cosmic(self) -> &'static CosmicTheme {
|
||||||
|
match self {
|
||||||
|
Self::Dark => &COSMIC_DARK,
|
||||||
|
Self::Light => &COSMIC_LIGHT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn palette(self) -> Palette {
|
||||||
|
match self {
|
||||||
|
Self::Dark => Palette::DARK,
|
||||||
|
Self::Light => Palette::LIGHT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extended_palette(&self) -> &self::palette::Extended {
|
||||||
|
match self {
|
||||||
|
Self::Dark => &self::palette::EXTENDED_DARK,
|
||||||
|
Self::Light => &self::palette::EXTENDED_LIGHT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Theme {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Dark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Application {
|
||||||
|
Default,
|
||||||
|
Custom(fn(Theme) -> application::Appearance),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Application {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl application::StyleSheet for Theme {
|
||||||
|
type Style = Application;
|
||||||
|
|
||||||
|
fn appearance(&self, style: Self::Style) -> application::Appearance {
|
||||||
|
let cosmic = self.cosmic();
|
||||||
|
|
||||||
|
match style {
|
||||||
|
Application::Default => application::Appearance {
|
||||||
|
background_color: cosmic.bg_color().into(),
|
||||||
|
text_color: cosmic.on_bg_color().into(),
|
||||||
|
},
|
||||||
|
Application::Custom(f) => f(*self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Button
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Button {
|
||||||
|
Primary,
|
||||||
|
Secondary,
|
||||||
|
Positive,
|
||||||
|
Destructive,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Button {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Button {
|
||||||
|
fn cosmic(&self, theme: &Theme) -> &'static CosmicComponent {
|
||||||
|
let cosmic = theme.cosmic();
|
||||||
|
match self {
|
||||||
|
Button::Primary => &cosmic.accent,
|
||||||
|
Button::Secondary => &cosmic.primary.component,
|
||||||
|
Button::Positive => &cosmic.success,
|
||||||
|
Button::Destructive => &cosmic.destructive,
|
||||||
|
Button::Text => &cosmic.secondary.component,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl button::StyleSheet for Theme {
|
||||||
|
type Style = Button;
|
||||||
|
|
||||||
|
fn active(&self, style: Self::Style) -> button::Appearance {
|
||||||
|
let cosmic = style.cosmic(self);
|
||||||
|
|
||||||
|
button::Appearance {
|
||||||
|
border_radius: 24.0,
|
||||||
|
background: match style {
|
||||||
|
Button::Text => None,
|
||||||
|
_ => Some(Background::Color(cosmic.base.into())),
|
||||||
|
},
|
||||||
|
text_color: cosmic.on.into(),
|
||||||
|
..button::Appearance::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self, style: Self::Style) -> button::Appearance {
|
||||||
|
let active = self.active(style);
|
||||||
|
let cosmic = style.cosmic(self);
|
||||||
|
|
||||||
|
button::Appearance {
|
||||||
|
background: Some(Background::Color(cosmic.hover.into())),
|
||||||
|
..active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Checkbox
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Checkbox {
|
||||||
|
Primary,
|
||||||
|
Secondary,
|
||||||
|
Success,
|
||||||
|
Danger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Checkbox {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl checkbox::StyleSheet for Theme {
|
||||||
|
type Style = Checkbox;
|
||||||
|
|
||||||
|
fn active(
|
||||||
|
&self,
|
||||||
|
style: Self::Style,
|
||||||
|
is_checked: bool,
|
||||||
|
) -> checkbox::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
match style {
|
||||||
|
Checkbox::Primary => checkbox_appearance(
|
||||||
|
palette.primary.strong.text,
|
||||||
|
palette.background.base,
|
||||||
|
palette.primary.strong,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
Checkbox::Secondary => checkbox_appearance(
|
||||||
|
palette.background.base.text,
|
||||||
|
palette.background.base,
|
||||||
|
palette.background.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
Checkbox::Success => checkbox_appearance(
|
||||||
|
palette.success.base.text,
|
||||||
|
palette.background.base,
|
||||||
|
palette.success.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
Checkbox::Danger => checkbox_appearance(
|
||||||
|
palette.danger.base.text,
|
||||||
|
palette.background.base,
|
||||||
|
palette.danger.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(
|
||||||
|
&self,
|
||||||
|
style: Self::Style,
|
||||||
|
is_checked: bool,
|
||||||
|
) -> checkbox::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
match style {
|
||||||
|
Checkbox::Primary => checkbox_appearance(
|
||||||
|
palette.primary.strong.text,
|
||||||
|
palette.background.weak,
|
||||||
|
palette.primary.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
Checkbox::Secondary => checkbox_appearance(
|
||||||
|
palette.background.base.text,
|
||||||
|
palette.background.weak,
|
||||||
|
palette.background.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
Checkbox::Success => checkbox_appearance(
|
||||||
|
palette.success.base.text,
|
||||||
|
palette.background.weak,
|
||||||
|
palette.success.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
Checkbox::Danger => checkbox_appearance(
|
||||||
|
palette.danger.base.text,
|
||||||
|
palette.background.weak,
|
||||||
|
palette.danger.base,
|
||||||
|
is_checked,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checkbox_appearance(
|
||||||
|
checkmark_color: Color,
|
||||||
|
base: palette::Pair,
|
||||||
|
accent: palette::Pair,
|
||||||
|
is_checked: bool,
|
||||||
|
) -> checkbox::Appearance {
|
||||||
|
checkbox::Appearance {
|
||||||
|
background: Background::Color(if is_checked {
|
||||||
|
accent.color
|
||||||
|
} else {
|
||||||
|
base.color
|
||||||
|
}),
|
||||||
|
checkmark_color,
|
||||||
|
border_radius: 4.0,
|
||||||
|
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||||
|
border_color: accent.color,
|
||||||
|
text_color: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Expander {
|
||||||
|
Default,
|
||||||
|
Custom(fn(&Theme) -> expander::Appearance),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Expander {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<fn(&Theme) -> expander::Appearance> for Expander {
|
||||||
|
fn from(f: fn(&Theme) -> expander::Appearance) -> Self {
|
||||||
|
Self::Custom(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl expander::StyleSheet for Theme {
|
||||||
|
type Style = Expander;
|
||||||
|
|
||||||
|
fn appearance(&self, style: Self::Style) -> expander::Appearance {
|
||||||
|
match style {
|
||||||
|
Expander::Default => Default::default(),
|
||||||
|
Expander::Custom(f) => f(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Container
|
||||||
|
*/
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Container {
|
||||||
|
Transparent,
|
||||||
|
Box,
|
||||||
|
Custom(fn(&Theme) -> container::Appearance),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Container {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Transparent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<fn(&Theme) -> container::Appearance> for Container {
|
||||||
|
fn from(f: fn(&Theme) -> container::Appearance) -> Self {
|
||||||
|
Self::Custom(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl container::StyleSheet for Theme {
|
||||||
|
type Style = Container;
|
||||||
|
|
||||||
|
fn appearance(&self, style: Self::Style) -> container::Appearance {
|
||||||
|
match style {
|
||||||
|
Container::Transparent => Default::default(),
|
||||||
|
Container::Box => {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
container::Appearance {
|
||||||
|
text_color: None,
|
||||||
|
background: palette.background.weak.color.into(),
|
||||||
|
border_radius: 2.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Container::Custom(f) => f(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slider
|
||||||
|
*/
|
||||||
|
impl slider::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn active(&self, _style: Self::Style) -> slider::Appearance {
|
||||||
|
let cosmic = self.cosmic();
|
||||||
|
|
||||||
|
//TODO: no way to set rail thickness
|
||||||
|
slider::Appearance {
|
||||||
|
rail_colors: (
|
||||||
|
cosmic.accent.base.into(),
|
||||||
|
//TODO: no way to set color before/after slider
|
||||||
|
Color::TRANSPARENT,
|
||||||
|
),
|
||||||
|
handle: slider::Handle {
|
||||||
|
shape: slider::HandleShape::Circle {
|
||||||
|
radius: 10.0,
|
||||||
|
},
|
||||||
|
color: cosmic.accent.base.into(),
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
border_width: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self, style: Self::Style) -> slider::Appearance {
|
||||||
|
let mut style = self.active(style);
|
||||||
|
style.handle.shape = slider::HandleShape::Circle {
|
||||||
|
radius: 16.0
|
||||||
|
};
|
||||||
|
style.handle.border_width = 6.0;
|
||||||
|
style.handle.border_color = match self {
|
||||||
|
Theme::Dark => Color::from_rgba8(0xFF, 0xFF, 0xFF, 0.1),
|
||||||
|
Theme::Light => Color::from_rgba8(0, 0, 0, 0.1),
|
||||||
|
};
|
||||||
|
style
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dragging(&self, style: Self::Style) -> slider::Appearance {
|
||||||
|
let mut style = self.hovered(style);
|
||||||
|
style.handle.border_color = match self {
|
||||||
|
Theme::Dark => Color::from_rgba8(0xFF, 0xFF, 0xFF, 0.2),
|
||||||
|
Theme::Light => Color::from_rgba8(0, 0, 0, 0.2),
|
||||||
|
};
|
||||||
|
style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Menu
|
||||||
|
*/
|
||||||
|
impl menu::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn appearance(&self, _style: Self::Style) -> menu::Appearance {
|
||||||
|
let cosmic = self.cosmic();
|
||||||
|
|
||||||
|
menu::Appearance {
|
||||||
|
text_color: cosmic.primary.component.on.into(),
|
||||||
|
background: Background::Color(cosmic.background.base.into()),
|
||||||
|
border_width: 0.0,
|
||||||
|
border_radius: 16.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
selected_text_color: cosmic.primary.component.on.into(),
|
||||||
|
selected_background: Background::Color(cosmic.primary.component.hover.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Pick List
|
||||||
|
*/
|
||||||
|
impl pick_list::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn active(&self, _style: ()) -> pick_list::Appearance {
|
||||||
|
let cosmic = &self.cosmic().primary.component;
|
||||||
|
|
||||||
|
pick_list::Appearance {
|
||||||
|
text_color: cosmic.on.into(),
|
||||||
|
background: Color::TRANSPARENT.into(),
|
||||||
|
placeholder_color: cosmic.on.into(),
|
||||||
|
border_radius: 24.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
icon_size: 0.7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self, style: ()) -> pick_list::Appearance {
|
||||||
|
let cosmic = &self.cosmic().primary.component;
|
||||||
|
|
||||||
|
pick_list::Appearance {
|
||||||
|
background: Background::Color(cosmic.hover.into()),
|
||||||
|
..self.active(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Radio
|
||||||
|
*/
|
||||||
|
impl radio::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn active(&self, _style: Self::Style) -> radio::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
radio::Appearance {
|
||||||
|
background: Color::TRANSPARENT.into(),
|
||||||
|
dot_color: palette.primary.strong.color,
|
||||||
|
border_width: 1.0,
|
||||||
|
border_color: palette.primary.strong.color,
|
||||||
|
text_color: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self, style: Self::Style) -> radio::Appearance {
|
||||||
|
let active = self.active(style);
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
radio::Appearance {
|
||||||
|
dot_color: palette.primary.strong.color,
|
||||||
|
background: palette.primary.weak.color.into(),
|
||||||
|
..active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Toggler
|
||||||
|
*/
|
||||||
|
impl toggler::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn active(
|
||||||
|
&self,
|
||||||
|
_style: Self::Style,
|
||||||
|
is_active: bool,
|
||||||
|
) -> toggler::Appearance {
|
||||||
|
let palette = self.palette();
|
||||||
|
|
||||||
|
toggler::Appearance {
|
||||||
|
background: if is_active {
|
||||||
|
palette.primary
|
||||||
|
} else {
|
||||||
|
//TODO: Grab neutral from palette
|
||||||
|
match self {
|
||||||
|
Theme::Dark => Color::from_rgb8(0x78, 0x78, 0x78),
|
||||||
|
Theme::Light => Color::from_rgb8(0x93, 0x93, 0x93),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
background_border: None,
|
||||||
|
//TODO: Grab neutral from palette
|
||||||
|
foreground: match self {
|
||||||
|
Theme::Dark => Color::from_rgb8(0x27, 0x27, 0x27),
|
||||||
|
Theme::Light => Color::from_rgb8(0xe4, 0xe4, 0xe4),
|
||||||
|
},
|
||||||
|
foreground_border: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(
|
||||||
|
&self,
|
||||||
|
style: Self::Style,
|
||||||
|
is_active: bool,
|
||||||
|
) -> toggler::Appearance {
|
||||||
|
//TODO: grab colors from palette
|
||||||
|
match self {
|
||||||
|
Theme::Dark => toggler::Appearance {
|
||||||
|
background: if is_active {
|
||||||
|
Color::from_rgb8(0x9f, 0xed, 0xed)
|
||||||
|
} else {
|
||||||
|
Color::from_rgb8(0xb6, 0xb6, 0xb6)
|
||||||
|
},
|
||||||
|
..self.active(style, is_active)
|
||||||
|
},
|
||||||
|
Theme::Light => toggler::Appearance {
|
||||||
|
background: if is_active {
|
||||||
|
Color::from_rgb8(0x00, 0x42, 0x62)
|
||||||
|
} else {
|
||||||
|
Color::from_rgb8(0x54, 0x54, 0x54)
|
||||||
|
},
|
||||||
|
..self.active(style, is_active)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Pane Grid
|
||||||
|
*/
|
||||||
|
impl pane_grid::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn picked_split(&self, _style: Self::Style) -> Option<pane_grid::Line> {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
Some(pane_grid::Line {
|
||||||
|
color: palette.primary.strong.color,
|
||||||
|
width: 2.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered_split(&self, _style: Self::Style) -> Option<pane_grid::Line> {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
Some(pane_grid::Line {
|
||||||
|
color: palette.primary.base.color,
|
||||||
|
width: 2.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Progress Bar
|
||||||
|
*/
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ProgressBar {
|
||||||
|
Primary,
|
||||||
|
Success,
|
||||||
|
Danger,
|
||||||
|
Custom(fn(&Theme) -> progress_bar::Appearance),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ProgressBar {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl progress_bar::StyleSheet for Theme {
|
||||||
|
type Style = ProgressBar;
|
||||||
|
|
||||||
|
fn appearance(&self, style: Self::Style) -> progress_bar::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
let from_palette = |bar: Color| progress_bar::Appearance {
|
||||||
|
background: palette.background.strong.color.into(),
|
||||||
|
bar: bar.into(),
|
||||||
|
border_radius: 2.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
match style {
|
||||||
|
ProgressBar::Primary => from_palette(palette.primary.base.color),
|
||||||
|
ProgressBar::Success => from_palette(palette.success.base.color),
|
||||||
|
ProgressBar::Danger => from_palette(palette.danger.base.color),
|
||||||
|
ProgressBar::Custom(f) => f(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Rule
|
||||||
|
*/
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Rule {
|
||||||
|
Default,
|
||||||
|
Custom(fn(&Theme) -> rule::Appearance),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Rule {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rule::StyleSheet for Theme {
|
||||||
|
type Style = Rule;
|
||||||
|
|
||||||
|
fn style(&self, style: Self::Style) -> rule::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
match style {
|
||||||
|
Rule::Default => rule::Appearance {
|
||||||
|
color: palette.background.strong.color,
|
||||||
|
width: 1,
|
||||||
|
radius: 0.0,
|
||||||
|
fill_mode: rule::FillMode::Full,
|
||||||
|
},
|
||||||
|
Rule::Custom(f) => f(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Scrollable
|
||||||
|
*/
|
||||||
|
impl scrollable::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn active(&self, _style: Self::Style) -> scrollable::Scrollbar {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
scrollable::Scrollbar {
|
||||||
|
background: palette.background.weak.color.into(),
|
||||||
|
border_radius: 4.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
scroller: scrollable::Scroller {
|
||||||
|
color: palette.background.strong.color,
|
||||||
|
border_radius: 4.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self, _style: Self::Style) -> scrollable::Scrollbar {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
scrollable::Scrollbar {
|
||||||
|
background: palette.background.weak.color.into(),
|
||||||
|
border_radius: 4.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
scroller: scrollable::Scroller {
|
||||||
|
color: palette.primary.strong.color,
|
||||||
|
border_radius: 4.0,
|
||||||
|
border_width: 0.0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Text
|
||||||
|
*/
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Text {
|
||||||
|
Default,
|
||||||
|
Color(Color),
|
||||||
|
Custom(fn(&Theme) -> text::Appearance),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Text {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for Text {
|
||||||
|
fn from(color: Color) -> Self {
|
||||||
|
Text::Color(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl text::StyleSheet for Theme {
|
||||||
|
type Style = Text;
|
||||||
|
|
||||||
|
fn appearance(&self, style: Self::Style) -> text::Appearance {
|
||||||
|
match style {
|
||||||
|
Text::Default => Default::default(),
|
||||||
|
Text::Color(c) => text::Appearance { color: Some(c) },
|
||||||
|
Text::Custom(f) => f(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Text Input
|
||||||
|
*/
|
||||||
|
impl text_input::StyleSheet for Theme {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn active(&self, _style: Self::Style) -> text_input::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
text_input::Appearance {
|
||||||
|
background: palette.background.base.color.into(),
|
||||||
|
border_radius: 2.0,
|
||||||
|
border_width: 1.0,
|
||||||
|
border_color: palette.background.strong.color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self, _style: Self::Style) -> text_input::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
text_input::Appearance {
|
||||||
|
background: palette.background.base.color.into(),
|
||||||
|
border_radius: 2.0,
|
||||||
|
border_width: 1.0,
|
||||||
|
border_color: palette.background.base.text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focused(&self, _style: Self::Style) -> text_input::Appearance {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
text_input::Appearance {
|
||||||
|
background: palette.background.base.color.into(),
|
||||||
|
border_radius: 2.0,
|
||||||
|
border_width: 1.0,
|
||||||
|
border_color: palette.primary.strong.color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn placeholder_color(&self, _style: Self::Style) -> Color {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
palette.background.strong.color
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_color(&self, _style: Self::Style) -> Color {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
palette.background.base.text
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selection_color(&self, _style: Self::Style) -> Color {
|
||||||
|
let palette = self.extended_palette();
|
||||||
|
|
||||||
|
palette.primary.weak.color
|
||||||
|
}
|
||||||
|
}
|
||||||
290
src/theme/palette.rs
Normal file
290
src/theme/palette.rs
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
//TODO: GET CORRECT PALETTE FROM COSMIC-THEME
|
||||||
|
use iced_core::Color;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use palette::{FromColor, Hsl, Mix, RelativeContrast, Srgb};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct Palette {
|
||||||
|
pub background: Color,
|
||||||
|
pub text: Color,
|
||||||
|
pub primary: Color,
|
||||||
|
pub success: Color,
|
||||||
|
pub danger: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Palette {
|
||||||
|
pub const LIGHT: Self = Self {
|
||||||
|
background: Color::from_rgb(
|
||||||
|
0xee as f32 / 255.0,
|
||||||
|
0xee as f32 / 255.0,
|
||||||
|
0xee as f32 / 255.0,
|
||||||
|
),
|
||||||
|
text: Color::from_rgb(
|
||||||
|
0x00 as f32 / 255.0,
|
||||||
|
0x00 as f32 / 255.0,
|
||||||
|
0x00 as f32 / 255.0,
|
||||||
|
),
|
||||||
|
primary: Color::from_rgb(
|
||||||
|
0x00 as f32 / 255.0,
|
||||||
|
0x49 as f32 / 255.0,
|
||||||
|
0x6d as f32 / 255.0,
|
||||||
|
),
|
||||||
|
success: Color::from_rgb(
|
||||||
|
0x3b as f32 / 255.0,
|
||||||
|
0x6e as f32 / 255.0,
|
||||||
|
0x43 as f32 / 255.0,
|
||||||
|
),
|
||||||
|
danger: Color::from_rgb(
|
||||||
|
0xa0 as f32 / 255.0,
|
||||||
|
0x25 as f32 / 255.0,
|
||||||
|
0x2b as f32 / 255.0,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DARK: Self = Self {
|
||||||
|
background: Color::from_rgb(
|
||||||
|
0x1e as f32 / 255.0,
|
||||||
|
0x1e as f32 / 255.0,
|
||||||
|
0x1e as f32 / 255.0
|
||||||
|
),
|
||||||
|
text: Color::from_rgb(
|
||||||
|
0xe4 as f32 / 255.0,
|
||||||
|
0xe4 as f32 / 255.0,
|
||||||
|
0xe4 as f32 / 255.0,
|
||||||
|
),
|
||||||
|
primary: Color::from_rgb(
|
||||||
|
0x94 as f32 / 255.0,
|
||||||
|
0xeb as f32 / 255.0,
|
||||||
|
0xeb as f32 / 255.0,
|
||||||
|
),
|
||||||
|
success: Color::from_rgb(
|
||||||
|
0xac as f32 / 255.0,
|
||||||
|
0xf7 as f32 / 255.0,
|
||||||
|
0xd2 as f32 / 255.0,
|
||||||
|
),
|
||||||
|
danger: Color::from_rgb(
|
||||||
|
0xff as f32 / 255.0,
|
||||||
|
0xb5 as f32 / 255.0,
|
||||||
|
0xb5 as f32 / 255.0,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Extended {
|
||||||
|
pub background: Background,
|
||||||
|
pub primary: Primary,
|
||||||
|
pub secondary: Secondary,
|
||||||
|
pub success: Success,
|
||||||
|
pub danger: Danger,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref EXTENDED_LIGHT: Extended =
|
||||||
|
Extended::generate(Palette::LIGHT);
|
||||||
|
pub static ref EXTENDED_DARK: Extended = Extended::generate(Palette::DARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Extended {
|
||||||
|
pub fn generate(palette: Palette) -> Self {
|
||||||
|
Self {
|
||||||
|
background: Background::new(palette.background, palette.text),
|
||||||
|
primary: Primary::generate(
|
||||||
|
palette.primary,
|
||||||
|
palette.background,
|
||||||
|
palette.text,
|
||||||
|
),
|
||||||
|
secondary: Secondary::generate(palette.background, palette.text),
|
||||||
|
success: Success::generate(
|
||||||
|
palette.success,
|
||||||
|
palette.background,
|
||||||
|
palette.text,
|
||||||
|
),
|
||||||
|
danger: Danger::generate(
|
||||||
|
palette.danger,
|
||||||
|
palette.background,
|
||||||
|
palette.text,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Pair {
|
||||||
|
pub color: Color,
|
||||||
|
pub text: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pair {
|
||||||
|
pub fn new(color: Color, text: Color) -> Self {
|
||||||
|
Self {
|
||||||
|
color,
|
||||||
|
text: readable(color, text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Background {
|
||||||
|
pub base: Pair,
|
||||||
|
pub weak: Pair,
|
||||||
|
pub strong: Pair,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Background {
|
||||||
|
pub fn new(base: Color, text: Color) -> Self {
|
||||||
|
let weak = mix(base, text, 0.15);
|
||||||
|
let strong = mix(base, text, 0.40);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base: Pair::new(base, text),
|
||||||
|
weak: Pair::new(weak, text),
|
||||||
|
strong: Pair::new(strong, text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Primary {
|
||||||
|
pub base: Pair,
|
||||||
|
pub weak: Pair,
|
||||||
|
pub strong: Pair,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Primary {
|
||||||
|
pub fn generate(base: Color, background: Color, text: Color) -> Self {
|
||||||
|
let weak = mix(base, background, 0.4);
|
||||||
|
let strong = deviate(base, 0.1);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base: Pair::new(base, text),
|
||||||
|
weak: Pair::new(weak, text),
|
||||||
|
strong: Pair::new(strong, text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Secondary {
|
||||||
|
pub base: Pair,
|
||||||
|
pub weak: Pair,
|
||||||
|
pub strong: Pair,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secondary {
|
||||||
|
pub fn generate(base: Color, text: Color) -> Self {
|
||||||
|
let base = mix(base, text, 0.2);
|
||||||
|
let weak = mix(base, text, 0.1);
|
||||||
|
let strong = mix(base, text, 0.3);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base: Pair::new(base, text),
|
||||||
|
weak: Pair::new(weak, text),
|
||||||
|
strong: Pair::new(strong, text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Success {
|
||||||
|
pub base: Pair,
|
||||||
|
pub weak: Pair,
|
||||||
|
pub strong: Pair,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Success {
|
||||||
|
pub fn generate(base: Color, background: Color, text: Color) -> Self {
|
||||||
|
let weak = mix(base, background, 0.4);
|
||||||
|
let strong = deviate(base, 0.1);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base: Pair::new(base, text),
|
||||||
|
weak: Pair::new(weak, text),
|
||||||
|
strong: Pair::new(strong, text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Danger {
|
||||||
|
pub base: Pair,
|
||||||
|
pub weak: Pair,
|
||||||
|
pub strong: Pair,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Danger {
|
||||||
|
pub fn generate(base: Color, background: Color, text: Color) -> Self {
|
||||||
|
let weak = mix(base, background, 0.4);
|
||||||
|
let strong = deviate(base, 0.1);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base: Pair::new(base, text),
|
||||||
|
weak: Pair::new(weak, text),
|
||||||
|
strong: Pair::new(strong, text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn darken(color: Color, amount: f32) -> Color {
|
||||||
|
let mut hsl = to_hsl(color);
|
||||||
|
|
||||||
|
hsl.lightness = if hsl.lightness - amount < 0.0 {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
hsl.lightness - amount
|
||||||
|
};
|
||||||
|
|
||||||
|
from_hsl(hsl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lighten(color: Color, amount: f32) -> Color {
|
||||||
|
let mut hsl = to_hsl(color);
|
||||||
|
|
||||||
|
hsl.lightness = if hsl.lightness + amount > 1.0 {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
hsl.lightness + amount
|
||||||
|
};
|
||||||
|
|
||||||
|
from_hsl(hsl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deviate(color: Color, amount: f32) -> Color {
|
||||||
|
if is_dark(color) {
|
||||||
|
lighten(color, amount)
|
||||||
|
} else {
|
||||||
|
darken(color, amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mix(a: Color, b: Color, factor: f32) -> Color {
|
||||||
|
let a_lin = Srgb::from(a).into_linear();
|
||||||
|
let b_lin = Srgb::from(b).into_linear();
|
||||||
|
|
||||||
|
let mixed = a_lin.mix(&b_lin, factor);
|
||||||
|
Srgb::from_linear(mixed).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readable(background: Color, text: Color) -> Color {
|
||||||
|
if is_readable(background, text) {
|
||||||
|
text
|
||||||
|
} else if is_dark(background) {
|
||||||
|
Color::WHITE
|
||||||
|
} else {
|
||||||
|
Color::BLACK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dark(color: Color) -> bool {
|
||||||
|
to_hsl(color).lightness < 0.6
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_readable(a: Color, b: Color) -> bool {
|
||||||
|
let a_srgb = Srgb::from(a);
|
||||||
|
let b_srgb = Srgb::from(b);
|
||||||
|
|
||||||
|
a_srgb.has_enhanced_contrast_text(&b_srgb)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_hsl(color: Color) -> Hsl {
|
||||||
|
Hsl::from_color(Srgb::from(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_hsl(hsl: Hsl) -> Color {
|
||||||
|
Srgb::from_color(hsl).into()
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use crate::{list_box_row, separator, widget::ListRow};
|
use crate::{list_box_row, separator, theme, widget::ListRow, Element, Renderer, Theme};
|
||||||
use apply::Apply;
|
use apply::Apply;
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced::{
|
use iced::{
|
||||||
theme,
|
|
||||||
widget::{self, button, container, horizontal_space, row, text, Column},
|
widget::{self, button, container, horizontal_space, row, text, Column},
|
||||||
Alignment, Background, Element, Length, Renderer, Theme,
|
Alignment, Background, Length,
|
||||||
};
|
};
|
||||||
use iced_lazy::Component;
|
use iced_lazy::Component;
|
||||||
use iced_native::widget::{column, event_container};
|
use iced_native::widget::{column, event_container};
|
||||||
|
|
@ -86,14 +85,14 @@ impl<'a, Message: Clone + 'a> Component<Message, Renderer> for Expander<'a, Mess
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, state: &Self::State) -> Element<Self::Event> {
|
fn view(&self, state: &Self::State) -> Element<Self::Event> {
|
||||||
let heading: Element<ExpanderEvent, Renderer> = {
|
let heading: Element<ExpanderEvent> = {
|
||||||
let mut captions = vec![text(&self.title).size(18).into()];
|
let mut captions = vec![text(&self.title).size(18).into()];
|
||||||
if let Some(subtitle) = &self.subtitle {
|
if let Some(subtitle) = &self.subtitle {
|
||||||
captions.push(text(subtitle).size(16).into());
|
captions.push(text(subtitle).size(16).into());
|
||||||
}
|
}
|
||||||
let text = column(captions);
|
let text = column(captions);
|
||||||
let space: Element<ExpanderEvent, Renderer> = horizontal_space(Length::Fill).into();
|
let space: Element<ExpanderEvent> = horizontal_space(Length::Fill).into();
|
||||||
let toggler: Element<ExpanderEvent, Renderer> = {
|
let toggler: Element<ExpanderEvent> = {
|
||||||
let mut icon = super::icon(
|
let mut icon = super::icon(
|
||||||
if state.expanded {
|
if state.expanded {
|
||||||
"go-down-symbolic"
|
"go-down-symbolic"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use apply::Apply;
|
use apply::Apply;
|
||||||
use derive_setters::*;
|
use derive_setters::*;
|
||||||
use iced::{self, alignment::Vertical, theme, widget, Element, Length, Renderer};
|
use iced::{self, alignment::Vertical, widget, Length};
|
||||||
use iced_lazy::Component;
|
use iced_lazy::Component;
|
||||||
|
use crate::{theme, Element, Renderer};
|
||||||
|
|
||||||
#[derive(Setters)]
|
#[derive(Setters)]
|
||||||
pub struct HeaderBar<Message> {
|
pub struct HeaderBar<Message> {
|
||||||
|
|
@ -103,7 +104,7 @@ impl<Message: Clone> Component<Message, Renderer> for HeaderBar<Message> {
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let window_controls = {
|
let window_controls = {
|
||||||
let mut widgets: Vec<Element<HeaderEvent, _>> = Vec::with_capacity(3);
|
let mut widgets: Vec<Element<HeaderEvent>> = Vec::with_capacity(3);
|
||||||
|
|
||||||
let icon = |name, size, on_press| {
|
let icon = |name, size, on_press| {
|
||||||
super::icon(name, size)
|
super::icon(name, size)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::separator;
|
use crate::separator;
|
||||||
|
use crate::theme::{self, Container};
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced::mouse::Interaction;
|
use iced::mouse::Interaction;
|
||||||
use iced::{overlay, Alignment, Length, Padding, Point, Rectangle};
|
use iced::{overlay, Alignment, Length, Padding, Point, Rectangle};
|
||||||
|
|
@ -12,8 +13,6 @@ use iced_native::{
|
||||||
renderer, row, Background, Clipboard, Color, Element, Event, Layout, Shell, Widget,
|
renderer, row, Background, Clipboard, Color, Element, Event, Layout, Shell, Widget,
|
||||||
};
|
};
|
||||||
use iced_style::container::{Appearance, StyleSheet};
|
use iced_style::container::{Appearance, StyleSheet};
|
||||||
use iced_style::theme;
|
|
||||||
use iced_style::theme::Container;
|
|
||||||
|
|
||||||
#[derive(Setters)]
|
#[derive(Setters)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub use iced::{widget, Background, Color, Theme};
|
pub use iced::{widget, Background, Color};
|
||||||
|
pub use crate::Theme;
|
||||||
|
|
||||||
pub mod list_view {
|
pub mod list_view {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
@ -82,7 +83,7 @@ pub mod list_view {
|
||||||
|
|
||||||
use crate::widget::{Background, Color};
|
use crate::widget::{Background, Color};
|
||||||
use iced::widget;
|
use iced::widget;
|
||||||
use iced_style::Theme;
|
use crate::Theme;
|
||||||
|
|
||||||
pub use list_view;
|
pub use list_view;
|
||||||
pub use list_view_item;
|
pub use list_view_item;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod nav_bar {
|
pub mod nav_bar {
|
||||||
use iced::{widget, Background, Color, Theme};
|
use iced::{widget, Background, Color};
|
||||||
|
use crate::Theme;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! nav_button {
|
macro_rules! nav_button {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::scrollable;
|
use crate::scrollable;
|
||||||
use crate::widget::nav_bar::{nav_bar_pages_style, nav_bar_sections_style};
|
use crate::widget::nav_bar::{nav_bar_pages_style, nav_bar_sections_style};
|
||||||
use crate::widget::{icon, Background};
|
use crate::widget::{icon, Background};
|
||||||
|
use crate::{theme, Theme};
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced::Length;
|
use iced::Length;
|
||||||
use iced_lazy::Component;
|
use iced_lazy::Component;
|
||||||
use iced_native::widget::{button, column, container, text};
|
use iced_native::widget::{button, column, container, text};
|
||||||
use iced_native::{row, Alignment, Element};
|
use iced_native::{row, Alignment, Element};
|
||||||
use iced_style::button::Appearance;
|
use iced_style::button::Appearance;
|
||||||
use iced_style::{scrollable, theme, Theme};
|
use iced_style::scrollable;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Setters, Default)]
|
#[derive(Setters, Default)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue