1use crate::core::base::Orientation;
7use crate::core::format::Visible;
8use crate::core::geometry::{Point, Position};
9use crate::core::style::{LineStyleKind, StyleAttr};
10use crate::std_shapes::render::get_shape_size;
11
12const PADDING: f64 = 60.;
13const CONN_PADDING: f64 = 10.;
14
15#[derive(Debug, Copy, Clone)]
16pub enum LineEndKind {
17 None,
18 Arrow,
19}
20
21#[derive(Debug, Clone)]
22pub enum RecordDef {
23 Text(String, Option<String>),
25 Array(Vec<RecordDef>),
26}
27
28impl RecordDef {
29 pub fn new_text(s: &str) -> Self {
30 RecordDef::Text(s.to_string(), None)
31 }
32
33 pub fn new_text_with_port(s: &str, p: &str) -> Self {
34 RecordDef::Text(s.to_string(), Some(p.to_string()))
35 }
36}
37
38#[derive(Debug, Clone)]
39pub enum ShapeKind {
40 None,
41 Box(String),
42 Circle(String),
43 DoubleCircle(String),
44 Record(RecordDef),
45 Connector(Option<String>),
46}
47
48impl ShapeKind {
49 pub fn new_box(s: &str) -> Self {
50 ShapeKind::Box(s.to_string())
51 }
52 pub fn new_circle(s: &str) -> Self {
53 ShapeKind::Circle(s.to_string())
54 }
55 pub fn new_double_circle(s: &str) -> Self {
56 ShapeKind::DoubleCircle(s.to_string())
57 }
58 pub fn new_record(r: &RecordDef) -> Self {
59 ShapeKind::Record(r.clone())
60 }
61 pub fn new_connector(s: &str) -> Self {
62 if s.is_empty() {
63 return ShapeKind::Connector(None);
64 }
65 ShapeKind::Connector(Some(s.to_string()))
66 }
67}
68
69#[derive(Clone, Debug)]
70pub struct Element {
71 pub shape: ShapeKind,
72 pub pos: Position,
73 pub look: StyleAttr,
74 pub orientation: Orientation,
75 pub properties: Option<String>,
76}
77
78impl Element {
79 pub fn create(
80 shape: ShapeKind,
81 look: StyleAttr,
82 orientation: Orientation,
83 size: Point,
84 ) -> Element {
85 Element {
86 shape,
87 look,
88 orientation,
89 pos: Position::new(
90 Point::zero(),
91 size,
92 Point::zero(),
93 Point::splat(PADDING),
94 ),
95 properties: Option::None,
96 }
97 }
98
99 pub fn create_with_properties(
100 shape: ShapeKind,
101 look: StyleAttr,
102 orientation: Orientation,
103 size: Point,
104 properties: impl Into<String>,
105 ) -> Element {
106 let mut elem = Element::create(shape, look, orientation, size);
107 elem.properties = Option::Some(properties.into());
108 elem
109 }
110 pub fn create_connector(
111 label: &str,
112 look: &StyleAttr,
113 dir: Orientation,
114 ) -> Element {
115 Element {
116 shape: ShapeKind::new_connector(label),
117 look: look.clone(),
118 orientation: dir,
119 pos: Position::new(
120 Point::zero(),
121 Point::zero(),
122 Point::zero(),
123 Point::splat(CONN_PADDING),
124 ),
125 properties: Option::None,
126 }
127 }
128
129 pub fn empty_connector(dir: Orientation) -> Element {
130 Self::create_connector("", &StyleAttr::simple(), dir)
131 }
132
133 pub fn move_to(&mut self, to: Point) {
135 self.pos.move_to(to)
136 }
137}
138
139#[derive(Debug, Clone)]
140pub struct Arrow {
141 pub start: LineEndKind,
142 pub end: LineEndKind,
143 pub line_style: LineStyleKind,
144 pub text: String,
145 pub look: StyleAttr,
146 pub properties: Option<String>,
147 pub src_port: Option<String>,
148 pub dst_port: Option<String>,
149}
150
151impl Default for Arrow {
152 fn default() -> Arrow {
153 Arrow {
154 start: LineEndKind::None,
155 end: LineEndKind::Arrow,
156 line_style: LineStyleKind::Normal,
157 text: String::new(),
158 look: StyleAttr::simple(),
159 properties: Option::None,
160 src_port: Option::None,
161 dst_port: Option::None,
162 }
163 }
164}
165
166impl Arrow {
167 pub fn reverse(&self) -> Arrow {
168 Arrow {
169 start: self.end,
170 end: self.start,
171 line_style: self.line_style,
172 text: self.text.clone(),
173 look: self.look.clone(),
174 properties: self.properties.clone(),
175 src_port: self.dst_port.clone(),
176 dst_port: self.src_port.clone(),
177 }
178 }
179
180 pub fn new(
181 start: LineEndKind,
182 end: LineEndKind,
183 line_style: LineStyleKind,
184 text: &str,
185 look: &StyleAttr,
186 src_port: &Option<String>,
187 dst_port: &Option<String>,
188 ) -> Arrow {
189 Arrow {
190 start,
191 end,
192 line_style,
193 text: String::from(text),
194 look: look.clone(),
195 properties: Option::None,
196 src_port: src_port.clone(),
197 dst_port: dst_port.clone(),
198 }
199 }
200
201 pub fn with_properties(
202 start: LineEndKind,
203 end: LineEndKind,
204 line_style: LineStyleKind,
205 text: &str,
206 look: &StyleAttr,
207 properties: impl Into<String>,
208 src_port: &Option<String>,
209 dst_port: &Option<String>,
210 ) -> Arrow {
211 Arrow {
212 start,
213 end,
214 line_style,
215 text: String::from(text),
216 look: look.clone(),
217 properties: Option::Some(properties.into()),
218 src_port: src_port.clone(),
219 dst_port: dst_port.clone(),
220 }
221 }
222
223 pub fn simple(text: &str) -> Arrow {
224 Arrow::new(
225 LineEndKind::None,
226 LineEndKind::Arrow,
227 LineStyleKind::Normal,
228 text,
229 &StyleAttr::simple(),
230 &None,
231 &None,
232 )
233 }
234
235 pub fn simple_with_properties(
236 text: &str,
237 properties: impl Into<String>,
238 ) -> Arrow {
239 let mut arrow = Arrow::simple(text);
240 arrow.properties = Some(properties.into());
241 arrow
242 }
243
244 pub fn invisible() -> Arrow {
245 Arrow::new(
246 LineEndKind::None,
247 LineEndKind::None,
248 LineStyleKind::None,
249 "",
250 &StyleAttr::simple(),
251 &None,
252 &None,
253 )
254 }
255}
256
257impl Visible for Element {
258 fn position(&self) -> Position {
259 self.pos
260 }
261 fn position_mut(&mut self) -> &mut Position {
262 &mut self.pos
263 }
264
265 fn is_connector(&self) -> bool {
266 matches!(self.shape, ShapeKind::Connector(_))
267 }
268
269 fn transpose(&mut self) {
270 self.orientation = self.orientation.flip();
271 self.pos.transpose();
272 }
273
274 fn resize(&mut self) {
275 if let ShapeKind::Connector(_) = self.shape.clone() {
276 let size = get_shape_size(
277 self.orientation,
278 &self.shape,
279 self.look.font_size,
280 false,
281 );
282 self.pos.set_size(size);
283 match self.orientation {
284 Orientation::TopToBottom => {
285 self.pos.set_new_center_point(Point::new(0., size.y / 2.));
286 }
287 Orientation::LeftToRight => {
288 self.pos.set_new_center_point(Point::new(size.x / 2., 0.));
289 }
290 }
291 }
292 }
293}