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}
120
121#[derive(Clone, Copy, Debug, PartialEq, Eq)]
123pub enum HoverPhase {
124 Enter,
125 Leave,
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
130pub enum HoverBy {
131 Pointer,
133 Content,
137}
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq)]
141pub struct Hover {
142 pub phase: HoverPhase,
143 pub by: HoverBy,
144}
145
146#[derive(Clone, Copy, Debug, PartialEq)]
148pub struct Layout {
149 pub rect: Rect,
150 pub parent: Rect,
151 pub scale: f32,
152}
153
154#[derive(Clone, Copy, Debug, PartialEq)]
157pub struct TextInput<'a> {
158 pub text: &'a str,
159 pub pasted: bool,
161 pub concealed: bool,
163 pub transient: bool,
165}
166
167fn point(p: &Value) -> Option<Vec2> {
168 Some(Vec2::new(p.get_f32("x")?, p.get_f32("y")?))
169}
170
171fn rect(p: &Value) -> Option<Rect> {
172 Some(Rect::new(
173 p.get_f32("x")?,
174 p.get_f32("y")?,
175 p.get_f32("w")?,
176 p.get_f32("h")?,
177 ))
178}
179
180fn small(p: &Value, key: &str) -> Option<u32> {
181 p.get_int(key).and_then(|v| u32::try_from(v).ok())
182}
183
184impl UiEvent {
185 pub fn tag(&self) -> Option<&Value> {
188 self.payload.get("tag")
189 }
190
191 pub fn drag(&self) -> Option<Drag> {
193 let p = &self.payload;
194 if self.kind()? != "drag" {
195 return None;
196 }
197 let phase = match p.get_str("phase")? {
198 "start" => DragPhase::Start,
199 "move" => DragPhase::Move,
200 "end" => DragPhase::End,
201 _ => return None,
202 };
203 let cell = p
204 .get("cell")
205 .and_then(|c| Some((small(c, "row")?, small(c, "col")?)));
206 Some(Drag {
207 phase,
208 pos: point(p)?,
209 delta: Vec2::new(p.get_f32("dx")?, p.get_f32("dy")?),
210 parent: p.get("parent").and_then(rect).unwrap_or_default(),
211 cell,
212 line: small(p, "line"),
213 byte: p.get_int("byte").and_then(|v| usize::try_from(v).ok()),
214 clicks: small(p, "clicks"),
215 })
216 }
217
218 pub fn button(&self) -> Option<ButtonEvent> {
221 let p = &self.payload;
222 if self.kind()? != "button" {
223 return None;
224 }
225 let phase = match p.get_str("phase")? {
226 "press" => ButtonPhase::Press,
227 "move" => ButtonPhase::Move,
228 "release" => ButtonPhase::Release,
229 _ => return None,
230 };
231 let button = match p.get("button")? {
232 Value::Str(name) => MouseButton::from_name(name)?,
233 Value::Int(code) => MouseButton::from_code(u32::try_from(*code).ok()?),
234 _ => return None,
235 };
236 let cell = p
237 .get("cell")
238 .and_then(|c| Some((small(c, "row")?, small(c, "col")?)));
239 Some(ButtonEvent {
240 phase,
241 button,
242 pos: point(p)?,
243 clicks: small(p, "clicks"),
244 cell,
245 line: small(p, "line"),
246 byte: p.get_int("byte").and_then(|v| usize::try_from(v).ok()),
247 })
248 }
249
250 pub fn key_press(&self) -> Option<(KeyPhase, KeyPress)> {
255 let p = &self.payload;
256 if self.kind()? != "key" {
257 return None;
258 }
259 let phase = match p.get_str("phase")? {
260 "down" => KeyPhase::Down,
261 "up" => KeyPhase::Up,
262 _ => return None,
263 };
264 let code = KeyCode::from_name(p.get_str("code")?)?;
265 let physical = p
266 .get_str("physical")
267 .and_then(KeyCode::from_name)
268 .unwrap_or(KeyCode::Unknown);
269 let press = KeyPress {
270 code,
271 physical,
272 mods: mods(p),
273 text: p.get_str("text").map(str::to_string),
274 repeat: p.get_bool("repeat").unwrap_or(false),
275 location: p
276 .get_str("location")
277 .and_then(crate::input::KeyLocation::from_name)
278 .unwrap_or_default(),
279 locks: crate::input::KeyLocks {
280 caps: p.get_bool("caps_lock").unwrap_or(false),
281 num: p.get_bool("num_lock").unwrap_or(false),
282 },
283 };
284 Some((phase, press))
285 }
286
287 pub fn text(&self) -> Option<TextInput<'_>> {
289 let p = &self.payload;
290 if self.kind()? != "text" {
291 return None;
292 }
293 Some(TextInput {
294 text: p.get_str("text")?,
295 pasted: p.get_bool("pasted").unwrap_or(false),
296 concealed: p.get_bool("concealed").unwrap_or(false),
297 transient: p.get_bool("transient").unwrap_or(false),
298 })
299 }
300
301 pub fn scroll(&self) -> Option<Scroll> {
303 let p = &self.payload;
304 if self.kind()? != "scroll" {
305 return None;
306 }
307 Some(Scroll {
308 pos: point(p)?,
309 delta: Vec2::new(p.get_f32("dx")?, p.get_f32("dy")?),
310 lines: p.get_int("lines"),
311 })
312 }
313
314 pub fn hover(&self) -> Option<Hover> {
316 if self.kind()? != "hover" {
317 return None;
318 }
319 let phase = match self.payload.get_str("phase")? {
320 "enter" => HoverPhase::Enter,
321 "leave" => HoverPhase::Leave,
322 _ => return None,
323 };
324 let by = match self.payload.get_str("by") {
325 Some("content") => HoverBy::Content,
326 _ => HoverBy::Pointer,
327 };
328 Some(Hover { phase, by })
329 }
330
331 pub fn modifiers(&self) -> Option<KeyMods> {
333 if self.kind()? != "modifiers" {
334 return None;
335 }
336 Some(mods(&self.payload))
337 }
338
339 pub fn layout(&self) -> Option<Layout> {
341 let p = &self.payload;
342 if self.kind()? != "layout" {
343 return None;
344 }
345 Some(Layout {
346 rect: rect(p)?,
347 parent: p.get("parent").and_then(rect).unwrap_or_default(),
348 scale: p.get_f32("scale").unwrap_or(1.0),
349 })
350 }
351}
352
353fn mods(p: &Value) -> KeyMods {
355 let on = |k| p.get_bool(k).unwrap_or(false);
356 KeyMods {
357 shift: on("shift"),
358 ctrl: on("ctrl"),
359 alt: on("alt"),
360 super_key: on("super"),
361 }
362}