1use crate::callback::{Callback, KeyHandler};
4use crate::core::event::KeyCode;
5use crate::core::event::KeyEvent;
6use crate::style::{Length, Style, StyleSlot};
7use crate::utils::gradient::ColorGradient;
8use crate::widgets::ScrollKeymap;
9use crate::widgets::{FocusAccordion, ListItem};
10use std::sync::Arc;
11
12#[derive(Clone, Debug, PartialEq, Eq, Hash)]
14pub struct TreePath(pub(crate) Arc<[usize]>);
15
16impl TreePath {
17 pub fn segments(&self) -> &[usize] {
19 &self.0
20 }
21}
22
23impl From<Vec<usize>> for TreePath {
24 fn from(value: Vec<usize>) -> Self {
25 Self(value.into())
26 }
27}
28
29impl AsRef<[usize]> for TreePath {
30 fn as_ref(&self) -> &[usize] {
31 &self.0
32 }
33}
34
35#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct TreeEvent {
38 pub index: usize,
40 pub path: TreePath,
42}
43
44#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct TreeToggleEvent {
47 pub index: usize,
49 pub path: TreePath,
51 pub expanded: bool,
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
57pub struct TreeKeymap(u8);
58
59impl TreeKeymap {
60 pub const NONE: Self = Self(0);
62 pub const ARROWS: Self = Self(1 << 0);
64 pub const VIM: Self = Self(1 << 1);
66 pub const TOGGLE: Self = Self(1 << 2);
68 pub const DEFAULT: Self = Self(Self::ARROWS.0 | Self::VIM.0 | Self::TOGGLE.0);
70
71 pub fn contains(self, other: Self) -> bool {
73 (self.0 & other.0) == other.0
74 }
75}
76
77impl std::ops::BitOr for TreeKeymap {
78 type Output = Self;
79
80 fn bitor(self, rhs: Self) -> Self {
81 Self(self.0 | rhs.0)
82 }
83}
84
85impl std::ops::BitOrAssign for TreeKeymap {
86 fn bitor_assign(&mut self, rhs: Self) {
87 self.0 |= rhs.0;
88 }
89}
90
91impl std::ops::BitAnd for TreeKeymap {
92 type Output = Self;
93
94 fn bitand(self, rhs: Self) -> Self {
95 Self(self.0 & rhs.0)
96 }
97}
98
99impl std::ops::BitAndAssign for TreeKeymap {
100 fn bitand_assign(&mut self, rhs: Self) {
101 self.0 &= rhs.0;
102 }
103}
104
105impl std::ops::Not for TreeKeymap {
106 type Output = Self;
107
108 fn not(self) -> Self {
109 Self(!self.0)
110 }
111}
112
113impl Default for TreeKeymap {
114 fn default() -> Self {
115 Self::DEFAULT
116 }
117}
118
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub(crate) enum TreeAction {
121 Expand,
122 Collapse,
123 Toggle,
124}
125
126pub(crate) fn tree_action_from_key(key: &KeyEvent, keymap: TreeKeymap) -> Option<TreeAction> {
127 match key.code {
128 KeyCode::Left if keymap.contains(TreeKeymap::ARROWS) => Some(TreeAction::Collapse),
129 KeyCode::Right if keymap.contains(TreeKeymap::ARROWS) => Some(TreeAction::Expand),
130 KeyCode::Char('h') if keymap.contains(TreeKeymap::VIM) => Some(TreeAction::Collapse),
131 KeyCode::Char('l') if keymap.contains(TreeKeymap::VIM) => Some(TreeAction::Expand),
132 KeyCode::Char(' ') if keymap.contains(TreeKeymap::TOGGLE) => Some(TreeAction::Toggle),
133 _ => None,
134 }
135}
136
137#[derive(Clone, Debug, PartialEq, Eq)]
139pub struct TreeNode {
140 pub(crate) item: ListItem,
141 pub(crate) children: Vec<TreeNode>,
142 pub(crate) expanded: bool,
143 pub(crate) indent: u16,
144 pub(crate) leading_guide_fill_cells: u16,
145}
146
147impl TreeNode {
148 pub fn new(item: impl Into<ListItem>) -> Self {
150 Self {
151 item: item.into(),
152 children: Vec::new(),
153 expanded: false,
154 indent: 2,
155 leading_guide_fill_cells: 0,
156 }
157 }
158
159 pub fn child(mut self, child: TreeNode) -> Self {
161 self.children.push(child);
162 self
163 }
164
165 pub fn children(mut self, children: impl IntoIterator<Item = TreeNode>) -> Self {
167 self.children = children.into_iter().collect();
168 self
169 }
170
171 pub fn expanded(mut self, expanded: bool) -> Self {
173 self.expanded = expanded;
174 self
175 }
176
177 pub fn indent(mut self, indent: u16) -> Self {
179 self.indent = indent;
180 self
181 }
182
183 pub(crate) fn leading_guide_fill_cells(mut self, cells: u16) -> Self {
184 self.leading_guide_fill_cells = cells;
185 self
186 }
187}
188
189#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
191pub enum IndentStyle {
192 #[default]
194 None,
195 Line,
197 Short,
199 ShortRounded,
201 Long,
203 LongRounded,
205}
206
207#[derive(Clone, PartialEq)]
208pub(crate) struct TreeProps {
209 pub root: TreeNode,
210 pub selected: Option<usize>,
211 pub force_scroll_to_selected: bool,
212 pub gap: u16,
213 pub icon_gap: u16,
214 pub show_icons: bool,
215 pub expanded_icon: Arc<str>,
216 pub collapsed_icon: Arc<str>,
217 pub leaf_icon: Option<Arc<str>>,
218 pub icon_style: Style,
219 pub width: Length,
220 pub height: Length,
221 pub style: Style,
222 pub hover_style: StyleSlot,
223 pub item_hover_style: StyleSlot,
224 pub selection_style: StyleSlot,
225 pub unfocused_selection_style: StyleSlot,
226 pub selection_symbol: Option<Arc<str>>,
227 pub selection_symbol_style: Option<Style>,
228 pub unfocused_selection_symbol_style: Option<Style>,
229 pub scrollbar: bool,
230 pub scrollbar_config: crate::style::ScrollbarConfig,
231 pub scroll_keys: ScrollKeymap,
232 pub scroll_wheel: bool,
233 pub show_scroll_indicators: bool,
234 pub scroll_indicator_style: Style,
235 pub empty_text: Option<Arc<str>>,
236 pub empty_text_style: Style,
237 pub activate_on_click: bool,
238 pub focusable: bool,
239 pub on_select: Option<Callback<TreeEvent>>,
240 pub on_activate: Option<Callback<TreeEvent>>,
241 pub on_toggle: Option<Callback<TreeToggleEvent>>,
242 pub keymap: TreeKeymap,
243 pub focus_policy: Option<FocusAccordion>,
244 pub indent_style: IndentStyle,
245 pub indent_guide_style: Style,
246 pub indent_gradient: Option<ColorGradient>,
247 pub(crate) solid_indent_connector_gap: bool,
248 pub selection_full_width: bool,
249 pub unselected_symbol: Option<Arc<str>>,
250 pub key_interceptor: Option<KeyHandler>,
251}