use alloc::{vec, vec::Vec};
use crate::{UnstructuredNodeList, render::{Layoutable, Renderer, LayoutComputationProperties}};
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct NavPath {
path: Vec<usize>,
}
impl NavPath {
pub fn new(path: Vec<usize>) -> Self { Self { path } }
pub fn to_navigator(&mut self) -> NavPathNavigator {
NavPathNavigator {
path: self,
index: 0
}
}
pub fn root(&self) -> bool {
self.path.len() == 1
}
pub fn pop(&mut self, n: usize) {
for _ in 0..n {
self.path.pop();
}
}
pub fn push(&mut self, index: usize) {
self.path.push(index);
}
pub fn offset(&mut self, n: isize) {
*self.path.last_mut().unwrap() = (*self.path.last().unwrap() as isize + n) as usize;
}
pub fn len(&self) -> usize {
self.path.len()
}
}
impl core::ops::Index<usize> for NavPath {
type Output = usize;
fn index(&self, index: usize) -> &Self::Output {
&self.path[index]
}
}
pub struct NavPathNavigator<'a> {
path: &'a NavPath,
index: usize,
}
impl<'a> NavPathNavigator<'a> {
pub fn next(&self) -> usize {
self.path.path[self.index]
}
pub fn here(&self) -> bool {
self.index == self.path.path.len() - 1
}
pub fn step(&self) -> NavPathNavigator {
NavPathNavigator { index: self.index + 1, path: self.path }
}
pub fn step_if_next(&self, required_next: usize) -> Option<NavPathNavigator> {
if self.next() == required_next {
Some(self.step())
} else {
None
}
}
}
pub enum MoveVerticalDirection {
Up,
Down,
}
pub fn match_vertical_cursor_points(
renderer: &mut impl Renderer,
top: &UnstructuredNodeList,
bottom: &UnstructuredNodeList,
direction: MoveVerticalDirection
) -> Vec<usize> {
let (from_node, to_node) = match direction {
MoveVerticalDirection::Up => (bottom, top),
MoveVerticalDirection::Down => (top, bottom),
};
let from_layouts = from_node.items
.iter()
.map(|node| node.layout(renderer, None, LayoutComputationProperties::default()))
.collect::<Vec<_>>();
let to_layouts = to_node.items
.iter()
.map(|node| node.layout(renderer, None, LayoutComputationProperties::default()))
.collect::<Vec<_>>();
let from_total_width: u64 = from_layouts
.iter()
.map(|x| x.area.width)
.sum();
let to_total_width: u64 = to_layouts
.iter()
.map(|x| x.area.width)
.sum();
let (from_offset, to_offset) = if from_total_width < to_total_width {
((to_total_width - from_total_width) / 2, 0)
} else if from_total_width > to_total_width {
(0, (from_total_width - to_total_width) / 2)
} else {
(0, 0)
};
let mut from_boundary_points = vec![from_offset];
for layout in &from_layouts {
from_boundary_points.push(
from_boundary_points.last().unwrap() + layout.area.width
)
}
let mut to_boundary_points = vec![to_offset];
for layout in &to_layouts {
to_boundary_points.push(
to_boundary_points.last().unwrap() + layout.area.width
)
}
let mut result = vec![];
for from_point in from_boundary_points {
let mut closest_to_idx_found = 0;
for (i, to_point) in to_boundary_points.iter().enumerate() {
let this_distance = (*to_point as i64 - from_point as i64).abs();
let best_distance = (to_boundary_points[closest_to_idx_found] as i64 - from_point as i64).abs();
if this_distance < best_distance {
closest_to_idx_found = i;
}
}
result.push(closest_to_idx_found);
}
result
}