7 releases

0.2.4 Aug 28, 2024
0.2.3 Aug 7, 2024
0.2.2 Jun 25, 2024
0.2.1 Apr 5, 2024
0.1.1 Nov 29, 2022

#632 in Command-line interface

Download history 126/week @ 2024-08-04 9/week @ 2024-08-11 1/week @ 2024-08-18 145/week @ 2024-08-25 8/week @ 2024-09-01 1/week @ 2024-09-08 33/week @ 2024-09-15 26/week @ 2024-09-22 50/week @ 2024-09-29 20/week @ 2024-10-06 29/week @ 2024-10-13 203/week @ 2024-10-20 64/week @ 2024-10-27 18/week @ 2024-11-03

316 downloads per month
Used in plastic_tui

MIT/Apache

29KB
500 lines

tui-menu

A menu widget for Ratatui.

Demo

Features

  • Sub menu groups.
  • Intuitive movement.
  • Item's data is generic as long as it Cloneable.

Try

cargo run --example basic

Example

take a look at examples/basic.rs

Render

// menu should be draw at last, so it can stay on top of other content
let menu = Menu::new();
frame.render_stateful_widget(menu, chunks[0], &mut app.menu);

Create nested menu tree

Note: MenuItems can be created from any type that implements Clone. Using an enum is just one option which can work. You could use strings or your own state types.

#[derive(Debug, Clone)]
enum Action {
    FileNew,
    FileOpen,
    FileOpenRecent(String),
    FileSaveAs,
    Exit,
    EditCopy,
    EditCut,
    EditPaste,
    AboutAuthor,
    AboutHelp,
}

let menu = MenuState::new(vec![
    MenuItem::group(
        "File",
        vec![
            MenuItem::item("New", Action::FileNew),
            MenuItem::item("Open", Action::FileOpen),
            MenuItem::group(
                "Open recent",
                ["file_1.txt", "file_2.txt"]
                    .iter()
                    .map(|&f| MenuItem::item(f, Action::FileOpenRecent(f.into())))
                    .collect(),
            ),
            MenuItem::item("Save as", Action::FileSaveAs),
            MenuItem::item("Exit", Action::Exit),
        ],
    ),
    MenuItem::group(
        "Edit",
        vec![
            MenuItem::item("Copy", Action::EditCopy),
            MenuItem::item("Cut", Action::EditCut),
            MenuItem::item("Paste", Action::EditPaste),
        ],
    ),
    MenuItem::group(
        "About",
        vec![
            MenuItem::item("Author", Action::AboutAuthor),
            MenuItem::item("Help", Action::AboutHelp),
        ],
    ),
]),

Consume events

for e in menu.drain_events() {
    match e {
        MenuEvent::Selected(item) => match item {
            Action::Exit => {
                return Ok(());
            }
            Action::FileNew => {
                self.content.clear();
            }
            Action::FileOpenRecent(file) => {
                self.content = format!("content of {file}");
            }
            action => {
                self.content = format!("{action:?} not implemented");
            }
        },
    }
    // close the menu once the event has been handled.
    menu.reset();
}

Dependencies

~7–16MB
~230K SLoC