ltrender/draw_object_builder/
mod.rs

1use std::time::Instant;
2
3use crate::{
4    DrawObject, DrawObjectKey, ScreenKey,
5    drawable_register::ObjectLifetime,
6    error::{AppError, DrawObjectBuilderError},
7    rendering::{render_handle::RenderHandle, renderer::RenderModeBehavior},
8    terminal_buffer::{Drawable, buffer_and_celldrawer::Shader},
9};
10pub mod sprite_drawable_builder;
11pub use sprite_drawable_builder::SpriteDrawableBuilder;
12pub mod circle_drawable_builder;
13pub use circle_drawable_builder::CircleDrawableBuilder;
14pub mod line_drawable_builder;
15pub use line_drawable_builder::LineDrawableBuilder;
16pub mod polygon_drawable_builder;
17pub use polygon_drawable_builder::PolygonDrawableBuilder;
18pub mod rect_drawable_builder;
19pub use rect_drawable_builder::RectDrawableBuilder;
20pub mod videostream_drawable_builder;
21pub use videostream_drawable_builder::VideoStreamDrawableBuilder;
22
23macro_rules! allow_drawable_building {
24    ($builder_name:ident, $fn_name:ident) => {
25        pub fn $fn_name<F>(mut self, build_fn: F) -> Result<Self, DrawObjectBuilderError>
26        where
27            F: FnOnce($builder_name) -> $builder_name,
28        {
29            let builder = build_fn($builder_name::new());
30            let drawable = builder.build()?;
31            self.drawable = Some(drawable);
32            Ok(self)
33        }
34    };
35}
36
37#[macro_export]
38macro_rules! handle_field {
39    ($fn_name:ident, $field_name:ident, $type:ty) => {
40        pub fn $fn_name(mut self, $field_name: $type) -> Self {
41            self.$field_name = Some($field_name);
42            self
43        }
44    };
45}
46
47#[macro_export]
48macro_rules! handle_pointed_field {
49    ($fn_name:ident, $field_name:ident) => {
50        pub fn $fn_name(mut self, $field_name: impl Into<Point<i32>>) -> Self {
51            let point = $field_name.into();
52            self.$field_name = Some(point);
53            self
54        }
55    };
56}
57
58#[macro_export]
59macro_rules! handle_char_field {
60    ($fn_name:ident, $field_name:ident) => {
61        pub fn $fn_name(mut self, $field_name: impl Into<TerminalChar>) -> Self {
62            let point = $field_name.into();
63            self.$field_name = Some(point);
64            self
65        }
66    };
67}
68
69#[derive(Default)]
70pub struct DrawObjectBuilder {
71    layer: Option<usize>,
72    shaders: Vec<Box<dyn Shader>>,
73    drawable: Option<Box<dyn Drawable>>,
74    screen_id: Option<ScreenKey>,
75    lt: Option<ObjectLifetime>,
76}
77
78impl DrawObjectBuilder {
79    handle_field!(layer, layer, usize);
80    handle_field!(screen, screen_id, usize);
81    handle_field!(add_lifetime, lt, ObjectLifetime);
82    pub fn shader<T>(mut self, shader: T) -> Self
83    where
84        T: Shader + 'static,
85    {
86        self.shaders.push(Box::new(shader));
87        self
88    }
89
90    pub fn drawable(mut self, drawable: Box<dyn Drawable>) -> Self {
91        self.drawable = Some(drawable);
92        self
93    }
94
95    allow_drawable_building!(SpriteDrawableBuilder, sprite_drawable);
96    allow_drawable_building!(CircleDrawableBuilder, circle_drawable);
97    allow_drawable_building!(LineDrawableBuilder, line_drawable);
98    allow_drawable_building!(PolygonDrawableBuilder, polygon_drawable);
99    allow_drawable_building!(RectDrawableBuilder, rect_drawable);
100    allow_drawable_building!(VideoStreamDrawableBuilder, videostream_drawable);
101
102    pub fn build<M>(
103        &mut self,
104        render_handle: &mut RenderHandle<M>,
105    ) -> Result<DrawObjectKey, AppError>
106    where
107        M: RenderModeBehavior,
108    {
109        let layer = self.layer.ok_or(DrawObjectBuilderError::NoLayerAdded())?;
110        let screen_id = self
111            .screen_id
112            .ok_or(DrawObjectBuilderError::NoScreenAdded())?;
113
114        let drawable = self
115            .drawable
116            .take()
117            .ok_or(DrawObjectBuilderError::NoDrawableAdded())?;
118
119        let lifetime = self.lt.ok_or(DrawObjectBuilderError::NoLifetimeAdded())?;
120
121        render_handle.register_drawable(
122            screen_id,
123            DrawObject {
124                lifetime,
125                layer,
126                drawable,
127                shaders: self.shaders.clone(),
128                creation_time: Instant::now(),
129            },
130        )
131    }
132}