1use crate::{
9 env::VideoState, registry::AnimationPropertyId, Env, GlobalState, LayoutRect, LayoutSize,
10 LayoutSnapshot, RuntimeState, ViewHandle,
11};
12use fission_i18n::I18nRegistry;
13use fission_ir::WidgetId;
14use fission_layout::BoxConstraints;
15use fission_theme::Theme;
16use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
17use std::hash::{BuildHasher, Hash};
18
19pub struct View<'a, S: GlobalState> {
33 pub state: &'a S,
35 pub runtime: &'a RuntimeState,
37 pub env: &'a Env,
39 pub layout: Option<&'a LayoutSnapshot>,
41}
42
43impl<'a, S: GlobalState> View<'a, S> {
44 pub fn new(
45 state: &'a S,
46 runtime: &'a RuntimeState,
47 env: &'a Env,
48 layout: Option<&'a LayoutSnapshot>,
49 ) -> Self {
50 Self {
51 state,
52 runtime,
53 env,
54 layout,
55 }
56 }
57
58 pub fn state(&self) -> &S {
59 self.state
60 }
61
62 pub fn runtime(&self) -> &RuntimeState {
63 self.runtime
64 }
65
66 pub fn env(&self) -> &Env {
67 self.env
68 }
69
70 pub fn layout(&self) -> Option<&LayoutSnapshot> {
71 self.layout
72 }
73
74 pub fn theme(&self) -> &Theme {
75 &self.env.theme
76 }
77 pub fn i18n(&self) -> &I18nRegistry {
78 &self.env.i18n
79 }
80
81 pub fn get_rect(&self, id: WidgetId) -> Option<LayoutRect> {
82 let node_id: WidgetId = id.into();
83 self.layout.and_then(|l| l.get_node_rect(node_id))
84 }
85
86 pub fn get_constraints(&self, id: WidgetId) -> Option<BoxConstraints> {
87 let node_id: WidgetId = id.into();
88 self.layout.and_then(|l| l.get_node_constraints(node_id))
89 }
90
91 pub fn viewport_size(&self) -> LayoutSize {
92 self.env.viewport_size
93 }
94
95 pub fn select<R>(&self, selector: impl FnOnce(&S) -> R) -> R {
96 selector(self.state)
97 }
98
99 pub fn animation_value(&self, widget_id: WidgetId, property: &AnimationPropertyId) -> f32 {
100 self.runtime
101 .animation
102 .values
103 .get(&(widget_id, property.clone()))
104 .copied()
105 .unwrap_or_else(|| property.default_value())
106 }
107
108 pub fn video_state(&self, widget_id: WidgetId) -> Option<&VideoState> {
109 self.runtime.video.states.get(&widget_id)
110 }
111}
112
113#[derive(Clone, Copy, Debug)]
119pub struct ValueView<'a, T> {
120 value: &'a T,
121}
122
123impl<'a, T> ValueView<'a, T> {
124 pub fn new(value: &'a T) -> Self {
125 Self { value }
126 }
127
128 pub fn borrow(&self) -> &'a T {
129 self.value
130 }
131
132 pub fn map<R>(&self, selector: impl FnOnce(&T) -> R) -> ComputedView<R> {
133 ComputedView::new(selector(self.value))
134 }
135}
136
137impl<T: Clone> ValueView<'_, T> {
138 pub fn get(&self) -> T {
139 self.value.clone()
140 }
141}
142
143impl<'a, T> ValueView<'a, Vec<T>> {
144 pub fn len(&self) -> usize {
145 self.value.len()
146 }
147
148 pub fn is_empty(&self) -> bool {
149 self.value.is_empty()
150 }
151
152 pub fn iter(&self) -> std::slice::Iter<'a, T> {
153 self.value.iter()
154 }
155}
156
157impl<'a, T> IntoIterator for ValueView<'a, Vec<T>> {
158 type Item = &'a T;
159 type IntoIter = std::slice::Iter<'a, T>;
160
161 fn into_iter(self) -> Self::IntoIter {
162 self.value.iter()
163 }
164}
165
166#[derive(Clone, Debug)]
168pub struct ComputedView<T> {
169 value: T,
170}
171
172impl<T> ComputedView<T> {
173 pub fn new(value: T) -> Self {
174 Self { value }
175 }
176
177 pub fn borrow(&self) -> &T {
178 &self.value
179 }
180
181 pub fn get(self) -> T {
182 self.value
183 }
184
185 pub fn map<R>(self, selector: impl FnOnce(&T) -> R) -> ComputedView<R> {
186 ComputedView::new(selector(&self.value))
187 }
188}
189
190pub trait FissionViewField {
195 type View<'a>
196 where
197 Self: 'a;
198
199 fn view_field<'a>(value: &'a Self) -> Self::View<'a>;
200}
201
202macro_rules! scalar_view_field {
203 ($($ty:ty),* $(,)?) => {
204 $(
205 impl FissionViewField for $ty {
206 type View<'a> = ValueView<'a, Self> where Self: 'a;
207
208 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
209 ValueView::new(value)
210 }
211 }
212 )*
213 };
214}
215
216scalar_view_field!(
217 bool, char, String, usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64
218);
219
220impl<T> FissionViewField for Vec<T> {
221 type View<'a>
222 = ValueView<'a, Self>
223 where
224 Self: 'a;
225
226 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
227 ValueView::new(value)
228 }
229}
230
231impl<T> FissionViewField for Option<T> {
232 type View<'a>
233 = ValueView<'a, Self>
234 where
235 Self: 'a;
236
237 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
238 ValueView::new(value)
239 }
240}
241
242impl<T, const N: usize> FissionViewField for [T; N] {
243 type View<'a>
244 = ValueView<'a, Self>
245 where
246 Self: 'a;
247
248 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
249 ValueView::new(value)
250 }
251}
252
253impl<T: Ord> FissionViewField for BTreeSet<T> {
254 type View<'a>
255 = ValueView<'a, Self>
256 where
257 Self: 'a;
258
259 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
260 ValueView::new(value)
261 }
262}
263
264impl<K: Ord, V> FissionViewField for BTreeMap<K, V> {
265 type View<'a>
266 = ValueView<'a, Self>
267 where
268 Self: 'a;
269
270 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
271 ValueView::new(value)
272 }
273}
274
275impl<T: Eq + Hash, S: BuildHasher> FissionViewField for HashSet<T, S> {
276 type View<'a>
277 = ValueView<'a, Self>
278 where
279 Self: 'a;
280
281 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
282 ValueView::new(value)
283 }
284}
285
286impl<K: Eq + Hash, V, S: BuildHasher> FissionViewField for HashMap<K, V, S> {
287 type View<'a>
288 = ValueView<'a, Self>
289 where
290 Self: 'a;
291
292 fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
293 ValueView::new(value)
294 }
295}
296
297pub trait Selector<S: GlobalState> {
317 type Output;
319 fn select(view: ViewHandle<S>) -> Self::Output;
321}