1use crate::geom::{Rect, Vec2};
34use crate::input::{KeyCode, KeyMods, KeyPhase, KeyPress, MouseButton, UiEvent};
35use crate::value::Value;
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum DragPhase {
40 Start,
41 Move,
42 End,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq)]
47pub struct Drag {
48 pub phase: DragPhase,
49 pub pos: Vec2,
51 pub delta: Vec2,
54 pub parent: Rect,
56 pub cell: Option<(u32, u32)>,
58 pub line: Option<u32>,
61 pub byte: Option<usize>,
62 pub clicks: Option<u32>,
63}
64
65impl Drag {
66 pub fn ratio(&self) -> Vec2 {
70 let along = |p: f32, at: f32, len: f32| {
71 if len > 0.0 {
72 ((p - at) / len).clamp(0.0, 1.0)
73 } else {
74 0.0
75 }
76 };
77 Vec2::new(
78 along(self.pos.x, self.parent.x, self.parent.w),
79 along(self.pos.y, self.parent.y, self.parent.h),
80 )
81 }
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub enum ButtonPhase {
87 Press,
88 Move,
89 Release,
90}
91
92#[derive(Clone, Copy, Debug, PartialEq)]
95pub struct ButtonEvent {
96 pub phase: ButtonPhase,
97 pub button: MouseButton,
98 pub pos: Vec2,
100 pub clicks: Option<u32>,
102 pub cell: Option<(u32, u32)>,
105 pub line: Option<u32>,
108 pub byte: Option<usize>,
109}
110
111#[derive(Clone, Copy, Debug, PartialEq)]
113pub struct Scroll {
114 pub pos: Vec2,
115 pub delta: Vec2,
116 pub lines: Option<i64>,
119 pub mods: Option<KeyMods>,
122}
123
124#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126pub enum HoverPhase {
127 Enter,
128 Leave,
129}
130
131#[derive(Clone, Copy, Debug, PartialEq, Eq)]
133pub enum HoverBy {
134 Pointer,
136 Content,
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144pub struct Hover {
145 pub phase: HoverPhase,
146 pub by: HoverBy,
147}
148
149#[derive(Clone, Copy, Debug, PartialEq)]
151pub struct Layout {
152 pub rect: Rect,
153 pub parent: Rect,
154 pub scale: f32,
155}
156
157#[derive(Clone, Copy, Debug, PartialEq)]
160pub struct TextInput<'a> {
161 pub text: &'a str,
162 pub pasted: bool,
164 pub concealed: bool,
166 pub transient: bool,
168}
169
170fn point(p: &Value) -> Option<Vec2> {
171 Some(Vec2::new(p.get_f32("x")?, p.get_f32("y")?))
172}
173
174fn rect(p: &Value) -> Option<Rect> {
175 Some(Rect::new(
176 p.get_f32("x")?,
177 p.get_f32("y")?,
178 p.get_f32("w")?,
179 p.get_f32("h")?,
180 ))
181}
182
183fn small(p: &Value, key: &str) -> Option<u32> {
184 p.get_int(key).and_then(|v| u32::try_from(v).ok())
185}
186
187impl UiEvent {
188 pub fn tag(&self) -> Option<&Value> {
191 self.payload.get("tag")
192 }
193
194 pub fn drag(&self) -> Option<Drag> {
196 let p = &self.payload;
197 if self.kind()? != "drag" {
198 return None;
199 }
200 let phase = match p.get_str("phase")? {
201 "start" => DragPhase::Start,
202 "move" => DragPhase::Move,
203 "end" => DragPhase::End,
204 _ => return None,
205 };
206 let cell = p
207 .get("cell")
208 .and_then(|c| Some((small(c, "row")?, small(c, "col")?)));
209 Some(Drag {
210 phase,
211 pos: point(p)?,
212 delta: Vec2::new(p.get_f32("dx")?, p.get_f32("dy")?),
213 parent: p.get("parent").and_then(rect).unwrap_or_default(),
214 cell,
215 line: small(p, "line"),
216 byte: p.get_int("byte").and_then(|v| usize::try_from(v).ok()),
217 clicks: small(p, "clicks"),
218 })
219 }
220
221 pub fn button(&self) -> Option<ButtonEvent> {
224 let p = &self.payload;
225 if self.kind()? != "button" {
226 return None;
227 }
228 let phase = match p.get_str("phase")? {
229 "press" => ButtonPhase::Press,
230 "move" => ButtonPhase::Move,
231 "release" => ButtonPhase::Release,
232 _ => return None,
233 };
234 let button = match p.get("button")? {
235 Value::Str(name) => MouseButton::from_name(name)?,
236 Value::Int(code) => MouseButton::from_code(u32::try_from(*code).ok()?),
237 _ => return None,
238 };
239 let cell = p
240 .get("cell")
241 .and_then(|c| Some((small(c, "row")?, small(c, "col")?)));
242 Some(ButtonEvent {
243 phase,
244 button,
245 pos: point(p)?,
246 clicks: small(p, "clicks"),
247 cell,
248 line: small(p, "line"),
249 byte: p.get_int("byte").and_then(|v| usize::try_from(v).ok()),
250 })
251 }
252
253 pub fn key_press(&self) -> Option<(KeyPhase, KeyPress)> {
258 let p = &self.payload;
259 if self.kind()? != "key" {
260 return None;
261 }
262 let phase = match p.get_str("phase")? {
263 "down" => KeyPhase::Down,
264 "up" => KeyPhase::Up,
265 _ => return None,
266 };
267 let code = KeyCode::from_name(p.get_str("code")?)?;
268 let physical = p
269 .get_str("physical")
270 .and_then(KeyCode::from_name)
271 .unwrap_or(KeyCode::Unknown);
272 let press = KeyPress {
273 code,
274 physical,
275 mods: mods(p),
276 text: p.get_str("text").map(str::to_string),
277 repeat: p.get_bool("repeat").unwrap_or(false),
278 location: p
279 .get_str("location")
280 .and_then(crate::input::KeyLocation::from_name)
281 .unwrap_or_default(),
282 locks: crate::input::KeyLocks {
283 caps: p.get_bool("caps_lock").unwrap_or(false),
284 num: p.get_bool("num_lock").unwrap_or(false),
285 },
286 };
287 Some((phase, press))
288 }
289
290 pub fn text(&self) -> Option<TextInput<'_>> {
292 let p = &self.payload;
293 if self.kind()? != "text" {
294 return None;
295 }
296 Some(TextInput {
297 text: p.get_str("text")?,
298 pasted: p.get_bool("pasted").unwrap_or(false),
299 concealed: p.get_bool("concealed").unwrap_or(false),
300 transient: p.get_bool("transient").unwrap_or(false),
301 })
302 }
303
304 pub fn scroll(&self) -> Option<Scroll> {
306 let p = &self.payload;
307 if self.kind()? != "scroll" {
308 return None;
309 }
310 Some(Scroll {
311 pos: point(p)?,
312 delta: Vec2::new(p.get_f32("dx")?, p.get_f32("dy")?),
313 lines: p.get_int("lines"),
314 mods: p.get("mods").map(mods),
315 })
316 }
317
318 pub fn hover(&self) -> Option<Hover> {
320 if self.kind()? != "hover" {
321 return None;
322 }
323 let phase = match self.payload.get_str("phase")? {
324 "enter" => HoverPhase::Enter,
325 "leave" => HoverPhase::Leave,
326 _ => return None,
327 };
328 let by = match self.payload.get_str("by") {
329 Some("content") => HoverBy::Content,
330 _ => HoverBy::Pointer,
331 };
332 Some(Hover { phase, by })
333 }
334
335 pub fn modifiers(&self) -> Option<KeyMods> {
337 if self.kind()? != "modifiers" {
338 return None;
339 }
340 Some(mods(&self.payload))
341 }
342
343 pub fn layout(&self) -> Option<Layout> {
345 let p = &self.payload;
346 if self.kind()? != "layout" {
347 return None;
348 }
349 Some(Layout {
350 rect: rect(p)?,
351 parent: p.get("parent").and_then(rect).unwrap_or_default(),
352 scale: p.get_f32("scale").unwrap_or(1.0),
353 })
354 }
355}
356
357fn mods(p: &Value) -> KeyMods {
359 let on = |k| p.get_bool(k).unwrap_or(false);
360 KeyMods {
361 shift: on("shift"),
362 ctrl: on("ctrl"),
363 alt: on("alt"),
364 super_key: on("super"),
365 }
366}