use std::rc::Rc;
use orrery_core::{
draw::{
ActivationBoxDefinition, ActorDefinition, ArrowDefinition, BoundaryDefinition,
ComponentDefinition, ControlDefinition, EntityDefinition, FragmentDefinition,
InterfaceDefinition, NoteDefinition, OvalDefinition, RectangleDefinition, ShapeDefinition,
StrokeDefinition, TextDefinition,
},
identifier::Id,
};
use crate::elaborate_utils::TypeDefinition;
pub const RECTANGLE: &str = "Rectangle";
pub const OVAL: &str = "Oval";
pub const COMPONENT: &str = "Component";
pub const BOUNDARY: &str = "Boundary";
pub const ACTOR: &str = "Actor";
pub const ENTITY: &str = "Entity";
pub const CONTROL: &str = "Control";
pub const INTERFACE: &str = "Interface";
pub const ARROW: &str = "Arrow";
pub const FRAGMENT: &str = "Fragment";
pub const FRAGMENT_ALT: &str = "FragmentAlt";
pub const FRAGMENT_OPT: &str = "FragmentOpt";
pub const FRAGMENT_LOOP: &str = "FragmentLoop";
pub const FRAGMENT_PAR: &str = "FragmentPar";
pub const NOTE: &str = "Note";
pub const ACTIVATE: &str = "Activate";
pub const STROKE: &str = "Stroke";
pub const TEXT: &str = "Text";
#[derive(Debug, Default)]
pub struct BuiltinTypeBuilder {
types: Vec<TypeDefinition>,
}
impl BuiltinTypeBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn add_shape(
mut self,
name: &str,
shape_definition: impl ShapeDefinition + 'static,
) -> Self {
self.types.push(TypeDefinition::new_shape(
Id::new(name),
Rc::new(Box::new(shape_definition)),
));
self
}
pub fn add_arrow(mut self, name: &str, arrow_definition: ArrowDefinition) -> Self {
self.types.push(TypeDefinition::new_arrow(
Id::new(name),
Rc::new(arrow_definition),
));
self
}
pub fn add_fragment(mut self, name: &str, fragment_definition: FragmentDefinition) -> Self {
self.types.push(TypeDefinition::new_fragment(
Id::new(name),
Rc::new(fragment_definition),
));
self
}
pub fn add_note(mut self, name: &str, note_definition: NoteDefinition) -> Self {
self.types.push(TypeDefinition::new_note(
Id::new(name),
Rc::new(note_definition),
));
self
}
pub fn add_activation_box(
mut self,
name: &str,
activation_box_definition: ActivationBoxDefinition,
) -> Self {
self.types.push(TypeDefinition::new_activation_box(
Id::new(name),
Rc::new(activation_box_definition),
));
self
}
pub fn add_stroke(mut self, name: &str, stroke_definition: StrokeDefinition) -> Self {
self.types
.push(TypeDefinition::new_stroke(Id::new(name), stroke_definition));
self
}
pub fn add_text(mut self, name: &str, text_definition: TextDefinition) -> Self {
self.types
.push(TypeDefinition::new_text(Id::new(name), text_definition));
self
}
pub fn build(self) -> Vec<TypeDefinition> {
self.types
}
}
pub fn defaults() -> Vec<TypeDefinition> {
BuiltinTypeBuilder::new()
.add_stroke(STROKE, StrokeDefinition::default())
.add_text(TEXT, TextDefinition::default())
.add_shape(RECTANGLE, RectangleDefinition::new())
.add_shape(OVAL, OvalDefinition::new())
.add_shape(COMPONENT, ComponentDefinition::new())
.add_shape(BOUNDARY, BoundaryDefinition::new())
.add_shape(ACTOR, ActorDefinition::new())
.add_shape(ENTITY, EntityDefinition::new())
.add_shape(CONTROL, ControlDefinition::new())
.add_shape(INTERFACE, InterfaceDefinition::new())
.add_arrow(ARROW, ArrowDefinition::default())
.add_fragment(FRAGMENT_ALT, FragmentDefinition::new())
.add_fragment(FRAGMENT_OPT, FragmentDefinition::new())
.add_fragment(FRAGMENT_LOOP, FragmentDefinition::new())
.add_fragment(FRAGMENT_PAR, FragmentDefinition::new())
.add_fragment(FRAGMENT, FragmentDefinition::new())
.add_note(NOTE, NoteDefinition::new())
.add_activation_box(ACTIVATE, ActivationBoxDefinition::new())
.build()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_starts_empty() {
let builder = BuiltinTypeBuilder::new();
let types = builder.build();
assert_eq!(types.len(), 0);
}
#[test]
fn test_builder_chaining() {
let types = BuiltinTypeBuilder::new()
.add_shape(RECTANGLE, RectangleDefinition::new())
.add_arrow(ARROW, ArrowDefinition::default())
.add_note(NOTE, NoteDefinition::new())
.build();
assert_eq!(types.len(), 3);
}
#[test]
fn test_defaults_creates_all_types() {
let types = defaults();
assert_eq!(types.len(), 18);
let has_type = |name: &str| types.iter().any(|t| t.id() == name);
assert!(has_type(STROKE));
assert!(has_type(TEXT));
assert!(has_type(RECTANGLE));
assert!(has_type(OVAL));
assert!(has_type(COMPONENT));
assert!(has_type(BOUNDARY));
assert!(has_type(ACTOR));
assert!(has_type(ENTITY));
assert!(has_type(CONTROL));
assert!(has_type(INTERFACE));
assert!(has_type(ARROW));
assert!(has_type(FRAGMENT));
assert!(has_type(FRAGMENT_ALT));
assert!(has_type(FRAGMENT_OPT));
assert!(has_type(FRAGMENT_LOOP));
assert!(has_type(FRAGMENT_PAR));
assert!(has_type(NOTE));
assert!(has_type(ACTIVATE));
}
}