use egui::Rect;
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TabIndex(pub usize);
impl From<usize> for TabIndex {
#[inline]
fn from(index: usize) -> Self {
TabIndex(index)
}
}
#[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,
},
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),
}
}
#[inline(always)]
pub const fn leaf_with(tabs: Vec<Tab>) -> Self {
Self::Leaf {
rect: Rect::NOTHING,
viewport: Rect::NOTHING,
tabs,
active: TabIndex(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, .. } => Some(tabs.remove(tab_index.0)),
_ => None,
}
}
#[inline]
pub fn tabs_count(&self) -> usize {
match self {
Node::Leaf { tabs, .. } => tabs.len(),
_ => Default::default(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct NodeIndex(pub usize);
impl From<usize> for NodeIndex {
#[inline(always)]
fn from(index: usize) -> Self {
NodeIndex(index)
}
}
impl NodeIndex {
#[inline(always)]
pub const fn root() -> Self {
Self(0)
}
#[inline(always)]
pub const fn left(self) -> Self {
Self(self.0 * 2 + 1)
}
#[inline(always)]
pub const fn right(self) -> Self {
Self(self.0 * 2 + 2)
}
#[inline]
pub const fn parent(self) -> Option<Self> {
if self.0 > 0 {
Some(Self((self.0 - 1) / 2))
} else {
None
}
}
#[inline(always)]
pub const fn level(self) -> usize {
(usize::BITS - (self.0 + 1).leading_zeros()) as usize
}
#[inline(always)]
pub const fn is_left(self) -> bool {
self.0 % 2 != 0
}
#[inline(always)]
pub const fn is_right(self) -> bool {
self.0 % 2 == 0
}
#[inline]
const fn children_at(self, level: usize) -> std::ops::Range<usize> {
let base = 1 << level;
let s = (self.0 + 1) * base - 1;
let e = (self.0 + 2) * base - 1;
s..e
}
#[inline]
const fn children_left(self, level: usize) -> std::ops::Range<usize> {
let base = 1 << level;
let s = (self.0 + 1) * base - 1;
let e = (self.0 + 1) * base + base / 2 - 1;
s..e
}
#[inline]
const fn children_right(self, level: usize) -> std::ops::Range<usize> {
let base = 1 << level;
let s = (self.0 + 1) * base + base / 2 - 1;
let e = (self.0 + 2) * base - 1;
s..e
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[allow(missing_docs)]
pub enum Split {
Left,
Right,
Above,
Below,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Tree<Tab> {
tree: Vec<Node<Tab>>,
focused_node: Option<NodeIndex>,
}
impl<Tab> fmt::Debug for Tree<Tab> {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
fmtr.debug_struct("Tree")
.field("focused_node", &self.focused_node)
.finish_non_exhaustive()
}
}
impl<Tab> Default for Tree<Tab> {
fn default() -> Self {
Self {
tree: Vec::new(),
focused_node: None,
}
}
}
impl<Tab> std::ops::Index<NodeIndex> for Tree<Tab> {
type Output = Node<Tab>;
#[inline(always)]
fn index(&self, index: NodeIndex) -> &Self::Output {
&self.tree[index.0]
}
}
impl<Tab> std::ops::IndexMut<NodeIndex> for Tree<Tab> {
#[inline(always)]
fn index_mut(&mut self, index: NodeIndex) -> &mut Self::Output {
&mut self.tree[index.0]
}
}
impl<Tab> Tree<Tab> {
#[inline(always)]
pub fn new(tabs: Vec<Tab>) -> Self {
let root = Node::leaf_with(tabs);
Self {
tree: vec![root],
focused_node: None,
}
}
#[inline]
pub fn find_active(&mut self) -> Option<(Rect, &mut Tab)> {
self.tree.iter_mut().find_map(|node| {
if let Node::Leaf {
tabs,
active,
viewport,
..
} = node
{
tabs.get_mut(active.0).map(|tab| (*viewport, tab))
} else {
None
}
})
}
#[inline]
pub fn find_active_focused(&mut self) -> Option<(Rect, &mut Tab)> {
if let Some(Node::Leaf {
tabs,
active,
viewport,
..
}) = self.focused_node.and_then(|idx| self.tree.get_mut(idx.0))
{
tabs.get_mut(active.0).map(|tab| (*viewport, tab))
} else {
None
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.tree.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.tree.is_empty()
}
#[inline(always)]
pub fn iter(&self) -> std::slice::Iter<'_, Node<Tab>> {
self.tree.iter()
}
#[inline(always)]
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Node<Tab>> {
self.tree.iter_mut()
}
#[inline(always)]
pub fn tabs(&self) -> TabIter<'_, Tab> {
TabIter::new(self)
}
#[inline]
pub fn num_tabs(&self) -> usize {
let mut count = 0;
for node in self.tree.iter() {
if let Node::Leaf { tabs, .. } = node {
count += tabs.len();
}
}
count
}
#[inline(always)]
pub fn split_tabs(
&mut self,
parent: NodeIndex,
split: Split,
fraction: f32,
tabs: Vec<Tab>,
) -> [NodeIndex; 2] {
self.split(parent, split, fraction, Node::leaf_with(tabs))
}
#[inline(always)]
pub fn split_above(
&mut self,
parent: NodeIndex,
fraction: f32,
tabs: Vec<Tab>,
) -> [NodeIndex; 2] {
self.split(parent, Split::Above, fraction, Node::leaf_with(tabs))
}
#[inline(always)]
pub fn split_below(
&mut self,
parent: NodeIndex,
fraction: f32,
tabs: Vec<Tab>,
) -> [NodeIndex; 2] {
self.split(parent, Split::Below, fraction, Node::leaf_with(tabs))
}
#[inline(always)]
pub fn split_left(
&mut self,
parent: NodeIndex,
fraction: f32,
tabs: Vec<Tab>,
) -> [NodeIndex; 2] {
self.split(parent, Split::Left, fraction, Node::leaf_with(tabs))
}
#[inline(always)]
pub fn split_right(
&mut self,
parent: NodeIndex,
fraction: f32,
tabs: Vec<Tab>,
) -> [NodeIndex; 2] {
self.split(parent, Split::Right, fraction, Node::leaf_with(tabs))
}
pub fn split(
&mut self,
parent: NodeIndex,
split: Split,
fraction: f32,
new: Node<Tab>,
) -> [NodeIndex; 2] {
let old = self[parent].split(split, fraction);
assert!(old.is_leaf());
{
let index = self.tree.iter().rposition(|n| !n.is_empty()).unwrap_or(0);
let level = NodeIndex(index).level();
self.tree.resize_with(1 << (level + 1), || Node::Empty);
}
let index = match split {
Split::Right | Split::Above => [parent.right(), parent.left()],
Split::Left | Split::Below => [parent.left(), parent.right()],
};
self[index[0]] = old;
self[index[1]] = new;
self.focused_node = Some(index[1]);
index
}
fn first_leaf(&self, top: NodeIndex) -> Option<NodeIndex> {
let left = top.left();
let right = top.right();
match (self.tree.get(left.0), self.tree.get(right.0)) {
(Some(&Node::Leaf { .. }), _) => Some(left),
(_, Some(&Node::Leaf { .. })) => Some(right),
(
Some(Node::Horizontal { .. } | Node::Vertical { .. }),
Some(Node::Horizontal { .. } | Node::Vertical { .. }),
) => match self.first_leaf(left) {
ret @ Some(_) => ret,
None => self.first_leaf(right),
},
(Some(Node::Horizontal { .. } | Node::Vertical { .. }), _) => self.first_leaf(left),
(_, Some(Node::Horizontal { .. } | Node::Vertical { .. })) => self.first_leaf(right),
(None, None)
| (Some(&Node::Empty), None)
| (None, Some(&Node::Empty))
| (Some(&Node::Empty), Some(&Node::Empty)) => None,
}
}
pub fn remove_empty_leaf(&mut self) {
let mut nodes = self.tree.iter().enumerate();
let node = nodes.find_map(|(index, node)| match node {
Node::Leaf { tabs, .. } if tabs.is_empty() => Some(index),
_ => None,
});
let node = match node {
Some(node) => NodeIndex(node),
None => return,
};
let parent = match node.parent() {
Some(val) => val,
None => {
self.tree.clear();
return;
}
};
if Some(node) == self.focused_node {
self.focused_node = None;
let mut node = node;
while let Some(parent) = node.parent() {
let next = if node.is_left() {
parent.right()
} else {
parent.left()
};
if let Some(Node::Leaf { .. }) = self.tree.get(next.0) {
self.focused_node = Some(next);
break;
}
if let Some(node) = self.first_leaf(next) {
self.focused_node = Some(node);
break;
}
node = parent;
}
}
self[parent] = Node::Empty;
self[node] = Node::Empty;
let mut level = 0;
if node.is_left() {
'left_end: loop {
let dst = parent.children_at(level);
let src = parent.children_right(level + 1);
for (dst, src) in dst.zip(src) {
if src >= self.tree.len() {
break 'left_end;
}
if Some(NodeIndex(src)) == self.focused_node {
self.focused_node = Some(NodeIndex(dst));
}
self.tree[dst] = std::mem::replace(&mut self.tree[src], Node::Empty);
}
level += 1;
}
} else {
'right_end: loop {
let dst = parent.children_at(level);
let src = parent.children_left(level + 1);
for (dst, src) in dst.zip(src) {
if src >= self.tree.len() {
break 'right_end;
}
if Some(NodeIndex(src)) == self.focused_node {
self.focused_node = Some(NodeIndex(dst));
}
self.tree[dst] = std::mem::replace(&mut self.tree[src], Node::Empty);
}
level += 1;
}
}
}
pub fn push_to_first_leaf(&mut self, tab: Tab) {
for (index, node) in &mut self.tree.iter_mut().enumerate() {
match node {
Node::Leaf { tabs, active, .. } => {
*active = TabIndex(tabs.len());
tabs.push(tab);
self.focused_node = Some(NodeIndex(index));
return;
}
Node::Empty => {
*node = Node::leaf(tab);
self.focused_node = Some(NodeIndex(index));
return;
}
_ => {}
}
}
assert!(self.tree.is_empty());
self.tree.push(Node::leaf_with(vec![tab]));
self.focused_node = Some(NodeIndex(0));
}
#[inline]
pub fn focused_leaf(&self) -> Option<NodeIndex> {
self.focused_node
}
#[inline]
pub fn set_focused_node(&mut self, node_index: NodeIndex) {
if let Some(Node::Leaf { .. }) = self.tree.get(node_index.0) {
self.focused_node = Some(node_index);
} else {
self.focused_node = None;
}
}
#[inline]
pub fn set_active_tab(&mut self, node_index: NodeIndex, tab_index: TabIndex) {
if let Some(Node::Leaf { active, .. }) = self.tree.get_mut(node_index.0) {
*active = tab_index;
}
}
pub fn push_to_focused_leaf(&mut self, tab: Tab) {
match self.focused_node {
Some(node) => {
if self.tree.is_empty() {
self.tree.push(Node::leaf(tab));
self.focused_node = Some(NodeIndex::root());
} else {
match &mut self[node] {
Node::Empty => {
self[node] = Node::leaf(tab);
self.focused_node = Some(node);
}
Node::Leaf { tabs, active, .. } => {
*active = TabIndex(tabs.len());
tabs.push(tab);
self.focused_node = Some(node);
}
_ => {
self.push_to_first_leaf(tab);
}
}
}
}
None => {
if self.tree.is_empty() {
self.tree.push(Node::leaf(tab));
self.focused_node = Some(NodeIndex::root());
} else {
self.push_to_first_leaf(tab);
}
}
}
}
pub fn remove_tab(&mut self, remove: (NodeIndex, TabIndex)) -> Option<Tab> {
match &mut self[remove.0] {
Node::Leaf { tabs, active, .. } => {
let tab = tabs.remove(remove.1 .0);
if remove.1 <= *active {
active.0 = active.0.saturating_sub(1);
}
if tabs.is_empty() {
self.remove_empty_leaf();
}
Some(tab)
}
_ => None,
}
}
}
impl<Tab> Tree<Tab>
where
Tab: PartialEq,
{
pub fn find_tab(&self, needle_tab: &Tab) -> Option<(NodeIndex, TabIndex)> {
for (node_index, node) in self.tree.iter().enumerate() {
if let Node::Leaf { tabs, .. } = node {
for (tab_index, tab) in tabs.iter().enumerate() {
if tab == needle_tab {
return Some((node_index.into(), tab_index.into()));
}
}
}
}
None
}
}
pub struct TabIter<'a, Tab> {
tree: &'a Tree<Tab>,
node_idx: usize,
tab_idx: usize,
}
impl<'a, Tab> TabIter<'a, Tab> {
fn new(tree: &'a Tree<Tab>) -> Self {
Self {
tree,
node_idx: 0,
tab_idx: 0,
}
}
}
impl<'a, Tab> Iterator for TabIter<'a, Tab> {
type Item = &'a Tab;
fn next(&mut self) -> Option<Self::Item> {
loop {
let node = self.tree.tree.get(self.node_idx)?;
match node {
Node::Leaf { tabs, .. } => match tabs.get(self.tab_idx) {
Some(tab) => {
self.tab_idx += 1;
return Some(tab);
}
None => {
self.node_idx += 1;
self.tab_idx = 0;
}
},
_ => {
self.node_idx += 1;
self.tab_idx = 0;
}
}
}
}
}
impl<'a, Tab> fmt::Debug for TabIter<'a, Tab> {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
fmtr.debug_struct("TabIter").finish_non_exhaustive()
}
}
#[test]
fn test_tabs_iter() {
fn tabs(tree: &Tree<i32>) -> Vec<i32> {
tree.tabs().copied().collect()
}
let mut tree = Tree::new(vec![1, 2, 3]);
assert_eq!(tabs(&tree), vec![1, 2, 3]);
tree.push_to_first_leaf(4);
assert_eq!(tabs(&tree), vec![1, 2, 3, 4]);
tree.push_to_first_leaf(5);
assert_eq!(tabs(&tree), vec![1, 2, 3, 4, 5]);
tree.push_to_focused_leaf(6);
assert_eq!(tabs(&tree), vec![1, 2, 3, 4, 5, 6]);
assert_eq!(tree.num_tabs(), tree.tabs().count());
}