simple_layout/
placement.rs

1use std::marker::PhantomData;
2use std::ops::DerefMut;
3use std::sync::Mutex;
4
5use embedded_graphics::draw_target::DrawTarget;
6use embedded_graphics::pixelcolor::PixelColor;
7use embedded_graphics::primitives::Rectangle;
8#[cfg(feature = "log")]
9use log::warn;
10
11use crate::layoutable::Layoutable;
12use crate::ComponentSize;
13
14///
15/// Get a callback from the layout process about the final placement of the containing element. So you can
16/// map a touched point onto the correct element
17///
18/// # Arguments
19///
20/// * `callback`: Callback processing the information about the latest placement of the containing layoutable
21/// * `layoutable`: Element to be watched
22///
23/// returns: impl Layoutable<C>+Sized
24///
25pub fn callback_placement<L: Layoutable<C>, C: PixelColor, F: FnMut(Rectangle)>(
26    callback: F,
27    layoutable: L,
28) -> impl Layoutable<C> {
29    CallbackPlacement {
30        callback: Mutex::new(callback),
31        layoutable,
32        p: PhantomData,
33    }
34}
35///
36/// Updates the placement onto a Option<Rectangle>
37///
38/// # Arguments
39///
40/// * `target`: target variable to update with the found placement informations
41/// * `layoutable`: layoutable to be watched
42///
43/// returns: impl Layoutable<C>+Sized
44///
45pub fn optional_placement<'a, L: Layoutable<C> + 'a, C: PixelColor + 'a>(
46    target: &'a mut Option<Rectangle>,
47    layoutable: L,
48) -> impl Layoutable<C> + 'a {
49    callback_placement(|rectangle: Rectangle| *target = Some(rectangle), layoutable)
50}
51
52struct CallbackPlacement<L: Layoutable<C>, C: PixelColor, F: FnMut(Rectangle)> {
53    callback: Mutex<F>,
54    layoutable: L,
55    p: PhantomData<C>,
56}
57
58impl<L: Layoutable<C>, C: PixelColor, F: FnMut(Rectangle)> Layoutable<C>
59    for CallbackPlacement<L, C, F>
60{
61    fn size(&self) -> ComponentSize {
62        self.layoutable.size()
63    }
64
65    fn draw_placed<DrawError>(
66        &self,
67        target: &mut impl DrawTarget<Color = C, Error = DrawError>,
68        position: Rectangle,
69    ) -> Result<(), DrawError> {
70        if let Ok(mut mutex) = self.callback.try_lock() {
71            (mutex.deref_mut())(position);
72        } else {
73            #[cfg(feature = "log")]
74            warn!("Cannot lock callback");
75        }
76        self.layoutable.draw_placed(target, position)
77    }
78}