use crate::reactive::{IntoSignal, Prop, Signal, create_stored};
use crate::renderer::Shadow;
use crate::transform::{Scale, Translate};
use crate::widgets::Color;
#[derive(Clone, Copy)]
pub struct RippleConfig {
pub color: Signal<Color>,
pub expand_speed: f32,
pub fade_speed: f32,
}
impl Default for RippleConfig {
fn default() -> Self {
Self {
color: create_stored(Color::rgba(1.0, 1.0, 1.0, 0.3)),
expand_speed: 1.0,
fade_speed: 1.0,
}
}
}
impl RippleConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_color<M>(color: impl IntoSignal<Color, M>) -> Self {
Self {
color: color.into_signal(),
expand_speed: 1.0,
fade_speed: 1.0,
}
}
}
#[derive(Clone, Copy)]
pub enum StateWhen {
Hovered,
Pressed,
Focused,
Disabled,
When(Signal<bool>),
}
#[derive(Clone, Copy)]
pub enum BackgroundOverride {
Exact(Signal<Color>),
Lighter(Signal<f32>),
Darker(Signal<f32>),
}
#[derive(Clone, Copy)]
pub struct BorderOverride {
pub width: Signal<f32>,
pub color: Signal<Color>,
}
#[derive(Clone, Default)]
pub struct StateStyle {
pub background: Option<BackgroundOverride>,
pub border: Option<BorderOverride>,
pub corners: Prop<crate::widgets::Corners>,
pub translate: Prop<Translate>,
pub rotate: Prop<f32>,
pub scale: Prop<Scale>,
pub shadow: Prop<Shadow>,
pub alpha: Prop<f32>,
pub ripple: Option<RippleConfig>,
}
#[derive(Debug, Clone, Copy, Default)]
pub(crate) struct Moves {
pub(crate) translate: bool,
pub(crate) rotate: bool,
pub(crate) scale: bool,
}
impl Moves {
pub(crate) fn any(&self) -> bool {
self.translate || self.rotate || self.scale
}
pub(crate) fn merge(&mut self, other: Moves) {
self.translate |= other.translate;
self.rotate |= other.rotate;
self.scale |= other.scale;
}
}
impl StateStyle {
pub(crate) fn moves_anything(&self) -> Moves {
Moves {
translate: self.translate.is_set(),
rotate: self.rotate.is_set(),
scale: self.scale.is_set(),
}
}
pub fn new() -> Self {
Self::default()
}
pub fn background<M>(mut self, color: impl IntoSignal<Color, M>) -> Self {
self.background = Some(BackgroundOverride::Exact(color.into_signal()));
self
}
pub fn lighter<M>(mut self, amount: impl IntoSignal<f32, M>) -> Self {
self.background = Some(BackgroundOverride::Lighter(amount.into_signal()));
self
}
pub fn darker<M>(mut self, amount: impl IntoSignal<f32, M>) -> Self {
self.background = Some(BackgroundOverride::Darker(amount.into_signal()));
self
}
pub fn border<M1, M2>(
mut self,
width: impl IntoSignal<f32, M1>,
color: impl IntoSignal<Color, M2>,
) -> Self {
self.border = Some(BorderOverride {
width: width.into_signal(),
color: color.into_signal(),
});
self
}
pub fn corners<M>(mut self, corners: impl IntoSignal<crate::widgets::Corners, M>) -> Self {
self.corners = corners.into_prop();
self
}
pub fn translate<M>(mut self, translate: impl IntoSignal<Translate, M>) -> Self {
self.translate = translate.into_prop();
self
}
pub fn rotate<M>(mut self, degrees: impl IntoSignal<f32, M>) -> Self {
self.rotate = degrees.into_prop();
self
}
pub fn scale<M>(mut self, factor: impl IntoSignal<Scale, M>) -> Self {
self.scale = factor.into_prop();
self
}
pub fn shadow<M>(mut self, shadow: impl IntoSignal<Shadow, M>) -> Self {
self.shadow = shadow.into_prop();
self
}
pub fn alpha<M>(mut self, alpha: impl IntoSignal<f32, M>) -> Self {
self.alpha = alpha.into_prop();
self
}
pub fn ripple(mut self) -> Self {
self.ripple = Some(RippleConfig::default());
self
}
pub fn ripple_with_color<M>(mut self, color: impl IntoSignal<Color, M>) -> Self {
self.ripple = Some(RippleConfig::with_color(color));
self
}
pub fn ripple_config(mut self, config: RippleConfig) -> Self {
self.ripple = Some(config);
self
}
}
pub fn resolve_background(base: Color, override_: &BackgroundOverride) -> Color {
match override_ {
BackgroundOverride::Exact(color) => color.get(),
BackgroundOverride::Lighter(amount) => base.lighter(amount.get()),
BackgroundOverride::Darker(amount) => base.darker(amount.get()),
}
}
pub trait Stateful: Sized {
type Style: Default;
#[doc(hidden)]
fn push_state_style(&mut self, when: StateWhen, style: Self::Style);
fn when_hovered(mut self, f: impl FnOnce(Self::Style) -> Self::Style) -> Self {
self.push_state_style(StateWhen::Hovered, f(Self::Style::default()));
self
}
fn when_pressed(mut self, f: impl FnOnce(Self::Style) -> Self::Style) -> Self {
self.push_state_style(StateWhen::Pressed, f(Self::Style::default()));
self
}
fn when_focused(mut self, f: impl FnOnce(Self::Style) -> Self::Style) -> Self {
self.push_state_style(StateWhen::Focused, f(Self::Style::default()));
self
}
fn when_disabled(mut self, f: impl FnOnce(Self::Style) -> Self::Style) -> Self {
self.push_state_style(StateWhen::Disabled, f(Self::Style::default()));
self
}
fn state<M>(
mut self,
condition: impl IntoSignal<bool, M>,
f: impl FnOnce(Self::Style) -> Self::Style,
) -> Self {
self.push_state_style(
StateWhen::When(condition.into_signal()),
f(Self::Style::default()),
);
self
}
}