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}