1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use fltk::prelude::*;
6use fltk::widget::Widget;
7
8use super::{IntoWidget, LayoutElement, LayoutWidgetWrapper, Size};
9
10pub struct SimpleWrapper {
11 pub widget: Widget,
12 pub min_size: Size,
13}
14
15impl LayoutElement for SimpleWrapper {
16 fn min_size(&self) -> Size {
17 self.min_size
18 }
19
20 fn layout(&self, x: i32, y: i32, width: i32, height: i32) {
21 self.widget.clone().resize(x, y, width, height);
22 }
23}
24
25impl<W: IntoWidget> LayoutWidgetWrapper<W> for SimpleWrapper {
26 fn wrap(widget: W) -> Self {
27 let widget = widget.into_widget();
28 let min_size = Size {
29 width: widget.width(),
30 height: widget.height(),
31 };
32 Self::new(widget, min_size)
33 }
34}
35
36impl SimpleWrapper {
37 pub fn new<W: IntoWidget>(widget: W, min_size: Size) -> Self {
38 Self {
39 widget: widget.into_widget(),
40 min_size,
41 }
42 }
43}
44
45pub struct WrapperFactory {
46 map: HashMap<TypeId, Box<dyn Any>>,
47 catch_all: Box<dyn Fn(Widget) -> Rc<dyn LayoutElement>>,
48}
49
50impl WrapperFactory {
51 pub fn new() -> Self {
52 Self::with_catch_all(|widget| Rc::new(SimpleWrapper::wrap(widget)))
53 }
54
55 pub fn with_catch_all(catch_all: impl Fn(Widget) -> Rc<dyn LayoutElement> + 'static) -> Self {
56 Self {
57 map: HashMap::new(),
58 catch_all: Box::new(catch_all),
59 }
60 }
61
62 pub fn set_wrapper<W: IntoWidget + 'static, L: LayoutWidgetWrapper<W> + 'static>(&mut self) {
63 self.map
64 .insert(TypeId::of::<W>(), Box::new(Factory::<W>::new::<L>()));
65 }
66
67 pub fn wrap<W: IntoWidget + 'static>(&self, widget: W) -> Rc<dyn LayoutElement> {
68 match self.factory_for::<W>() {
69 Some(factory) => (factory.0)(widget),
70 None => (self.catch_all)(widget.into_widget()),
71 }
72 }
73
74 fn factory_for<W: IntoWidget + 'static>(&self) -> Option<&Factory<W>> {
75 let erased = self.map.get(&TypeId::of::<W>())?;
76 let erased = &*erased;
77 erased.downcast_ref::<Factory<W>>()
78 }
79}
80
81struct Factory<W: IntoWidget + 'static>(fn(W) -> Rc<dyn LayoutElement>);
82
83impl<W: IntoWidget + 'static> Factory<W> {
84 fn new<L: LayoutWidgetWrapper<W> + 'static>() -> Self {
85 Self(|widget| Rc::new(L::wrap(widget)))
86 }
87}