craft_core/elements/
container.rs1use crate::components::component::ComponentSpecification;
2use crate::components::Props;
3use crate::components::Event;
4use crate::elements::element::Element;
5use crate::elements::element_data::ElementData;
6use crate::elements::element_styles::ElementStyles;
7use crate::layout::layout_context::LayoutContext;
8use crate::elements::scroll_state::ScrollState;
9use crate::events::CraftMessage;
10use crate::geometry::{Point, Size};
11use crate::reactive::element_state_store::{ElementStateStore, ElementStateStoreItem};
12use crate::style::Style;
13use crate::{generate_component_methods};
14use std::any::Any;
15use std::sync::Arc;
16use taffy::{NodeId, TaffyTree};
17use winit::window::Window;
18use crate::renderer::renderer::RenderList;
19use crate::text::text_context::TextContext;
20
21#[derive(Clone, Default, Debug)]
23pub struct Container {
24 pub element_data: ElementData,
25}
26
27#[derive(Clone, Copy, Default)]
28pub struct ContainerState {
29 pub(crate) scroll_state: ScrollState,
30}
31
32impl Element for Container {
33 fn element_data(&self) -> &ElementData {
34 &self.element_data
35 }
36
37 fn element_data_mut(&mut self) -> &mut ElementData {
38 &mut self.element_data
39 }
40
41 fn name(&self) -> &'static str {
42 "Container"
43 }
44
45 fn draw(
46 &mut self,
47 renderer: &mut RenderList,
48 text_context: &mut TextContext,
49 taffy_tree: &mut TaffyTree<LayoutContext>,
50 _root_node: NodeId,
51 element_state: &mut ElementStateStore,
52 pointer: Option<Point>,
53 window: Option<Arc<dyn Window>>,
54 ) {
55 let base_state = self.get_base_state_mut(element_state);
56 let current_style = base_state.base.current_style(self.element_data());
57
58 if !current_style.visible() {
59 return;
60 }
61
62 self.draw_borders(renderer, element_state);
64 self.maybe_start_layer(renderer);
65 {
66 self.draw_children(renderer, text_context, taffy_tree, element_state, pointer, window);
67 }
68 self.maybe_end_layer(renderer);
69
70 self.draw_scrollbar(renderer);
71 }
72
73 fn compute_layout(
74 &mut self,
75 taffy_tree: &mut TaffyTree<LayoutContext>,
76 element_state: &mut ElementStateStore,
77 scale_factor: f64,
78 ) -> Option<NodeId> {
79 self.merge_default_style();
80 let mut child_nodes: Vec<NodeId> = Vec::with_capacity(self.children().len());
81
82 for child in self.element_data.children.iter_mut() {
83 let child_node = child.internal.compute_layout(taffy_tree, element_state, scale_factor);
84 if let Some(child_node) = child_node {
85 child_nodes.push(child_node);
86 }
87 }
88
89 let base_state = self.get_base_state_mut(element_state);
90 let current_style = base_state.base.current_style(self.element_data());
91 let style: taffy::Style = current_style.to_taffy_style_with_scale_factor(scale_factor);
92
93 self.element_data_mut().taffy_node_id = Some(taffy_tree.new_with_children(style, &child_nodes).unwrap());
94 self.element_data().taffy_node_id
95 }
96
97 fn finalize_layout(
98 &mut self,
99 taffy_tree: &mut TaffyTree<LayoutContext>,
100 root_node: NodeId,
101 position: Point,
102 z_index: &mut u32,
103 transform: glam::Mat4,
104 element_state: &mut ElementStateStore,
105 pointer: Option<Point>,
106 text_context: &mut TextContext,
107 ) {
108 let result = taffy_tree.layout(root_node).unwrap();
109 self.resolve_box(position, transform, result, z_index);
110
111 self.finalize_borders(element_state);
112
113 self.element_data.scrollbar_size = Size::new(result.scrollbar_size.width, result.scrollbar_size.height);
114 self.element_data.computed_scrollbar_size = Size::new(result.scroll_width(), result.scroll_height());
115
116 let scroll_y = if let Some(container_state) =
117 element_state.storage.get(&self.element_data.component_id).unwrap().data.downcast_ref::<ContainerState>()
118 {
119 container_state.scroll_state.scroll_y
120 } else {
121 0.0
122 };
123
124 self.finalize_scrollbar(scroll_y);
125 let child_transform = glam::Mat4::from_translation(glam::Vec3::new(0.0, -scroll_y, 0.0));
126
127 for child in self.element_data.children.iter_mut() {
128 let taffy_child_node_id = child.internal.element_data().taffy_node_id;
129 if taffy_child_node_id.is_none() {
130 continue;
131 }
132
133 child.internal.finalize_layout(
134 taffy_tree,
135 taffy_child_node_id.unwrap(),
136 self.element_data.computed_box.position,
137 z_index,
138 transform * child_transform,
139 element_state,
140 pointer,
141 text_context,
142 );
143 }
144 }
145
146 fn as_any(&self) -> &dyn Any {
147 self
148 }
149
150 fn on_event(
151 &self,
152 message: &CraftMessage,
153 element_state: &mut ElementStateStore,
154 _text_context: &mut TextContext,
155 should_style: bool,
156 ) -> Event {
157 self.on_style_event(message, element_state, should_style);
158 let base_state = self.get_base_state_mut(element_state);
159 let container_state = base_state.data.as_mut().downcast_mut::<ContainerState>().unwrap();
160
161 container_state.scroll_state.on_event(message, &self.element_data, &mut base_state.base)
162 }
163
164 fn initialize_state(&mut self, _scaling_factor: f64) -> ElementStateStoreItem {
165 ElementStateStoreItem {
166 base: Default::default(),
167 data: Box::new(ContainerState::default()),
168 }
169 }
170}
171
172impl Container {
173 #[allow(dead_code)]
174 fn get_state<'a>(&self, element_state: &'a ElementStateStore) -> &'a ContainerState {
175 element_state.storage.get(&self.element_data.component_id).unwrap().data.as_ref().downcast_ref().unwrap()
176 }
177
178 pub fn new() -> Container {
179 Container {
180 element_data: Default::default(),
181 }
182 }
183
184 generate_component_methods!();
185}
186
187impl ElementStyles for Container {
188 fn styles_mut(&mut self) -> &mut Style {
189 self.element_data.current_style_mut()
190 }
191}