1use glam::{Vec2, Vec3};
2use uuid::Uuid;
3
4use crate::anim_obj::{
5 AnimObj, AnimObjKind, CodeHandle, CodeWindowHandle, StretchMode, Syntax, TextAlign,
6};
7use crate::color::Color;
8use crate::theme::Theme;
9use crate::transform::Transform;
10
11macro_rules! impl_transform_methods {
12 ($builder:ty) => {
13 #[allow(clippy::return_self_not_must_use)]
14 impl $builder {
15 pub const fn pos(mut self, position: Vec2) -> Self {
17 self.transform.position = position.extend(self.transform.position.z);
18 self
19 }
20
21 pub const fn z(mut self, z: f32) -> Self {
23 self.transform.position.z = z;
24 self
25 }
26 pub const fn scale(mut self, scale: Vec2) -> Self {
28 self.transform.scale = scale;
29 self
30 }
31 pub const fn rot(mut self, rotation: f32) -> Self {
33 self.transform.rotation = rotation;
34 self
35 }
36 }
37 };
38}
39
40pub fn svg() -> SvgBuilder {
49 SvgBuilder::default()
50}
51
52#[must_use]
53pub struct SvgBuilder {
54 path: String,
55 size: Vec2,
56 tint: Color,
57 fill: Option<Color>,
58 stroke: Option<Color>,
59 stroke_width: Option<f32>,
60 stretch: StretchMode,
61 transform: Transform,
62}
63
64impl Default for SvgBuilder {
65 fn default() -> Self {
66 Self {
67 path: String::new(),
68 size: Vec2::splat(40.0),
69 tint: Color::WHITE,
70 fill: None,
71 stroke: None,
72 stroke_width: None,
73 stretch: StretchMode::Fit,
74 transform: Transform::new(Vec3::ZERO),
75 }
76 }
77}
78
79#[allow(clippy::return_self_not_must_use)]
80impl SvgBuilder {
81 pub fn path(mut self, path: impl Into<String>) -> Self {
83 self.path = path.into();
84 self
85 }
86 pub const fn size(mut self, size: Vec2) -> Self {
88 self.size = size;
89 self
90 }
91 pub const fn color(mut self, color: Color) -> Self {
93 self.tint = color;
94 self
95 }
96 pub const fn fill(mut self, color: Color) -> Self {
98 self.fill = Some(color);
99 self
100 }
101 pub const fn stroke(mut self, color: Color) -> Self {
103 self.stroke = Some(color);
104 self
105 }
106 pub const fn stroke_width(mut self, width: f32) -> Self {
108 self.stroke_width = Some(width);
109 self
110 }
111 pub const fn stretch(mut self, stretch: StretchMode) -> Self {
113 self.stretch = stretch;
114 self
115 }
116 #[must_use]
117 pub fn build(self) -> AnimObj {
118 let id = self.transform.uuid;
119 AnimObj {
120 id,
121 transform: self.transform,
122 kind: AnimObjKind::Svg {
123 path: self.path,
124 size: self.size,
125 tint: self.tint,
126 fill: self.fill,
127 stroke: self.stroke,
128 stroke_width: self.stroke_width,
129 stretch: self.stretch,
130 },
131 }
132 }
133}
134
135impl_transform_methods!(SvgBuilder);
136
137pub fn rectangle() -> RectangleBuilder {
146 RectangleBuilder::default()
147}
148
149#[must_use]
150pub struct RectangleBuilder {
151 size: Vec2,
152 corner_radius: f32,
153 color: Color,
154 transform: Transform,
155}
156
157impl Default for RectangleBuilder {
158 fn default() -> Self {
159 Self {
160 size: Vec2::splat(100.0),
161 corner_radius: 0.0,
162 color: Color::WHITE,
163 transform: Transform::new(Vec3::ZERO),
164 }
165 }
166}
167
168#[allow(clippy::return_self_not_must_use)]
169impl RectangleBuilder {
170 pub const fn size(mut self, size: Vec2) -> Self {
171 self.size = size;
172 self
173 }
174 pub const fn corner_radius(mut self, radius: f32) -> Self {
175 self.corner_radius = radius;
176 self
177 }
178 pub const fn color(mut self, color: Color) -> Self {
179 self.color = color;
180 self
181 }
182 #[must_use]
183 pub const fn build(self) -> AnimObj {
184 let id = self.transform.uuid;
185 AnimObj {
186 id,
187 transform: self.transform,
188 kind: AnimObjKind::Rectangle {
189 size: self.size,
190 corner_radius: self.corner_radius,
191 color: self.color,
192 },
193 }
194 }
195}
196
197impl_transform_methods!(RectangleBuilder);
198
199pub fn circle() -> CircleBuilder {
207 CircleBuilder::default()
208}
209
210#[must_use]
211pub struct CircleBuilder {
212 radius: f32,
213 color: Color,
214 transform: Transform,
215}
216
217impl Default for CircleBuilder {
218 fn default() -> Self {
219 Self {
220 radius: 50.0,
221 color: Color::WHITE,
222 transform: Transform::new(Vec3::ZERO),
223 }
224 }
225}
226
227#[allow(clippy::return_self_not_must_use)]
228impl CircleBuilder {
229 pub const fn radius(mut self, radius: f32) -> Self {
231 self.radius = radius;
232 self
233 }
234 pub const fn color(mut self, color: Color) -> Self {
236 self.color = color;
237 self
238 }
239 #[must_use]
240 pub const fn build(self) -> AnimObj {
241 let id = self.transform.uuid;
242 AnimObj {
243 id,
244 transform: self.transform,
245 kind: AnimObjKind::Circle {
246 radius: self.radius,
247 color: self.color,
248 },
249 }
250 }
251}
252
253impl_transform_methods!(CircleBuilder);
254
255pub fn code() -> CodeBuilder {
264 CodeBuilder::default()
265}
266
267#[must_use]
268pub struct CodeBuilder {
269 source_code: String,
270 font_family: String,
271 font_size: f32,
272 syntax: Syntax,
273 theme: Option<Theme>,
274 padding: f32,
275 show_line_numbers: bool,
276 line_number_color: Color,
277 transform: Transform,
278}
279
280impl Default for CodeBuilder {
281 fn default() -> Self {
282 Self {
283 source_code: String::new(),
284 font_family: "sans-serif".to_string(),
285 font_size: 20.0,
286 syntax: Syntax::Rust,
287 theme: None,
288 padding: 20.0,
289 show_line_numbers: false,
290 line_number_color: Color::new(0.5, 0.5, 0.5, 0.6),
291 transform: Transform::new(Vec3::ZERO),
292 }
293 }
294}
295
296#[allow(clippy::return_self_not_must_use)]
297impl CodeBuilder {
298 pub fn source(mut self, code: impl Into<String>) -> Self {
300 self.source_code = code.into();
301 self
302 }
303 pub fn font_family(mut self, family: impl Into<String>) -> Self {
305 self.font_family = family.into();
306 self
307 }
308 pub const fn font_size(mut self, size: f32) -> Self {
310 self.font_size = size;
311 self
312 }
313 pub const fn syntax(mut self, syntax: Syntax) -> Self {
315 self.syntax = syntax;
316 self
317 }
318 pub fn theme(mut self, theme: Theme) -> Self {
320 self.theme = Some(theme);
321 self
322 }
323 pub const fn padding(mut self, padding: f32) -> Self {
325 self.padding = padding;
326 self
327 }
328 pub const fn line_numbers(mut self, show: bool) -> Self {
330 self.show_line_numbers = show;
331 self
332 }
333 #[must_use]
334 pub fn build(self) -> CodeHandle {
335 let id = self.transform.uuid;
336 CodeHandle(AnimObj {
337 id,
338 transform: self.transform,
339 kind: AnimObjKind::Code {
340 source_code: self.source_code,
341 font_family: self.font_family,
342 font_size: self.font_size,
343 syntax: self.syntax,
344 theme: self.theme,
345 padding: self.padding,
346 show_line_numbers: self.show_line_numbers,
347 line_number_color: self.line_number_color,
348 },
349 })
350 }
351}
352
353impl_transform_methods!(CodeBuilder);
354
355pub fn polygon() -> PolygonBuilder {
364 PolygonBuilder::default()
365}
366
367#[must_use]
368pub struct PolygonBuilder {
369 radius: f32,
370 sides: u32,
371 color: Color,
372 transform: Transform,
373}
374
375impl Default for PolygonBuilder {
376 fn default() -> Self {
377 Self {
378 radius: 50.0,
379 sides: 6,
380 color: Color::WHITE,
381 transform: Transform::new(Vec3::ZERO),
382 }
383 }
384}
385
386impl PolygonBuilder {
387 pub const fn radius(mut self, radius: f32) -> Self {
389 self.radius = radius;
390 self
391 }
392 pub const fn sides(mut self, sides: u32) -> Self {
394 self.sides = sides;
395 self
396 }
397 pub const fn color(mut self, color: Color) -> Self {
399 self.color = color;
400 self
401 }
402 #[must_use]
403 pub const fn build(self) -> AnimObj {
404 let id = self.transform.uuid;
405 AnimObj {
406 id,
407 transform: self.transform,
408 kind: AnimObjKind::Polygon {
409 radius: self.radius,
410 sides: self.sides,
411 color: self.color,
412 },
413 }
414 }
415}
416
417impl_transform_methods!(PolygonBuilder);
418
419pub fn image() -> ImageBuilder {
427 ImageBuilder::default()
428}
429
430#[must_use]
431pub struct ImageBuilder {
432 path: String,
433 size: Vec2,
434 color: Color,
435 stretch: StretchMode,
436 transform: Transform,
437}
438
439impl Default for ImageBuilder {
440 fn default() -> Self {
441 Self {
442 path: String::new(),
443 size: Vec2::splat(100.0),
444 color: Color::WHITE,
445 stretch: StretchMode::Fit,
446 transform: Transform::new(Vec3::ZERO),
447 }
448 }
449}
450
451impl ImageBuilder {
452 pub fn path(mut self, path: impl Into<String>) -> Self {
454 self.path = path.into();
455 self
456 }
457 pub const fn size(mut self, size: Vec2) -> Self {
459 self.size = size;
460 self
461 }
462 pub const fn color(mut self, color: Color) -> Self {
464 self.color = color;
465 self
466 }
467 pub const fn stretch(mut self, stretch: StretchMode) -> Self {
469 self.stretch = stretch;
470 self
471 }
472 #[must_use]
473 pub fn build(self) -> AnimObj {
474 let id = self.transform.uuid;
475 AnimObj {
476 id,
477 transform: self.transform,
478 kind: AnimObjKind::Image {
479 path: self.path,
480 size: self.size,
481 color: self.color,
482 stretch: self.stretch,
483 },
484 }
485 }
486}
487
488impl_transform_methods!(ImageBuilder);
489
490pub fn text() -> TextBuilder {
499 TextBuilder::default()
500}
501
502#[must_use]
503pub struct TextBuilder {
504 value: String,
505 font_family: String,
506 alignment: TextAlign,
507 color: Color,
508 font_size: f32,
509 transform: Transform,
510}
511
512impl Default for TextBuilder {
513 fn default() -> Self {
514 Self {
515 value: String::new(),
516 font_family: "sans-serif".to_string(),
517 alignment: TextAlign::Center,
518 color: Color::WHITE,
519 font_size: 24.0,
520 transform: Transform::new(Vec3::ZERO),
521 }
522 }
523}
524
525impl TextBuilder {
526 pub fn value(mut self, value: impl Into<String>) -> Self {
528 self.value = value.into();
529 self
530 }
531 pub fn font_family(mut self, family: impl Into<String>) -> Self {
533 self.font_family = family.into();
534 self
535 }
536 pub const fn alignment(mut self, align: TextAlign) -> Self {
538 self.alignment = align;
539 self
540 }
541 pub const fn color(mut self, color: Color) -> Self {
543 self.color = color;
544 self
545 }
546 pub const fn font_size(mut self, size: f32) -> Self {
548 self.font_size = size;
549 self
550 }
551 #[must_use]
552 pub fn build(self) -> AnimObj {
553 let id = self.transform.uuid;
554 AnimObj {
555 id,
556 transform: self.transform,
557 kind: AnimObjKind::Text {
558 value: self.value,
559 font_family: self.font_family,
560 alignment: self.alignment,
561 color: self.color,
562 font_size: self.font_size,
563 },
564 }
565 }
566}
567
568impl_transform_methods!(TextBuilder);
569
570pub fn code_window() -> CodeWindowBuilder {
579 CodeWindowBuilder::default()
580}
581
582#[must_use]
583pub struct CodeWindowBuilder {
584 source_code: String,
585 font_family: String,
586 font_size: f32,
587 syntax: Syntax,
588 theme: Option<Theme>,
589 title: String,
590 title_font_size: f32,
591 width: f32,
592 height: f32,
593 background_color: Color,
594 show_line_numbers: bool,
595 line_number_color: Color,
596 transform: Transform,
597}
598
599impl Default for CodeWindowBuilder {
600 fn default() -> Self {
601 Self {
602 source_code: String::new(),
603 font_family: "sans-serif".to_string(),
604 font_size: 20.0,
605 syntax: Syntax::Rust,
606 theme: None,
607 title: String::new(),
608 title_font_size: 16.0,
609 width: 800.0,
610 height: 600.0,
611 background_color: Color::new(0.176, 0.176, 0.176, 1.0),
612 show_line_numbers: false,
613 line_number_color: Color::new(0.5, 0.5, 0.5, 0.6),
614 transform: Transform::new(Vec3::ZERO),
615 }
616 }
617}
618
619impl CodeWindowBuilder {
620 pub fn source(mut self, code: impl Into<String>) -> Self {
622 self.source_code = code.into();
623 self
624 }
625 pub fn font_family(mut self, family: impl Into<String>) -> Self {
627 self.font_family = family.into();
628 self
629 }
630 pub const fn font_size(mut self, size: f32) -> Self {
632 self.font_size = size;
633 self
634 }
635 pub const fn syntax(mut self, syntax: Syntax) -> Self {
637 self.syntax = syntax;
638 self
639 }
640 pub fn theme(mut self, theme: Theme) -> Self {
642 self.theme = Some(theme);
643 self
644 }
645 pub fn title(mut self, title: impl Into<String>) -> Self {
647 self.title = title.into();
648 self
649 }
650 pub const fn title_font_size(mut self, size: f32) -> Self {
652 self.title_font_size = size;
653 self
654 }
655 pub const fn width(mut self, width: f32) -> Self {
657 self.width = width;
658 self
659 }
660 pub const fn height(mut self, height: f32) -> Self {
662 self.height = height;
663 self
664 }
665 pub const fn background_color(mut self, color: Color) -> Self {
667 self.background_color = color;
668 self
669 }
670 pub const fn line_numbers(mut self, show: bool) -> Self {
672 self.show_line_numbers = show;
673 self
674 }
675 #[must_use]
676 pub fn build(self) -> CodeWindowHandle {
677 let id = self.transform.uuid;
678 let code_id = Uuid::new_v5(&id, b"code");
679 let close_btn_id = Uuid::new_v5(&id, b"close");
680 let minimize_btn_id = Uuid::new_v5(&id, b"minimize");
681 let maximize_btn_id = Uuid::new_v5(&id, b"maximize");
682 let title_id = Uuid::new_v5(&id, b"title");
683 let bg_id = Uuid::new_v5(&id, b"bg");
684 let container_id = Uuid::new_v5(&id, b"container");
685 let title_bar_bg_id = Uuid::new_v5(&id, b"title_bg");
686 CodeWindowHandle(AnimObj {
687 id,
688 transform: self.transform,
689 kind: AnimObjKind::CodeWindow {
690 source_code: self.source_code,
691 font_family: self.font_family,
692 font_size: self.font_size,
693 syntax: self.syntax,
694 theme: self.theme,
695 title: self.title,
696 title_font_size: self.title_font_size,
697 width: self.width,
698 height: self.height,
699 background_color: self.background_color,
700 code_id,
701 close_btn_id,
702 minimize_btn_id,
703 maximize_btn_id,
704 title_id,
705 bg_id,
706 container_id,
707 title_bar_bg_id,
708 show_line_numbers: self.show_line_numbers,
709 line_number_color: self.line_number_color,
710 },
711 })
712 }
713}
714
715impl_transform_methods!(CodeWindowBuilder);