use serde::{Deserialize, Serialize};
use crate::{Rect, SplitDirection};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct Window {
pub id: u64,
pub viewport_id: u64,
pub buffer_id: u64,
pub bounds: Rect,
pub focused: bool,
}
impl Window {
#[must_use]
pub const fn new(id: u64, viewport_id: u64, buffer_id: u64, bounds: Rect) -> Self {
Self {
id,
viewport_id,
buffer_id,
bounds,
focused: false,
}
}
#[must_use]
pub const fn with_focus(mut self, focused: bool) -> Self {
self.focused = focused;
self
}
#[must_use]
pub const fn area(&self) -> u32 {
self.bounds.area()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum WindowTree {
Leaf(Window),
Split {
direction: SplitDirection,
children: Vec<Self>,
bounds: Rect,
},
Tabs {
tabs: Vec<Self>,
active: usize,
bounds: Rect,
},
}
impl WindowTree {
#[must_use]
pub const fn leaf(window: Window) -> Self {
Self::Leaf(window)
}
#[must_use]
pub const fn split(direction: SplitDirection, children: Vec<Self>, bounds: Rect) -> Self {
Self::Split {
direction,
children,
bounds,
}
}
#[must_use]
pub const fn tabs(tabs: Vec<Self>, active: usize, bounds: Rect) -> Self {
Self::Tabs {
tabs,
active,
bounds,
}
}
#[must_use]
pub const fn bounds(&self) -> Rect {
match self {
Self::Leaf(window) => window.bounds,
Self::Split { bounds, .. } | Self::Tabs { bounds, .. } => *bounds,
}
}
#[must_use]
pub fn window_count(&self) -> usize {
match self {
Self::Leaf(_) => 1,
Self::Split { children, .. } => children.iter().map(Self::window_count).sum(),
Self::Tabs { tabs, .. } => tabs.iter().map(Self::window_count).sum(),
}
}
#[must_use]
pub fn focused_window(&self) -> Option<&Window> {
match self {
Self::Leaf(window) if window.focused => Some(window),
Self::Leaf(_) => None,
Self::Split { children, .. } => children.iter().find_map(Self::focused_window),
Self::Tabs { tabs, active, .. } => tabs.get(*active).and_then(Self::focused_window),
}
}
#[must_use]
pub fn find_by_viewport(&self, viewport_id: u64) -> Option<&Window> {
match self {
Self::Leaf(window) if window.viewport_id == viewport_id => Some(window),
Self::Leaf(_) => None,
Self::Split { children, .. } => children
.iter()
.find_map(|c| c.find_by_viewport(viewport_id)),
Self::Tabs { tabs, .. } => tabs.iter().find_map(|t| t.find_by_viewport(viewport_id)),
}
}
#[must_use]
pub fn all_windows(&self) -> Vec<&Window> {
match self {
Self::Leaf(window) => vec![window],
Self::Split { children, .. } => children.iter().flat_map(Self::all_windows).collect(),
Self::Tabs { tabs, .. } => tabs.iter().flat_map(Self::all_windows).collect(),
}
}
#[must_use]
pub const fn is_leaf(&self) -> bool {
matches!(self, Self::Leaf(_))
}
}
#[cfg(test)]
#[path = "window_tests.rs"]
mod tests;