1use crate::layout_algorithm::axis_utils::Axis;
2use crate::layout_algorithm::commands::{calculate_render_commands, sort_commands};
3use crate::layout_algorithm::positions::calculate_child_positions;
4use crate::layout_algorithm::sizing::fit_grow_shrink_children_axis;
5use crate::layout_algorithm::wrapping::recursive_wrap_left_to_right;
6use crate::layout_struct::layout_states::{
7 ChildWrapping, LayoutElementConfig, LayoutElementInfo, LayoutElementStyle, element_info_states,
8};
9use crate::layout_struct::layout_tree::{
10 LayoutElement, LayoutTree, LayoutTreeCursor, LayoutTreeCursorBorrow, LayoutTreeIndex,
11};
12use crate::layout_struct::{RenderCommandOutput, TextDrawPayload};
13use crate::text::TextMeasuringFun;
14use cotis::utils::ElementId;
15use cotis::utils::ElementIdConfig;
16use cotis::utils::OwnedOrRef;
17use cotis_defaults::element_configs::style::sizing::Sizing::DoubleAxis;
18use cotis_defaults::element_configs::style::sizing::{AxisSizing, DoubleAxisSizing};
19use cotis_defaults::element_configs::style::types::{
20 Alignment, LayoutAlignmentX, LayoutAlignmentY, LayoutDirection, Padding,
21};
22use cotis_defaults::element_configs::text_config::TextConfig as DefaultTextConfig;
23use cotis_utils::math::Dimensions;
24use cotis_utils::text::{LayoutTextMeasuring, TextMeasurer};
25use std::collections::{HashMap, VecDeque};
26
27pub struct CotisLayoutManager {
36 root_id: ElementIdConfig<'static>,
37 root: LayoutTree,
38 screen_dimensions: Dimensions,
39 cache_elements: HashMap<ElementId, LayoutElement>,
40 element_parent: HashMap<ElementId, ElementId>,
42 text_dim_fun: Option<TextMeasuringFun>,
43}
44
45pub struct CotisLayoutRun<'layout, Config> {
53 pub(crate) layout_manager: &'layout mut CotisLayoutManager,
54 open_element_index: LayoutTreeIndex,
55 configs: HashMap<ElementId, Config>,
56 pub(crate) text_fragments: HashMap<ElementId, TextDrawPayload>,
57}
58
59impl CotisLayoutManager {
60 pub fn set_text_dim_fun(&mut self, fun: TextMeasuringFun) {
66 self.text_dim_fun = Some(fun);
67 }
68
69 pub(crate) fn text_dim_fun(&self) -> Option<&TextMeasuringFun> {
70 self.text_dim_fun.as_ref()
71 }
72}
73
74impl LayoutTextMeasuring<DefaultTextConfig> for CotisLayoutManager {
75 fn set_text_measuring_function(&mut self, text: Box<TextMeasurer<'_, DefaultTextConfig>>) {
76 self.text_dim_fun = Some(unsafe {
80 std::mem::transmute::<Box<TextMeasurer<'_, DefaultTextConfig>>, TextMeasuringFun>(text)
81 });
82 }
83}
84
85impl CotisLayoutManager {
86 fn default_node(&self) -> LayoutElement {
87 LayoutElement {
88 id: self.root_id.get_handle(),
89 name: "Root".to_string(),
90 info: LayoutElementInfo::NotInitialized,
91 config: LayoutElementConfig {
92 layout: LayoutElementStyle {
93 sizing: DoubleAxis(DoubleAxisSizing {
94 width: AxisSizing::Fixed(self.screen_dimensions.width),
95 height: AxisSizing::Fixed(self.screen_dimensions.height),
96 }),
97 padding: Padding {
98 top: 0.0,
99 bottom: 0.0,
100 right: 0.0,
101 left: 0.0,
102 },
103 child_gap: 0.0,
104 child_alignment: Alignment {
105 x: LayoutAlignmentX::Left,
106 y: LayoutAlignmentY::Top,
107 },
108 layout_direction: LayoutDirection::LeftToRight,
109 wrapping: ChildWrapping::None,
110 },
111 ..LayoutElementConfig::default()
112 },
113 }
114 }
115
116 pub fn new(screen_dimensions: Dimensions) -> Self {
118 let root = LayoutTree::new();
119 let root_id = ElementIdConfig::new_empty();
120 let mut res = Self {
121 root_id,
122 root,
123 screen_dimensions,
124 cache_elements: Default::default(),
125 element_parent: Default::default(),
126 text_dim_fun: None,
127 };
128 res.root.add_root(res.default_node());
129 res.configure_roots();
130 res
131 }
132
133 pub fn set_dimensions(&mut self, screen_dimensions: Dimensions) {
138 self.screen_dimensions = screen_dimensions;
139 }
140
141 pub fn get_cache_element(&self, id: ElementId) -> Option<&LayoutElement> {
148 self.cache_elements.get(&id)
149 }
150
151 pub(crate) fn cached_element_ids(&self) -> Vec<ElementId> {
152 self.cache_elements.values().map(|e| e.id).collect()
153 }
154
155 pub(crate) fn parent_layout_slot_of(&self, child_slot: ElementId) -> Option<ElementId> {
156 self.element_parent.get(&child_slot).copied()
157 }
158
159 pub(crate) fn direct_child_slots(&self, parent_slot: ElementId) -> Vec<ElementId> {
160 self.element_parent
161 .iter()
162 .filter_map(|(child, &parent)| (parent == parent_slot).then_some(*child))
163 .collect()
164 }
165
166 pub(crate) fn clear_tree_no_cache(&mut self) {
167 self.root.clear_tree_structure();
168 self.root.add_root(self.default_node());
170
171 self.configure_roots();
172 }
173 pub(crate) fn clear_tree(&mut self) {
174 let (cache_elements, parent_map) = self.root.clear_tree_structure_with_parent_map();
175 self.cache_elements = cache_elements;
176 self.element_parent = parent_map;
177 }
178
179 pub(crate) fn tree(&mut self) -> &mut LayoutTree {
180 &mut self.root
181 }
182
183 pub(crate) fn configure_roots(&mut self) {
184 let mut root_element = self
186 .root
187 .get_node_mut(&LayoutTreeIndex::new(&[self.root_id.get_handle()]))
188 .unwrap();
189 let root_element = root_element.get_local().self_element;
190 root_element.info =
191 LayoutElementInfo::TotalSizedAndPosition(element_info_states::TotalSizedAndPosition {
192 x: 0.0,
193 y: 0.0,
194 width: self.screen_dimensions.width,
195 height: self.screen_dimensions.height,
196 });
197 }
198}
199
200impl<'layout, Config> CotisLayoutRun<'layout, Config> {
201 pub fn new(layout_manager: &'layout mut CotisLayoutManager) -> Self {
203 layout_manager.clear_tree_no_cache();
204 let root_id = layout_manager.root_id.get_handle();
205 Self {
206 layout_manager,
207 open_element_index: LayoutTreeIndex::new(&[root_id]),
208 configs: Default::default(),
209 text_fragments: Default::default(),
210 }
211 }
212
213 pub fn get_tree_cursor(&mut self) -> LayoutTreeCursor<'_> {
219 LayoutTreeCursor::new_from_index(self.layout_manager.tree(), &self.open_element_index)
220 .unwrap()
221 }
222
223 pub fn new_child_element(&mut self) {
229 let id_conf = ElementIdConfig::new_empty();
230 let element = LayoutElement::new(id_conf.get_handle(), String::new());
231 let child_index = self
232 .layout_manager
233 .root
234 .add_child(&self.open_element_index, element)
235 .expect("[Cotis Layout] New Element added to missing parent element");
236 self.open_element_index.push(child_index);
237 }
238
239 pub fn set_open_element_config(
247 &mut self,
248 config: LayoutElementConfig,
249 id: ElementId,
250 name: Option<OwnedOrRef<str>>,
251 true_config: Config,
252 ) {
253 let mut current_id = self.open_element_id();
254 let mut node = self
255 .layout_manager
256 .root
257 .get_node_mut(&self.open_element_index)
258 .expect("[Cotis Layout] Tried to set config for open element, but no element is open");
259 if id != current_id {
260 current_id = id;
261 node.change_node_id(id);
262 self.open_element_index.pop();
263 self.open_element_index.push(id);
264 }
265 {
266 let node = node.get_local().self_element;
267 node.config = config;
268 if let Some(name) = name {
269 node.name += name.as_ref();
270 }
271 }
272 self.configs.insert(current_id, true_config);
273 node.get_local().open_configuration()
274 }
275
276 pub fn open_element_id(&self) -> ElementId {
282 let node = self
283 .layout_manager
284 .root
285 .get_node(&self.open_element_index)
286 .expect("[Cotis Layout] Tried to set config for open element, but no element is open");
287 node.get_local().self_element.id
288 }
289
290 pub(crate) fn set_open_element_layout_direction(&mut self, layout_direction: LayoutDirection) {
291 let mut node = self.layout_manager.root.get_node_mut(&self.open_element_index).expect("[Cotis Layout] Tried to set layout direction for open element, but no element is open");
292 node.get_local().self_element.config.layout.layout_direction = layout_direction;
293 }
294
295 pub(crate) fn get_config(&self, id: ElementId) -> Option<&Config> {
296 self.configs.get(&id)
297 }
298
299 pub fn close_open_element(&mut self) {
301 let mut cursor = self.get_tree_cursor();
302 cursor.get_local().close_element();
303 self.open_element_index.pop();
304 }
305
306 fn calculate_final_layout_sizes(&mut self) {
307 self.layout_manager.configure_roots();
308
309 for root in self
310 .layout_manager
311 .root
312 .get_root_nodes()
313 .map(|c| LayoutTreeIndex::new(&[c.tree_node_id]))
314 .collect::<Vec<_>>()
315 {
316 let tree = &mut self.layout_manager.root;
317 fit_grow_shrink_children_axis(
319 &mut LayoutTreeCursor::new_from_index(tree, &root).unwrap(),
320 Axis::Width,
321 );
322 recursive_wrap_left_to_right(
324 &mut LayoutTreeCursor::new_from_index(tree, &root).unwrap(),
325 );
326 fit_grow_shrink_children_axis(
328 &mut LayoutTreeCursor::new_from_index(tree, &root).unwrap(),
329 Axis::Height,
330 );
331 }
332 }
333
334 fn calculate_positions(&mut self) {
335 for root in self
336 .layout_manager
337 .root
338 .get_root_nodes()
339 .map(|c| LayoutTreeIndex::new(&[c.tree_node_id]))
340 .collect::<Vec<_>>()
341 {
342 let tree = self.layout_manager.tree();
343 calculate_child_positions(&mut LayoutTreeCursor::new_from_index(tree, &root).unwrap());
344 }
345 }
346
347 fn calculate_render_commands(&mut self) -> Vec<RenderCommandOutput<Config>> {
348 let mut render_commands = Vec::new();
349 let mut open_nodes = VecDeque::new();
350 for root_id in self
351 .layout_manager
352 .root
353 .get_root_nodes_borrow()
354 .map(|c| c.tree_node_id)
355 .collect::<Vec<_>>()
356 {
357 let mut render_commands_buffer = Vec::new();
358 let root = LayoutTreeIndex::new(&[root_id]);
359 open_nodes.push_back(root);
360 while let Some(node) = open_nodes.pop_front() {
361 calculate_render_commands(
362 &self.layout_manager.root,
363 node,
364 &mut open_nodes,
365 &mut render_commands_buffer,
366 &mut self.configs,
367 &self.text_fragments,
368 );
369 }
370 let root = LayoutTreeIndex::new(&[root_id]);
371 let self_node =
372 LayoutTreeCursorBorrow::new_from_index(&self.layout_manager.root, &root).unwrap();
373 sort_commands(
374 &mut render_commands_buffer,
375 self_node.get_local().self_element.config.floating.z_index,
376 );
377 render_commands.append(&mut render_commands_buffer);
378 }
379 render_commands
380 }
381
382 pub fn finalize_layouts(&mut self) -> Vec<RenderCommandOutput<Config>> {
391 if let Some(id) = self.open_element_index.pop()
392 && id != self.layout_manager.root_id.get_handle()
393 {
394 println!("[Cotis Layout] Not all elements have been closed");
395 }
396
397 self.calculate_final_layout_sizes();
399 self.calculate_positions();
400 let res = self.calculate_render_commands();
401 self.layout_manager.clear_tree();
402 res
403 }
404
405 pub fn remove_custom(&mut self, element_id: ElementId) -> Config {
411 self.configs
412 .remove(&element_id)
413 .expect("[Cotis Layout] Can't find config from element id")
414 }
415}