1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
use crate::interactive::{
react::Component,
widgets::{
Entries, Header, ListState, ReactFooter, ReactFooterProps, ReactHelpPane,
ReactHelpPaneProps,
},
FocussedPane, TerminalApp,
};
use dua::traverse::Traversal;
use std::borrow::Borrow;
use tui::style::{Color, Style};
use tui::{
buffer::Buffer,
layout::{Constraint, Direction, Layout, Rect},
style::Modifier,
widgets::Widget,
};
/// The state that can be mutated while drawing
/// This is easiest compared to alternatives, but at least it's restricted to a subset of the state
#[derive(Default, Clone)] // TODO: remove Clone derive
pub struct DrawState {
entries_list: ListState,
}
#[derive(Default, Clone)] // TODO: remove clone derive
pub struct ReactMainWindow {
pub draw_state: DrawState,
pub help_pane: Option<ReactHelpPane>,
}
impl<'a, 'b> Component for ReactMainWindow {
type Props = TerminalApp;
fn render(&mut self, props: impl Borrow<TerminalApp>, area: Rect, buf: &mut Buffer) {
let TerminalApp {
traversal:
Traversal {
tree,
entries_traversed,
total_bytes,
..
},
display,
state,
..
} = props.borrow();
let draw_state = &mut self.draw_state;
let regions = Layout::default()
.direction(Direction::Vertical)
.constraints(
[
Constraint::Length(1),
Constraint::Max(256),
Constraint::Length(1),
]
.as_ref(),
)
.split(area);
let (header_area, entries_area, footer_area) = (regions[0], regions[1], regions[2]);
let (entries_area, help_pane) = match self.help_pane {
Some(ref mut pane) => {
let regions = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(entries_area);
(regions[0], Some((regions[1], pane)))
}
None => (entries_area, None),
};
let grey = Style {
fg: Color::DarkGray,
bg: Color::Reset,
modifier: Modifier::empty(),
};
let white = Style {
fg: Color::White,
..grey
};
let (entries_style, help_style) = match state.focussed {
FocussedPane::Main => (white, grey),
FocussedPane::Help => (grey, white),
};
Header.draw(header_area, buf);
Entries {
tree: &tree,
root: state.root,
display: *display,
entries: &state.entries,
selected: state.selected,
border_style: entries_style,
list_state: &mut draw_state.entries_list,
is_focussed: if let FocussedPane::Main = state.focussed {
true
} else {
false
},
}
.draw(entries_area, buf);
if let Some((help_area, pane)) = help_pane {
let props = ReactHelpPaneProps {
border_style: help_style,
};
pane.render(props, help_area, buf);
}
ReactFooter.render(
ReactFooterProps {
total_bytes: *total_bytes,
entries_traversed: *entries_traversed,
format: display.byte_format,
message: state.message.clone(),
},
footer_area,
buf,
);
}
}
|