use crate::{Split, TabIndex};
use egui::Rect;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum Node<Tab> {
Empty,
Leaf {
rect: Rect,
viewport: Rect,
tabs: Vec<Tab>,
active: TabIndex,
scroll: f32,
},
Vertical {
rect: Rect,
fraction: f32,
},
Horizontal {
rect: Rect,
fraction: f32,
},
}
impl<Tab> Node<Tab> {
#[inline(always)]
pub fn leaf(tab: Tab) -> Self {
Self::Leaf {
rect: Rect::NOTHING,
viewport: Rect::NOTHING,
tabs: vec![tab],
active: TabIndex(0),
scroll: 0.0,
}
}
#[inline(always)]
pub const fn leaf_with(tabs: Vec<Tab>) -> Self {
Self::Leaf {
rect: Rect::NOTHING,
viewport: Rect::NOTHING,
tabs,
active: TabIndex(0),
scroll: 0.0,
}
}
#[inline]
pub fn set_rect(&mut self, new_rect: Rect) {
match self {
Self::Empty => (),
Self::Leaf { rect, .. }
| Self::Vertical { rect, .. }
| Self::Horizontal { rect, .. } => *rect = new_rect,
}
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
#[inline(always)]
pub const fn is_leaf(&self) -> bool {
matches!(self, Self::Leaf { .. })
}
#[inline(always)]
pub const fn is_horizontal(&self) -> bool {
matches!(self, Self::Horizontal { .. })
}
#[inline(always)]
pub const fn is_vertical(&self) -> bool {
matches!(self, Self::Vertical { .. })
}
#[inline(always)]
pub const fn is_parent(&self) -> bool {
self.is_horizontal() || self.is_vertical()
}
#[inline]
pub fn split(&mut self, split: Split, fraction: f32) -> Self {
let rect = Rect::NOTHING;
let src = match split {
Split::Left | Split::Right => Node::Horizontal { fraction, rect },
Split::Above | Split::Below => Node::Vertical { fraction, rect },
};
std::mem::replace(self, src)
}
#[track_caller]
#[inline]
pub fn append_tab(&mut self, tab: Tab) {
match self {
Node::Leaf { tabs, active, .. } => {
*active = TabIndex(tabs.len());
tabs.push(tab);
}
_ => unreachable!(),
}
}
#[track_caller]
#[inline]
pub fn insert_tab(&mut self, index: TabIndex, tab: Tab) {
match self {
Node::Leaf { tabs, active, .. } => {
tabs.insert(index.0, tab);
*active = index;
}
_ => unreachable!(),
}
}
#[inline]
pub fn remove_tab(&mut self, tab_index: TabIndex) -> Option<Tab> {
match self {
Node::Leaf { tabs, active, .. } => {
if tab_index <= *active {
active.0 = active.0.saturating_sub(1);
}
Some(tabs.remove(tab_index.0))
}
_ => None,
}
}
#[inline]
pub fn tabs_count(&self) -> usize {
match self {
Node::Leaf { tabs, .. } => tabs.len(),
_ => Default::default(),
}
}
}