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: Box<dyn Fn(&str, &DefaultTextConfig) -> Dimensions>) {
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.clone()).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 pub(crate) fn tree_borrow(&self) -> &LayoutTree {
183 &self.root
184 }
185
186 pub(crate) fn configure_roots(&mut self) {
187 let mut root_element = self
189 .root
190 .get_node_mut(&LayoutTreeIndex::new(&[self.root_id.get_handle()]))
191 .unwrap();
192 let root_element = root_element.get_local().self_element;
193 root_element.info =
194 LayoutElementInfo::TotalSizedAndPosition(element_info_states::TotalSizedAndPosition {
195 x: 0.0,
196 y: 0.0,
197 width: self.screen_dimensions.width,
198 height: self.screen_dimensions.height,
199 });
200 }
201}
202
203impl<'layout, Config> CotisLayoutRun<'layout, Config> {
204 pub fn new(layout_manager: &'layout mut CotisLayoutManager) -> Self {
206 layout_manager.clear_tree_no_cache();
207 let root_id = layout_manager.root_id.get_handle();
208 Self {
209 layout_manager,
210 open_element_index: LayoutTreeIndex::new(&[root_id]),
211 configs: Default::default(),
212 text_fragments: Default::default(),
213 }
214 }
215
216 pub fn get_tree_cursor(&mut self) -> LayoutTreeCursor {
222 LayoutTreeCursor::new_from_index(self.layout_manager.tree(), &self.open_element_index)
223 .unwrap()
224 }
225
226 pub fn new_child_element(&mut self) {
232 let id_conf = ElementIdConfig::new_empty();
233 let element = LayoutElement::new(id_conf.get_handle(), String::new());
234 let child_index = self
235 .layout_manager
236 .root
237 .add_child(&self.open_element_index, element)
238 .expect("[Cotis Layout] New Element added to missing parent element");
239 self.open_element_index.push(child_index);
240 }
241
242 pub fn set_open_element_config(
250 &mut self,
251 config: LayoutElementConfig,
252 id: ElementId,
253 name: Option<OwnedOrRef<str>>,
254 true_config: Config,
255 ) {
256 let mut current_id = self.open_element_id();
257 let mut node = self
258 .layout_manager
259 .root
260 .get_node_mut(&self.open_element_index)
261 .expect("[Cotis Layout] Tried to set config for open element, but no element is open");
262 if id != current_id {
263 current_id = id;
264 node.change_node_id(id.clone());
265 self.open_element_index.pop();
266 self.open_element_index.push(id);
267 }
268 {
269 let node = node.get_local().self_element;
270 node.config = config;
271 if let Some(name) = name {
272 node.name += name.as_ref();
273 }
274 }
275 self.configs.insert(current_id, true_config);
276 node.get_local().open_configuration()
277 }
278
279 pub fn open_element_id(&self) -> ElementId {
285 let node = self
286 .layout_manager
287 .root
288 .get_node(&self.open_element_index)
289 .expect("[Cotis Layout] Tried to set config for open element, but no element is open");
290 node.get_local().self_element.id
291 }
292
293 pub(crate) fn set_open_element_layout_direction(&mut self, layout_direction: LayoutDirection) {
294 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");
295 node.get_local().self_element.config.layout.layout_direction = layout_direction;
296 }
297
298 pub(crate) fn get_config(&self, id: ElementId) -> Option<&Config> {
299 self.configs.get(&id)
300 }
301
302 pub(crate) fn open_element_config_mut(&mut self) -> Option<&mut Config> {
303 let id = self.open_element_id();
304 self.configs.get_mut(&id)
305 }
306
307 pub fn close_open_element(&mut self) {
309 let mut cursor = self.get_tree_cursor();
310 cursor.get_local().close_element();
311 self.open_element_index.pop();
312 }
313
314 fn calculate_final_layout_sizes(&mut self) {
315 self.layout_manager.configure_roots();
316
317 for root in self
318 .layout_manager
319 .root
320 .get_root_nodes()
321 .map(|c| LayoutTreeIndex::new(&[c.tree_node_id]))
322 .collect::<Vec<_>>()
323 {
324 let tree = &mut self.layout_manager.root;
325 fit_grow_shrink_children_axis(
327 &mut LayoutTreeCursor::new_from_index(tree, &root).unwrap(),
328 Axis::Width,
329 );
330 recursive_wrap_left_to_right(
332 &mut LayoutTreeCursor::new_from_index(tree, &root).unwrap(),
333 );
334 fit_grow_shrink_children_axis(
336 &mut LayoutTreeCursor::new_from_index(tree, &root).unwrap(),
337 Axis::Height,
338 );
339 }
340 }
341
342 fn calculate_positions(&mut self) {
343 for root in self
344 .layout_manager
345 .root
346 .get_root_nodes()
347 .map(|c| LayoutTreeIndex::new(&[c.tree_node_id]))
348 .collect::<Vec<_>>()
349 {
350 let tree = self.layout_manager.tree();
351 calculate_child_positions(&mut LayoutTreeCursor::new_from_index(tree, &root).unwrap());
352 }
353 }
354
355 fn calculate_render_commands(&mut self) -> Vec<RenderCommandOutput<Config>> {
356 let mut render_commands = Vec::new();
357 let mut open_nodes = VecDeque::new();
358 for root_id in self
359 .layout_manager
360 .root
361 .get_root_nodes_borrow()
362 .map(|c| c.tree_node_id)
363 .collect::<Vec<_>>()
364 {
365 let mut render_commands_buffer = Vec::new();
366 let root = LayoutTreeIndex::new(&[root_id]);
367 open_nodes.push_back(root);
368 while let Some(node) = open_nodes.pop_front() {
369 calculate_render_commands(
370 &self.layout_manager.root,
371 node,
372 &mut open_nodes,
373 &mut render_commands_buffer,
374 &mut self.configs,
375 &self.text_fragments,
376 );
377 }
378 let root = LayoutTreeIndex::new(&[root_id]);
379 let self_node =
380 LayoutTreeCursorBorrow::new_from_index(&self.layout_manager.root, &root).unwrap();
381 sort_commands(
382 &mut render_commands_buffer,
383 self_node.get_local().self_element.config.floating.z_index,
384 );
385 render_commands.append(&mut render_commands_buffer);
386 }
387 render_commands
388 }
389
390 pub fn finalize_layouts(&mut self) -> Vec<RenderCommandOutput<Config>> {
399 if let Some(id) = self.open_element_index.pop() {
400 if id != self.layout_manager.root_id.get_handle() {
401 println!("[Cotis Layout] Not all elements have been closed");
402 }
403 }
404 self.calculate_final_layout_sizes();
406 self.calculate_positions();
407 let res = self.calculate_render_commands();
408 self.layout_manager.clear_tree();
409 res
410 }
411
412 pub fn remove_custom(&mut self, element_id: ElementId) -> Config {
418 self.configs
419 .remove(&element_id)
420 .expect("[Cotis Layout] Can't find config from element id")
421 }
422}