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