fltk_float/
wrappers.rs

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}