pub fn partition_tabs(widths: &[f32], available: f32, gap: f32, overflow_w: f32, active: Option<usize>) -> Vec<usize> {
let count = widths.len();
let room = available.max(0.0);
let total: f32 = widths.iter().sum::<f32>() + gap * count.saturating_sub(1) as f32;
if total <= room {
return (0..count).collect();
}
let budget = (room - overflow_w - gap).max(0.0);
let active = active.filter(|&a| a < count);
let mut visible = Vec::new();
let mut used = active.map(|a| widths[a]).unwrap_or(0.0);
let mut tabs = usize::from(active.is_some());
for (index, &width) in widths.iter().enumerate() {
if Some(index) == active {
visible.push(index);
continue;
}
let next = used + width + if tabs > 0 { gap } else { 0.0 };
if next > budget && tabs > 0 {
break;
}
visible.push(index);
used = next;
tabs += 1;
}
if let Some(a) = active {
if !visible.contains(&a) {
visible.push(a);
}
}
if visible.is_empty() && count > 0 {
visible.push(0);
}
visible.sort_unstable();
visible
}
pub fn tab_drop_slot(centers: &[f32], from: usize, delta: f32, rtl: bool) -> usize {
let Some(&start) = centers.get(from) else { return from };
let at = start + delta;
centers.iter().enumerate().filter(|&(k, &c)| k != from && if rtl { c > at } else { c < at }).count()
}
pub fn tab_key_slot(count: usize, from: usize, key: &str, rtl: bool) -> Option<usize> {
let step: i64 = match key {
"ArrowRight" => 1,
"ArrowLeft" => -1,
_ => return None,
};
let to = from as i64 + if rtl { -step } else { step };
(to >= 0 && (to as usize) < count).then_some(to as usize)
}
pub fn tab_reorder(visible: &[usize], from_slot: usize, to_slot: usize) -> Option<(usize, usize)> {
let from = *visible.get(from_slot)?;
let to = *visible.get(to_slot)?;
(from != to).then_some((from, to))
}
pub fn move_tab<T: Clone>(order: &[T], from: usize, to: usize) -> Vec<T> {
let mut out = order.to_vec();
if from < out.len() && to < out.len() {
let moved = out.remove(from);
out.insert(to, moved);
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn move_tab_is_the_preview_order() {
assert_eq!(move_tab(&[0, 1, 2, 3], 0, 2), vec![1, 2, 0, 3]);
assert_eq!(move_tab(&[0, 1, 2, 3], 3, 0), vec![3, 0, 1, 2]);
assert_eq!(move_tab(&[0, 1], 0, 5), vec![0, 1]);
}
}