|
|
|
@ -16,11 +16,7 @@ use tui::{
|
|
|
|
|
};
|
|
|
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
|
|
|
|
|
|
pub fn draw<B: Backend>(
|
|
|
|
|
f: &mut Frame<'_, B>,
|
|
|
|
|
app: &mut App,
|
|
|
|
|
table: &mut StatefulTable,
|
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
|
pub fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) -> anyhow::Result<()> {
|
|
|
|
|
let main_chunks = Layout::default()
|
|
|
|
|
.direction(Direction::Vertical)
|
|
|
|
|
.margin(2)
|
|
|
|
@ -78,72 +74,31 @@ pub fn draw<B: Backend>(
|
|
|
|
|
|
|
|
|
|
let right_chunks = Layout::default()
|
|
|
|
|
.direction(Direction::Vertical)
|
|
|
|
|
.constraints(
|
|
|
|
|
[
|
|
|
|
|
Constraint::Length(1),
|
|
|
|
|
Constraint::Length(3),
|
|
|
|
|
Constraint::Min(1),
|
|
|
|
|
]
|
|
|
|
|
.as_ref(),
|
|
|
|
|
)
|
|
|
|
|
.constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
|
|
|
|
|
.split(main_chunks[1]);
|
|
|
|
|
|
|
|
|
|
let (msg, style) = match app.input_mode {
|
|
|
|
|
InputMode::Normal => (
|
|
|
|
|
vec![
|
|
|
|
|
Span::raw("Press "),
|
|
|
|
|
Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
|
|
|
|
|
Span::raw(" to exit, "),
|
|
|
|
|
Span::styled("e", Style::default().add_modifier(Modifier::BOLD)),
|
|
|
|
|
Span::raw(" to start editing."),
|
|
|
|
|
],
|
|
|
|
|
Style::default().add_modifier(Modifier::RAPID_BLINK),
|
|
|
|
|
),
|
|
|
|
|
InputMode::Editing => (
|
|
|
|
|
vec![
|
|
|
|
|
Span::raw("Press "),
|
|
|
|
|
Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD)),
|
|
|
|
|
Span::raw(" to stop editing, "),
|
|
|
|
|
Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)),
|
|
|
|
|
Span::raw(" to record the message"),
|
|
|
|
|
],
|
|
|
|
|
Style::default(),
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
let mut text = Text::from(Spans::from(msg));
|
|
|
|
|
text.patch_style(style);
|
|
|
|
|
let help_message = Paragraph::new(text);
|
|
|
|
|
f.render_widget(help_message, right_chunks[0]);
|
|
|
|
|
|
|
|
|
|
let input = Paragraph::new(app.input.as_ref())
|
|
|
|
|
.style(match app.input_mode {
|
|
|
|
|
InputMode::Normal => Style::default(),
|
|
|
|
|
InputMode::Editing => Style::default().fg(Color::Yellow),
|
|
|
|
|
})
|
|
|
|
|
.block(Block::default().borders(Borders::ALL).title("Input"));
|
|
|
|
|
f.render_widget(input, right_chunks[1]);
|
|
|
|
|
.block(Block::default().borders(Borders::ALL).title("Query"));
|
|
|
|
|
f.render_widget(input, right_chunks[0]);
|
|
|
|
|
match app.input_mode {
|
|
|
|
|
InputMode::Normal =>
|
|
|
|
|
// Hide the cursor. `Frame` does this by default, so we don't need to do anything here
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
InputMode::Editing => {
|
|
|
|
|
// Make the cursor visible and ask tui-rs to put it at the specified coordinates after rendering
|
|
|
|
|
f.set_cursor(
|
|
|
|
|
// Put cursor past the end of the input text
|
|
|
|
|
right_chunks[1].x + app.input.width() as u16 + 1,
|
|
|
|
|
// Move one line down, from the border to the input line
|
|
|
|
|
right_chunks[1].y + 1,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
InputMode::Normal => (),
|
|
|
|
|
InputMode::Editing => f.set_cursor(
|
|
|
|
|
right_chunks[0].x + app.input.width() as u16 + 1,
|
|
|
|
|
right_chunks[0].y + 1,
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let header_cells = table
|
|
|
|
|
let header_cells = app
|
|
|
|
|
.record_table
|
|
|
|
|
.headers
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|h| Cell::from(h.to_string()).style(Style::default().fg(Color::White)));
|
|
|
|
|
let header = Row::new(header_cells).height(1).bottom_margin(1);
|
|
|
|
|
let rows = table.items.iter().map(|item| {
|
|
|
|
|
let rows = app.record_table.rows.iter().map(|item| {
|
|
|
|
|
let height = item
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|content| content.chars().filter(|c| *c == '\n').count())
|
|
|
|
@ -155,6 +110,17 @@ pub fn draw<B: Backend>(
|
|
|
|
|
.map(|c| Cell::from(c.to_string()).style(Style::default().fg(Color::White)));
|
|
|
|
|
Row::new(cells).height(height as u16).bottom_margin(1)
|
|
|
|
|
});
|
|
|
|
|
let widths = (0..app.record_table.headers.len() + 1)
|
|
|
|
|
.map(|idx| {
|
|
|
|
|
if idx >= app.record_table.column_index as usize
|
|
|
|
|
&& idx <= app.record_table.column_index as usize + 9
|
|
|
|
|
{
|
|
|
|
|
Constraint::Percentage(10)
|
|
|
|
|
} else {
|
|
|
|
|
Constraint::Percentage(0)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.collect::<Vec<Constraint>>();
|
|
|
|
|
let t = Table::new(rows)
|
|
|
|
|
.header(header)
|
|
|
|
|
.block(Block::default().borders(Borders::ALL).title("Records"))
|
|
|
|
@ -164,19 +130,8 @@ pub fn draw<B: Backend>(
|
|
|
|
|
FocusType::Records(true) => Style::default().fg(Color::Green),
|
|
|
|
|
_ => Style::default(),
|
|
|
|
|
})
|
|
|
|
|
.widths(&[
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
Constraint::Percentage(10),
|
|
|
|
|
]);
|
|
|
|
|
f.render_stateful_widget(t, right_chunks[2], &mut table.state);
|
|
|
|
|
.widths(&widths);
|
|
|
|
|
f.render_stateful_widget(t, right_chunks[1], &mut app.record_table.state);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|