1#[derive(Clone, Debug, Copy, PartialEq)]
7pub enum ShapeType {
8 Rectangle,
10 RoundedRectangle,
11 Ellipse,
12 Circle, Triangle,
14 RightTriangle,
15 Diamond,
16 Pentagon,
17 Hexagon,
18 Octagon,
19
20 RightArrow,
22 LeftArrow,
23 UpArrow,
24 DownArrow,
25 LeftRightArrow,
26 UpDownArrow,
27 BentArrow,
28 UTurnArrow,
29
30 Star4,
32 Star5,
33 Star6,
34 Star8,
35 Ribbon,
36 Wave,
37
38 WedgeRectCallout,
40 WedgeEllipseCallout,
41 CloudCallout,
42
43 FlowChartProcess,
45 FlowChartDecision,
46 FlowChartTerminator,
47 FlowChartDocument,
48 FlowChartPredefinedProcess,
49 FlowChartInternalStorage,
50 FlowChartData,
51 FlowChartInputOutput,
52 FlowChartManualInput,
53 FlowChartManualOperation,
54 FlowChartConnector,
55 FlowChartOffPageConnector,
56 FlowChartPunchedCard,
57 FlowChartPunchedTape,
58 FlowChartSummingJunction,
59 FlowChartOr,
60 FlowChartCollate,
61 FlowChartSort,
62 FlowChartExtract,
63 FlowChartMerge,
64 FlowChartOnlineStorage,
65 FlowChartDelay,
66 FlowChartMagneticTape,
67 FlowChartMagneticDisk,
68 FlowChartMagneticDrum,
69 FlowChartDisplay,
70 FlowChartPreparation,
71
72 CurvedRightArrow,
74 CurvedLeftArrow,
75 CurvedUpArrow,
76 CurvedDownArrow,
77 CurvedLeftRightArrow,
78 CurvedUpDownArrow,
79 StripedRightArrow,
80 NotchedRightArrow,
81 PentagonArrow,
82 ChevronArrow,
83 RightArrowCallout,
84 LeftArrowCallout,
85 UpArrowCallout,
86 DownArrowCallout,
87 LeftRightArrowCallout,
88 UpDownArrowCallout,
89 QuadArrow,
90 LeftRightUpArrow,
91 CircularArrow,
92
93 Parallelogram,
95 Trapezoid,
96 NonIsoscelesTrapezoid,
97 IsoscelesTrapezoid,
98 Cube,
99 Can,
100 Cone,
101 Cylinder,
102 Bevel,
103 Donut,
104 NoSmoking,
105 BlockArc,
106 FoldedCorner,
107 SmileyFace,
108 Arc,
109 Chord,
110 Pie,
111 Teardrop,
112 Plaque,
113 MusicNote,
114 PictureFrame,
115
116 Star10,
118 Star12,
119 Star16,
120 Star24,
121 Star32,
122 Seal,
123 Seal4,
124 Seal8,
125 Seal16,
126 Seal32,
127 ActionButtonBlank,
128 ActionButtonHome,
129 ActionButtonHelp,
130 ActionButtonInformation,
131 ActionButtonForwardNext,
132 ActionButtonBackPrevious,
133 ActionButtonBeginning,
134 ActionButtonEnd,
135 ActionButtonReturn,
136 ActionButtonDocument,
137 ActionButtonSound,
138 ActionButtonMovie,
139
140 Heart,
142 Lightning,
143 Sun,
144 Moon,
145 Cloud,
146 Brace,
147 Bracket,
148 Plus,
149 Minus,
150}
151
152impl ShapeType {
153 pub fn preset_name(&self) -> &'static str {
155 match self {
156 ShapeType::Rectangle => "rect",
157 ShapeType::RoundedRectangle => "roundRect",
158 ShapeType::Ellipse | ShapeType::Circle => "ellipse",
159 ShapeType::Triangle => "triangle",
160 ShapeType::RightTriangle => "rtTriangle",
161 ShapeType::Diamond => "diamond",
162 ShapeType::Pentagon => "pentagon",
163 ShapeType::Hexagon => "hexagon",
164 ShapeType::Octagon => "octagon",
165
166 ShapeType::RightArrow => "rightArrow",
167 ShapeType::LeftArrow => "leftArrow",
168 ShapeType::UpArrow => "upArrow",
169 ShapeType::DownArrow => "downArrow",
170 ShapeType::LeftRightArrow => "leftRightArrow",
171 ShapeType::UpDownArrow => "upDownArrow",
172 ShapeType::BentArrow => "bentArrow",
173 ShapeType::UTurnArrow => "uturnArrow",
174
175 ShapeType::Star4 => "star4",
176 ShapeType::Star5 => "star5",
177 ShapeType::Star6 => "star6",
178 ShapeType::Star8 => "star8",
179 ShapeType::Ribbon => "ribbon2",
180 ShapeType::Wave => "wave",
181
182 ShapeType::WedgeRectCallout => "wedgeRectCallout",
183 ShapeType::WedgeEllipseCallout => "wedgeEllipseCallout",
184 ShapeType::CloudCallout => "cloudCallout",
185
186 ShapeType::FlowChartProcess => "flowChartProcess",
187 ShapeType::FlowChartDecision => "flowChartDecision",
188 ShapeType::FlowChartTerminator => "flowChartTerminator",
189 ShapeType::FlowChartDocument => "flowChartDocument",
190 ShapeType::FlowChartPredefinedProcess => "flowChartPredefinedProcess",
191 ShapeType::FlowChartInternalStorage => "flowChartInternalStorage",
192 ShapeType::FlowChartData => "flowChartData",
193 ShapeType::FlowChartInputOutput => "flowChartInputOutput",
194 ShapeType::FlowChartManualInput => "flowChartManualInput",
195 ShapeType::FlowChartManualOperation => "flowChartManualOperation",
196 ShapeType::FlowChartConnector => "flowChartConnector",
197 ShapeType::FlowChartOffPageConnector => "flowChartOffPageConnector",
198 ShapeType::FlowChartPunchedCard => "flowChartPunchedCard",
199 ShapeType::FlowChartPunchedTape => "flowChartPunchedTape",
200 ShapeType::FlowChartSummingJunction => "flowChartSummingJunction",
201 ShapeType::FlowChartOr => "flowChartOr",
202 ShapeType::FlowChartCollate => "flowChartCollate",
203 ShapeType::FlowChartSort => "flowChartSort",
204 ShapeType::FlowChartExtract => "flowChartExtract",
205 ShapeType::FlowChartMerge => "flowChartMerge",
206 ShapeType::FlowChartOnlineStorage => "flowChartOnlineStorage",
207 ShapeType::FlowChartDelay => "flowChartDelay",
208 ShapeType::FlowChartMagneticTape => "flowChartMagneticTape",
209 ShapeType::FlowChartMagneticDisk => "flowChartMagneticDisk",
210 ShapeType::FlowChartMagneticDrum => "flowChartMagneticDrum",
211 ShapeType::FlowChartDisplay => "flowChartDisplay",
212 ShapeType::FlowChartPreparation => "flowChartPreparation",
213
214 ShapeType::CurvedRightArrow => "curvedRightArrow",
215 ShapeType::CurvedLeftArrow => "curvedLeftArrow",
216 ShapeType::CurvedUpArrow => "curvedUpArrow",
217 ShapeType::CurvedDownArrow => "curvedDownArrow",
218 ShapeType::CurvedLeftRightArrow => "curvedLeftRightArrow",
219 ShapeType::CurvedUpDownArrow => "curvedUpDownArrow",
220 ShapeType::StripedRightArrow => "stripedRightArrow",
221 ShapeType::NotchedRightArrow => "notchedRightArrow",
222 ShapeType::PentagonArrow => "pentArrow",
223 ShapeType::ChevronArrow => "chevron",
224 ShapeType::RightArrowCallout => "rightArrowCallout",
225 ShapeType::LeftArrowCallout => "leftArrowCallout",
226 ShapeType::UpArrowCallout => "upArrowCallout",
227 ShapeType::DownArrowCallout => "downArrowCallout",
228 ShapeType::LeftRightArrowCallout => "leftRightArrowCallout",
229 ShapeType::UpDownArrowCallout => "upDownArrowCallout",
230 ShapeType::QuadArrow => "quadArrow",
231 ShapeType::LeftRightUpArrow => "leftRightUpArrow",
232 ShapeType::CircularArrow => "circularArrow",
233
234 ShapeType::Parallelogram => "parallelogram",
235 ShapeType::Trapezoid => "trapezoid",
236 ShapeType::NonIsoscelesTrapezoid => "nonIsoscelesTrapezoid",
237 ShapeType::IsoscelesTrapezoid => "isoTrapezoid",
238 ShapeType::Cube => "cube",
239 ShapeType::Can => "can",
240 ShapeType::Cone => "cone",
241 ShapeType::Cylinder => "cylinder",
242 ShapeType::Bevel => "bevel",
243 ShapeType::Donut => "donut",
244 ShapeType::NoSmoking => "noSmoking",
245 ShapeType::BlockArc => "blockArc",
246 ShapeType::FoldedCorner => "foldedCorner",
247 ShapeType::SmileyFace => "smileyFace",
248 ShapeType::Arc => "arc",
249 ShapeType::Chord => "chord",
250 ShapeType::Pie => "pie",
251 ShapeType::Teardrop => "teardrop",
252 ShapeType::Plaque => "plaque",
253 ShapeType::MusicNote => "musicNote",
254 ShapeType::PictureFrame => "frame",
255
256 ShapeType::Star10 => "star10",
257 ShapeType::Star12 => "star12",
258 ShapeType::Star16 => "star16",
259 ShapeType::Star24 => "star24",
260 ShapeType::Star32 => "star32",
261 ShapeType::Seal => "seal",
262 ShapeType::Seal4 => "seal4",
263 ShapeType::Seal8 => "seal8",
264 ShapeType::Seal16 => "seal16",
265 ShapeType::Seal32 => "seal32",
266 ShapeType::ActionButtonBlank => "actionButtonBlank",
267 ShapeType::ActionButtonHome => "actionButtonHome",
268 ShapeType::ActionButtonHelp => "actionButtonHelp",
269 ShapeType::ActionButtonInformation => "actionButtonInformation",
270 ShapeType::ActionButtonForwardNext => "actionButtonForwardNext",
271 ShapeType::ActionButtonBackPrevious => "actionButtonBackPrevious",
272 ShapeType::ActionButtonBeginning => "actionButtonBeginning",
273 ShapeType::ActionButtonEnd => "actionButtonEnd",
274 ShapeType::ActionButtonReturn => "actionButtonReturn",
275 ShapeType::ActionButtonDocument => "actionButtonDocument",
276 ShapeType::ActionButtonSound => "actionButtonSound",
277 ShapeType::ActionButtonMovie => "actionButtonMovie",
278
279 ShapeType::Heart => "heart",
280 ShapeType::Lightning => "lightningBolt",
281 ShapeType::Sun => "sun",
282 ShapeType::Moon => "moon",
283 ShapeType::Cloud => "cloud",
284 ShapeType::Brace => "leftBrace",
285 ShapeType::Bracket => "leftBracket",
286 ShapeType::Plus => "mathPlus",
287 ShapeType::Minus => "mathMinus",
288 }
289 }
290
291 pub fn display_name(&self) -> &'static str {
293 match self {
294 ShapeType::Rectangle => "Rectangle",
295 ShapeType::RoundedRectangle => "Rounded Rectangle",
296 ShapeType::Ellipse => "Ellipse",
297 ShapeType::Circle => "Circle",
298 ShapeType::Triangle => "Triangle",
299 ShapeType::RightTriangle => "Right Triangle",
300 ShapeType::Diamond => "Diamond",
301 ShapeType::Pentagon => "Pentagon",
302 ShapeType::Hexagon => "Hexagon",
303 ShapeType::Octagon => "Octagon",
304 ShapeType::RightArrow => "Right Arrow",
305 ShapeType::LeftArrow => "Left Arrow",
306 ShapeType::UpArrow => "Up Arrow",
307 ShapeType::DownArrow => "Down Arrow",
308 ShapeType::LeftRightArrow => "Left-Right Arrow",
309 ShapeType::UpDownArrow => "Up-Down Arrow",
310 ShapeType::BentArrow => "Bent Arrow",
311 ShapeType::UTurnArrow => "U-Turn Arrow",
312 ShapeType::Star4 => "4-Point Star",
313 ShapeType::Star5 => "5-Point Star",
314 ShapeType::Star6 => "6-Point Star",
315 ShapeType::Star8 => "8-Point Star",
316 ShapeType::Ribbon => "Ribbon",
317 ShapeType::Wave => "Wave",
318 ShapeType::WedgeRectCallout => "Rectangle Callout",
319 ShapeType::WedgeEllipseCallout => "Oval Callout",
320 ShapeType::CloudCallout => "Cloud Callout",
321 ShapeType::FlowChartProcess => "Process",
322 ShapeType::FlowChartDecision => "Decision",
323 ShapeType::FlowChartTerminator => "Terminator",
324 ShapeType::FlowChartDocument => "Document",
325 ShapeType::FlowChartPredefinedProcess => "Predefined Process",
326 ShapeType::FlowChartInternalStorage => "Internal Storage",
327 ShapeType::FlowChartData => "Data",
328 ShapeType::FlowChartInputOutput => "Input/Output",
329 ShapeType::FlowChartManualInput => "Manual Input",
330 ShapeType::FlowChartManualOperation => "Manual Operation",
331 ShapeType::FlowChartConnector => "Connector",
332 ShapeType::FlowChartOffPageConnector => "Off-page Connector",
333 ShapeType::FlowChartPunchedCard => "Punched Card",
334 ShapeType::FlowChartPunchedTape => "Punched Tape",
335 ShapeType::FlowChartSummingJunction => "Summing Junction",
336 ShapeType::FlowChartOr => "Or",
337 ShapeType::FlowChartCollate => "Collate",
338 ShapeType::FlowChartSort => "Sort",
339 ShapeType::FlowChartExtract => "Extract",
340 ShapeType::FlowChartMerge => "Merge",
341 ShapeType::FlowChartOnlineStorage => "Online Storage",
342 ShapeType::FlowChartDelay => "Delay",
343 ShapeType::FlowChartMagneticTape => "Magnetic Tape",
344 ShapeType::FlowChartMagneticDisk => "Magnetic Disk",
345 ShapeType::FlowChartMagneticDrum => "Magnetic Drum",
346 ShapeType::FlowChartDisplay => "Display",
347 ShapeType::FlowChartPreparation => "Preparation",
348
349 ShapeType::CurvedRightArrow => "Curved Right Arrow",
350 ShapeType::CurvedLeftArrow => "Curved Left Arrow",
351 ShapeType::CurvedUpArrow => "Curved Up Arrow",
352 ShapeType::CurvedDownArrow => "Curved Down Arrow",
353 ShapeType::CurvedLeftRightArrow => "Curved Left-Right Arrow",
354 ShapeType::CurvedUpDownArrow => "Curved Up-Down Arrow",
355 ShapeType::StripedRightArrow => "Striped Right Arrow",
356 ShapeType::NotchedRightArrow => "Notched Right Arrow",
357 ShapeType::PentagonArrow => "Pentagon Arrow",
358 ShapeType::ChevronArrow => "Chevron Arrow",
359 ShapeType::RightArrowCallout => "Right Arrow Callout",
360 ShapeType::LeftArrowCallout => "Left Arrow Callout",
361 ShapeType::UpArrowCallout => "Up Arrow Callout",
362 ShapeType::DownArrowCallout => "Down Arrow Callout",
363 ShapeType::LeftRightArrowCallout => "Left-Right Arrow Callout",
364 ShapeType::UpDownArrowCallout => "Up-Down Arrow Callout",
365 ShapeType::QuadArrow => "Quad Arrow",
366 ShapeType::LeftRightUpArrow => "Left-Right-Up Arrow",
367 ShapeType::CircularArrow => "Circular Arrow",
368
369 ShapeType::Parallelogram => "Parallelogram",
370 ShapeType::Trapezoid => "Trapezoid",
371 ShapeType::NonIsoscelesTrapezoid => "Non-Isosceles Trapezoid",
372 ShapeType::IsoscelesTrapezoid => "Isosceles Trapezoid",
373 ShapeType::Cube => "Cube",
374 ShapeType::Can => "Can",
375 ShapeType::Cone => "Cone",
376 ShapeType::Cylinder => "Cylinder",
377 ShapeType::Bevel => "Bevel",
378 ShapeType::Donut => "Donut",
379 ShapeType::NoSmoking => "No Smoking",
380 ShapeType::BlockArc => "Block Arc",
381 ShapeType::FoldedCorner => "Folded Corner",
382 ShapeType::SmileyFace => "Smiley Face",
383 ShapeType::Arc => "Arc",
384 ShapeType::Chord => "Chord",
385 ShapeType::Pie => "Pie",
386 ShapeType::Teardrop => "Teardrop",
387 ShapeType::Plaque => "Plaque",
388 ShapeType::MusicNote => "Music Note",
389 ShapeType::PictureFrame => "Picture Frame",
390
391 ShapeType::Star10 => "10-Point Star",
392 ShapeType::Star12 => "12-Point Star",
393 ShapeType::Star16 => "16-Point Star",
394 ShapeType::Star24 => "24-Point Star",
395 ShapeType::Star32 => "32-Point Star",
396 ShapeType::Seal => "Seal",
397 ShapeType::Seal4 => "4-Point Seal",
398 ShapeType::Seal8 => "8-Point Seal",
399 ShapeType::Seal16 => "16-Point Seal",
400 ShapeType::Seal32 => "32-Point Seal",
401 ShapeType::ActionButtonBlank => "Action Button (Blank)",
402 ShapeType::ActionButtonHome => "Action Button (Home)",
403 ShapeType::ActionButtonHelp => "Action Button (Help)",
404 ShapeType::ActionButtonInformation => "Action Button (Information)",
405 ShapeType::ActionButtonForwardNext => "Action Button (Forward/Next)",
406 ShapeType::ActionButtonBackPrevious => "Action Button (Back/Previous)",
407 ShapeType::ActionButtonBeginning => "Action Button (Beginning)",
408 ShapeType::ActionButtonEnd => "Action Button (End)",
409 ShapeType::ActionButtonReturn => "Action Button (Return)",
410 ShapeType::ActionButtonDocument => "Action Button (Document)",
411 ShapeType::ActionButtonSound => "Action Button (Sound)",
412 ShapeType::ActionButtonMovie => "Action Button (Movie)",
413
414 ShapeType::Heart => "Heart",
415 ShapeType::Lightning => "Lightning Bolt",
416 ShapeType::Sun => "Sun",
417 ShapeType::Moon => "Moon",
418 ShapeType::Cloud => "Cloud",
419 ShapeType::Brace => "Brace",
420 ShapeType::Bracket => "Bracket",
421 ShapeType::Plus => "Plus",
422 ShapeType::Minus => "Minus",
423 }
424 }
425}
426
427#[derive(Clone, Debug)]
429pub struct ShapeFill {
430 pub color: String, pub transparency: Option<u32>, }
433
434impl ShapeFill {
435 pub fn new(color: &str) -> Self {
437 ShapeFill {
438 color: color.trim_start_matches('#').to_uppercase(),
439 transparency: None,
440 }
441 }
442
443 pub fn transparency(mut self, percent: u32) -> Self {
445 let alpha = ((100 - percent.min(100)) * 1000) as u32;
446 self.transparency = Some(alpha);
447 self
448 }
449}
450
451#[derive(Clone, Debug)]
453pub struct ShapeLine {
454 pub color: String,
455 pub width: u32, }
457
458impl ShapeLine {
459 pub fn new(color: &str, width: u32) -> Self {
461 ShapeLine {
462 color: color.trim_start_matches('#').to_uppercase(),
463 width,
464 }
465 }
466}
467
468#[derive(Clone, Debug)]
470pub struct Shape {
471 pub shape_type: ShapeType,
472 pub x: u32, pub y: u32, pub width: u32, pub height: u32, pub fill: Option<ShapeFill>,
477 pub line: Option<ShapeLine>,
478 pub text: Option<String>,
479}
480
481impl Shape {
482 pub fn new(shape_type: ShapeType, x: u32, y: u32, width: u32, height: u32) -> Self {
484 Shape {
485 shape_type,
486 x,
487 y,
488 width,
489 height,
490 fill: None,
491 line: None,
492 text: None,
493 }
494 }
495
496 pub fn with_fill(mut self, fill: ShapeFill) -> Self {
498 self.fill = Some(fill);
499 self
500 }
501
502 pub fn with_line(mut self, line: ShapeLine) -> Self {
504 self.line = Some(line);
505 self
506 }
507
508 pub fn with_text(mut self, text: &str) -> Self {
510 self.text = Some(text.to_string());
511 self
512 }
513}
514
515pub fn emu_to_inches(emu: u32) -> f64 {
517 emu as f64 / 914400.0
518}
519
520pub fn inches_to_emu(inches: f64) -> u32 {
522 (inches * 914400.0) as u32
523}
524
525pub fn cm_to_emu(cm: f64) -> u32 {
527 (cm * 360000.0) as u32
528}
529
530#[cfg(test)]
531mod tests {
532 use super::*;
533
534 #[test]
535 fn test_shape_type_names() {
536 assert_eq!(ShapeType::Rectangle.preset_name(), "rect");
537 assert_eq!(ShapeType::Circle.preset_name(), "ellipse");
538 assert_eq!(ShapeType::RightArrow.preset_name(), "rightArrow");
539 assert_eq!(ShapeType::Star5.preset_name(), "star5");
540 assert_eq!(ShapeType::Heart.preset_name(), "heart");
541 }
542
543 #[test]
544 fn test_shape_fill_builder() {
545 let fill = ShapeFill::new("FF0000").transparency(50);
546 assert_eq!(fill.color, "FF0000");
547 assert_eq!(fill.transparency, Some(50000));
548 }
549
550 #[test]
551 fn test_shape_builder() {
552 let shape = Shape::new(ShapeType::Rectangle, 0, 0, 1000000, 500000)
553 .with_fill(ShapeFill::new("0000FF"))
554 .with_line(ShapeLine::new("000000", 25400))
555 .with_text("Hello");
556
557 assert_eq!(shape.x, 0);
558 assert_eq!(shape.width, 1000000);
559 assert_eq!(shape.text, Some("Hello".to_string()));
560 }
561
562 #[test]
563 fn test_emu_conversions() {
564 let emu = inches_to_emu(1.0);
565 assert_eq!(emu, 914400);
566 assert!((emu_to_inches(emu) - 1.0).abs() < 0.001);
567 }
568
569 #[test]
570 fn test_cm_to_emu() {
571 let emu = cm_to_emu(2.54); assert_eq!(emu, 914400);
573 }
574}