Skip to main content

geop_core_editor/editor/
context.rs

1//! What a panel, a tool or a settler is given of the [`Editor`] it extends
2//! ([`EditorContext`], [`Rerun`]), and what it says a command changed
3//! ([`Changed`]).
4
5use geop_core_program::{
6    element::PickedElement, part::Part, program::Program, reader::Reader, runner::Runner,
7    values::StateValues,
8};
9
10use super::Editor;
11use crate::{output::Inspection, view::Visible};
12use geop_core_math::geop_error::{GeopError, GeopResult};
13
14/// What a command changed: what the editor runs, settles and shows again
15/// after it.
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum Changed {
18    Nothing,
19    /// The arguments of the step being edited.
20    Step,
21    /// What runs: which steps, or up to where — or the program's state, as
22    /// a drag let go moved it, which is no edit to undo by itself.
23    Run,
24    /// Only the program's state, as an event of a drag moves it: what it
25    /// moved is sent with the scene, and the program — its state, the
26    /// steps listed, the panels — once the drag is let go ([`Changed::Run`]).
27    /// Every event resending the whole program state grew with the
28    /// assembly, where one part moved.
29    State,
30    /// The program.
31    Program,
32    /// How the program is shown ([`geop_core_program::program::Display`]):
33    /// an edit to undo, and to save with it, that runs nothing.
34    Display,
35}
36
37/// A program, its runner and the part it last ran on: what a solve runs
38/// again at every state it tries, the program's state set to it.
39pub struct Rerun<'r> {
40    pub runner: &'r Runner,
41    pub part: &'r mut Part,
42    pub program: &'r Program,
43}
44
45impl Rerun<'_> {
46    /// The part as the program last ran.
47    pub fn reader(&self) -> Reader<'_> {
48        self.part.current()
49    }
50}
51
52/// The [`Editor`], as a panel's command, a tool or a panel told of an edit
53/// sees it: the program and what it built, and the few ways they change
54/// that the editor keeps track of — so that undo, the marker and the step
55/// being edited stay right whatever the extension does.
56pub struct EditorContext<'a> {
57    editor: &'a mut Editor,
58}
59
60impl<'a> EditorContext<'a> {
61    pub(super) fn new(editor: &'a mut Editor) -> Self {
62        Self { editor }
63    }
64
65    /// The program, as saved: the file edited.
66    pub fn program(&self) -> &Program {
67        &self.editor.file
68    }
69
70    /// The part the program builds, as far as it last ran.
71    pub fn part(&self) -> Reader<'_> {
72        self.editor.part()
73    }
74
75    /// The part as last drawn, but what the viewer was told not to draw:
76    /// what a tool picks in.
77    pub fn drawn(&self) -> Option<Visible<'_>> {
78        let view = self.editor.drawn.as_deref()?;
79        let hidden = (self.editor.shown.as_ref()).map_or(&[][..], |shown| &shown.hidden);
80        Some(Visible { view, hidden })
81    }
82
83    /// How many times the editor has run the program: what the part is
84    /// built as changes only when this does.
85    pub fn runs(&self) -> u64 {
86        self.editor.run
87    }
88
89    /// Refuses while a step is edited.
90    pub fn idle(&self) -> GeopResult<()> {
91        self.editor.idle()
92    }
93
94    /// Runs the whole of the program run now: the step edited's, or the
95    /// file's.
96    pub fn run_all(&mut self) {
97        self.editor.run_to(None);
98    }
99
100    /// The program run now — the step edited's, or the file's — with the
101    /// part as it last ran, to run again.
102    pub fn rerun(&mut self) -> Rerun<'_> {
103        let editor = &mut *self.editor;
104        Rerun {
105            runner: &editor.build.runner,
106            part: &mut editor.build.part,
107            program: match &editor.open {
108                Some(open) if open.within.is_none() => &open.program,
109                _ => &editor.file,
110            },
111        }
112    }
113
114    /// Moves the file's state to `moved`, where it says.
115    pub fn move_state(&mut self, moved: StateValues) {
116        self.editor.file.state.extend(moved);
117    }
118
119    /// Edits the file — and the program of the step being edited, which
120    /// then sees the edit too — by `edit`. The marker and the step edited
121    /// stay at their steps, found again by id: an edit may move steps.
122    pub fn edit_program(
123        &mut self,
124        edit: impl Fn(&mut Program) -> GeopResult<()>,
125    ) -> GeopResult<()> {
126        let editor = &mut *self.editor;
127        editor.edit_file(&edit)?;
128        // A step of a placed part is of another program.
129        if let Some(open) = &mut editor.open
130            && open.within.is_none()
131        {
132            edit(&mut open.program)?;
133            open.index = (open.program.steps.iter().position(|s| s.id == open.id))
134                .ok_or_else(|| GeopError::new(format!("no step {:?}", open.id)))?;
135        }
136        Ok(())
137    }
138
139    /// Makes the file going back to `before` one edit to undo — what a
140    /// drag of many events is — if it changed since.
141    pub fn undoable(&mut self, before: Program) {
142        if before != self.editor.file {
143            self.editor.undo.push(super::Undone::Program(before));
144            self.editor.redo.clear();
145        }
146    }
147
148    /// The answer of the inspector `kind` about the elements `picked` of
149    /// the part as far as it runs.
150    pub fn inspect(&mut self, kind: &str, picked: &[PickedElement]) -> GeopResult<Inspection> {
151        let null = serde_json::Value::Null;
152        self.editor.ask("", |outputs, output| {
153            outputs.get_inspector(kind)?.inspect(output, picked, &null)
154        })
155    }
156}