diff --git a/examples/list.rs b/examples/list.rs index 915d5ae..ea36a40 100644 --- a/examples/list.rs +++ b/examples/list.rs @@ -16,6 +16,12 @@ use tui::{ Terminal, }; +/// This struct holds the current state of the app. In particular, it has the `items` field which is a wrapper +/// around `ListState`. Keeping track of the items state let us render the associated widget with its state +/// and have access to features such as natural scrolling. +/// +/// Check the event handling at the bottom to see how to change the state on incoming events. +/// Check the drawing logic for items on how to specify the highlighting style for selected items. struct App<'a> { items: StatefulList<(&'a str, usize)>, events: Vec<(&'a str, &'a str)>, @@ -82,9 +88,11 @@ impl<'a> App<'a> { } } + /// Rotate through the event list. + /// This only exists to simulate some kind of "progress" fn advance(&mut self) { - let event = self.events.pop().unwrap(); - self.events.insert(0, event); + let event = self.events.remove(0); + self.events.push(event); } } @@ -98,16 +106,18 @@ fn main() -> Result<(), Box> { let events = Events::new(); - // App + // Create a new app with some exapmle state let mut app = App::new(); loop { terminal.draw(|f| { + // Create two chunks with equal horizontal screen space let chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) .split(f.size()); + // Iterate through all elements in the `items` app and append some debug text to it. let items: Vec = app .items .items @@ -123,6 +133,8 @@ fn main() -> Result<(), Box> { ListItem::new(lines).style(Style::default().fg(Color::Black).bg(Color::White)) }) .collect(); + + // Create a List from all list items and highlight the currently selected one let items = List::new(items) .block(Block::default().borders(Borders::ALL).title("List")) .highlight_style( @@ -131,12 +143,18 @@ fn main() -> Result<(), Box> { .add_modifier(Modifier::BOLD), ) .highlight_symbol(">> "); + + // We can now render the item list f.render_stateful_widget(items, chunks[0], &mut app.items.state); + // Let's do the same for the events. + // The event list doesn't have any state and only displays the current state of the list. let events: Vec = app .events .iter() - .map(|&(evt, level)| { + .rev() + .map(|&(event, level)| { + // Colorcode the level depending on its type let s = match level { "CRITICAL" => Style::default().fg(Color::Red), "ERROR" => Style::default().fg(Color::Magenta), @@ -144,6 +162,7 @@ fn main() -> Result<(), Box> { "INFO" => Style::default().fg(Color::Blue), _ => Style::default(), }; + // Add a example datetime and apply proper spacing between them let header = Spans::from(vec![ Span::styled(format!("{:<9}", level), s), Span::raw(" "), @@ -152,7 +171,14 @@ fn main() -> Result<(), Box> { Style::default().add_modifier(Modifier::ITALIC), ), ]); - let log = Spans::from(vec![Span::raw(evt)]); + // The event gets it's own line + let log = Spans::from(vec![Span::raw(event)]); + + // Here several things happen: + // 1. Add a `---` spacing line above the final list entry + // 2. Add the Level + datetime + // 3. Add a spacer line + // 4. Add the actual event ListItem::new(vec![ Spans::from("-".repeat(chunks[1].width as usize)), header, @@ -167,6 +193,10 @@ fn main() -> Result<(), Box> { f.render_widget(events_list, chunks[1]); })?; + // This is a simple example on how to handle events + // 1. This breaks the loop and exits the program on `q` button press. + // 2. The `up`/`down` keys change the currently selected item in the App's `items` list. + // 3. `left` unselects the current item. match events.next()? { Event::Input(input) => match input { Key::Char('q') => {