Skip to content

Commit

Permalink
feat: starter example
Browse files Browse the repository at this point in the history
  • Loading branch information
TaylorHo committed Nov 14, 2023
0 parents commit 5c8d227
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 0 deletions.
Binary file added .github/images/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
Cargo.lock
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "test"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
crossterm = "0.27.0"
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 🦀 Rust Custom Selectable List

This package uses _[crossterm](https://crates.io/crates/crossterm)_ to create a custom selectable list.


### Example
---
![Demo of the program](./.github/images/demo.gif)
147 changes: 147 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use crossterm::{
cursor,
event::{self},
execute,
style::{self, Color, Stylize},
terminal::{self, ClearType},
};
use std::io;
use std::io::Write;

struct SelectableItem {
label: String,
selected: bool,
}

impl SelectableItem {
fn new(label: &str) -> Self {
SelectableItem {
label: label.to_string(),
selected: false,
}
}
}

struct SelectableList {
items: Vec<SelectableItem>,
selected_index: usize,
}

impl SelectableList {
fn new(items: Vec<&str>) -> Self {
let items = items
.into_iter()
.map(|label| SelectableItem::new(label))
.collect();

SelectableList {
items,
selected_index: 0,
}
}

fn draw(&self) {
for (index, item) in self.items.iter().enumerate() {
let line = if index == self.selected_index {
format!(
"{}{}{}{}",
style::Attribute::Bold,
if item.selected { "* " } else { "> " },
style::style(&item.label)
.with(if item.selected { Color::Green } else { Color::White }),
style::Attribute::Reset,
)
} else {
format!(
"{}{}",
{ " " },
if item.selected {
style::style(&item.label)
.with(Color::Green)
.to_string()
} else {
style::style(&item.label).to_string()
}
)
};

execute!(
io::stdout(),
cursor::MoveToColumn(0)
)
.unwrap();

println!("{line}");
}
}

fn toggle_selected(&mut self) {
if let Some(item) = self.items.get_mut(self.selected_index) {
item.selected = !item.selected;
}
}

fn move_selection(&mut self, offset: i32) {
let len = self.items.len() as i32;
self.selected_index = ((self.selected_index as i32 + offset + len) % len) as usize;
}
}

fn main() {
// Set up terminal
terminal::enable_raw_mode().expect("Failed to enable raw mode");

let items = vec!["Item 1", "Item 2", "Item 3", "Item 4"];
let mut selectable_list = SelectableList::new(items);

loop {

execute!(
io::stdout(),
cursor::Hide,
style::PrintStyledContent(
style::style("\n\nWelcome to the Selectable List Example!\n\n").bold()
)
)
.unwrap();

selectable_list.draw();
io::stdout().flush().unwrap();

if event::poll(std::time::Duration::from_millis(50)).unwrap() {
if let event::Event::Key(key_event) = event::read().unwrap() {
if key_event.modifiers == event::KeyModifiers::CONTROL
&& key_event.code == event::KeyCode::Char('c')
{
break;
}

match key_event.code {
event::KeyCode::Char('q') => break,
event::KeyCode::Esc => break,
event::KeyCode::Enter => selectable_list.toggle_selected(),
event::KeyCode::Char(' ') => selectable_list.toggle_selected(),
event::KeyCode::Up => selectable_list.move_selection(-1),
event::KeyCode::Down => selectable_list.move_selection(1),
event::KeyCode::Tab => selectable_list.move_selection(1),
_ => {}
}
}
}

execute!(
io::stdout(),
cursor::MoveTo(0, 0),
terminal::Clear(ClearType::FromCursorDown)
)
.unwrap();
}

// Clean up terminal
execute!(
io::stdout(),
cursor::Show,
)
.unwrap();
terminal::disable_raw_mode().expect("Failed to disable raw mode");
}

0 comments on commit 5c8d227

Please sign in to comment.