#![allow(dead_code)]
mod context_menu;
mod helpers;
mod menu_bar;
mod types;
pub use context_menu::ContextMenu;
pub use helpers::{context_menu, menu, menu_bar, menu_item};
pub use menu_bar::MenuBar;
pub use types::{Menu, MenuItem};
#[cfg(test)]
mod tests {
use super::context_menu::ContextMenu;
use super::menu_bar::MenuBar;
use super::types::{Menu, MenuItem};
use crate::event::Key;
use crate::layout::Rect;
use crate::render::Buffer;
use crate::style::Color;
use crate::widget::traits::{RenderContext, View};
#[test]
fn test_menu_item() {
let item = MenuItem::new("Open").shortcut("Ctrl+O").disabled(false);
assert_eq!(item.label, "Open");
assert_eq!(item.shortcut, Some("Ctrl+O".to_string()));
assert!(!item.disabled);
}
#[test]
fn test_menu() {
let m = Menu::new("File")
.item(MenuItem::new("New"))
.item(MenuItem::new("Open"))
.separator()
.item(MenuItem::new("Exit"));
assert_eq!(m.title, "File");
assert_eq!(m.items.len(), 4);
assert!(m.items[2].separator);
}
#[test]
fn test_menu_bar() {
let mut bar = MenuBar::new()
.menu(Menu::new("File").item(MenuItem::new("New")))
.menu(Menu::new("Edit").item(MenuItem::new("Copy")));
assert_eq!(bar.menus.len(), 2);
assert!(!bar.is_open());
bar.open_menu(0);
assert!(bar.is_open());
bar.next_menu();
assert_eq!(bar.selected_menu, 1);
bar.close();
assert!(!bar.is_open());
}
#[test]
fn test_context_menu() {
let mut menu = ContextMenu::new()
.item(MenuItem::new("Cut"))
.item(MenuItem::new("Copy"))
.item(MenuItem::new("Paste"));
assert!(!menu.is_visible());
menu.show(10, 10);
assert!(menu.is_visible());
menu.handle_key(&Key::Down);
assert_eq!(menu.selected, 1);
menu.hide();
assert!(!menu.is_visible());
}
#[test]
fn test_menu_bar_render() {
let mut buffer = Buffer::new(80, 24);
let area = Rect::new(0, 0, 80, 24);
let mut ctx = RenderContext::new(&mut buffer, area);
let bar = MenuBar::new()
.menu(Menu::new("File"))
.menu(Menu::new("Edit"));
bar.render(&mut ctx);
}
#[test]
fn test_menu_item_checked() {
let item = MenuItem::new("Toggle").checked(true);
assert_eq!(item.checked, Some(true));
let item2 = MenuItem::new("Toggle2").checked(false);
assert_eq!(item2.checked, Some(false));
}
#[test]
fn test_menu_item_submenu() {
let item = MenuItem::new("Parent")
.submenu(vec![MenuItem::new("Child 1"), MenuItem::new("Child 2")]);
assert!(item.has_submenu());
assert_eq!(item.submenu.len(), 2);
}
#[test]
fn test_menu_item_has_submenu() {
let item1 = MenuItem::new("No Submenu");
assert!(!item1.has_submenu());
let item2 = MenuItem::new("With Submenu").submenu(vec![MenuItem::new("Child")]);
assert!(item2.has_submenu());
}
#[test]
fn test_menu_item_on_select_and_execute() {
use std::cell::Cell;
use std::rc::Rc;
let called = Rc::new(Cell::new(false));
let called_clone = called.clone();
let item = MenuItem::new("Action").on_select(move || {
called_clone.set(true);
});
item.execute();
assert!(called.get());
}
#[test]
fn test_menu_item_execute_disabled() {
use std::cell::Cell;
use std::rc::Rc;
let called = Rc::new(Cell::new(false));
let called_clone = called.clone();
let item = MenuItem::new("Disabled Action")
.disabled(true)
.on_select(move || {
called_clone.set(true);
});
item.execute();
assert!(!called.get()); }
#[test]
fn test_menu_items() {
let m = Menu::new("Edit").items(vec![
MenuItem::new("Cut"),
MenuItem::new("Copy"),
MenuItem::new("Paste"),
]);
assert_eq!(m.items.len(), 3);
}
#[test]
fn test_menu_bar_colors() {
let bar = MenuBar::new().bg(Color::BLACK).fg(Color::WHITE);
assert_eq!(bar.bg, Color::BLACK);
assert_eq!(bar.fg, Color::WHITE);
}
#[test]
fn test_menu_bar_toggle() {
let mut bar = MenuBar::new().menu(Menu::new("File").item(MenuItem::new("New")));
assert!(!bar.is_open());
bar.toggle();
assert!(bar.is_open());
bar.toggle();
assert!(!bar.is_open());
}
#[test]
fn test_menu_bar_prev_menu() {
let mut bar = MenuBar::new()
.menu(Menu::new("File"))
.menu(Menu::new("Edit"))
.menu(Menu::new("View"));
bar.selected_menu = 2;
bar.prev_menu();
assert_eq!(bar.selected_menu, 1);
bar.prev_menu();
assert_eq!(bar.selected_menu, 0);
bar.prev_menu();
assert_eq!(bar.selected_menu, 2);
}
#[test]
fn test_menu_bar_next_prev_item() {
let mut bar = MenuBar::new().menu(
Menu::new("File")
.item(MenuItem::new("New"))
.item(MenuItem::new("Open"))
.item(MenuItem::new("Save")),
);
bar.open_menu(0);
assert_eq!(bar.selected_item, Some(0));
bar.next_item();
assert_eq!(bar.selected_item, Some(1));
bar.next_item();
assert_eq!(bar.selected_item, Some(2));
bar.next_item();
assert_eq!(bar.selected_item, Some(0));
bar.prev_item();
assert_eq!(bar.selected_item, Some(2));
}
#[test]
fn test_menu_bar_skip_separators() {
let mut bar = MenuBar::new().menu(
Menu::new("File")
.item(MenuItem::new("New"))
.separator()
.item(MenuItem::new("Exit")),
);
bar.open_menu(0);
bar.next_item();
assert_eq!(bar.selected_item, Some(2));
}
#[test]
fn test_menu_bar_execute_selected() {
use std::cell::Cell;
use std::rc::Rc;
let called = Rc::new(Cell::new(false));
let called_clone = called.clone();
let mut bar = MenuBar::new().menu(Menu::new("File").item(
MenuItem::new("Action").on_select(move || {
called_clone.set(true);
}),
));
bar.open_menu(0);
let result = bar.execute_selected();
assert!(result);
assert!(called.get());
assert!(!bar.is_open()); }
#[test]
fn test_menu_bar_handle_key() {
let mut bar = MenuBar::new()
.menu(Menu::new("File").item(MenuItem::new("New")))
.menu(Menu::new("Edit").item(MenuItem::new("Copy")));
assert!(bar.handle_key(&Key::Right));
assert_eq!(bar.selected_menu, 1);
assert!(bar.handle_key(&Key::Left));
assert_eq!(bar.selected_menu, 0);
assert!(bar.handle_key(&Key::Char('l')));
assert_eq!(bar.selected_menu, 1);
assert!(bar.handle_key(&Key::Char('h')));
assert_eq!(bar.selected_menu, 0);
assert!(bar.handle_key(&Key::Enter));
assert!(bar.is_open());
assert!(bar.handle_key(&Key::Down));
assert!(bar.handle_key(&Key::Char('j')));
assert!(bar.handle_key(&Key::Up));
assert!(bar.handle_key(&Key::Char('k')));
assert!(bar.handle_key(&Key::Escape));
assert!(!bar.is_open());
assert!(bar.handle_key(&Key::Char(' ')));
assert!(bar.is_open());
bar.close();
assert!(!bar.handle_key(&Key::Char('x')));
}
#[test]
fn test_menu_bar_default() {
let bar = MenuBar::default();
assert!(bar.menus.is_empty());
assert!(!bar.is_open());
}
#[test]
fn test_context_menu_navigation() {
let mut menu = ContextMenu::new()
.item(MenuItem::new("Cut"))
.item(MenuItem::new("Copy"))
.item(MenuItem::new("Paste"));
menu.show(10, 10);
menu.handle_key(&Key::Down);
assert_eq!(menu.selected, 1);
menu.handle_key(&Key::Char('j'));
assert_eq!(menu.selected, 2);
menu.handle_key(&Key::Up);
assert_eq!(menu.selected, 1);
menu.handle_key(&Key::Char('k'));
assert_eq!(menu.selected, 0);
}
#[test]
fn test_context_menu_boundary() {
let mut menu = ContextMenu::new()
.item(MenuItem::new("Item 1"))
.item(MenuItem::new("Item 2"));
menu.show(0, 0);
menu.handle_key(&Key::Down);
assert_eq!(menu.selected, 1);
menu.handle_key(&Key::Down);
assert_eq!(menu.selected, 1);
menu.handle_key(&Key::Up);
assert_eq!(menu.selected, 0);
menu.handle_key(&Key::Up);
assert_eq!(menu.selected, 0);
}
#[test]
fn test_context_menu_execute() {
use std::cell::Cell;
use std::rc::Rc;
let called = Rc::new(Cell::new(false));
let called_clone = called.clone();
let mut menu = ContextMenu::new().item(MenuItem::new("Action").on_select(move || {
called_clone.set(true);
}));
menu.show(0, 0);
let result = menu.handle_key(&Key::Enter);
assert!(result);
assert!(called.get());
assert!(!menu.is_visible());
}
#[test]
fn test_context_menu_escape() {
let mut menu = ContextMenu::new().item(MenuItem::new("Item"));
menu.show(0, 0);
assert!(menu.is_visible());
menu.handle_key(&Key::Escape);
assert!(!menu.is_visible());
}
#[test]
fn test_context_menu_render() {
let mut buffer = Buffer::new(40, 20);
let area = Rect::new(0, 0, 40, 20);
let mut ctx = RenderContext::new(&mut buffer, area);
let mut menu = ContextMenu::new()
.item(MenuItem::new("Cut").shortcut("Ctrl+X"))
.item(MenuItem::new("Copy").shortcut("Ctrl+C"))
.item(MenuItem::separator())
.item(MenuItem::new("Paste").shortcut("Ctrl+V"));
menu.show(5, 5);
menu.render(&mut ctx);
}
#[test]
fn test_menu_bar_render_open() {
let mut buffer = Buffer::new(80, 24);
let area = Rect::new(0, 0, 80, 24);
let mut ctx = RenderContext::new(&mut buffer, area);
let mut bar = MenuBar::new().menu(
Menu::new("File")
.item(MenuItem::new("New").shortcut("Ctrl+N"))
.item(MenuItem::new("Open").shortcut("Ctrl+O"))
.separator()
.item(MenuItem::new("Exit")),
);
bar.open_menu(0);
bar.render(&mut ctx);
}
#[test]
fn test_menu_bar_empty() {
let mut bar = MenuBar::new();
bar.next_menu();
bar.prev_menu();
bar.next_item();
bar.prev_item();
assert!(!bar.execute_selected());
}
#[test]
fn test_context_menu_separator() {
let menu = ContextMenu::new()
.item(MenuItem::new("Cut"))
.item(MenuItem::separator())
.item(MenuItem::new("Paste"));
assert_eq!(menu.items.len(), 3);
assert!(menu.items[1].separator);
}
#[test]
fn test_context_menu_default_colors() {
let menu = ContextMenu::new();
assert_eq!(menu.bg, Color::rgb(40, 40, 40));
assert_eq!(menu.fg, Color::WHITE);
}
#[test]
fn test_menu_bar_open_menu_with_items() {
let mut bar = MenuBar::new()
.menu(Menu::new("File").item(MenuItem::new("New")))
.menu(Menu::new("Empty"));
bar.open_menu(0);
assert_eq!(bar.selected_item, Some(0));
bar.open_menu(1);
assert_eq!(bar.selected_item, None); }
#[test]
fn test_menu_bar_open_out_of_bounds() {
let mut bar = MenuBar::new().menu(Menu::new("File"));
bar.open_menu(10); assert!(!bar.is_open());
}
}