Skip to main content

geop_ops/operation/
mod.rs

1//! What an operation is.
2//!
3//! An operation is a unit struct implementing [`Operation`], with an `Args`
4//! struct holding everything a step of it needs and a `Session` holding the
5//! temporary state of editing one, if it needs any. Built, a step maps
6//!
7//! ```text
8//! (part, args) -> part                                            apply
9//! ```
10//!
11//! and edited, it shows a [`Form`] — fields, each with what setting it
12//! does, and visuals — whose fields the editor sets:
13//!
14//! ```text
15//! (part, args, selection)                -> form                  form
16//! (part, args, selection, field, value)  -> args, selection       set
17//! ```
18//!
19//! `set` is the form's: each field is described once, with its setter.
20//!
21//! Picking entities for a field, dragging handles, selecting visuals and
22//! dragging them are the editor's (see [`crate::ui::StepEditor`]), the same
23//! for every operation; an operation that draws in a canvas of its own — a
24//! sketch — also takes what the pointer and the keys do beyond that
25//! ([`Operation::event`]), with a `Session` for what it keeps between
26//! events.
27//!
28//! Arguments are plain design data — `f64` lengths, sketches — and refer to
29//! existing entities of the part only by name, never by an internal id: an
30//! id only means something inside the one build that produced it, a name
31//! means the same thing in every build of the same program (see the crate
32//! docs). Entities a step builds on directly — a sketch's plane, what a
33//! datum is built from — are [`EntityRef`]s.
34//!
35//! A set of operations is an enum with one variant `Name(NameArgs)` per
36//! operation, implementing [`Operations`] through `#[derive(Operations)]`:
37//! what a program step holds, and what serializes as `{"operation":
38//! "extrude", "args": {...}}`.
39
40mod aspects;
41mod entity;
42
43pub use aspects::{Aspects, Role, describe_roles};
44pub use entity::{EntityRef, frame_along};
45
46pub use geop_ops_derive::Operations;
47
48use std::any::Any;
49
50use geop_core_math::{geop_error::GeopResult, scalars::Scalar};
51use serde::{Serialize, de::DeserializeOwned};
52
53use crate::{
54    Part,
55    ui::{CanvasEvent, Edit, Form, Value},
56};
57
58/// An operation of a set: how a step spells it, its short name and what it
59/// does — what an editor offers it by.
60#[derive(Clone, Debug, PartialEq, Serialize)]
61pub struct OperationInfo {
62    pub kind: &'static str,
63    pub label: &'static str,
64    pub doc: &'static str,
65}
66
67/// One kind of operation on a [`Part`].
68pub trait Operation {
69    /// Everything a step needs, as plain, serializable design data.
70    type Args: Clone;
71    /// The temporary state of editing a step beyond its arguments — `()`
72    /// for every operation whose form says all there is to it. Starts
73    /// afresh whenever an editor opens a step.
74    type Session: Default + 'static;
75
76    /// The arguments of a new step inserted after `before`: sensible
77    /// defaults, taking what `before` holds into account.
78    fn new_args<S: Scalar>(&self, before: &Part<S>) -> Self::Args;
79
80    /// Applies the operation as the program step `operation_id`, consuming
81    /// `part` and returning the part it produces. Everything the operation
82    /// creates is named after `operation_id` (see the crate docs), so the id
83    /// has to be unique within a program.
84    ///
85    /// On error no part is returned — a caller that still needs the
86    /// original should clone it first.
87    fn apply<S: Scalar>(
88        &self,
89        part: Part<S>,
90        operation_id: &str,
91        args: &Self::Args,
92    ) -> GeopResult<Part<S>>;
93
94    /// What a step shows while it is edited against `before`: its fields —
95    /// numbers, choices, entities to pick — each with what setting it does,
96    /// and what it draws, with `selection` the keys of its visuals selected.
97    /// Never fails: an editor needs the form most exactly when the arguments
98    /// do not build, so whatever is wrong is said in it.
99    ///
100    /// Its setters may capture `before`, never the arguments: they are
101    /// handed the arguments to change (see [`Operation::set`]).
102    fn form<'a, S: Scalar>(
103        &self,
104        before: &'a Part<S>,
105        args: &Self::Args,
106        session: &Self::Session,
107        selection: &[String],
108    ) -> Form<'a, S, Self::Args, Self::Session>;
109
110    /// The field `key` of the form set to `value`: typed or chosen in the
111    /// dialog, picked in the viewport, dragged as a handle — by the setter
112    /// the form gave it (see [`Form`]).
113    fn set<S: Scalar>(
114        &self,
115        before: &Part<S>,
116        args: &mut Self::Args,
117        session: &mut Self::Session,
118        selection: &mut Vec<String>,
119        key: &str,
120        value: Value,
121    ) {
122        let form = self.form(before, args, session, selection);
123        let edit = Edit {
124            args,
125            session,
126            selection,
127        };
128        form.set(key, edit, value);
129    }
130
131    /// A pointer or key event the editor passed on (see [`CanvasEvent`]).
132    /// Only an operation that draws in a canvas of its own, like a sketch,
133    /// needs these.
134    fn event<S: Scalar>(
135        &self,
136        before: &Part<S>,
137        args: &mut Self::Args,
138        session: &mut Self::Session,
139        selection: &mut Vec<String>,
140        event: &CanvasEvent<S>,
141    ) {
142        let _ = (before, args, session, selection, event);
143    }
144}
145
146/// A set of operations, each together with its arguments: the enum a
147/// [`crate::Program`]'s steps hold.
148///
149/// Written by `#[derive(Operations)]` on an enum whose every variant is
150/// `Name(NameArgs)`, with `Name` the unit struct implementing [`Operation`]
151/// with `Args = NameArgs`: it dispatches to `Name`, and converts from each
152/// `NameArgs`. A variant's doc comment describes the operation, and
153/// `#[operation(label = "...")]` gives its short name if that is not the
154/// variant's. A step's session is the session of its operation, boxed:
155/// sessions differ by operation.
156pub trait Operations: Clone + std::fmt::Debug + PartialEq + Serialize + DeserializeOwned {
157    /// Every operation of the set.
158    fn infos() -> Vec<OperationInfo>;
159
160    /// A new step of the operation `kind`, inserted after `before`, see
161    /// [`Operation::new_args`].
162    fn new_step<S: Scalar>(kind: &str, before: &Part<S>) -> GeopResult<Self>;
163
164    /// See [`Operation::apply`].
165    fn apply<S: Scalar>(&self, part: Part<S>, operation_id: &str) -> GeopResult<Part<S>>;
166
167    /// A fresh session for editing this step.
168    fn new_session(&self) -> Box<dyn Any>;
169
170    /// See [`Operation::form`], as an editor reads it; `session` is one
171    /// [`Operations::new_session`] made for a step of the same operation.
172    fn form<'a, S: Scalar>(
173        &self,
174        before: &'a Part<S>,
175        session: &dyn Any,
176        selection: &[String],
177    ) -> Form<'a, S>;
178
179    /// See [`Operation::set`].
180    fn set<S: Scalar>(
181        &mut self,
182        before: &Part<S>,
183        session: &mut dyn Any,
184        selection: &mut Vec<String>,
185        key: &str,
186        value: Value,
187    );
188
189    /// See [`Operation::event`].
190    fn event<S: Scalar>(
191        &mut self,
192        before: &Part<S>,
193        session: &mut dyn Any,
194        selection: &mut Vec<String>,
195        event: &CanvasEvent<S>,
196    );
197
198    /// The operation's kind, as it is serialized: `extrude`.
199    fn kind(&self) -> &'static str;
200
201    /// The operation's short name: `Extrude`.
202    fn label(&self) -> &'static str;
203}