1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7use crate::node::{ActionId, Common, IntoNode, Key, Node};
8use crate::style::Style;
9use crate::text::{Line, Span};
10
11#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
13#[serde(rename_all = "camelCase")]
14pub struct TabTitle {
15 pub key: Key,
17 pub title: Line,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub badge: Option<Line>,
22}
23
24impl TabTitle {
25 #[must_use]
27 pub fn new(key: impl Into<Key>, title: impl Into<Line>) -> Self {
28 Self {
29 key: key.into(),
30 title: title.into(),
31 badge: None,
32 }
33 }
34
35 #[must_use]
37 pub fn badge(mut self, badge: impl Into<Line>) -> Self {
38 self.badge = Some(badge.into());
39 self
40 }
41}
42
43#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
46#[serde(rename_all = "camelCase")]
47pub struct Tabs {
48 #[serde(flatten)]
50 pub common: Common,
51 pub titles: Vec<TabTitle>,
53 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub selected: Option<Key>,
56 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub divider: Option<Span>,
59 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub padding: Option<[Line; 2]>,
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub highlight_style: Option<Style>,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
67 pub panes: Option<BTreeMap<Key, Node>>,
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub on_select: Option<ActionId>,
71}
72
73impl Tabs {
74 #[must_use]
76 pub fn new(titles: impl IntoIterator<Item = TabTitle>) -> Self {
77 Self {
78 titles: titles.into_iter().collect(),
79 ..Self::default()
80 }
81 }
82
83 #[must_use]
85 pub fn selected(mut self, key: impl Into<Key>) -> Self {
86 self.selected = Some(key.into());
87 self
88 }
89
90 #[must_use]
92 pub fn divider(mut self, divider: impl Into<Span>) -> Self {
93 self.divider = Some(divider.into());
94 self
95 }
96
97 #[must_use]
99 pub fn padding(mut self, padding: [Line; 2]) -> Self {
100 self.padding = Some(padding);
101 self
102 }
103
104 #[must_use]
106 pub fn highlight_style(mut self, style: Style) -> Self {
107 self.highlight_style = Some(style);
108 self
109 }
110
111 #[must_use]
113 pub fn panes(mut self, panes: impl IntoIterator<Item = (Key, impl IntoNode)>) -> Self {
114 self.panes = Some(panes.into_iter().map(|(k, n)| (k, n.into_node())).collect());
115 self
116 }
117
118 #[must_use]
120 pub fn on_select(mut self, action: impl Into<ActionId>) -> Self {
121 self.on_select = Some(action.into());
122 self
123 }
124}
125
126impl IntoNode for Tabs {}
127impl From<Tabs> for Node {
128 fn from(t: Tabs) -> Self {
129 Node::Tabs(t)
130 }
131}