1use crate::geom::{Rect, Vec2};
23use crate::input::{KeyCode, KeyMods, KeyPhase, KeyPress, MouseButton, UiEvent};
24use crate::value::Value;
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum DragPhase {
29 Start,
30 Move,
31 End,
32}
33
34#[derive(Clone, Copy, Debug, PartialEq)]
36pub struct Drag {
37 pub phase: DragPhase,
38 pub pos: Vec2,
40 pub delta: Vec2,
43 pub parent: Rect,
45 pub cell: Option<(u32, u32)>,
47 pub line: Option<u32>,
50 pub byte: Option<usize>,
51 pub clicks: Option<u32>,
52}
53
54impl Drag {
55 pub fn ratio(&self) -> Vec2 {
59 let along = |p: f32, at: f32, len: f32| {
60 if len > 0.0 {
61 ((p - at) / len).clamp(0.0, 1.0)
62 } else {
63 0.0
64 }
65 };
66 Vec2::new(
67 along(self.pos.x, self.parent.x, self.parent.w),
68 along(self.pos.y, self.parent.y, self.parent.h),
69 )
70 }
71}
72
73#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub enum ButtonPhase {
77 Press,
78 Move,
79 Release,
80}
81
82#[derive(Clone, Copy, Debug, PartialEq)]
85pub struct ButtonEvent {
86 pub phase: ButtonPhase,
87 pub button: MouseButton,
88 pub pos: Vec2,
90 pub clicks: Option<u32>,
92 pub cell: Option<(u32, u32)>,
95 pub line: Option<u32>,
98 pub byte: Option<usize>,
99}
100
101#[derive(Clone, Copy, Debug, PartialEq)]
103pub struct Scroll {
104 pub pos: Vec2,
105 pub delta: Vec2,
106 pub lines: Option<i64>,
109}
110
111#[derive(Clone, Copy, Debug, PartialEq, Eq)]
113pub enum HoverPhase {
114 Enter,
115 Leave,
116}
117
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub enum HoverBy {
121 Pointer,
123 Content,
127}
128
129#[derive(Clone, Copy, Debug, PartialEq, Eq)]
131pub struct Hover {
132 pub phase: HoverPhase,
133 pub by: HoverBy,
134}
135
136#[derive(Clone, Copy, Debug, PartialEq)]
138pub struct Layout {
139 pub rect: Rect,
140 pub parent: Rect,
141 pub scale: f32,
142}
143
144#[derive(Clone, Copy, Debug, PartialEq)]
147pub struct TextInput<'a> {
148 pub text: &'a str,
149 pub pasted: bool,
151 pub concealed: bool,
153 pub transient: bool,
155}
156
157fn point(p: &Value) -> Option<Vec2> {
158 Some(Vec2::new(p.get_f32("x")?, p.get_f32("y")?))
159}
160
161fn rect(p: &Value) -> Option<Rect> {
162 Some(Rect::new(
163 p.get_f32("x")?,
164 p.get_f32("y")?,
165 p.get_f32("w")?,
166 p.get_f32("h")?,
167 ))
168}
169
170fn small(p: &Value, key: &str) -> Option<u32> {
171 p.get_int(key).and_then(|v| u32::try_from(v).ok())
172}
173
174impl UiEvent {
175 pub fn tag(&self) -> Option<&Value> {
178 self.payload.get("tag")
179 }
180
181 pub fn drag(&self) -> Option<Drag> {
183 let p = &self.payload;
184 if self.kind()? != "drag" {
185 return None;
186 }
187 let phase = match p.get_str("phase")? {
188 "start" => DragPhase::Start,
189 "move" => DragPhase::Move,
190 "end" => DragPhase::End,
191 _ => return None,
192 };
193 let cell = p
194 .get("cell")
195 .and_then(|c| Some((small(c, "row")?, small(c, "col")?)));
196 Some(Drag {
197 phase,
198 pos: point(p)?,
199 delta: Vec2::new(p.get_f32("dx")?, p.get_f32("dy")?),
200 parent: p.get("parent").and_then(rect).unwrap_or_default(),
201 cell,
202 line: small(p, "line"),
203 byte: p.get_int("byte").and_then(|v| usize::try_from(v).ok()),
204 clicks: small(p, "clicks"),
205 })
206 }
207
208 pub fn button(&self) -> Option<ButtonEvent> {
211 let p = &self.payload;
212 if self.kind()? != "button" {
213 return None;
214 }
215 let phase = match p.get_str("phase")? {
216 "press" => ButtonPhase::Press,
217 "move" => ButtonPhase::Move,
218 "release" => ButtonPhase::Release,
219 _ => return None,
220 };
221 let button = match p.get("button")? {
222 Value::Str(name) => MouseButton::from_name(name)?,
223 Value::Int(code) => MouseButton::from_code(u32::try_from(*code).ok()?),
224 _ => return None,
225 };
226 let cell = p
227 .get("cell")
228 .and_then(|c| Some((small(c, "row")?, small(c, "col")?)));
229 Some(ButtonEvent {
230 phase,
231 button,
232 pos: point(p)?,
233 clicks: small(p, "clicks"),
234 cell,
235 line: small(p, "line"),
236 byte: p.get_int("byte").and_then(|v| usize::try_from(v).ok()),
237 })
238 }
239
240 pub fn key_press(&self) -> Option<(KeyPhase, KeyPress)> {
245 let p = &self.payload;
246 if self.kind()? != "key" {
247 return None;
248 }
249 let phase = match p.get_str("phase")? {
250 "down" => KeyPhase::Down,
251 "up" => KeyPhase::Up,
252 _ => return None,
253 };
254 let code = KeyCode::from_name(p.get_str("code")?)?;
255 let physical = p
256 .get_str("physical")
257 .and_then(KeyCode::from_name)
258 .unwrap_or(KeyCode::Unknown);
259 let press = KeyPress {
260 code,
261 physical,
262 mods: mods(p),
263 text: p.get_str("text").map(str::to_string),
264 repeat: p.get_bool("repeat").unwrap_or(false),
265 location: p
266 .get_str("location")
267 .and_then(crate::input::KeyLocation::from_name)
268 .unwrap_or_default(),
269 locks: crate::input::KeyLocks {
270 caps: p.get_bool("caps_lock").unwrap_or(false),
271 num: p.get_bool("num_lock").unwrap_or(false),
272 },
273 };
274 Some((phase, press))
275 }
276
277 pub fn text(&self) -> Option<TextInput<'_>> {
279 let p = &self.payload;
280 if self.kind()? != "text" {
281 return None;
282 }
283 Some(TextInput {
284 text: p.get_str("text")?,
285 pasted: p.get_bool("pasted").unwrap_or(false),
286 concealed: p.get_bool("concealed").unwrap_or(false),
287 transient: p.get_bool("transient").unwrap_or(false),
288 })
289 }
290
291 pub fn scroll(&self) -> Option<Scroll> {
293 let p = &self.payload;
294 if self.kind()? != "scroll" {
295 return None;
296 }
297 Some(Scroll {
298 pos: point(p)?,
299 delta: Vec2::new(p.get_f32("dx")?, p.get_f32("dy")?),
300 lines: p.get_int("lines"),
301 })
302 }
303
304 pub fn hover(&self) -> Option<Hover> {
306 if self.kind()? != "hover" {
307 return None;
308 }
309 let phase = match self.payload.get_str("phase")? {
310 "enter" => HoverPhase::Enter,
311 "leave" => HoverPhase::Leave,
312 _ => return None,
313 };
314 let by = match self.payload.get_str("by") {
315 Some("content") => HoverBy::Content,
316 _ => HoverBy::Pointer,
317 };
318 Some(Hover { phase, by })
319 }
320
321 pub fn modifiers(&self) -> Option<KeyMods> {
323 if self.kind()? != "modifiers" {
324 return None;
325 }
326 Some(mods(&self.payload))
327 }
328
329 pub fn layout(&self) -> Option<Layout> {
331 let p = &self.payload;
332 if self.kind()? != "layout" {
333 return None;
334 }
335 Some(Layout {
336 rect: rect(p)?,
337 parent: p.get("parent").and_then(rect).unwrap_or_default(),
338 scale: p.get_f32("scale").unwrap_or(1.0),
339 })
340 }
341}
342
343fn mods(p: &Value) -> KeyMods {
345 let on = |k| p.get_bool(k).unwrap_or(false);
346 KeyMods {
347 shift: on("shift"),
348 ctrl: on("ctrl"),
349 alt: on("alt"),
350 super_key: on("super"),
351 }
352}