use crate::style::{Color, Style};
pub use crate::widget::theme::{DISABLED_BG, DISABLED_FG};
#[derive(Debug, Clone, Default)]
pub struct WidgetProps {
pub id: Option<String>,
pub classes: Vec<String>,
pub inline_style: Option<Style>,
}
impl WidgetProps {
pub fn new() -> Self {
Self::default()
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn class(mut self, class: impl Into<String>) -> Self {
self.classes.push(class.into());
self
}
pub fn style(mut self, style: Style) -> Self {
self.inline_style = Some(style);
self
}
pub fn classes_slice(&self) -> &[String] {
&self.classes
}
pub fn classes_vec(&self) -> Vec<String> {
self.classes.to_vec()
}
}
#[derive(Debug, Clone, Default)]
pub struct WidgetState {
pub focused: bool,
pub disabled: bool,
pub pressed: bool,
pub hovered: bool,
pub fg: Option<Color>,
pub bg: Option<Color>,
}
impl WidgetState {
pub fn new() -> Self {
Self::default()
}
pub fn focused(mut self, focused: bool) -> Self {
self.focused = focused;
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn pressed(mut self, pressed: bool) -> Self {
self.pressed = pressed;
self
}
pub fn hovered(mut self, hovered: bool) -> Self {
self.hovered = hovered;
self
}
pub fn fg(mut self, color: Color) -> Self {
self.fg = Some(color);
self
}
pub fn bg(mut self, color: Color) -> Self {
self.bg = Some(color);
self
}
pub fn is_focused(&self) -> bool {
self.focused
}
pub fn is_disabled(&self) -> bool {
self.disabled
}
pub fn is_pressed(&self) -> bool {
self.pressed
}
pub fn is_hovered(&self) -> bool {
self.hovered
}
pub fn is_interactive(&self) -> bool {
!self.disabled && (self.focused || self.hovered || self.pressed)
}
pub fn effective_fg(&self, default: Color) -> Color {
if self.disabled {
DISABLED_FG
} else {
self.fg.unwrap_or(default)
}
}
pub fn effective_bg(&self, default: Color) -> Color {
if self.disabled {
DISABLED_BG
} else {
self.bg.unwrap_or(default)
}
}
pub fn state_colors(&self, base_fg: Color, base_bg: Color, hover_bg: Color) -> (Color, Color) {
if self.disabled {
(DISABLED_FG, DISABLED_BG)
} else if self.hovered || self.pressed {
(base_fg, hover_bg)
} else {
(self.fg.unwrap_or(base_fg), self.bg.unwrap_or(base_bg))
}
}
pub fn reset_transient(&mut self) {
self.pressed = false;
self.hovered = false;
}
pub fn set_focused(&mut self, focused: bool) {
self.focused = focused;
}
pub fn set_disabled(&mut self, disabled: bool) {
self.disabled = disabled;
}
pub fn set_hovered(&mut self, hovered: bool) {
self.hovered = hovered;
}
pub fn set_pressed(&mut self, pressed: bool) {
self.pressed = pressed;
}
pub fn set_fg(&mut self, color: Option<Color>) {
self.fg = color;
}
pub fn set_bg(&mut self, color: Option<Color>) {
self.bg = color;
}
pub fn effective_fg_opt(&self) -> Option<Color> {
if self.disabled {
Some(DISABLED_FG)
} else {
self.fg
}
}
pub fn effective_bg_opt(&self) -> Option<Color> {
if self.disabled {
Some(DISABLED_BG)
} else {
self.bg
}
}
pub fn resolve_fg(&self, css_style: Option<&Style>, default: Color) -> Color {
if self.disabled {
return DISABLED_FG;
}
if let Some(fg) = self.fg {
return fg;
}
if let Some(style) = css_style {
let c = style.visual.color;
if c != Color::default() {
return c;
}
}
default
}
pub fn resolve_bg(&self, css_style: Option<&Style>, default: Color) -> Color {
if self.disabled {
return DISABLED_BG;
}
if let Some(bg) = self.bg {
return bg;
}
if let Some(style) = css_style {
let c = style.visual.background;
if c != Color::default() {
return c;
}
}
default
}
pub fn resolve_colors(
&self,
css_style: Option<&Style>,
default_fg: Color,
default_bg: Color,
) -> (Color, Color) {
(
self.resolve_fg(css_style, default_fg),
self.resolve_bg(css_style, default_bg),
)
}
pub fn resolve_colors_interactive(
&self,
css_style: Option<&Style>,
default_fg: Color,
default_bg: Color,
) -> (Color, Color) {
if self.disabled {
return (DISABLED_FG, DISABLED_BG);
}
let fg = self.resolve_fg(css_style, default_fg);
let bg = self.resolve_bg(css_style, default_bg);
let bg = bg.with_interaction(self.pressed, self.hovered, self.focused);
(fg, bg)
}
pub fn visual_changed(&self, other: &WidgetState) -> bool {
self.focused != other.focused
|| self.disabled != other.disabled
|| self.pressed != other.pressed
|| self.hovered != other.hovered
}
}