1use std::{cell::RefCell, collections::BTreeMap, rc::Rc};
13
14use geop_core_math::geop_error::{GeopError, GeopResult};
15use geop_core_program::{
16 element::PickedElement,
17 kept::{Keeper, made_kept},
18 operation_registry::OperationRegistry,
19 program::Program,
20 reader::{Reader, Reads},
21 runner::Runner,
22 values::StateValues,
23};
24use serde::{Serialize, de::DeserializeOwned};
25
26use crate::{
27 editable::{Editable, Editors, Listed},
28 editing::Pull,
29 editor::{Changed, EditorContext, Rerun},
30 output::{Exporter, Inspector, Outputs},
31 tools::{Tool, ToolInfo, pick::PickTool},
32 view::{PartView, annotations_of, listed_by_steps},
33};
34
35pub trait Drawer: 'static {
40 fn draw(&self, reader: &Reader, view: &mut PartView) -> GeopResult<()>;
42
43 fn structure(&self, reader: &Reader) -> GeopResult<Vec<StructureItem>>;
47
48 fn hidden(&self, _reader: &Reader) -> Vec<String> {
53 Vec::new()
54 }
55
56 fn kept(&self) -> bool {
61 false
62 }
63}
64
65const KEPT_DRAWING: Keeper<PartView> = Keeper {
67 write: crate::view::kept::write,
68 read: crate::view::kept::read,
69};
70
71#[derive(Default)]
75pub struct Drawings(RefCell<BTreeMap<usize, Vec<Drawn>>>);
76
77type Drawn = (Reads, Rc<PartView>);
79
80const KEPT_DRAWINGS: usize = 4;
83
84impl Drawings {
85 fn drawn(
90 &self,
91 drawer: usize,
92 reader: &Reader,
93 kept_by: Option<&Runner>,
94 draw: impl FnOnce(&Reader) -> GeopResult<PartView>,
95 ) -> GeopResult<Rc<PartView>> {
96 let mut kept = self.0.borrow_mut();
97 let kept = kept.entry(drawer).or_default();
98 let entry = match kept.iter().position(|(reads, _)| reader.reads_same(reads)) {
99 Some(k) => kept.remove(k),
100 None => match kept_by {
101 Some(runner) => {
102 let key = format!("drawn:{drawer}");
103 let (drawn, reads) = made_kept(reader, runner, &key, KEPT_DRAWING, draw);
104 (reads, drawn?)
105 }
106 None => {
107 let (drawn, reads) = reader.recorded(draw);
108 (reads, Rc::new(drawn?))
109 }
110 },
111 };
112 let drawn = entry.1.clone();
113 kept.push(entry);
114 if kept.len() > KEPT_DRAWINGS {
115 kept.remove(0);
116 }
117 Ok(drawn)
118 }
119}
120
121#[derive(Clone, Debug, PartialEq, Serialize)]
124pub struct StructureItem {
125 pub kind: String,
128 pub kind_label: String,
130 pub name: String,
132 pub detail: Option<String>,
135 pub visible: Option<bool>,
138 pub elements: Vec<PickedElement>,
141}
142
143impl StructureItem {
144 pub fn drawn(kind: &str, kind_label: &str, name: &str) -> Self {
147 Self {
148 kind: kind.to_string(),
149 kind_label: kind_label.to_string(),
150 name: name.to_string(),
151 detail: None,
152 visible: Some(true),
153 elements: Vec::new(),
154 }
155 }
156
157 pub fn detailed(self, detail: String) -> Self {
160 Self {
161 detail: Some(detail),
162 ..self
163 }
164 }
165}
166
167pub trait Panel: 'static {
172 const KEY: &'static str;
175 type State: Serialize;
177 type Command: DeserializeOwned;
179
180 fn state(&self, program: &Program, part: &Reader) -> Self::State;
183
184 fn details(&self, state: &Self::State) -> BTreeMap<String, String> {
188 let _ = state;
189 BTreeMap::new()
190 }
191
192 fn command(&self, ctx: &mut EditorContext, command: Self::Command) -> GeopResult<Changed>;
194
195 fn after_edit(&self, _ctx: &mut EditorContext) {}
200}
201
202pub trait ErasedPanel {
205 fn key(&self) -> &'static str;
206 fn state(
209 &self,
210 program: &Program,
211 part: &Reader,
212 ) -> GeopResult<(serde_json::Value, BTreeMap<String, String>)>;
213 fn command(&self, ctx: &mut EditorContext, payload: serde_json::Value) -> GeopResult<Changed>;
214 fn after_edit(&self, ctx: &mut EditorContext);
215}
216
217impl<P: Panel> ErasedPanel for P {
218 fn key(&self) -> &'static str {
219 P::KEY
220 }
221
222 fn state(
223 &self,
224 program: &Program,
225 part: &Reader,
226 ) -> GeopResult<(serde_json::Value, BTreeMap<String, String>)> {
227 let state = Panel::state(self, program, part);
228 let details = Panel::details(self, &state);
229 let state = serde_json::to_value(state)
230 .map_err(|e| GeopError::new(format!("the state of the panel `{}`: {e}", P::KEY)))?;
231 Ok((state, details))
232 }
233
234 fn command(&self, ctx: &mut EditorContext, payload: serde_json::Value) -> GeopResult<Changed> {
235 let command = serde_json::from_value(payload)
236 .map_err(|e| GeopError::new(format!("a command of the panel `{}`: {e}", P::KEY)))?;
237 Panel::command(self, ctx, command)
238 }
239
240 fn after_edit(&self, ctx: &mut EditorContext) {
241 Panel::after_edit(self, ctx)
242 }
243}
244
245pub trait Settle: 'static {
251 fn settle(
256 &self,
257 rerun: &mut Rerun,
258 pulls: &[Pull],
259 own: Option<&str>,
260 ) -> GeopResult<StateValues>;
261
262 fn solvable(&self, reader: &Reader) -> GeopResult<Vec<String>>;
265}
266
267pub type Example<T> = (&'static str, fn() -> T);
270
271pub type ExampleFiles = Vec<(&'static str, Program)>;
274
275#[derive(Default)]
278pub struct ExampleSet {
279 pub programs: Vec<Example<Program>>,
280 pub workspaces: Vec<Example<ExampleFiles>>,
281}
282
283type MakeTool = Rc<dyn Fn() -> Box<dyn Tool>>;
285
286#[derive(Default)]
288pub struct Registry {
289 editors: Editors,
290 operations: OperationRegistry,
291 drawers: Vec<Rc<dyn Drawer>>,
292 outputs: Outputs,
293 panels: Vec<Rc<dyn ErasedPanel>>,
294 tools: Vec<(ToolInfo, MakeTool)>,
295 idle: Option<String>,
298 settler: Option<Rc<dyn Settle>>,
299 examples: Vec<ExampleSet>,
300}
301
302impl Registry {
303 pub fn operation<O: Editable>(mut self, operation: O) -> GeopResult<Self> {
306 let operation = Rc::new(operation);
307 self.editors.add(operation.clone())?;
308 self.operations = self.operations.with_erased(operation)?;
309 Ok(self)
310 }
311
312 pub fn drawer<D: Drawer>(mut self, drawer: D) -> GeopResult<Self> {
314 self.drawers.push(Rc::new(drawer));
315 Ok(self)
316 }
317
318 pub fn exporter<E: Exporter>(mut self, exporter: E) -> GeopResult<Self> {
320 self.outputs = self.outputs.exporter(exporter)?;
321 Ok(self)
322 }
323
324 pub fn inspector<I: Inspector>(mut self, inspector: I) -> GeopResult<Self> {
326 self.outputs = self.outputs.inspector(inspector)?;
327 Ok(self)
328 }
329
330 pub fn panel<P: Panel>(mut self, panel: P) -> GeopResult<Self> {
332 if self.panels.iter().any(|p| p.key() == P::KEY) {
333 return Err(GeopError::new(format!(
334 "the panel `{}` is registered twice",
335 P::KEY
336 )));
337 }
338 self.panels.push(Rc::new(panel));
339 Ok(self)
340 }
341
342 pub fn tool<T: Tool + Clone>(mut self, info: ToolInfo, tool: T) -> GeopResult<Self> {
346 let key = info.key;
347 if self.tools.iter().any(|(i, _)| i.key == key) || key.starts_with(PickTool::PREFIX) {
348 return Err(GeopError::new(format!(
349 "the tool `{key}` is registered twice"
350 )));
351 }
352 self.tools
353 .push((info, Rc::new(move || Box::new(tool.clone()))));
354 Ok(self)
355 }
356
357 pub fn idle_tool(mut self, key: &str) -> GeopResult<Self> {
363 if !self.tools.iter().any(|(info, _)| info.key == key) {
364 return Err(GeopError::new(format!(
365 "the idle tool `{key}` is no tool added"
366 )));
367 }
368 if let Some(idle) = &self.idle {
369 return Err(GeopError::new(format!(
370 "the idle tool is `{idle}` already, not also `{key}`"
371 )));
372 }
373 self.idle = Some(key.to_string());
374 Ok(self)
375 }
376
377 pub fn settler<Scalar: Settle>(mut self, settler: Scalar) -> GeopResult<Self> {
380 if self.settler.is_some() {
381 return Err(GeopError::new("a settler is registered twice"));
382 }
383 self.settler = Some(Rc::new(settler));
384 Ok(self)
385 }
386
387 pub fn examples(mut self, set: ExampleSet) -> GeopResult<Self> {
390 let names = (set.programs.iter().map(|(name, _)| name))
391 .chain(set.workspaces.iter().map(|(name, _)| name));
392 for name in names {
393 let mut known =
394 (self.example_names().chain(self.workspace_example_names())).map(|n| n == *name);
395 if known.any(|same| same) {
396 return Err(GeopError::new(format!(
397 "the example `{name}` is registered twice"
398 )));
399 }
400 }
401 self.examples.push(set);
402 Ok(self)
403 }
404
405 pub fn operations(&self) -> OperationRegistry {
407 self.operations.clone()
408 }
409
410 pub fn editors(&self) -> &Editors {
412 &self.editors
413 }
414
415 pub fn infos(&self) -> Vec<Listed> {
417 self.editors.infos()
418 }
419
420 pub fn outputs(&self) -> &Outputs {
422 &self.outputs
423 }
424
425 pub fn into_outputs(self) -> Outputs {
427 self.outputs
428 }
429
430 pub fn draw(
436 &self,
437 reader: &Reader,
438 drawings: &Drawings,
439 kept_by: Option<&Runner>,
440 ) -> GeopResult<PartView> {
441 let mut view = PartView::new();
442 for (k, drawer) in self.drawers.iter().enumerate() {
443 let kept_by = kept_by.filter(|_| drawer.kept());
444 let drawn = drawings.drawn(k, reader, kept_by, |reader| {
445 let mut drawn = PartView::new();
446 drawer.draw(reader, &mut drawn)?;
447 Ok(drawn)
448 })?;
449 view.add(&drawn);
450 }
451 view.annotations = annotations_of(reader);
452 Ok(view.finish())
453 }
454
455 pub fn structure(&self, reader: &Reader, hidden: &[String]) -> GeopResult<Vec<StructureItem>> {
459 let mut items = Vec::new();
460 for drawer in &self.drawers {
461 items.extend(drawer.structure(reader)?);
462 }
463 for item in &mut items {
464 if item.visible.is_some() {
465 item.visible = Some(!hidden.contains(&item.name));
466 }
467 }
468 items.extend(
469 listed_by_steps(reader)
470 .into_iter()
471 .map(|listed| StructureItem {
472 kind_label: plural(&listed.kind),
473 kind: listed.kind,
474 name: listed.name,
475 detail: None,
476 visible: None,
477 elements: listed.elements,
478 }),
479 );
480 Ok(items)
481 }
482
483 pub fn hidden(&self, reader: &Reader) -> Vec<String> {
486 (self.drawers.iter())
487 .flat_map(|drawer| drawer.hidden(reader))
488 .collect()
489 }
490
491 pub fn panels(&self) -> impl Iterator<Item = &dyn ErasedPanel> {
493 self.panels.iter().map(Rc::as_ref)
494 }
495
496 pub fn get_panel(&self, key: &str) -> GeopResult<&dyn ErasedPanel> {
498 (self.panels())
499 .find(|panel| panel.key() == key)
500 .ok_or_else(|| GeopError::new(format!("there is no panel `{key}`")))
501 }
502
503 pub fn tools(&self) -> Vec<&ToolInfo> {
506 self.tools.iter().map(|(info, _)| info).collect()
507 }
508
509 pub fn tool_in_hand(&self, key: &str) -> GeopResult<Box<dyn Tool>> {
512 if let Some(inspector) = key.strip_prefix(PickTool::PREFIX) {
513 let info = self.outputs.get_inspector(inspector)?.info();
514 return Ok(Box::new(PickTool::new(info)?));
515 }
516 let (_, make) = (self.tools.iter())
517 .find(|(info, _)| info.key == key)
518 .ok_or_else(|| GeopError::new(format!("there is no tool `{key}`")))?;
519 Ok(make())
520 }
521
522 pub fn idle_in_hand(&self) -> Option<(String, Box<dyn Tool>)> {
525 let key = self.idle.as_ref()?;
526 Some((key.clone(), self.tool_in_hand(key).ok()?))
527 }
528
529 pub fn get_settler(&self) -> Option<&dyn Settle> {
531 self.settler.as_deref()
532 }
533
534 pub fn example_names(&self) -> impl Iterator<Item = &'static str> + '_ {
536 (self.examples.iter()).flat_map(|set| set.programs.iter().map(|(name, _)| *name))
537 }
538
539 pub fn example_programs(&self) -> Vec<Example<Program>> {
542 (self.examples.iter())
543 .flat_map(|set| set.programs.iter().copied())
544 .collect()
545 }
546
547 pub fn workspace_example_names(&self) -> impl Iterator<Item = &'static str> + '_ {
549 (self.examples.iter()).flat_map(|set| set.workspaces.iter().map(|(name, _)| *name))
550 }
551
552 pub fn example(&self, name: &str) -> GeopResult<Program> {
554 (self.examples.iter())
555 .flat_map(|set| &set.programs)
556 .find(|(n, _)| *n == name)
557 .map(|(_, make)| make())
558 .ok_or_else(|| GeopError::new(format!("there is no example {name:?}")))
559 }
560
561 pub fn workspace_example(&self, name: &str) -> GeopResult<ExampleFiles> {
563 (self.examples.iter())
564 .flat_map(|set| &set.workspaces)
565 .find(|(n, _)| *n == name)
566 .map(|(_, make)| make())
567 .ok_or_else(|| GeopError::new(format!("there is no example {name:?}")))
568 }
569}
570
571fn plural(kind: &str) -> String {
574 let words = kind.replace('_', " ");
575 let mut chars = words.chars();
576 match chars.next() {
577 Some(first) => format!("{}{}s", first.to_uppercase(), chars.as_str()),
578 None => String::new(),
579 }
580}