1pub mod button;
5pub mod domain_line;
6pub mod domain_point;
7pub mod flexbox;
8pub mod gridbox;
9pub mod image;
10pub mod line;
11pub mod listbox;
12pub mod mouse_area;
13pub mod paragraph;
14pub mod region;
15pub mod scroll_area;
16pub mod shape;
17pub mod text;
18pub mod textbox;
19pub mod window;
20
21use crate::component::window::Window;
22use crate::event::EventRouter;
23use crate::layout::{Desc, Layout, Staged, root};
24use crate::{
25 DispatchPair, Dispatchable, InputResult, PxRect, Slot, SourceID, StateMachineChild,
26 StateManager, graphics, rtree,
27};
28use dyn_clone::DynClone;
29use eyre::{OptionExt, Result};
30use smallvec::SmallVec;
31use std::any::Any;
32use std::collections::HashMap;
33use std::sync::Arc;
34use window::WindowStateMachine;
35
36pub trait StateMachineWrapper: Any {
37 fn process(
38 &mut self,
39 input: DispatchPair,
40 index: u64,
41 dpi: crate::RelDim,
42 area: PxRect,
43 extent: PxRect,
44 driver: &std::sync::Weak<crate::Driver>,
45 ) -> InputResult<SmallVec<[DispatchPair; 1]>>;
46 fn output_slot(&self, i: usize) -> Result<&Option<Slot>>;
47 fn input_mask(&self) -> u64;
48 fn changed(&self) -> bool;
49 fn set_changed(&mut self, changed: bool);
50}
51
52pub struct StateMachine<State, const OUTPUT_SIZE: usize> {
53 pub state: State,
54 pub output: [Option<Slot>; OUTPUT_SIZE],
55 pub input_mask: u64,
56 pub(crate) changed: bool,
57}
58
59impl<State: EventRouter + PartialEq + 'static, const OUTPUT_SIZE: usize> StateMachineWrapper
60 for StateMachine<State, OUTPUT_SIZE>
61{
62 fn process(
63 &mut self,
64 input: DispatchPair,
65 _index: u64,
66 dpi: crate::RelDim,
67 area: PxRect,
68 extent: PxRect,
69 driver: &std::sync::Weak<crate::Driver>,
70 ) -> InputResult<SmallVec<[DispatchPair; 1]>> {
71 if input.0 & self.input_mask == 0 {
72 return InputResult::Error(crate::Error::UnhandledEvent.into());
73 }
74
75 let s = match State::Input::restore(input) {
76 Ok(s) => s,
77 Err(e) => return InputResult::Error(e.into()),
78 };
79
80 State::process(
81 crate::AccessCell {
82 value: &mut self.state,
83 changed: &mut self.changed,
84 },
85 s,
86 area,
87 extent,
88 dpi,
89 driver,
90 )
91 .map(|x| x.into_iter().map(|x| x.extract()).collect())
92 }
93 fn output_slot(&self, i: usize) -> Result<&Option<Slot>> {
94 self.output.get(i).ok_or(crate::Error::OutOfRange(i).into())
95 }
96 fn input_mask(&self) -> u64 {
97 self.input_mask
98 }
99 fn changed(&self) -> bool {
100 self.changed
101 }
102 fn set_changed(&mut self, changed: bool) {
103 self.changed = changed
104 }
105}
106
107pub trait Component: crate::StateMachineChild + DynClone {
189 type Props: 'static;
190
191 fn layout(
192 &self,
193 state: &mut StateManager,
194 driver: &graphics::Driver,
195 window: &Arc<SourceID>,
196 ) -> Box<dyn Layout<Self::Props> + 'static>;
197}
198
199dyn_clone::clone_trait_object!(<Parent> Component<Props = Parent> where Parent:?Sized);
200
201pub type ChildOf<D> = dyn ComponentWrap<<D as Desc>::Child>;
202
203pub trait ComponentWrap<T: ?Sized>: crate::StateMachineChild + DynClone {
204 fn layout(
205 &self,
206 state: &mut StateManager,
207 driver: &graphics::Driver,
208 window: &Arc<SourceID>,
209 ) -> Box<dyn Layout<T> + 'static>;
210}
211
212dyn_clone::clone_trait_object!(<T> ComponentWrap<T> where T:?Sized);
213
214impl<U: ?Sized, C: Component> ComponentWrap<U> for C
215where
216 for<'a> &'a U: From<&'a <C as Component>::Props>,
217 <C as Component>::Props: Sized,
218{
219 fn layout(
220 &self,
221 state: &mut StateManager,
222 driver: &graphics::Driver,
223 window: &Arc<SourceID>,
224 ) -> Box<dyn Layout<U> + 'static> {
225 Box::new(Component::layout(self, state, driver, window))
226 }
227}
228
229impl<T: Component + 'static, U> From<Box<T>> for Box<dyn ComponentWrap<U>>
230where
231 for<'a> &'a U: std::convert::From<&'a <T as Component>::Props>,
232 <T as Component>::Props: std::marker::Sized,
233{
234 fn from(value: Box<T>) -> Self {
235 value
236 }
237}
238
239pub struct RootState {
242 pub(crate) id: Arc<SourceID>,
243 layout_tree: Option<Box<dyn crate::layout::Layout<crate::PxDim>>>,
244 pub(crate) staging: Option<Box<dyn Staged>>,
245 rtree: std::rc::Weak<rtree::Node>,
246}
247
248impl RootState {
249 fn new(id: Arc<SourceID>) -> Self {
250 Self {
251 id,
252 layout_tree: None,
253 staging: None,
254 rtree: std::rc::Weak::<rtree::Node>::new(),
255 }
256 }
257}
258
259pub struct Root {
260 pub(crate) states: HashMap<winit::window::WindowId, RootState>,
261 pub(crate) children: im::HashMap<Arc<SourceID>, Option<Window>>,
263}
264
265impl Default for Root {
266 fn default() -> Self {
267 Self::new()
268 }
269}
270
271impl Root {
272 pub fn new() -> Self {
273 Self {
274 states: HashMap::new(),
275 children: im::HashMap::new(),
276 }
277 }
278
279 pub fn layout_all(
280 &mut self,
281 manager: &mut StateManager,
282 driver: &mut std::sync::Weak<graphics::Driver>,
283 on_driver: &mut Option<Box<dyn FnOnce(std::sync::Weak<graphics::Driver>) + 'static>>,
284 instance: &wgpu::Instance,
285 event_loop: &winit::event_loop::ActiveEventLoop,
286 ) -> eyre::Result<()> {
287 for (_, window) in self.children.iter() {
290 let window = window.as_ref().unwrap();
291 window.init_custom(manager, driver, instance, event_loop, on_driver)?;
292 let state: &WindowStateMachine = manager.get(&window.id())?;
293 let id = state.state.window.id();
294 self.states
295 .entry(id)
296 .or_insert_with(|| RootState::new(window.id().clone()));
297
298 let root = self
299 .states
300 .get_mut(&id)
301 .ok_or_eyre("Couldn't find window state")?;
302 let driver = state.state.driver.clone();
303 root.layout_tree = Some(crate::component::Component::layout(
304 window,
305 manager,
306 &driver,
307 &window.id(),
308 ));
309 }
310 Ok(())
311 }
312
313 pub fn stage_all(&mut self, states: &mut StateManager) -> eyre::Result<()> {
314 for (_, window) in self.children.iter() {
315 let window = window.as_ref().unwrap();
316 let state: &mut WindowStateMachine = states.get_mut(&window.id())?;
317 let id = state.state.window.id();
318 let root = self
319 .states
320 .get_mut(&id)
321 .ok_or_eyre("Couldn't find window state")?;
322 if let Some(layout) = root.layout_tree.as_ref() {
323 let layout: &dyn Layout<dyn root::Prop> = &layout.as_ref();
324 let staging =
325 layout.stage(Default::default(), Default::default(), &mut state.state);
326 root.rtree = staging.get_rtree();
327 root.staging = Some(staging);
328 state.state.window.request_redraw();
329 }
330 }
331 Ok(())
332 }
333
334 pub fn validate_ids(&self) -> eyre::Result<()> {
335 struct Validator(std::collections::HashSet<Arc<SourceID>>);
336 impl Validator {
337 fn f(&mut self, x: &dyn StateMachineChild) -> eyre::Result<()> {
338 let id = x.id();
339 if !self.0.insert(id.clone()) {
340 return Err(eyre::eyre!(
341 "Duplicate ID found! Did you forget to add a child index to an ID? {}",
342 x.id()
343 ));
344 }
345
346 x.apply_children(&mut |x| self.f(x))
347 }
348 }
349 let mut v = Validator(std::collections::HashSet::new());
350 for (_, child) in &self.children {
351 if let Some(window) = child {
352 v.f(window)?;
353 }
354 }
355
356 Ok(())
357 }
358}