1use glam::Vec2;
7
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
10pub struct Modifiers {
11 pub shift: bool,
12 pub ctrl: bool,
13 pub alt: bool,
14 pub meta: bool,
15}
16
17#[derive(Debug, Clone)]
19pub enum PlotEvent {
20 MousePress {
21 position: Vec2,
22 button: MouseButton,
23 modifiers: Modifiers,
24 },
25 MouseRelease {
26 position: Vec2,
27 button: MouseButton,
28 modifiers: Modifiers,
29 },
30 MouseMove {
31 position: Vec2,
32 delta: Vec2,
33 buttons: u32,
34 modifiers: Modifiers,
35 },
36 MouseWheel {
40 position: Vec2,
41 delta: Vec2,
42 modifiers: Modifiers,
43 },
44 KeyPress {
45 key: KeyCode,
46 },
47 KeyRelease {
48 key: KeyCode,
49 },
50 Resize {
51 width: u32,
52 height: u32,
53 },
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum MouseButton {
59 Left,
60 Right,
61 Middle,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum KeyCode {
67 Escape,
68 Space,
69 Enter,
70 Tab,
71 Backspace,
72 Delete,
73 Home,
74 End,
75 PageUp,
76 PageDown,
77 ArrowUp,
78 ArrowDown,
79 ArrowLeft,
80 ArrowRight,
81 }
83
84pub trait EventHandler {
86 fn handle_event(&mut self, event: PlotEvent) -> bool;
87}
88
89#[cfg(feature = "egui-overlay")]
90pub fn egui_raw_input_from_plot_events(
91 screen_rect: egui::Rect,
92 pixels_per_point: f32,
93 events: Vec<PlotEvent>,
94) -> egui::RawInput {
95 let ppp = pixels_per_point.max(0.5);
96 let mut egui_events = Vec::with_capacity(events.len());
97 for event in events {
98 match event {
99 PlotEvent::MousePress {
100 position,
101 button,
102 modifiers,
103 } => {
104 egui_events.push(egui::Event::PointerMoved(egui_pos(position, ppp)));
105 egui_events.push(egui::Event::PointerButton {
106 pos: egui_pos(position, ppp),
107 button: egui_button(button),
108 pressed: true,
109 modifiers: egui_modifiers(modifiers),
110 });
111 }
112 PlotEvent::MouseRelease {
113 position,
114 button,
115 modifiers,
116 } => {
117 egui_events.push(egui::Event::PointerMoved(egui_pos(position, ppp)));
118 egui_events.push(egui::Event::PointerButton {
119 pos: egui_pos(position, ppp),
120 button: egui_button(button),
121 pressed: false,
122 modifiers: egui_modifiers(modifiers),
123 });
124 }
125 PlotEvent::MouseMove {
126 position, delta, ..
127 } => {
128 egui_events.push(egui::Event::PointerMoved(egui_pos(position, ppp)));
129 if delta.length_squared() > f32::EPSILON {
130 egui_events.push(egui::Event::MouseMoved(egui::vec2(
131 delta.x / ppp,
132 delta.y / ppp,
133 )));
134 }
135 }
136 PlotEvent::MouseWheel {
137 position,
138 delta,
139 modifiers,
140 } => {
141 egui_events.push(egui::Event::PointerMoved(egui_pos(position, ppp)));
142 #[cfg(target_arch = "wasm32")]
143 egui_events.push(egui::Event::MouseWheel {
144 unit: egui::MouseWheelUnit::Point,
145 delta: egui::vec2(delta.x * 80.0, delta.y * 80.0),
146 modifiers: egui_modifiers(modifiers),
147 });
148 #[cfg(not(target_arch = "wasm32"))]
149 egui_events.push(egui::Event::Scroll(egui::vec2(
150 delta.x * 80.0,
151 delta.y * 80.0,
152 )));
153 if modifiers.ctrl || modifiers.meta {
154 egui_events.push(egui::Event::Zoom((1.0 + delta.y * 0.08).clamp(0.2, 5.0)));
155 }
156 }
157 PlotEvent::Resize { .. }
158 | PlotEvent::KeyPress { .. }
159 | PlotEvent::KeyRelease { .. } => {}
160 }
161 }
162
163 egui::RawInput {
164 screen_rect: Some(screen_rect),
165 events: egui_events,
166 viewports: std::iter::once((
167 egui::ViewportId::ROOT,
168 egui::ViewportInfo {
169 native_pixels_per_point: Some(ppp),
170 inner_rect: Some(screen_rect),
171 outer_rect: Some(screen_rect),
172 focused: Some(true),
173 ..Default::default()
174 },
175 ))
176 .collect(),
177 ..Default::default()
178 }
179}
180
181#[cfg(feature = "egui-overlay")]
182fn egui_pos(position: Vec2, pixels_per_point: f32) -> egui::Pos2 {
183 egui::pos2(position.x / pixels_per_point, position.y / pixels_per_point)
184}
185
186#[cfg(feature = "egui-overlay")]
187fn egui_modifiers(value: Modifiers) -> egui::Modifiers {
188 egui::Modifiers {
189 alt: value.alt,
190 ctrl: value.ctrl,
191 shift: value.shift,
192 mac_cmd: value.meta,
193 command: value.meta || value.ctrl,
194 }
195}
196
197#[cfg(feature = "egui-overlay")]
198fn egui_button(button: MouseButton) -> egui::PointerButton {
199 match button {
200 MouseButton::Left => egui::PointerButton::Primary,
201 MouseButton::Right => egui::PointerButton::Secondary,
202 MouseButton::Middle => egui::PointerButton::Middle,
203 }
204}