use nightshade::ecs::ui::components::TileNode;
use nightshade::prelude::*;
pub struct GridLayout {
pub main_pane: TileId,
pub extras: Vec<(TileId, Entity)>,
}
pub fn rebuild_grid(
world: &mut World,
container: Entity,
main_pane: TileId,
main_content: Entity,
extra_titles: &[String],
) -> Option<GridLayout> {
let total = 1 + extra_titles.len();
if total <= 1 {
let _ = main_content;
return Some(GridLayout {
main_pane,
extras: Vec::new(),
});
}
let cols = (total as f32).sqrt().ceil() as usize;
let rows = total.div_ceil(cols);
let mut col_heads: Vec<(TileId, Entity)> = Vec::with_capacity(cols);
let mut remaining_pane = main_pane;
let mut remaining_content = main_content;
for i in 0..cols.saturating_sub(1) {
let ratio = 1.0 / (cols - i) as f32;
let (old_id, new_id, new_content) = split_pane(
world,
container,
remaining_pane,
SplitDirection::Horizontal,
ratio,
"",
)?;
col_heads.push((old_id, remaining_content));
remaining_pane = new_id;
remaining_content = new_content;
}
col_heads.push((remaining_pane, remaining_content));
let mut all_cells: Vec<(TileId, Entity)> = Vec::with_capacity(total);
let mut placed = 0;
for (col_i, (head_pane, head_content)) in col_heads.into_iter().enumerate() {
let cells_in_col = std::cmp::min(rows, total - col_i * rows);
if cells_in_col == 0 {
continue;
}
let mut col_cells: Vec<(TileId, Entity)> = Vec::with_capacity(cells_in_col);
col_cells.push((head_pane, head_content));
let mut top_remaining_pane = head_pane;
let mut top_remaining_content = head_content;
for row_i in 0..cells_in_col.saturating_sub(1) {
let ratio = 1.0 / (cells_in_col - row_i) as f32;
let (old_id, new_id, new_content) = split_pane(
world,
container,
top_remaining_pane,
SplitDirection::Vertical,
ratio,
"",
)?;
col_cells.last_mut().unwrap().0 = old_id;
col_cells.push((new_id, new_content));
top_remaining_pane = new_id;
top_remaining_content = new_content;
}
let _ = top_remaining_content;
all_cells.extend(col_cells);
placed += cells_in_col;
}
debug_assert_eq!(placed, total);
let new_main_pane = all_cells[0].0;
for (pane_id, _) in &all_cells {
ui_tile_wrap_pane_in_tabs(world, container, *pane_id);
}
let extras: Vec<(TileId, Entity)> = all_cells.into_iter().skip(1).collect();
for (index, (pane_id, _)) in extras.iter().enumerate() {
if let Some(title) = extra_titles.get(index)
&& !title.is_empty()
{
set_pane_title(world, container, *pane_id, title);
}
}
Some(GridLayout {
main_pane: new_main_pane,
extras,
})
}
fn split_pane(
world: &mut World,
container: Entity,
target: TileId,
direction: SplitDirection,
ratio: f32,
title: &str,
) -> Option<(TileId, TileId, Entity)> {
let (new_pane_id, new_content) =
ui_tile_split(world, container, target, direction, ratio, title)?;
let data = world.ui.get_ui_tile_container(container)?;
let TileNode::Split { children, .. } = data.get(target)? else {
return None;
};
Some((children[0], new_pane_id, new_content))
}
fn set_pane_title(world: &mut World, container: Entity, pane_id: TileId, title: &str) {
if let Some(data) = world.ui.get_ui_tile_container_mut(container)
&& let Some(TileNode::Pane { title: t, .. }) = data.get_mut(pane_id)
{
*t = title.to_string();
}
}