Skip to main content

cursive_tree/view/
view.rs

1use super::{
2    super::{backend::*, model::*},
3    actions::*,
4    tree::*,
5};
6
7use cursive::{direction::*, event::*, theme::*, view::*, *};
8
9const TYPE_NAME: &str = "TreeView";
10
11impl<BackendT> View for TreeView<BackendT>
12where
13    BackendT: 'static + TreeBackend + Send + Sync,
14    BackendT::Context: Clone + Send + Sync,
15    BackendT::Error: Send + Sync,
16    BackendT::ID: Send + Sync,
17    BackendT::Data: Send + Sync,
18{
19    fn type_name(&self) -> &'static str {
20        TYPE_NAME
21    }
22
23    fn take_focus(&mut self, _source: Direction) -> Result<EventResult, CannotFocus> {
24        if self.model.is_empty() { Err(CannotFocus) } else { Ok(EventResult::consumed()) }
25    }
26
27    fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
28        self.model.extents()
29    }
30
31    fn important_area(&self, view_size: Vec2) -> Rect {
32        if let Some(selected_row) = self.selected_row {
33            Rect::from_size((0, selected_row), (view_size.x, 1))
34        } else {
35            Rect::from_size((0, 0), view_size)
36        }
37    }
38
39    fn on_event(&mut self, event: Event) -> EventResult {
40        let selected_row = self.selected_row;
41
42        match self.actions.get(&event) {
43            Some(action) => match action {
44                Action::SelectTop => self.select_top(),
45                Action::SelectUp => self.move_selection(-1),
46                Action::SelectUpPage => self.move_selection(-(self.page as isize)),
47                Action::SelectBottom => self.select_bottom(),
48                Action::SelectDown => self.move_selection(1),
49                Action::SelectDownPage => self.move_selection(self.page as isize),
50
51                Action::Expand => {
52                    let context = self.model.context.clone();
53                    if let Some(node) = self.selected_node_mut() {
54                        return Self::on_expand_branch(node, Some(1), context);
55                    }
56                }
57
58                Action::ExpandRecursive => {
59                    let context = self.model.context.clone();
60                    if let Some(node) = self.selected_node_mut() {
61                        return Self::on_expand_branch(node, None, context);
62                    }
63                }
64
65                Action::ExpandAll => {
66                    self.selected_row = None; // TODO: keep the selected node?
67                    return self.on_expand_all();
68                }
69
70                Action::Collapse => {
71                    if let Some(node) = self.selected_node_mut() {
72                        node.collapse(Some(1));
73                    }
74                }
75
76                Action::CollapseRecursive => {
77                    if let Some(node) = self.selected_node_mut() {
78                        node.collapse(None);
79                    }
80                }
81
82                Action::CollapseAll => {
83                    self.selected_row = None; // TODO: keep the selected node?
84                    self.model.collapse(None);
85                }
86
87                Action::ToggleState => {
88                    let context = self.model.context.clone();
89                    if let Some(node) = self.selected_node_mut() {
90                        return Self::on_toggle_branch_state(node, context);
91                    }
92                }
93            },
94
95            None => {
96                match event {
97                    Event::Mouse { offset, position, event: MouseEvent::Press(_) } => {
98                        self.selected_row = if let Some(position) = position.checked_sub(offset)
99                            && let Some(node) = self.model.at_row(position.y)
100                        {
101                            if node.kind.is_branch() && (position.x < node.depth * 2 + 2) {
102                                // If we click to the left of the representation then toggle state
103                                let context = self.model.context.clone();
104                                if let Some(path) = self.model.path(node)
105                                    && let Some(node) = self.model.at_path_mut(path)
106                                {
107                                    return Self::on_toggle_branch_state(node, context);
108                                } else {
109                                    None
110                                }
111                            } else {
112                                // Otherwise just select
113                                Some(position.y)
114                            }
115                        } else {
116                            None
117                        };
118                    }
119
120                    _ => return EventResult::Ignored,
121                }
122            }
123        }
124
125        EventResult::Consumed(if self.selected_row != selected_row {
126            // Selection has changed
127            Some(Callback::from_fn_once(BackendT::handle_selection_changed))
128        } else {
129            None
130        })
131    }
132
133    fn draw(&self, printer: &Printer) {
134        let mut start = Vec2::default();
135        for node in self.model.iter(true) {
136            if start.y >= printer.offset.y + printer.size.y {
137                // We're beyond the print area
138                break;
139            }
140
141            // Start printing only when we're within the print area
142            if start.y >= printer.content_offset.y {
143                // Symbol
144
145                start.x = node.depth * 2;
146                match node.symbol(self.model.context.clone()) {
147                    Symbol::Representation(symbol) => printer.print_styled(start, &symbol),
148                    Symbol::String(symbol) => printer.print(start, symbol),
149                };
150                start.x += 2;
151
152                // Representation
153
154                let mut representation = &node.representation;
155
156                let debug_representation = if self.debug
157                    && let Some(path) = self.model.path(node)
158                {
159                    let path: Vec<_> = path.into_iter().map(|i| i.to_string()).collect();
160                    let mut representation = representation.clone();
161                    representation.append(format!(" {}", path.join(".")));
162                    Some(representation)
163                } else {
164                    None
165                };
166
167                if let Some(debug_representation) = &debug_representation {
168                    representation = debug_representation;
169                }
170
171                let highlight = if self.is_selected(start.y) {
172                    Some(if printer.focused { PaletteStyle::Highlight } else { PaletteStyle::HighlightInactive })
173                } else {
174                    None
175                };
176
177                let print = |printer: &Printer| printer.print_styled(start, representation);
178
179                match highlight {
180                    Some(highlight) => printer.with_style(highlight, print),
181                    None => print(printer),
182                }
183            }
184
185            start.y += node.representation_size.y;
186        }
187    }
188}