craft_core/elements/
canvas.rs

1use crate::components::component::ComponentSpecification;
2use crate::components::Props;
3use crate::elements::element::Element;
4use crate::elements::element_data::ElementData;
5use crate::elements::element_styles::ElementStyles;
6use crate::layout::layout_context::LayoutContext;
7use crate::geometry::{Point, Rectangle};
8use crate::reactive::element_state_store::ElementStateStore;
9use crate::renderer::renderer::RenderList;
10use crate::renderer::RenderCommand;
11use crate::style::Style;
12use crate::Color;
13use crate::generate_component_methods_no_children;
14use std::any::Any;
15use std::sync::Arc;
16use taffy::{NodeId, TaffyTree};
17use winit::window::Window;
18use crate::text::text_context::TextContext;
19
20#[derive(Clone, Default, Debug)]
21pub struct Canvas {
22    pub element_data: ElementData,
23    pub render_list: Vec<RenderCommand>,
24}
25
26#[derive(Clone, Copy, Default)]
27pub struct CanvasState {}
28
29impl Element for Canvas {
30    fn element_data(&self) -> &ElementData {
31        &self.element_data
32    }
33
34    fn element_data_mut(&mut self) -> &mut ElementData {
35        &mut self.element_data
36    }
37
38    fn name(&self) -> &'static str {
39        "Canvas"
40    }
41
42    fn draw(
43        &mut self,
44        renderer: &mut RenderList,
45        _text_context: &mut TextContext,
46        _taffy_tree: &mut TaffyTree<LayoutContext>,
47        _root_node: NodeId,
48        element_state: &mut ElementStateStore,
49        _pointer: Option<Point>,
50        _window: Option<Arc<dyn Window>>,
51    ) {
52        if !self.element_data.style.visible() {
53            return;
54        }
55        let _border_color: Color = self.style().border_color().top;
56        let computed_box_transformed = self.element_data.computed_box_transformed;
57        let _border_rectangle = computed_box_transformed.border_rectangle();
58        let _content_rectangle = computed_box_transformed.content_rectangle();
59
60        // background
61        let computed_x_transformed = self.element_data.computed_box_transformed.position.x;
62        let computed_y_transformed = self.element_data.computed_box_transformed.position.y;
63
64        let computed_width = self.element_data.computed_box_transformed.size.width;
65        let computed_height = self.element_data.computed_box_transformed.size.height;
66
67        let border_top = self.element_data.computed_box_transformed.border.top;
68        let border_right = self.element_data.computed_box_transformed.border.right;
69        let border_bottom = self.element_data.computed_box_transformed.border.bottom;
70        let border_left = self.element_data.computed_box_transformed.border.left;
71
72        self.draw_borders(renderer, element_state);
73
74        renderer.push_layer(Rectangle::new(
75            computed_x_transformed + border_left,
76            computed_y_transformed + border_top,
77            computed_width - (border_right + border_left),
78            computed_height - (border_top + border_bottom),
79        ));
80
81        for render_command in self.render_list.iter() {
82            match render_command {
83                RenderCommand::DrawRect(rectangle, color) => {
84                    let translated_rectangle = Rectangle::new(
85                        rectangle.x + computed_x_transformed,
86                        rectangle.y + computed_y_transformed,
87                        rectangle.width,
88                        rectangle.height,
89                    );
90                    renderer.draw_rect(translated_rectangle, *color);
91                }
92                RenderCommand::DrawRectOutline(rectangle, color) => {
93                    let translated_rectangle = Rectangle::new(
94                        rectangle.x + computed_x_transformed,
95                        rectangle.y + computed_y_transformed,
96                        rectangle.width,
97                        rectangle.height,
98                    );
99                    renderer.draw_rect_outline(translated_rectangle, *color);
100                }
101                RenderCommand::DrawImage(rectangle, resource_identifier) => {
102                    let translated_rectangle = Rectangle::new(
103                        rectangle.x + computed_x_transformed,
104                        rectangle.y + computed_y_transformed,
105                        rectangle.width,
106                        rectangle.height,
107                    );
108                    renderer.draw_image(translated_rectangle, resource_identifier.clone());
109                }
110                RenderCommand::DrawText(text_renderer, rectangle, text_scroll, show_cursor,) => {
111                    let translated_rectangle = Rectangle::new(
112                        rectangle.x + computed_x_transformed,
113                        rectangle.y + computed_y_transformed,
114                        rectangle.width,
115                        rectangle.height,
116                    );
117                    renderer.draw_text(text_renderer.clone(), translated_rectangle, *text_scroll, *show_cursor);
118                }
119                RenderCommand::PushLayer(rectangle) => {
120                    let translated_rectangle = Rectangle::new(
121                        rectangle.x + computed_x_transformed,
122                        rectangle.y + computed_y_transformed,
123                        rectangle.width,
124                        rectangle.height,
125                    );
126                    renderer.push_layer(translated_rectangle);
127                }
128                RenderCommand::PopLayer => {
129                    renderer.pop_layer();
130                }
131                RenderCommand::FillBezPath(path, brush) => {
132                    renderer.fill_bez_path(path.clone(), brush.clone());
133                }
134                RenderCommand::DrawTinyVg(rectangle, resource_identifier, color) => {
135                    renderer.draw_tiny_vg(*rectangle, resource_identifier.clone(), *color);
136                }
137                RenderCommand::StartOverlay => {
138                    renderer.start_overlay();
139                }
140                RenderCommand::EndOverlay => {
141                    renderer.end_overlay();
142                }    
143            }
144        }
145
146        renderer.pop_layer();
147    }
148
149    fn compute_layout(
150        &mut self,
151        taffy_tree: &mut TaffyTree<LayoutContext>,
152        element_state: &mut ElementStateStore,
153        scale_factor: f64,
154    ) -> Option<NodeId> {
155        self.merge_default_style();
156        let mut child_nodes: Vec<NodeId> = Vec::with_capacity(self.children().len());
157
158        for child in self.element_data.children.iter_mut() {
159            let child_node = child.internal.compute_layout(taffy_tree, element_state, scale_factor);
160            if let Some(child_node) = child_node {
161                child_nodes.push(child_node);
162            }
163        }
164
165        let style: taffy::Style = self.element_data.style.to_taffy_style_with_scale_factor(scale_factor);
166
167        self.element_data_mut().taffy_node_id = Some(taffy_tree.new_with_children(style, &child_nodes).unwrap());
168        self.element_data().taffy_node_id
169    }
170
171    fn finalize_layout(
172        &mut self,
173        taffy_tree: &mut TaffyTree<LayoutContext>,
174        root_node: NodeId,
175        position: Point,
176        z_index: &mut u32,
177        transform: glam::Mat4,
178        element_state: &mut ElementStateStore,
179        pointer: Option<Point>,
180        text_context: &mut TextContext,
181    ) {
182        let result = taffy_tree.layout(root_node).unwrap();
183        self.resolve_box(position, transform, result, z_index);
184        self.finalize_borders(element_state);
185
186        for child in self.element_data.children.iter_mut() {
187            let taffy_child_node_id = child.internal.taffy_node_id();
188            if taffy_child_node_id.is_none() {
189                continue;
190            }
191
192            child.internal.finalize_layout(
193                taffy_tree,
194                taffy_child_node_id.unwrap(),
195                self.element_data.computed_box.position,
196                z_index,
197                transform,
198                element_state,
199                pointer,
200                text_context,
201            );
202        }
203    }
204
205    fn as_any(&self) -> &dyn Any {
206        self
207    }
208}
209
210impl Canvas {
211    #[allow(dead_code)]
212    fn get_state<'a>(&self, element_state: &'a ElementStateStore) -> &'a CanvasState {
213        element_state.storage.get(&self.element_data.component_id).unwrap().data.as_ref().downcast_ref().unwrap()
214    }
215
216    #[allow(dead_code)]
217    fn get_state_mut<'a>(&self, element_state: &'a mut ElementStateStore) -> &'a mut CanvasState {
218        element_state.storage.get_mut(&self.element_data.component_id).unwrap().data.as_mut().downcast_mut().unwrap()
219    }
220
221    pub fn new() -> Canvas {
222        Canvas {
223            element_data: Default::default(),
224            render_list: Vec::new(),
225        }
226    }
227
228    generate_component_methods_no_children!();
229}
230
231impl ElementStyles for Canvas {
232    fn styles_mut(&mut self) -> &mut Style {
233        self.element_data.current_style_mut()
234    }
235}