feat(cli): switch widget

This commit is contained in:
Lucas Colombo 2024-09-20 23:11:54 -03:00
parent 79842ae70d
commit 7e896d04bd
Signed by: lucas
GPG Key ID: EF34786CFEFFAE35
7 changed files with 195 additions and 3 deletions

View File

@ -110,3 +110,8 @@ required-features = ["cli.tui.widgets", "tokio.rt"]
name = "widget_grid_selector" name = "widget_grid_selector"
path = "examples/widget_grid_selector.rs" path = "examples/widget_grid_selector.rs"
required-features = ["cli.tui.widgets", "tokio.rt"] required-features = ["cli.tui.widgets", "tokio.rt"]
[[example]]
name = "widget_switch"
path = "examples/widget_switch.rs"
required-features = ["cli.tui.widgets", "tokio.rt"]

View File

@ -34,6 +34,11 @@ tasks:
cmds: cmds:
- cargo watch --features=cli.tui.widgets,tokio.rt -c -x "run --example widget_grid_selector" - cargo watch --features=cli.tui.widgets,tokio.rt -c -x "run --example widget_grid_selector"
example:switch:
desc: 🚀 run lool «example widget_switch»
cmds:
- cargo watch --features=cli.tui.widgets,tokio.rt -c -x "run --example widget_switch"
fmt: fmt:
desc: 🎨 format lool desc: 🎨 format lool
cmds: cmds:

80
examples/widget_switch.rs Normal file
View File

@ -0,0 +1,80 @@
use {
lool::tui::{
ratatui::{
backend::CrosstermBackend,
crossterm::{
event::{self},
execute,
terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
},
},
layout::{Constraint, Layout},
Terminal,
},
widgets::{
switch::Switch,
textarea::{Input, Key},
},
},
ratatui::layout::Flex,
std::io,
};
fn main() -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
enable_raw_mode()?;
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend)?;
let mut switch_state = false;
loop {
term.draw(|f| {
// Render the textarea
let switch =
Switch::with_status(switch_state).with_color_on(ratatui::style::Color::Blue);
let [horiz] = Layout::horizontal([Constraint::Percentage(100)])
.flex(Flex::Center)
.areas(f.area());
let [verti] = Layout::vertical([Constraint::Length(2)]).flex(Flex::Center).areas(horiz);
let [centered] =
Layout::horizontal([Constraint::Length(14)]).flex(Flex::Center).areas(verti);
f.render_widget(switch, centered);
})?;
match event::read()?.into() {
Input { key: Key::Esc, .. }
| Input {
key: Key::Char('c'),
shift: false,
ctrl: true,
alt: false,
} => break,
Input {
key: Key::Enter,
ctrl: false,
shift: false,
alt: false,
}
| Input {
key: Key::Char(' '),
..
} => {
switch_state = !switch_state;
}
_ => {}
}
}
disable_raw_mode()?;
execute!(term.backend_mut(), LeaveAlternateScreen)?;
term.show_cursor()?;
Ok(())
}

View File

@ -244,3 +244,12 @@ As a part of this library, the `Into<GridItem>` trait is implemented for `String
The example at [`widget_grid_selector.rs`](/examples/widget_grid_selector.rs) demonstrates how to The example at [`widget_grid_selector.rs`](/examples/widget_grid_selector.rs) demonstrates how to
implement the `Into<GridItem>` trait for a custom type. implement the `Into<GridItem>` trait for a custom type.
## `Switch` Widget
A simple stateless switch widget that can be used to show visual feedback of a boolean state.
### Example
See the [`widget_switch.rs`](/examples/widget_switch.rs) example for a full demonstration of how to
use the `Switch` widget.

View File

@ -40,6 +40,11 @@ pub mod widgets {
} }
pub mod textarea; pub mod textarea;
pub mod switch {
mod widget;
pub use widget::*;
}
} }
// ratatui prelude // ratatui prelude

View File

@ -29,9 +29,9 @@ impl AsRef<str> for GridItem {
} }
// convert Label into String // convert Label into String
impl Into<String> for GridItem { impl From<GridItem> for String {
fn into(self) -> String { fn from(val: GridItem) -> Self {
self.0.clone() val.0.clone()
} }
} }

View File

@ -0,0 +1,88 @@
use ratatui::{
buffer::Buffer,
layout::{Constraint, Layout, Rect},
style::{Color, Style},
widgets::{Block, Widget},
};
/// A switch widget
///
/// This widget is used to show visual confirmation of a boolean state
pub struct Switch {
/// The state of the switch
state: bool,
/// The color of the "on" state (`Green` by default)
color_on: Color,
/// The color of the "off" state (`DarkGray` by default)
color_off: Color,
/// The color of the switch itself (`White` by default)
color_switch: Color,
}
impl Switch {
pub fn with_status(state: bool) -> Self {
Switch {
state,
color_on: Color::Green,
color_off: Color::DarkGray,
color_switch: Color::White,
}
}
pub fn with_color_on(mut self, color: Color) -> Self {
self.color_on = color;
self
}
pub fn with_color_off(mut self, color: Color) -> Self {
self.color_off = color;
self
}
pub fn with_color_switch(mut self, color: Color) -> Self {
self.color_switch = color;
self
}
pub fn get_layout(&self, area: Rect) -> (Rect, Rect) {
let main = Layout::default()
.direction(ratatui::layout::Direction::Vertical)
.constraints([Constraint::Length(2)])
.split(area);
let layout = Layout::default()
.direction(ratatui::layout::Direction::Horizontal)
.constraints([Constraint::Length(7), Constraint::Length(7)])
.split(main[0]);
(layout[0], layout[1])
}
fn get_left_color(&self) -> Color {
if self.state {
self.color_on
} else {
self.color_switch
}
}
fn get_right_color(&self) -> Color {
if self.state {
self.color_switch
} else {
self.color_off
}
}
}
impl Widget for Switch {
fn render(self, area: Rect, buf: &mut Buffer) {
let (left, right) = self.get_layout(area);
let left_block = Block::default().style(Style::default().bg(self.get_left_color()));
let right_block = Block::default().style(Style::default().bg(self.get_right_color()));
left_block.render(left, buf);
right_block.render(right, buf);
}
}