Files
feresaria/crates/ferese-theme/src/controls.rs
T

236 lines
8.0 KiB
Rust

use cosmic::iced::{Background, Border, Color, Vector};
use cosmic::widget::{button, container};
use cosmic::{theme, widget};
use crate::{Palette, mix};
pub fn surface(background: Color, radius: f32) -> theme::Container<'static> {
theme::Container::custom(move |_| surface_appearance(background, radius))
}
pub fn button_style(p: Palette, selected: bool) -> theme::Button {
styled_button(p, selected, false)
}
pub fn text_button<'a, M: Clone + 'a>(
label: impl Into<std::borrow::Cow<'a, str>> + 'a,
font: cosmic::font::Font,
palette: Palette,
selected: bool,
) -> button::Button<'a, M> {
let theme = cosmic::theme::active();
let native = theme.cosmic();
let content = widget::row![
crate::text(label, font)
.size(14)
.line_height(cosmic::iced::widget::text::LineHeight::Absolute(20.into())),
]
.height(native.space_l())
.padding([0, native.space_s()])
.align_y(cosmic::iced::Alignment::Center);
button::custom(content)
.padding(0)
.class(button_style(palette, selected))
}
pub fn navigation_style(p: Palette, selected: bool) -> theme::Button {
styled_button(p, selected, true)
}
pub fn settings_input(p: Palette) -> theme::TextInput {
let appearance = move |focused: bool, hovered: bool| cosmic::widget::text_input::Appearance {
background: mix(p.sidebar, p.card, if hovered { 0.65 } else { 0.4 }).into(),
border_radius: p.radius.min(7.).into(),
border_width: if focused { 1. } else { 0. },
border_offset: None,
border_color: p.accent,
icon_color: Some(p.muted),
text_color: Some(p.text),
placeholder_color: p.muted,
selected_text_color: p.sidebar,
selected_fill: p.accent,
label_color: p.muted,
};
theme::TextInput::Custom {
active: Box::new(move |_| appearance(false, false)),
hovered: Box::new(move |_| appearance(false, true)),
focused: Box::new(move |_| appearance(true, true)),
error: Box::new(move |_| appearance(true, false)),
disabled: Box::new(move |_| appearance(false, false)),
}
}
fn styled_button(p: Palette, selected: bool, navigation: bool) -> theme::Button {
let style = move |hover: bool| {
let background = if selected {
mix(p.sidebar, p.accent, if hover { 0.24 } else { 0.17 })
} else if hover {
mix(p.card, crate::surface_shade(p.sidebar), 0.06)
} else if navigation {
p.sidebar
} else {
p.card
};
let (background, on) = if selected {
crate::accent_pair(background, p.text)
} else {
(background, p.text)
};
button::Style {
background: Some(Background::Color(background)),
text_color: Some(on),
icon_color: Some(on),
border_radius: p.radius.min(9.).into(),
border_width: if selected { 1. } else { 0. },
border_color: if selected { p.accent } else { Color::TRANSPARENT },
outline_width: 0.,
outline_color: Color::TRANSPARENT,
overlay: None,
shadow_offset: Vector::ZERO,
}
};
theme::Button::Custom {
active: Box::new(move |_, _| style(false)),
hovered: Box::new(move |_, _| style(true)),
pressed: Box::new(move |_, _| style(true)),
disabled: Box::new(move |_| style(false)),
}
}
pub fn authentication_input(palette: Palette) -> theme::TextInput {
let text = palette.text;
let muted = palette.muted;
let accent = palette.accent;
let radius = palette.radius.min(10.);
let appearance = move |focused: bool| widget::text_input::Appearance {
background: Color::from_rgba(text.r, text.g, text.b, 0.045).into(),
border_radius: radius.into(),
border_width: 1.,
border_offset: None,
border_color: if focused {
accent.scale_alpha(0.82)
} else {
muted.scale_alpha(0.26)
},
icon_color: Some(muted),
text_color: Some(text),
placeholder_color: muted,
selected_text_color: text,
selected_fill: accent.scale_alpha(0.35),
label_color: text,
};
theme::TextInput::Custom {
active: Box::new(move |_| appearance(false)),
hovered: Box::new(move |_| appearance(true)),
focused: Box::new(move |_| appearance(true)),
error: Box::new(move |_| appearance(false)),
disabled: Box::new(move |_| appearance(false)),
}
}
pub fn lock_input(radius: f32, accent: cosmic::iced::Color, surface: cosmic::iced::Color) -> theme::TextInput {
let appearance = move |focused: bool| widget::text_input::Appearance {
background: cosmic::iced::Color::from_rgba(
(surface.r + 1.) * 0.5,
(surface.g + 1.) * 0.5,
(surface.b + 1.) * 0.5,
0.24,
)
.into(),
border_radius: (radius * 2.).min(26.).into(),
border_width: 1.,
border_offset: None,
border_color: if focused {
accent.scale_alpha(0.7)
} else {
cosmic::iced::Color::WHITE.scale_alpha(0.15)
},
icon_color: Some(cosmic::iced::Color::WHITE.scale_alpha(0.8)),
text_color: Some(cosmic::iced::Color::WHITE),
placeholder_color: cosmic::iced::Color::WHITE.scale_alpha(0.55),
selected_text_color: cosmic::iced::Color::WHITE,
selected_fill: accent.scale_alpha(0.5),
label_color: cosmic::iced::Color::WHITE,
};
theme::TextInput::Custom {
active: Box::new(move |_| appearance(false)),
hovered: Box::new(move |_| appearance(true)),
focused: Box::new(move |_| appearance(true)),
error: Box::new(move |_| appearance(false)),
disabled: Box::new(move |_| appearance(false)),
}
}
pub fn shell_button(
foreground: Color,
selected: bool,
opacity: f32,
radius: f32,
progress: f32,
pressed: bool,
) -> button::Style {
button::Style {
text_color: Some(foreground),
icon_color: Some(foreground),
border_radius: radius.into(),
background: Some(Background::Color(Color {
a: if pressed {
0.20 * opacity
} else {
((if selected { 0.14 } else { 0.0 }) + progress * if selected { 0.02 } else { 0.08 }) * opacity
},
..foreground
})),
..Default::default()
}
}
pub fn surface_appearance(background: Color, radius: f32) -> container::Style {
container::Style {
background: Some(Background::Color(background)),
border: Border {
radius: radius.into(),
..Default::default()
},
..Default::default()
}
}
pub fn notification_button(foreground: Color, hover: Color, radius: f32, filled: bool) -> theme::Button {
let style = move |active: bool| button::Style {
text_color: Some(foreground),
icon_color: Some(foreground),
background: (active || filled).then_some(Background::Color(hover)),
border_radius: radius.into(),
..Default::default()
};
theme::Button::Custom {
active: Box::new(move |_, _| style(false)),
hovered: Box::new(move |_, _| style(true)),
pressed: Box::new(move |_, _| style(true)),
disabled: Box::new(move |_| style(false)),
}
}
pub fn filled_button(fill: Color, foreground: Color, radius: f32, opacity: f32) -> theme::Button {
let paint = move |outline| button::Style {
background: Some(Color { a: opacity, ..fill }.into()),
text_color: Some(foreground),
icon_color: Some(foreground),
border_radius: radius.into(),
outline_width: outline,
outline_color: foreground,
..Default::default()
};
theme::Button::Custom {
active: Box::new(move |focused, _| paint(if focused { 1. } else { 0. })),
hovered: Box::new(move |_, _| paint(1.)),
pressed: Box::new(move |_, _| paint(2.)),
disabled: Box::new(move |_| paint(0.)),
}
}