use std::fmt;
use std::borrow::Borrow;
use xml::writer::EventWriter;
use crate::point::{Vec2D, ScreenUnit, WorldUnit};
use crate::transform::Transform;
use crate::draw_commands::DrawCommand;
use crate::style::Style;
pub mod builder;
pub mod stored;
use self::builder::free_hand_line::FreeHandLine;
use self::builder::foci_and_point_ellipse::FociAndPointEllipse;
use self::builder::polygon::PolygonBuilder;
use self::builder::center_and_radius_circle::CenterAndRadiusCircle;
use self::builder::rectangle::AxisAlignedRectangleBuilder;
use self::builder::three_point_circle::CircleThroughThreePointsBuilder;
use self::builder::grid::Grid;
use self::builder::free_grid::FreeGrid;
#[derive(Debug)]
pub enum ShapeFinished {
Yes(Vec<Box<dyn ShapeStored>>),
No,
Cancelled,
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum ShapeType {
Path,
Circle,
Ellipse,
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum ShapeTool {
Path,
Polygon,
Rectangle,
CircleByCenterAndPoint,
CircleThroughThreePoints,
ThreePointEllipse,
Grid,
FreeGrid,
}
impl ShapeTool {
pub fn start(&self, initial: Vec2D<WorldUnit>, style: Style<WorldUnit>) -> Box<dyn ShapeBuilder> {
match *self {
ShapeTool::Path => Box::new(FreeHandLine::start(initial, style)),
ShapeTool::Rectangle => Box::new(AxisAlignedRectangleBuilder::start(initial, style)),
ShapeTool::Polygon => Box::new(PolygonBuilder::start(initial, style)),
ShapeTool::CircleByCenterAndPoint => Box::new(CenterAndRadiusCircle::start(initial, style)),
ShapeTool::CircleThroughThreePoints => Box::new(CircleThroughThreePointsBuilder::start(initial, style)),
ShapeTool::ThreePointEllipse => Box::new(FociAndPointEllipse::start(initial, style)),
ShapeTool::Grid => Box::new(Grid::start(initial, style)),
ShapeTool::FreeGrid => Box::new(FreeGrid::start(initial, style)),
}
}
}
pub trait ShapeBuilder: fmt::Debug {
fn handle_mouse_moved(&mut self, pos: Vec2D<ScreenUnit>, transform: Transform, snap: ScreenUnit);
fn handle_button_pressed(&mut self, pos: Vec2D<ScreenUnit>, transform: Transform, snap: ScreenUnit);
fn handle_button_released(&mut self, pos: Vec2D<ScreenUnit>, transform: Transform, snap: ScreenUnit) -> ShapeFinished;
fn draw_commands(&self, transform: Transform, snap: ScreenUnit) -> Vec<DrawCommand>;
}
pub trait ShapeStored: fmt::Debug {
fn draw_commands(&self) -> DrawCommand;
fn bbox(&self) -> [Vec2D<WorldUnit>; 2];
fn shape_type(&self) -> ShapeType;
fn intersects_circle(&self, center: Vec2D<WorldUnit>, radius: WorldUnit) -> bool;
fn style(&self) -> Style<WorldUnit>;
fn serialize(&self, writer: &mut EventWriter<&mut Vec<u8>>);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ShapeId(usize);
impl ShapeId {
pub fn next(self) -> ShapeId {
ShapeId(self.0 + 1)
}
}
impl From<usize> for ShapeId {
fn from(data: usize) -> ShapeId {
ShapeId(data)
}
}
impl fmt::Display for ShapeId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "shape{}", self.0)
}
}
pub struct Shape {
id: ShapeId,
z_index: usize,
shape_impl: Box<dyn ShapeStored>,
}
impl Shape {
pub fn from_shape(shape: Box<dyn ShapeStored>, id: ShapeId, z_index: usize) -> Shape {
Shape {
id,
shape_impl: shape,
z_index,
}
}
pub fn draw_commands(&self) -> DrawCommand {
self.shape_impl.draw_commands()
}
pub fn shape_type(&self) -> ShapeType {
self.shape_impl.shape_type()
}
pub fn id(&self) -> ShapeId {
self.id
}
pub fn z_index(&self) -> usize {
self.z_index
}
pub fn style(&self) -> Style<WorldUnit> {
self.shape_impl.style()
}
pub fn bbox(&self) -> [Vec2D<WorldUnit>; 2] {
self.shape_impl.bbox()
}
pub fn intersects_circle(&self, center: Vec2D<WorldUnit>, radius: WorldUnit) -> bool {
self.shape_impl.intersects_circle(center, radius)
}
pub fn shape_impl(&self) -> &dyn ShapeStored {
self.shape_impl.borrow()
}
}
impl fmt::Debug for Shape {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Shape({:?}, {}, {:?})", self.shape_impl.shape_type(), self.id, self.style())
}
}