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}