use super::id::ItemId;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pane {
items: Vec<ItemId>,
active: usize,
}
impl Pane {
pub fn new(item: ItemId) -> Self {
Self {
items: vec![item],
active: 0,
}
}
pub fn items(&self) -> &[ItemId] {
&self.items
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn active(&self) -> ItemId {
self.items[self.active]
}
pub fn active_index(&self) -> usize {
self.active
}
pub fn index_of(&self, item: ItemId) -> Option<usize> {
self.items.iter().position(|&i| i == item)
}
pub fn contains(&self, item: ItemId) -> bool {
self.items.contains(&item)
}
pub fn activate(&mut self, index: usize) -> bool {
if index >= self.items.len() {
return false;
}
self.active = index;
true
}
pub fn activate_item(&mut self, item: ItemId) -> bool {
match self.index_of(item) {
Some(i) => {
self.active = i;
true
}
None => false,
}
}
pub fn activate_next(&mut self) {
self.active = (self.active + 1) % self.items.len();
}
pub fn activate_prev(&mut self) {
self.active = (self.active + self.items.len() - 1) % self.items.len();
}
pub fn add(&mut self, item: ItemId, at: Option<usize>) -> usize {
if let Some(i) = self.index_of(item) {
self.active = i;
return i;
}
let index = at.unwrap_or(self.items.len()).min(self.items.len());
self.items.insert(index, item);
self.active = index;
index
}
pub fn remove(&mut self, item: ItemId) -> bool {
let Some(i) = self.index_of(item) else {
return self.items.is_empty();
};
self.items.remove(i);
if self.items.is_empty() {
return true;
}
if self.active >= self.items.len() {
self.active = self.items.len() - 1;
} else if i < self.active {
self.active -= 1;
}
false
}
pub fn reorder(&mut self, from: usize, to: usize) -> bool {
if from >= self.items.len() {
return false;
}
let to = to.min(self.items.len() - 1);
if from == to {
return true;
}
let active_item = self.items[self.active];
let item = self.items.remove(from);
self.items.insert(to, item);
self.active = self.index_of(active_item).unwrap_or(self.active);
true
}
}
#[cfg(test)]
mod tests {
use super::super::id::ItemIds;
use super::*;
fn items(n: usize) -> Vec<ItemId> {
let mut a = ItemIds::new();
(0..n).map(|_| a.next()).collect()
}
#[test]
fn add_activate_and_reorder() {
let it = items(3);
let mut p = Pane::new(it[0]);
assert_eq!(p.add(it[1], None), 1);
assert_eq!(p.add(it[2], Some(0)), 0);
assert_eq!(p.items(), &[it[2], it[0], it[1]]);
assert_eq!(p.active(), it[2]);
assert!(p.reorder(0, 2));
assert_eq!(p.items(), &[it[0], it[1], it[2]]);
assert_eq!(p.active(), it[2]); }
#[test]
fn remove_keeps_active_and_reports_empty() {
let it = items(2);
let mut p = Pane::new(it[0]);
p.add(it[1], None); assert!(!p.remove(it[0])); assert_eq!(p.active(), it[1]);
assert!(p.remove(it[1])); assert!(p.is_empty());
}
}