feat(cli): ✨ switch widget
This commit is contained in:
parent
79842ae70d
commit
7e896d04bd
@ -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"]
|
||||||
|
|||||||
@ -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
80
examples/widget_switch.rs
Normal 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(())
|
||||||
|
}
|
||||||
@ -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.
|
||||||
@ -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
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
88
lib/cli/tui/widgets/switch/widget.rs
Normal file
88
lib/cli/tui/widgets/switch/widget.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user