cursive_tree/view/
view.rs1use super::{
2 super::{backend::*, model::*},
3 tree::*,
4};
5
6use cursive::{direction::*, event::*, theme::*, view::*, *};
7
8const TYPE_NAME: &str = "TreeView";
9
10impl<BackendT> View for TreeView<BackendT>
11where
12 BackendT: 'static + TreeBackend + Send + Sync,
13 BackendT::Context: Clone + Send + Sync,
14 BackendT::Error: Send + Sync,
15 BackendT::ID: Send + Sync,
16 BackendT::Data: Send + Sync,
17{
18 fn type_name(&self) -> &'static str {
19 TYPE_NAME
20 }
21
22 fn take_focus(&mut self, _source: Direction) -> Result<EventResult, CannotFocus> {
23 if self.model.is_empty() { Err(CannotFocus) } else { Ok(EventResult::consumed()) }
24 }
25
26 fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
27 self.model.extents()
28 }
29
30 fn important_area(&self, view_size: Vec2) -> Rect {
31 if let Some(selected_row) = self.selected_row {
32 Rect::from_size((0, selected_row), (view_size.x, 1))
33 } else {
34 Rect::from_size((0, 0), view_size)
35 }
36 }
37
38 fn on_event(&mut self, event: Event) -> EventResult {
39 let selected_row = self.selected_row;
40
41 match event {
42 Event::Key(Key::Up) => self.move_selection(-1),
43 Event::Key(Key::Down) => self.move_selection(1),
44 Event::Key(Key::PageUp) => self.move_selection(-(self.page as isize)),
45 Event::Key(Key::PageDown) => self.move_selection(self.page as isize),
46 Event::Key(Key::Home) => self.select_top(),
47 Event::Key(Key::End) => self.select_bottom(),
48
49 Event::Key(Key::Left) => {
50 if let Some(node) = self.selected_node_mut() {
51 node.collapse(Some(1));
52 }
53 }
54
55 Event::Key(Key::Right) => {
56 let context = self.model.context.clone();
57 if let Some(node) = self.selected_node_mut() {
58 return Self::on_expand_branch(node, Some(1), context);
59 }
60 }
61
62 Event::Char('-') => {
63 if let Some(node) = self.selected_node_mut() {
64 node.collapse(None);
65 }
66 }
67
68 Event::Char('+') => {
69 let context = self.model.context.clone();
70 if let Some(node) = self.selected_node_mut() {
71 return Self::on_expand_branch(node, None, context);
72 }
73 }
74
75 Event::Key(Key::Enter) => {
76 let context = self.model.context.clone();
77 if let Some(node) = self.selected_node_mut() {
78 return Self::on_toggle_branch_state(node, context);
79 }
80 }
81
82 Event::Mouse { offset, position, event: MouseEvent::Press(_) } => {
83 self.selected_row = if let Some(position) = position.checked_sub(offset)
84 && let Some(node) = self.model.at_row(position.y)
85 {
86 if node.kind.is_branch() && (position.x < node.depth * 2 + 2) {
87 let context = self.model.context.clone();
89 if let Some(path) = self.model.path(node)
90 && let Some(node) = self.model.at_path_mut(path)
91 {
92 return Self::on_toggle_branch_state(node, context);
93 } else {
94 None
95 }
96 } else {
97 Some(position.y)
99 }
100 } else {
101 None
102 };
103 }
104
105 _ => return EventResult::Ignored,
106 }
107
108 EventResult::Consumed(if self.selected_row != selected_row {
109 Some(Callback::from_fn_once(|cursive| {
111 BackendT::handle_selection_changed(cursive);
112 }))
113 } else {
114 None
115 })
116 }
117
118 fn draw(&self, printer: &Printer) {
119 let mut start = Vec2::default();
120 for node in self.model.iter(true) {
121 if start.y >= printer.offset.y + printer.size.y {
122 break;
124 }
125
126 if start.y >= printer.content_offset.y {
128 start.x = node.depth * 2;
131 match node.symbol(self.model.context.clone()) {
132 Symbol::Representation(symbol) => printer.print_styled(start, &symbol),
133 Symbol::String(symbol) => printer.print(start, symbol),
134 };
135 start.x += 2;
136
137 let mut representation = &node.representation;
140
141 let debug_representation = if self.debug
142 && let Some(path) = self.model.path(node)
143 {
144 let path: Vec<_> = path.into_iter().map(|i| i.to_string()).collect();
145 let mut representation = representation.clone();
146 representation.append(format!(" {}", path.join(".")));
147 Some(representation)
148 } else {
149 None
150 };
151
152 if let Some(debug_representation) = &debug_representation {
153 representation = debug_representation;
154 }
155
156 let highlight = if self.is_selected(start.y) {
157 Some(if printer.focused { PaletteStyle::Highlight } else { PaletteStyle::HighlightInactive })
158 } else {
159 None
160 };
161
162 let print = |printer: &Printer| printer.print_styled(start, representation);
163
164 match highlight {
165 Some(highlight) => printer.with_style(highlight, print),
166 None => print(printer),
167 }
168 }
169
170 start.y += node.representation_size.y;
171 }
172 }
173}