fret_ui_kit/style/
state.rs1use std::ops::{BitOr, BitOrAssign};
2
3use fret_ui::element::PressableState;
4use fret_ui::{ElementContext, UiHost};
5use smallvec::SmallVec;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[repr(u16)]
9pub enum WidgetState {
10 Disabled = 1 << 0,
11 Hovered = 1 << 1,
12 Active = 1 << 2,
13 Focused = 1 << 3,
14 FocusVisible = 1 << 4,
15 Selected = 1 << 5,
16 Open = 1 << 6,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
20pub struct WidgetStates(u16);
21
22impl WidgetStates {
23 pub const fn empty() -> Self {
24 Self(0)
25 }
26
27 pub const DISABLED: Self = Self(WidgetState::Disabled as u16);
28 pub const HOVERED: Self = Self(WidgetState::Hovered as u16);
29 pub const ACTIVE: Self = Self(WidgetState::Active as u16);
30 pub const FOCUSED: Self = Self(WidgetState::Focused as u16);
31 pub const FOCUS_VISIBLE: Self = Self(WidgetState::FocusVisible as u16);
32 pub const SELECTED: Self = Self(WidgetState::Selected as u16);
33 pub const OPEN: Self = Self(WidgetState::Open as u16);
34
35 pub const fn contains(self, other: Self) -> bool {
36 (self.0 & other.0) == other.0
37 }
38
39 pub fn has(self, state: WidgetState) -> bool {
40 self.contains(Self::from(state))
41 }
42
43 pub fn insert(&mut self, state: WidgetState) {
44 self.0 |= state as u16;
45 }
46
47 pub fn remove(&mut self, state: WidgetState) {
48 self.0 &= !(state as u16);
49 }
50
51 pub fn set(&mut self, state: WidgetState, enabled: bool) {
52 if enabled {
53 self.insert(state);
54 } else {
55 self.remove(state);
56 }
57 }
58
59 pub fn from_pressable<H: UiHost>(
60 cx: &mut ElementContext<'_, H>,
61 st: PressableState,
62 enabled: bool,
63 ) -> Self {
64 let mut states = Self::empty();
65 states.set(WidgetState::Disabled, !enabled);
66 states.set(WidgetState::Hovered, enabled && st.hovered);
67 states.set(WidgetState::Active, enabled && st.pressed);
68 states.set(WidgetState::Focused, enabled && st.focused);
69 states.set(
70 WidgetState::FocusVisible,
71 enabled
72 && st.focused
73 && fret_ui::focus_visible::is_focus_visible(cx.app, Some(cx.window)),
74 );
75 states
76 }
77}
78
79impl From<WidgetState> for WidgetStates {
80 fn from(value: WidgetState) -> Self {
81 Self(value as u16)
82 }
83}
84
85impl BitOr for WidgetStates {
86 type Output = Self;
87
88 fn bitor(self, rhs: Self) -> Self::Output {
89 Self(self.0 | rhs.0)
90 }
91}
92
93impl BitOrAssign for WidgetStates {
94 fn bitor_assign(&mut self, rhs: Self) {
95 self.0 |= rhs.0;
96 }
97}
98
99#[derive(Debug, Clone)]
100pub struct WidgetStateProperty<T> {
101 default: T,
102 overrides: SmallVec<[(WidgetStates, T); 4]>,
103}
104
105impl<T> WidgetStateProperty<T> {
106 pub fn new(default: T) -> Self {
107 Self {
108 default,
109 overrides: SmallVec::new(),
110 }
111 }
112
113 pub fn when(mut self, states: WidgetStates, value: T) -> Self {
117 self.overrides.push((states, value));
118 self
119 }
120
121 pub fn resolve(&self, states: WidgetStates) -> &T {
122 for (required, value) in self.overrides.iter().rev() {
123 if states.contains(*required) {
124 return value;
125 }
126 }
127 &self.default
128 }
129}
130
131pub fn resolve_slot<T: Clone>(
136 overrides: Option<&WidgetStateProperty<Option<T>>>,
137 default: T,
138 states: WidgetStates,
139) -> T {
140 if let Some(overrides) = overrides
141 && let Some(value) = overrides.resolve(states).clone()
142 {
143 return value;
144 }
145 default
146}
147
148pub fn merge_slot<T>(dst: &mut Option<T>, src: Option<T>) {
150 if src.is_some() {
151 *dst = src;
152 }
153}