Skip to main content

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}