geop_ops/ui/event.rs
1//! [`StepEditEvent`]: what the user did, as an operation receives it.
2
3use geop_core_math::{
4 primitives::Ray,
5 scalars::{Scalar, as_f64},
6 vector::Vector3,
7};
8use serde::{Deserialize, Serialize};
9
10use crate::operation::EntityRef;
11
12/// How far from its ray a [`Pointer`] reaches: what counts as under it, at
13/// any distance along the ray. Everything a viewer draws at a constant size
14/// on screen — a handle, a label, a frame datum — is laid out in reaches,
15/// so it is hit where it is drawn however far away or zoomed in the view is.
16#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
17#[serde(tag = "type", rename_all = "snake_case", bound = "S: Scalar")]
18pub enum Reach<S: Scalar> {
19 /// Seen in perspective: a cone around the ray, from its origin — the
20 /// eye — widening by `slope` per unit of distance.
21 Cone {
22 #[serde(with = "as_f64")]
23 slope: S,
24 },
25 /// Seen orthographically: a tube of `radius` around the ray.
26 Tube {
27 #[serde(with = "as_f64")]
28 radius: S,
29 },
30}
31
32impl<S: Scalar> Reach<S> {
33 /// How far from the ray it reaches, `t` along it.
34 pub fn at(&self, t: S) -> S {
35 match *self {
36 Reach::Cone { slope } => slope.mul(t),
37 Reach::Tube { radius } => radius,
38 }
39 }
40}
41
42/// Where the pointer is: the ray from the eye through it, and how far from
43/// that ray it reaches.
44#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
45#[serde(bound = "S: Scalar")]
46pub struct Pointer<S: Scalar> {
47 pub ray: Ray<S>,
48 pub reach: Reach<S>,
49}
50
51impl<S: Scalar> Pointer<S> {
52 /// `reaches` of the pointer's reach, `t` along its ray.
53 pub fn reach_at(&self, reaches: f64, t: S) -> S {
54 self.reach.at(t).mul(S::from_f64(reaches))
55 }
56
57 /// Whether something `dist` from the ray, `t` along it, could lie within
58 /// `reaches` of it.
59 pub fn within(&self, dist: S, t: S, reaches: f64) -> bool {
60 !dist.definitely_greater(self.reach_at(reaches, t))
61 }
62}
63
64/// Which mouse button.
65#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "snake_case")]
67pub enum Button {
68 #[default]
69 Primary,
70 Secondary,
71}
72
73/// What a field was set to — or that it was pressed: in the dialog, by a
74/// pick in the viewport, or by dragging a handle.
75#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
76#[serde(tag = "type", content = "value", rename_all = "snake_case")]
77pub enum Value {
78 /// A button, a list item or a reference field was pressed.
79 Press,
80 /// A list item's remove button was pressed.
81 Remove,
82 Bool(bool),
83 Number(f64),
84 /// An action, or a select's option, by its value.
85 Choice(String),
86 /// The entity at this index was taken out of a reference field.
87 RemoveAt(usize),
88 /// Everything was taken out of a reference field.
89 Clear,
90 /// What a reference field holds now: all an operation is ever sent for
91 /// one (see [`super::Reference`]).
92 Entities(Vec<EntityRef>),
93}
94
95/// One thing the user did while editing a step.
96#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
97#[serde(tag = "type", rename_all = "snake_case", bound = "S: Scalar")]
98pub enum StepEditEvent<S: Scalar> {
99 /// The dialog field `key` was used.
100 Dialog { key: String, value: Value },
101 /// The pointer moved over the viewport with no button held.
102 Hover { pointer: Pointer<S> },
103 /// The pointer left the viewport.
104 Leave,
105 /// A click in the viewport: a press and release without moving.
106 Click {
107 pointer: Pointer<S>,
108 #[serde(default)]
109 button: Button,
110 /// The second click of a double click.
111 #[serde(default)]
112 double: bool,
113 #[serde(default)]
114 shift: bool,
115 },
116 /// A drag with the primary button that started where the last
117 /// presentation offered a grab (see [`super::Presentation::grab`]): the
118 /// ray where it went down and the ray where the pointer is now. `done`
119 /// on release.
120 Drag {
121 from: Pointer<S>,
122 to: Pointer<S>,
123 #[serde(default)]
124 done: bool,
125 },
126 /// A key, as the browser names it: `l`, `Escape`, `Enter`, `Delete`.
127 Key { key: String },
128}
129
130impl<S: Scalar> StepEditEvent<S> {
131 /// The dialog field this event uses, and its value.
132 pub fn dialog(&self) -> Option<(&str, &Value)> {
133 match self {
134 StepEditEvent::Dialog { key, value } => Some((key, value)),
135 _ => None,
136 }
137 }
138
139 /// Where the pointer is, for any event that has one — for a drag, where
140 /// it is now.
141 pub fn pointer(&self) -> Option<&Pointer<S>> {
142 match self {
143 StepEditEvent::Hover { pointer } | StepEditEvent::Click { pointer, .. } => {
144 Some(pointer)
145 }
146 StepEditEvent::Drag { to, .. } => Some(to),
147 _ => None,
148 }
149 }
150}
151
152/// A pointer or key event the editor passes on to an operation, having
153/// taken what is its own: picks, selecting, dragging handles (see
154/// [`super::StepEditor`]).
155#[derive(Clone, Debug, PartialEq)]
156pub enum CanvasEvent<S: Scalar> {
157 /// The pointer moved over the viewport with no button held.
158 Hover { pointer: Pointer<S> },
159 /// The pointer left the viewport.
160 Leave,
161 /// A click that selected nothing: a secondary one, a double one, one
162 /// while the operation has a tool in hand, one on nothing selectable.
163 Click {
164 pointer: Pointer<S>,
165 button: Button,
166 double: bool,
167 shift: bool,
168 },
169 /// The draggable visual `key` dragged in the plane worked in, from
170 /// where it was grabbed to where the pointer is now. `done` on release.
171 Move {
172 key: String,
173 from: Vector3<S>,
174 to: Vector3<S>,
175 done: bool,
176 },
177 /// A key, as the browser names it.
178 Key { key: String },
179}