Skip to main content

geop_core_editor/
part_operation.rs

1//! [`PartOperation`]: an operation and how it is edited, in one trait — what
2//! a step is given, how it runs, and the one form it is edited through,
3//! whose fields each set what they show, so a field's key is written once —
4//! and [`part_operation!`](crate::part_operation), which makes it an
5//! [`Operation`](geop_core_program::operation::Operation) and an
6//! [`Editable`](crate::editable::Editable), its editing state a
7//! [`FormState`] of its session.
8
9use std::fmt::Debug;
10
11use geop_core_math::geop_error::GeopResult;
12use geop_core_program::part::StepContext;
13use serde::{Serialize, de::DeserializeOwned};
14
15use crate::{
16    edit_form::{Edit, EditForm, FormState},
17    editable::{Context, OperationInfo},
18    editing::CanvasEvent,
19};
20
21/// One kind of step of a part, and how it is edited.
22pub trait PartOperation: 'static {
23    /// The name programs store its steps under.
24    const KIND: &'static str;
25    const INFO: OperationInfo;
26    /// What a step is given. It is saved with the program, so it names
27    /// targets and elements, never holds their internal ids.
28    type Args: Serialize + DeserializeOwned + Debug + PartialEq + Clone + 'static;
29    /// What the editor keeps while a step is edited besides its arguments
30    /// and the visuals selected: `()` for most.
31    type Session: Clone + Default + 'static;
32
33    /// The arguments of a new step: sensible defaults, taking the part it
34    /// is inserted into into account.
35    fn new_args(context: &Context) -> Self::Args;
36
37    /// Declares what the step produces, through `ctx` (see
38    /// [`StepContext::produce`]).
39    fn run(ctx: &mut StepContext, args: &Self::Args) -> GeopResult<()>;
40
41    /// What the editor shows while the step is edited, with what setting
42    /// each field does. Never fails: an editor needs the form most exactly
43    /// when the arguments do not build, so whatever is wrong is said in it.
44    fn form<'a>(
45        context: &'a Context<'a>,
46        args: &Self::Args,
47        editing: &FormState<Self::Session>,
48    ) -> EditForm<'a, Self::Args, Self::Session>;
49
50    /// What the session forgets at the start of every event, before the
51    /// event is handled: nothing, by default.
52    fn begin_event(session: &mut Self::Session) {
53        let _ = session;
54    }
55
56    /// What the pointer or a key did on the canvas: nothing, by default.
57    fn canvas(context: &Context, edit: Edit<'_, Self::Args, Self::Session>, event: &CanvasEvent) {
58        let _ = (context, edit, event);
59    }
60}
61
62/// Makes each [`PartOperation`] named, `Operation(Args)`, an
63/// [`Operation`](geop_core_program::operation::Operation) and an
64/// [`Editable`](crate::editable::Editable), edited through its form — and
65/// its arguments the [`StepArgs`](geop_core_program::operation::StepArgs)
66/// of it. (Named, since what an operation's `Args` stand for is not known
67/// to other crates' impls.)
68#[macro_export]
69macro_rules! part_operation {
70    ($($operation:ident($args:ty)),* $(,)?) => {$(
71        impl $crate::__program::operation::StepArgs for $args {
72            const KIND: &'static str = <$operation as $crate::part_operation::PartOperation>::KIND;
73        }
74
75        impl $crate::__program::operation::Operation for $operation {
76            const KIND: &'static str = <$operation as $crate::part_operation::PartOperation>::KIND;
77            type Args = <$operation as $crate::part_operation::PartOperation>::Args;
78
79            fn run(
80                ctx: &mut $crate::__program::part::StepContext,
81                args: &Self::Args,
82            ) -> $crate::__GeopResult<()> {
83                <$operation as $crate::part_operation::PartOperation>::run(ctx, args)
84            }
85        }
86
87        impl $crate::editable::Editable for $operation {
88            const INFO: $crate::editable::OperationInfo =
89                <$operation as $crate::part_operation::PartOperation>::INFO;
90            type EditingState = $crate::edit_form::FormState<
91                <$operation as $crate::part_operation::PartOperation>::Session,
92            >;
93
94            fn new_args(
95                context: &$crate::editable::Context,
96            ) -> Self::Args {
97                <$operation as $crate::part_operation::PartOperation>::new_args(context)
98            }
99
100            fn presentation(
101                context: &$crate::editable::Context,
102                args: &Self::Args,
103                editing: &Self::EditingState,
104            ) -> $crate::editing::Form {
105                <$operation as $crate::part_operation::PartOperation>::form(context, args, editing)
106                    .into_form()
107            }
108
109            fn process_user_event(
110                context: &$crate::editable::Context,
111                args: &Self::Args,
112                editing: &Self::EditingState,
113                event: $crate::editing::Event,
114            ) -> (Self::Args, Self::EditingState) {
115                let mut editing = editing.clone();
116                <$operation as $crate::part_operation::PartOperation>::begin_event(
117                    &mut editing.session,
118                );
119                editing.handle(
120                    args,
121                    event,
122                    |args, editing| {
123                        <$operation as $crate::part_operation::PartOperation>::form(
124                            context, args, editing,
125                        )
126                    },
127                    |edit, event| {
128                        <$operation as $crate::part_operation::PartOperation>::canvas(
129                            context, edit, event,
130                        )
131                    },
132                )
133            }
134        }
135    )*};
136}