egui_canvas/
widget.rs

1#[cfg(feature = "click")]
2use crate::event;
3use crate::holder;
4use egui::{
5    epaint::{Color32, CornerRadius, Rect, RectShape},
6    Pos2, Response, Sense, Ui, Widget, WidgetInfo, WidgetType
7};
8#[cfg(feature = "click")]
9use egui::PointerButton;
10use std::{ops::Deref, sync::{Arc, Mutex}};
11#[cfg(feature = "click")]
12use std::ops::DerefMut;
13#[cfg(not(feature = "click"))]
14use std::marker::PhantomData;
15
16pub struct CanvasWidget<'a> {
17    shapes: Arc<Mutex<holder::ShapeMap>>,
18    background_color: Option<Color32>,
19    pos: Option<holder::PositionInfo>,
20    needless_click_sense: bool,
21    #[cfg(feature = "click")]
22    click_handler: Arc<Mutex<Option<holder::ClickHandler<'a>>>>,
23    #[cfg(feature = "click")]
24    has_click_handler: bool,
25    #[cfg(not(feature = "click"))]
26    _marker: PhantomData<&'a ()>
27}
28
29#[cfg(not(feature = "click"))]
30impl CanvasWidget<'_> {
31    pub fn new(
32        shapes: Arc<Mutex<holder::ShapeMap>>,
33        background_color: Option<Color32>,
34        pos: Option<holder::PositionInfo>,
35        needless_click_sense: bool
36    ) -> Self {
37        Self {
38            shapes, background_color, pos,
39            needless_click_sense, _marker: PhantomData
40        }
41    }
42}
43
44#[cfg(feature = "click")]
45impl<'a> CanvasWidget<'a> {
46    pub fn new(
47        shapes: Arc<Mutex<holder::ShapeMap>>,
48        background_color: Option<Color32>,
49        pos: Option<holder::PositionInfo>,
50        needless_click_sense: bool,
51        click_handler: Arc<Mutex<Option<holder::ClickHandler<'a>>>>,
52        has_click_handler: bool
53    ) -> Self {
54        Self {
55            shapes, background_color, pos, needless_click_sense,
56            click_handler, has_click_handler
57        }
58    }
59}
60
61impl CanvasWidget<'_> {
62    fn get_self_pos(&self, ui: &Ui) -> holder::PositionInfo {
63        match self.pos {
64            Some(pos) => pos,
65            None => holder::PositionInfo::new(Pos2::ZERO, ui.available_size())
66        }
67    }
68
69    #[cfg(feature = "click")]
70    fn handle_click(&mut self, response: &Response, ui: &Ui) {
71        if !self.has_click_handler { return; }
72        let pos = response.interact_pointer_pos();
73        if pos.is_none() { return; }
74        let button = if response.clicked_by(PointerButton::Primary) {
75            PointerButton::Primary
76        } else if response.clicked_by(PointerButton::Secondary) {
77            PointerButton::Secondary
78        } else if response.clicked_by(PointerButton::Middle) {
79            PointerButton::Middle
80        } else if response.clicked_by(PointerButton::Extra1) {
81            PointerButton::Extra1
82        } else if response.clicked_by(PointerButton::Extra2) {
83            PointerButton::Extra2
84        } else { return; };
85        let pos = pos.unwrap();
86        let holder::PositionInfo{ pos: self_pos, size: self_size } = self.get_self_pos(ui);
87        let self_other_corner = self_pos + self_size;
88        if pos.x <= self_pos.x || pos.x >= self_other_corner.x ||
89            pos.y <= self_pos.y || pos.y >= self_other_corner.y
90        { return; }
91        let mut lock = self.click_handler.lock().unwrap();
92        let click_handler = lock.deref_mut().as_mut().unwrap();
93        click_handler(event::ClickEvent::new(button, pos));
94    }
95}
96
97impl Widget for CanvasWidget<'_> {
98    #[cfg(not(feature = "click"))]
99    fn ui(self, ui: &mut Ui) -> Response {
100        let sense = if self.needless_click_sense {
101            Sense::click()
102        } else {
103            Sense::hover()
104        };
105        let holder::PositionInfo { pos, size } = self.get_self_pos(ui);
106        let rect = Rect { min: pos, max: pos + size };
107        let response = ui.allocate_rect(rect, sense);
108        response.widget_info(
109            || WidgetInfo::new(WidgetType::Other)
110        );
111        if ui.is_visible() {
112            if let Some(bg) = self.background_color {
113                ui.painter().add(RectShape::filled(
114                    rect, CornerRadius::ZERO, bg
115                ));
116            }
117            for pred_arc in self.shapes.lock().expect(crate::LOCK_ERR_MSG).values() {
118                let pred_lock = pred_arc.lock().unwrap();
119                if let Some(shape) = pred_lock.deref().finalise(ui) {
120                    ui.painter().add(shape);
121                }
122            }
123        }
124        response
125    }
126
127    #[cfg(feature = "click")]
128    fn ui(mut self, ui: &mut Ui) -> Response {
129        let sense = if self.has_click_handler || self.needless_click_sense {
130            Sense::click()
131        } else {
132            Sense::hover()
133        };
134        let holder::PositionInfo { pos, size } = self.get_self_pos(ui);
135        let rect = Rect { min: pos, max: pos + size };
136        let response = ui.allocate_rect(rect, sense);
137        response.widget_info(
138            || WidgetInfo::new(WidgetType::Other)
139        );
140        if ui.is_visible() {
141            self.handle_click(&response, ui);
142            if let Some(bg) = self.background_color {
143                ui.painter().add(RectShape::filled(
144                    rect, CornerRadius::ZERO, bg
145                ));
146            }
147            for pred_arc in self.shapes.lock().expect(crate::LOCK_ERR_MSG).values() {
148                let pred_lock = pred_arc.lock().unwrap();
149                if let Some(shape) = pred_lock.deref().finalise(ui) {
150                    ui.painter().add(shape);
151                }
152            }
153        }
154        response
155    }
156}