buffer_graphics_lib/
drawable.rs

1use crate::shapes::CreateDrawable;
2use graphics_shapes::coord::Coord;
3use graphics_shapes::{IntersectsContains, Shape};
4use ici_files::prelude::*;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9#[derive(Debug, Clone, Copy, Eq, PartialEq)]
10pub enum DrawType {
11    Stroke(Color),
12    Fill(Color),
13}
14
15impl DrawType {
16    pub fn is_stroke(&self) -> bool {
17        matches!(self, DrawType::Stroke(_))
18    }
19
20    #[inline]
21    pub fn color(&self) -> Color {
22        *match self {
23            DrawType::Stroke(c) => c,
24            DrawType::Fill(c) => c,
25        }
26    }
27}
28
29#[inline]
30pub fn fill(color: Color) -> DrawType {
31    DrawType::Fill(color)
32}
33
34#[inline]
35pub fn stroke(color: Color) -> DrawType {
36    DrawType::Stroke(color)
37}
38
39/// Represents a shape that is made of points that can be drawn either as a outline or solid
40#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41#[derive(Debug, Eq, PartialEq, Clone)]
42pub struct Drawable<T: Clone> {
43    obj: T,
44    draw_type: DrawType,
45    drawing_points: Vec<Coord>,
46}
47
48impl<T: Clone> Drawable<T> {
49    #[inline]
50    pub fn obj(&self) -> &T {
51        &self.obj
52    }
53    #[inline]
54    pub fn draw_type(&self) -> DrawType {
55        self.draw_type
56    }
57    #[inline]
58    pub fn drawing_points(&self) -> &Vec<Coord> {
59        &self.drawing_points
60    }
61}
62
63impl<T: Clone> Drawable<T> {
64    #[inline]
65    pub fn new(obj: T, draw_type: DrawType, drawing_points: Vec<Coord>) -> Drawable<T> {
66        Self {
67            obj,
68            draw_type,
69            drawing_points,
70        }
71    }
72}
73
74impl<T: Clone> Drawable<T> {
75    pub fn with_draw_type(&self, draw_type: DrawType) -> Drawable<T> {
76        Drawable::new(self.obj.clone(), draw_type, self.drawing_points.clone())
77    }
78}
79
80impl<T> Drawable<T>
81where
82    Self: CreateDrawable<T>,
83    T: Shape + Clone,
84{
85    pub fn with_translation<P: Into<Coord>>(&self, delta: P) -> Drawable<T> {
86        let moved = self.obj.translate_by(delta.into());
87        Drawable::from_obj(moved, self.draw_type)
88    }
89
90    pub fn with_move<P: Into<Coord>>(&self, xy: P) -> Drawable<T> {
91        let moved = self.obj.move_to(xy.into());
92        Drawable::from_obj(moved, self.draw_type)
93    }
94
95    pub fn with_move_center<P: Into<Coord>>(&self, xy: P) -> Drawable<T> {
96        let moved = self.obj.move_center_to(xy.into());
97        Drawable::from_obj(moved, self.draw_type)
98    }
99
100    pub fn with_scale(&self, scale: f32) -> Drawable<T> {
101        let moved = self.obj.scale(scale);
102        Drawable::from_obj(moved, self.draw_type)
103    }
104
105    pub fn with_scale_around<P: Into<Coord>>(&self, scale: f32, point: P) -> Drawable<T> {
106        let moved = self.obj.scale_around(scale, point.into());
107        Drawable::from_obj(moved, self.draw_type)
108    }
109
110    pub fn with_rotation(&self, degrees: isize) -> Drawable<T> {
111        let rotated = self.obj.rotate(degrees);
112        Drawable::from_obj(rotated, self.draw_type)
113    }
114
115    pub fn with_rotation_around<P: Into<Coord>>(&self, degrees: isize, point: P) -> Drawable<T> {
116        let rotated = self.obj.rotate_around(degrees, point.into());
117        Drawable::from_obj(rotated, self.draw_type)
118    }
119
120    pub fn left(&self) -> isize {
121        self.obj.left()
122    }
123
124    pub fn right(&self) -> isize {
125        self.obj.right()
126    }
127
128    pub fn top(&self) -> isize {
129        self.obj.top()
130    }
131
132    pub fn bottom(&self) -> isize {
133        self.obj.bottom()
134    }
135}
136
137impl<T> Drawable<T>
138where
139    Self: CreateDrawable<T>,
140    T: IntersectsContains + Clone,
141{
142    pub fn intersects_shape(&self, shape: &dyn Shape) -> Option<bool> {
143        self.obj.intersects_shape(shape)
144    }
145
146    pub fn contains_shape(&self, shape: &dyn Shape) -> Option<bool> {
147        self.obj.contains_shape(shape)
148    }
149
150    pub fn intersects_drawable<S: Shape + Clone>(&self, drawable: &Drawable<S>) -> Option<bool> {
151        self.obj.intersects_shape(&drawable.obj)
152    }
153
154    pub fn contains_drawable<S: Shape + Clone>(&self, drawable: &Drawable<S>) -> Option<bool> {
155        self.obj.contains_shape(&drawable.obj)
156    }
157}