use {reovim_driver_layout::RootCompositor, reovim_kernel::api::v1::TabId};
use crate::WindowLayout;
pub struct TabPage {
id: TabId,
label: String,
compositor: Option<Box<dyn RootCompositor>>,
windows: WindowLayout,
}
impl std::fmt::Debug for TabPage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TabPage")
.field("id", &self.id)
.field("label", &self.label)
.field("has_compositor", &self.compositor.is_some())
.field("windows", &self.windows)
.finish()
}
}
impl Clone for TabPage {
fn clone(&self) -> Self {
Self {
id: self.id,
label: self.label.clone(),
compositor: self.compositor.as_ref().map(|c| c.boxed_clone()),
windows: self.windows.clone(),
}
}
}
impl TabPage {
#[must_use]
pub fn new(label: impl Into<String>) -> Self {
Self {
id: TabId::new(),
label: label.into(),
compositor: None,
windows: WindowLayout::empty(),
}
}
#[must_use]
pub fn with_id(id: TabId, label: impl Into<String>) -> Self {
Self {
id,
label: label.into(),
compositor: None,
windows: WindowLayout::empty(),
}
}
#[must_use]
pub const fn id(&self) -> TabId {
self.id
}
#[must_use]
pub fn label(&self) -> &str {
&self.label
}
pub fn set_label(&mut self, label: impl Into<String>) {
self.label = label.into();
}
#[must_use]
pub const fn compositor(&self) -> &Option<Box<dyn RootCompositor>> {
&self.compositor
}
pub fn compositor_mut(&mut self) -> &mut Option<Box<dyn RootCompositor>> {
&mut self.compositor
}
pub fn set_compositor(&mut self, compositor: Option<Box<dyn RootCompositor>>) {
self.compositor = compositor;
}
#[must_use]
pub const fn windows(&self) -> &WindowLayout {
&self.windows
}
pub const fn windows_mut(&mut self) -> &mut WindowLayout {
&mut self.windows
}
}
#[derive(Debug, Clone)]
pub struct TabPageSet {
tabs: Vec<TabPage>,
active_index: usize,
}
impl TabPageSet {
#[must_use]
pub fn new() -> Self {
Self {
tabs: vec![TabPage::new("1")],
active_index: 0,
}
}
#[must_use]
pub fn active_tab(&self) -> &TabPage {
&self.tabs[self.active_index]
}
pub fn active_tab_mut(&mut self) -> &mut TabPage {
&mut self.tabs[self.active_index]
}
#[must_use]
pub const fn active_index(&self) -> usize {
self.active_index
}
#[must_use]
pub fn active_tab_id(&self) -> TabId {
self.tabs[self.active_index].id
}
#[must_use]
pub const fn tab_count(&self) -> usize {
self.tabs.len()
}
#[must_use]
pub fn tabs(&self) -> &[TabPage] {
&self.tabs
}
pub fn new_tab(&mut self) -> TabId {
let label = (self.tabs.len() + 1).to_string();
let tab = TabPage::new(label);
let id = tab.id;
let insert_pos = self.active_index + 1;
self.tabs.insert(insert_pos, tab);
self.active_index = insert_pos;
id
}
pub fn close_tab(&mut self) -> bool {
if self.tabs.len() <= 1 {
return false;
}
self.tabs.remove(self.active_index);
if self.active_index >= self.tabs.len() {
self.active_index = self.tabs.len() - 1;
}
true
}
pub fn next_tab(&mut self) -> TabId {
self.active_index = (self.active_index + 1) % self.tabs.len();
self.tabs[self.active_index].id
}
pub fn prev_tab(&mut self) -> TabId {
self.active_index = if self.active_index == 0 {
self.tabs.len() - 1
} else {
self.active_index - 1
};
self.tabs[self.active_index].id
}
pub fn goto_tab(&mut self, index: usize) -> Option<TabId> {
if index < self.tabs.len() {
self.active_index = index;
Some(self.tabs[self.active_index].id)
} else {
None
}
}
#[must_use]
pub fn find_tab(&self, id: TabId) -> Option<(usize, &TabPage)> {
self.tabs.iter().enumerate().find(|(_, tab)| tab.id == id)
}
#[must_use]
pub fn tab_info(&self) -> Vec<(TabId, &str, bool)> {
self.tabs
.iter()
.enumerate()
.map(|(i, tab)| (tab.id, tab.label.as_str(), i == self.active_index))
.collect()
}
#[must_use]
pub fn active_windows(&self) -> &WindowLayout {
&self.tabs[self.active_index].windows
}
pub fn active_windows_mut(&mut self) -> &mut WindowLayout {
&mut self.tabs[self.active_index].windows
}
#[must_use]
pub fn active_compositor(&self) -> &Option<Box<dyn RootCompositor>> {
&self.tabs[self.active_index].compositor
}
pub fn active_compositor_mut(&mut self) -> &mut Option<Box<dyn RootCompositor>> {
&mut self.tabs[self.active_index].compositor
}
}
impl Default for TabPageSet {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
#[path = "tab_tests.rs"]
mod tests;