cursive_tree/view/
tree.rs1use super::super::{backend::*, model::*};
2
3use cursive::{direction::*, event::*, theme::*, view::*, *};
4
5const TYPE_NAME: &str = "TreeView";
6
7pub struct TreeView<BackendT, ContextT, ErrorT, IdT, DataT> {
30 pub model: TreeModel<BackendT, ContextT, ErrorT, IdT, DataT>,
32
33 pub selected_row: Option<usize>,
35
36 pub page: usize,
38
39 pub debug: bool,
41}
42
43impl<BackendT, ContextT, ErrorT, IdT, DataT> View for TreeView<BackendT, ContextT, ErrorT, IdT, DataT>
44where
45 BackendT: 'static + TreeBackend<ContextT, ErrorT, IdT, DataT> + Send + Sync,
46 ContextT: 'static + Clone + Send + Sync,
47 ErrorT: 'static + Send + Sync,
48 IdT: 'static + Send + Sync,
49 DataT: 'static + Send + Sync,
50{
51 fn type_name(&self) -> &'static str {
52 TYPE_NAME
53 }
54
55 fn take_focus(&mut self, _source: Direction) -> Result<EventResult, CannotFocus> {
56 if self.model.is_empty() { Err(CannotFocus) } else { Ok(EventResult::consumed()) }
57 }
58
59 fn required_size(&mut self, _constraint: XY<usize>) -> XY<usize> {
60 self.model.size()
61 }
62
63 fn important_area(&self, view_size: XY<usize>) -> Rect {
64 if let Some(selected_row) = self.selected_row {
65 Rect::from_size((0, selected_row), (view_size.x, selected_row))
66 } else {
67 Rect::from_size((0, 0), view_size)
68 }
69 }
70
71 fn on_event(&mut self, event: Event) -> EventResult {
72 let selected_row = self.selected_row;
73
74 match event {
75 Event::Key(Key::Up) => self.move_selection(-1),
76 Event::Key(Key::Down) => self.move_selection(1),
77 Event::Key(Key::PageUp) => self.move_selection(-(self.page as isize)),
78 Event::Key(Key::PageDown) => self.move_selection(self.page as isize),
79 Event::Key(Key::Home) => self.select_top(),
80 Event::Key(Key::End) => self.select_bottom(),
81
82 Event::Key(Key::Left) => {
83 if let Some(node) = self.selected_node_mut()
84 && node.kind.is_branch()
85 {
86 node.collapse_branch();
87 }
88 }
89
90 Event::Key(Key::Right) => {
91 let context = self.model.context.clone();
92 if let Some(node) = self.selected_node_mut()
93 && node.kind.is_branch()
94 {
95 return Self::expand_branch(node, context);
96 }
97 }
98
99 Event::Key(Key::Enter) => {
100 let context = self.model.context.clone();
101 if let Some(node) = self.selected_node_mut()
102 && node.kind.is_branch()
103 {
104 return Self::toggle_branch_state(node, context);
105 }
106 }
107
108 Event::Mouse { offset, position, event: MouseEvent::Press(_) } => {
109 self.selected_row = if let Some(position) = position.checked_sub(offset)
110 && let Some(node) = self.model.at_row(position.y)
111 {
112 if node.kind.is_branch() && (position.x < node.depth * 2 + 2) {
113 let context = self.model.context.clone();
115 if let Some(path) = self.model.path(node)
116 && let Some(node) = self.model.at_path_mut(path)
117 {
118 return Self::toggle_branch_state(node, context);
119 } else {
120 None
121 }
122 } else {
123 Some(position.y)
125 }
126 } else {
127 None
128 };
129 }
130
131 _ => return EventResult::Ignored,
132 }
133
134 EventResult::Consumed(if self.selected_row != selected_row {
135 Some(Callback::from_fn_once(|cursive| {
137 BackendT::handle_selection_changed(cursive);
138 }))
139 } else {
140 None
141 })
142 }
143
144 fn draw(&self, printer: &Printer) {
145 let mut start = XY::<usize>::default();
146 for node in self.model.iter(true) {
147 start.x = node.depth * 2;
150 match node.symbol(self.model.context.clone()) {
151 Symbol::Representation(symbol) => printer.print_styled(start, &symbol),
152 Symbol::String(symbol) => printer.print(start, symbol),
153 };
154 start.x += 2;
155
156 let mut representation = &node.representation;
159
160 let debug_representation = if self.debug
161 && let Some(path) = self.model.path(node)
162 {
163 let path: Vec<_> = path.into_iter().map(|i| i.to_string()).collect();
164 let mut representation = representation.clone();
165 representation.append(format!(" {}", path.join(".")));
166 Some(representation)
167 } else {
168 None
169 };
170
171 if let Some(debug_representation) = &debug_representation {
172 representation = debug_representation;
173 }
174
175 let highlight = if self.is_selected(start.y) {
176 Some(if printer.focused { PaletteStyle::Highlight } else { PaletteStyle::HighlightInactive })
177 } else {
178 None
179 };
180
181 let print = |printer: &Printer| printer.print_styled(start, representation);
182
183 match highlight {
184 Some(highlight) => printer.with_style(highlight, print),
185 None => print(printer),
186 }
187
188 start.y += node.representation_size.y;
189 }
190 }
191}
192
193impl<BackendT, ContextT, ErrorT, IdT, DataT> From<TreeModel<BackendT, ContextT, ErrorT, IdT, DataT>>
194 for TreeView<BackendT, ContextT, ErrorT, IdT, DataT>
195{
196 fn from(model: TreeModel<BackendT, ContextT, ErrorT, IdT, DataT>) -> Self {
197 Self { model, selected_row: None, page: 10, debug: false }
198 }
199}