use turbo_vision::core::command::{CM_NEW, CM_OPEN, CM_QUIT, CM_SAVE};
use turbo_vision::core::event::{KB_ALT_X, KB_CTRL_C, KB_CTRL_N, KB_CTRL_O, KB_CTRL_S, KB_ESC_ESC, KB_F1, KB_F10};
use turbo_vision::core::menu_data::{Menu, MenuItem};
use turbo_vision::prelude::*;
use turbo_vision::views::button::ButtonBuilder;
use turbo_vision::views::dialog::DialogBuilder;
use turbo_vision::views::menu_bar::{MenuBar, SubMenu};
use turbo_vision::views::msgbox::message_box_ok;
use turbo_vision::views::static_text::StaticTextBuilder;
use turbo_vision::views::status_line::{StatusItem, StatusLine};
use turbo_vision::views::text_viewer::TextViewer;
use turbo_vision::views::window::WindowBuilder;
const CMD_ABOUT: u16 = 100;
const CMD_HELP: u16 = 101;
fn main() -> turbo_vision::core::error::Result<()> {
let mut app = Application::new()?;
setup_menu_bar(&mut app);
setup_status_line(&mut app);
setup_win1(&mut app);
setup_win2(&mut app);
setup_win3(&mut app);
show_welcome(&mut app);
run_event_loop(&mut app);
Ok(())
}
fn run_event_loop(app: &mut Application) {
app.running = true;
while app.running {
app.desktop.draw(&mut app.terminal);
if let Some(ref mut menu_bar) = app.menu_bar {
menu_bar.draw(&mut app.terminal);
}
if let Some(ref mut status_line) = app.status_line {
status_line.draw(&mut app.terminal);
}
let _ = app.terminal.flush();
if let Ok(Some(mut event)) = app.terminal.poll_event(std::time::Duration::from_millis(50)) {
handle_global_shortcuts(&mut event);
if let Some(ref mut menu_bar) = app.menu_bar {
menu_bar.handle_event(&mut event);
}
app.desktop.handle_event(&mut event);
if let Some(ref mut status_line) = app.status_line {
status_line.handle_event(&mut event);
}
if event.what == EventType::Command {
app.desktop.draw(&mut app.terminal);
if let Some(ref mut menu_bar) = app.menu_bar {
menu_bar.draw(&mut app.terminal);
}
if let Some(ref mut status_line) = app.status_line {
status_line.draw(&mut app.terminal);
}
let _ = app.terminal.flush();
}
if event.what == EventType::Command {
match event.command {
CM_QUIT => {
app.running = false;
}
CM_NEW => {
message_box_ok(app, "Create a new file (Ctrl+N)");
}
CM_OPEN => {
message_box_ok(app, "Open an existing file (Ctrl+O)");
}
CM_SAVE => {
message_box_ok(app, "Save the current file (Ctrl+S)");
}
CMD_ABOUT => {
show_about(app);
}
CMD_HELP => {
show_help(app);
}
_ => {}
}
}
}
}
}
fn handle_global_shortcuts(event: &mut Event) {
if event.what != EventType::Keyboard {
return;
}
let command = match event.key_code {
KB_CTRL_N => Some(CM_NEW),
KB_CTRL_O => Some(CM_OPEN),
KB_CTRL_S => Some(CM_SAVE),
KB_ALT_X | KB_CTRL_C | KB_ESC_ESC => Some(CM_QUIT),
KB_F1 => Some(CMD_HELP),
_ => None,
};
if let Some(cmd) = command {
*event = Event::command(cmd);
}
}
fn setup_menu_bar(app: &mut Application) {
let (width, _) = app.terminal.size();
let mut menu_bar = MenuBar::new(Rect::new(0, 0, width, 1));
let file_menu_items = vec![
MenuItem::with_shortcut("~N~ew", CM_NEW, 0, "Ctrl+N", 0),
MenuItem::with_shortcut("~O~pen...", CM_OPEN, 0, "Ctrl+O", 0),
MenuItem::with_shortcut("~S~ave", CM_SAVE, 0, "Ctrl+S", 0),
MenuItem::separator(),
MenuItem::with_shortcut("E~x~it", CM_QUIT, 0, "Alt+X", 0),
];
let file_menu = SubMenu::new("~F~ile", Menu::from_items(file_menu_items));
let window_menu_items = vec![
MenuItem::new("~T~ile", 0, 0, 0),
MenuItem::new("~C~ascade", 0, 0, 0),
MenuItem::separator(),
MenuItem::new("~N~ext", 0, 0, 0),
];
let window_menu = SubMenu::new("~W~indow", Menu::from_items(window_menu_items));
let help_menu_items = vec![
MenuItem::with_shortcut("~H~elp", CMD_HELP, 0, "F1", 0),
MenuItem::separator(),
MenuItem::new("~A~bout", CMD_ABOUT, 0, 0),
];
let help_menu = SubMenu::new("~H~elp", Menu::from_items(help_menu_items));
menu_bar.add_submenu(file_menu);
menu_bar.add_submenu(window_menu);
menu_bar.add_submenu(help_menu);
app.set_menu_bar(menu_bar);
}
fn setup_status_line(app: &mut Application) {
let (width, height) = app.terminal.size();
let status_line = StatusLine::new(
Rect::new(0, height - 1, width, height),
vec![StatusItem::new("~F10~ Menu", KB_F10, 0), StatusItem::new("~F1~ Help", 0, CMD_HELP)],
);
app.set_status_line(status_line);
}
fn create_text_window(app: &mut Application, bounds: Rect, title: &str, content: &str) {
let mut window = WindowBuilder::new().bounds(bounds).title(title).build();
let text_viewer_bounds = Rect::new(1, 1, bounds.width() - 2, bounds.height() - 4);
let mut text_viewer = TextViewer::new(text_viewer_bounds).with_scrollbars(false).with_indicator(false);
text_viewer.set_text(content);
window.add(Box::new(text_viewer));
app.desktop.add(Box::new(window));
}
fn setup_win1(app: &mut Application) {
let instructions = r"WINDOW RESIZING:
1. Move your mouse to the bottom-right corner
2. Click and drag when you see the last 2 columns and last row
3. The window will resize as you drag
Note: minimum size = 16x6
";
create_text_window(app, Rect::new(2, 2, 50, 18), "Resize & Shortcuts Demo", instructions);
}
fn setup_win2(app: &mut Application) {
let shortcuts_info = r"KEYBOARD SHORTCUTS:
Shortcuts are visual aids showing users what keys to press.
File menu shows:
New Ctrl+N
Open Ctrl+O
Save Ctrl+S
Exit Alt+X
Help menu shows:
Help F1
Note: F1 can be pressed anytime to show help, but About must be accessed by opening the Help menu.
";
create_text_window(app, Rect::new(52, 2, 100, 18), "Menu Shortcuts", shortcuts_info);
}
fn setup_win3(app: &mut Application) {
let features = r"FEATURES DEMONSTRATED:
✓ Window Resizing
- Drag bottom-right corner
- Minimum size enforced
- Child views auto-update
✓ Menu Shortcuts Display
- Right-aligned in menus
- Auto-width calculation
- Professional appearance
✓ Window Dragging
- Click title bar to drag
- Z-order management
All matching Borland TV!";
create_text_window(app, Rect::new(26, 10, 76, 24), "Features", features);
}
fn show_msg(app: &mut Application, text: &str, title: &str, dialog_width: i16, dialog_height: i16) {
let (term_width, term_height) = app.terminal.size();
let dialog_x = (term_width - dialog_width) / 2;
let dialog_y = (term_height - dialog_height) / 2;
let mut dialog = DialogBuilder::new()
.bounds(Rect::new(dialog_x, dialog_y, dialog_x + dialog_width, dialog_y + dialog_height))
.title(title)
.build();
let text = StaticTextBuilder::new().bounds(Rect::new(2, 1, dialog_width - 4, dialog_height - 6)).text(text).build();
dialog.add(Box::new(text));
let button_width = 10;
let button_x = (dialog_width - 2 - button_width) / 2;
let button = ButtonBuilder::new()
.bounds(Rect::new(button_x, dialog_height - 4, button_x + button_width, dialog_height - 2))
.title("~O~K")
.command(CM_OK)
.default(true)
.build();
dialog.add(Box::new(button));
dialog.set_initial_focus();
dialog.execute(app);
}
fn show_welcome(app: &mut Application) {
let dialog_width = 60;
let dialog_height = 15;
let title = "Window Resize & Menu Shortcuts Demo";
let text = r"This example demonstrates:
• Window resizing (drag bottom-right corner)
• Menu keyboard shortcuts (displayed right-aligned)
• Window dragging (drag title bar)
• Multiple overlapping windows
Resize the windows and check out the menus.";
show_msg(app, text, title, dialog_width, dialog_height);
}
fn show_about(app: &mut Application) {
let dialog_width = 55;
let dialog_height = 14;
let title = "About";
let text = r"Turbo Vision for Rust: Version 0.1.8
Features:
• Status Line Hot Spots (v0.1.8)
• Window Resize Support (v0.1.6)
• Menu Shortcuts Display (v0.1.7)
• Based on Borland Turbo Vision";
show_msg(app, text, title, dialog_width, dialog_height);
}
fn show_help(app: &mut Application) {
let dialog_width = 60;
let dialog_height = 19;
let title = "Help";
let text = r"WINDOW OPERATIONS:
Move: Click and drag the title bar
Resize: Click and drag the bottom-right corner
Close: Click the [■] button in the title bar
Focus: Click anywhere on the window
MENUS:
Open: Click on menu name or press Alt+Letter
Select: Use arrow keys or click on item
Close: Press Esc or click outside menu
Keyboard shortcuts are shown in menus.";
show_msg(app, text, title, dialog_width, dialog_height);
}