use super::{TabIter, TabIterMut};
use std::cmp::min;
use cursive_core::{
Printer, Vec2, View, Rect,
views::BoxedView,
direction::Direction,
event::{AnyCb, Event, EventResult},
view::{CannotFocus, Selector, ViewNotFound}
};
pub struct TabContainer {
tabs: Vec<(usize, BoxedView)>,
focused_id: Option<usize>
}
impl TabContainer {
#[must_use]
pub fn new() -> TabContainer {
TabContainer {
tabs: vec![],
focused_id: None
}
}
pub fn cur_id(&self) -> Option<usize> { self.focused_id }
pub fn cur_view(&self) -> Option<&BoxedView> {
if let Some(focused) = self.focused_id {
self.get_view(focused)
}
else { None }
}
pub fn cur_view_mut(&mut self) -> Option<&mut BoxedView> {
if let Some(focused) = self.focused_id {
self.get_view_mut(focused)
}
else { None }
}
pub fn get_view(&self, id: usize) -> Option<&BoxedView> {
for (view_id, view) in &self.tabs {
if id == *view_id { return Some(view); }
}
None
}
pub fn get_view_mut(&mut self, id: usize) -> Option<&mut BoxedView> {
for (view_id, view) in &mut self.tabs {
if id == *view_id { return Some(view); }
}
None
}
pub fn views(&self) -> TabIter { self.tabs.iter() }
pub fn views_mut(&mut self) -> TabIterMut { self.tabs.iter_mut() }
pub fn ids(&self) -> Vec<usize> {
let mut ids = self.views().map(|(id, _)| *id).collect::<Vec<_>>();
ids.sort_unstable();
ids
}
pub fn set_cur_tab(&mut self, id: usize) {
if self.get_view(id).is_some() {
self.focused_id = Some(id)
}
}
pub fn add_tab<V: View>(&mut self, view: V) -> usize {
if self.tabs.is_empty() {
self.tabs.push((0, BoxedView::boxed(view)));
0
}
else {
let new_id = self.ids().last().unwrap() + 1;
self.tabs.push((new_id, BoxedView::boxed(view)));
new_id
}
}
#[must_use]
pub fn tab<V: View>(mut self, view: V) -> TabContainer {
self.add_tab(view);
self.set_cur_tab(0);
self
}
pub fn remove_tab(&mut self, id: usize) {
self.tabs.retain(|(v_id, _)| *v_id != id);
if self.tabs.is_empty() {
self.focused_id = None;
}
else {
let last_id = self.tabs.last().unwrap().0;
self.set_cur_tab(last_id);
}
}
pub fn swap_tabs(&mut self, id_1: usize, id_2: usize) {
if let Some(idx_1) = self.find_tab_idx(id_1) {
if let Some(idx_2) = self.find_tab_idx(id_2) {
self.tabs.swap(idx_1, idx_2);
}
}
}
pub fn next(&mut self) {
if let Some(focused) = self.focused_id {
let idx = self.find_tab_idx(focused).unwrap();
let mut new_idx = 0;
if idx < self.tabs.len() - 1 {
new_idx = idx + 1;
}
self.set_cur_tab(self.tabs[new_idx].0);
}
}
pub fn prev(&mut self) {
if let Some(focused) = self.focused_id {
let idx = self.find_tab_idx(focused).unwrap();
let mut new_idx = self.tabs.len() - 1;
if idx > 0 {
new_idx = idx - 1;
}
self.set_cur_tab(self.tabs[new_idx].0);
}
}
pub fn set_as_first(&mut self, id: usize) {
if let Some(idx) = self.find_tab_idx(id) {
let tab = self.tabs.remove(idx);
self.tabs.insert(0, tab);
}
}
pub fn set_as_last(&mut self, id: usize) {
if let Some(idx) = self.find_tab_idx(id) {
let tab = self.tabs.remove(idx);
self.tabs.push(tab);
}
}
fn find_tab_idx(&self, id: usize) -> Option<usize> {
for (i, (v_id, _)) in self.views().enumerate() {
if id == *v_id { return Some(i) }
}
None
}
}
impl View for TabContainer {
fn draw(&self, printer: &Printer) {
if let Some(view) = self.cur_view() {
view.draw(printer)
}
}
fn layout(&mut self, size: Vec2) {
if let Some(view) = self.cur_view_mut() {
view.layout(size);
}
}
fn required_size(&mut self, constraint: Vec2) -> Vec2 {
if let Some(view) = self.cur_view_mut() {
let tab_size = view.required_size(constraint);
Vec2::from((min(tab_size.x, constraint.x), min(tab_size.y, constraint.y)))
}
else { Vec2::from((1, 1)) }
}
fn on_event(&mut self, event: Event) -> EventResult {
if let Some(view) = self.cur_view_mut() { view.on_event(event) }
else { EventResult::Ignored }
}
fn take_focus(&mut self, dir: Direction) -> Result<EventResult, CannotFocus> {
if let Some(view) = self.cur_view_mut() { view.take_focus(dir) }
else { Err(CannotFocus) }
}
fn call_on_any(&mut self, sel: &Selector, cb: AnyCb) {
for (_, view) in self.views_mut() {
view.call_on_any(sel, cb);
}
}
fn focus_view(&mut self, sel: &Selector) -> Result<EventResult, ViewNotFound> {
if let Some(view) = self.cur_view_mut() { view.focus_view(sel) }
else { Err(ViewNotFound) }
}
fn needs_relayout(&self) -> bool {
if let Some(view) = self.cur_view() { view.needs_relayout() }
else { true }
}
fn important_area(&self, size: Vec2) -> Rect {
if let Some(view) = self.cur_view() { view.important_area(size) }
else { Rect::from_point((1, 1)) }
}
}
impl Default for TabContainer {
fn default() -> Self { Self::new() }
}