mouse_event_handler.rs

  1use crate::{
  2    geometry::{rect::RectF, vector::Vector2F},
  3    AfterLayoutContext, AppContext, DebugContext, Element, ElementBox, Event, EventContext,
  4    LayoutContext, PaintContext, SizeConstraint, ValueHandle,
  5};
  6use serde_json::json;
  7
  8pub struct MouseEventHandler {
  9    state: ValueHandle<MouseState>,
 10    child: ElementBox,
 11}
 12
 13#[derive(Clone, Copy, Default)]
 14pub struct MouseState {
 15    hovered: bool,
 16    clicked: bool,
 17}
 18
 19impl MouseEventHandler {
 20    pub fn new<Tag: 'static>(
 21        id: usize,
 22        ctx: &AppContext,
 23        render_child: impl FnOnce(MouseState) -> ElementBox,
 24    ) -> Self {
 25        let state = ctx.value::<Tag, _>(id);
 26        let child = state.map(ctx, |state| render_child(*state));
 27        Self { state, child }
 28    }
 29}
 30
 31impl Element for MouseEventHandler {
 32    type LayoutState = ();
 33
 34    type PaintState = ();
 35
 36    fn layout(
 37        &mut self,
 38        constraint: SizeConstraint,
 39        ctx: &mut LayoutContext,
 40    ) -> (Vector2F, Self::LayoutState) {
 41        (self.child.layout(constraint, ctx), ())
 42    }
 43
 44    fn after_layout(
 45        &mut self,
 46        _: Vector2F,
 47        _: &mut Self::LayoutState,
 48        ctx: &mut AfterLayoutContext,
 49    ) {
 50        self.child.after_layout(ctx);
 51    }
 52
 53    fn paint(
 54        &mut self,
 55        bounds: RectF,
 56        _: &mut Self::LayoutState,
 57        ctx: &mut PaintContext,
 58    ) -> Self::PaintState {
 59        self.child.paint(bounds.origin(), ctx);
 60    }
 61
 62    fn dispatch_event(
 63        &mut self,
 64        event: &Event,
 65        bounds: RectF,
 66        _: &mut Self::LayoutState,
 67        _: &mut Self::PaintState,
 68        ctx: &mut EventContext,
 69    ) -> bool {
 70        self.state.map(ctx.app, |state| match event {
 71            Event::MouseMoved { position } => {
 72                let mouse_in = bounds.contains_point(*position);
 73                if state.hovered != mouse_in {
 74                    state.hovered = mouse_in;
 75                    log::info!("hovered {}", state.hovered);
 76                    // ctx.notify();
 77                    true
 78                } else {
 79                    false
 80                }
 81            }
 82            Event::LeftMouseDown { position, .. } => {
 83                if bounds.contains_point(*position) {
 84                    log::info!("clicked");
 85                    state.clicked = true;
 86                    // ctx.notify();
 87                    true
 88                } else {
 89                    false
 90                }
 91            }
 92            Event::LeftMouseUp { .. } => {
 93                if state.clicked {
 94                    log::info!("unclicked");
 95                    state.clicked = false;
 96                    // ctx.notify();
 97                    true
 98                } else {
 99                    false
100                }
101            }
102            _ => false,
103        })
104    }
105
106    fn debug(
107        &self,
108        _: RectF,
109        _: &Self::LayoutState,
110        _: &Self::PaintState,
111        ctx: &DebugContext,
112    ) -> serde_json::Value {
113        json!({
114            "type": "MouseEventHandler",
115            "child": self.child.debug(ctx),
116        })
117    }
118}