Documentation site Β· Getting started Β· User guide Β· Tutorials Β· vs. C++ Β· What's new Β· Upgrading to 3.0
A Rust implementation of the classic Borland Turbo Vision text user interface framework.
Full documentation, user guide, tutorials and a side-by-side comparison with the original C++ application model live at tv.enzolombardi.net.
Version 3.0.0 - PRODUCTION READY β
Based on kloczek Borland Turbo Vision C++ port here
Other C++ implementations:
This port achieves 100% API parity with kloczek port of Borland Turbo Vision C++. All features from the original framework have been implemented. While the codebase is complete and production-ready, it may contain bugs. Please report any issues you encounter!
The showcase demo with Calculator, Calendar, ASCII Table, and Puzzle windows demonstrating overlapping window management, z-ordering, and shadows.
A full-featured text editor (pascal_ide) editing its own source code, with menu bar, status line, and scrollable editing area.
Context-sensitive help system (F1) with scrollable content, rendered over the editor window.
A tree view widget displaying a hierarchical file system with expandable/collapsible directories, keyboard navigation, and selection highlighting.
The built-in file dialog with directory navigation, file list, and keyboard/mouse support.
- Complete UI Component Set: Windows, dialogs, buttons, input fields, menus, status bars, scrollbars
- Z-Order Management: Click any non-modal window to bring it to the front
- Modal Dialog Support: Modal dialogs block interaction with background windows
- Borland-Accurate Styling: Menu borders and shadows match original Borland Turbo Vision
- Scrollable Views: Built-in scrollbar support with keyboard navigation
- Text Viewer: Ready-to-use scrollable text viewer with line numbers
- Event-Driven Architecture:
- Three-phase event processing (PreProcess β Focused β PostProcess)
- Event re-queuing for deferred processing
- Owner-aware broadcast system to prevent echo back to sender
- Mouse Support: Full mouse support for buttons, menus, status bar, dialog close buttons, scroll wheel, and double-click detection
- Window Dragging and Resizing: Drag windows by title bar, resize by bottom-right corner
- Owner-Relative Layout: Children keep coordinates relative to their owner, as in Borland's
TView::origin; views draw at(0,0)and the owners translate (seedocs/OWNER-COORDINATES.md) - Color Support: 16-color palette with Borland-accurate attribute system and context-aware remapping
- Text Styling: Bold, dim, italic, underline, reverse, and strikethrough attributes β composable via
Attr::new(fg, bg).bold().italic(), emitted as real SGR codes on the terminal and in ANSI dumps (seecargo run --example text_styling) - Editor Selection: Stream selection (Shift+arrows / drag) plus rectangular block selection with columnar copy/cut and single-step undo, switched with the global block-edit mode (
Application::set_block_edit_mode,CM_TOGGLE_BLOCK_MODE) rather than a modifier key;CM_SELECT_ALLcommand and Ctrl+A select all content of the focused window - Cross-Platform: Built on crossterm for wide terminal compatibility
- SSH Support: Optional SSH backend to serve TUI applications over SSH connections
- Modal Dialogs: Built-in support for modal dialog execution
- Focus Management: Tab navigation and keyboard shortcuts
- Screen Capture: F12 saves an ASCII (ANSI) dump of the whole screen; Ctrl+F12 saves a PNG screenshot. Programmatic dumps of screen/views/regions via
dump_screen/dump_region/dump_to_file
use turbo_vision::prelude::*;
fn main() -> turbo_vision::core::error::Result<()> {
// Create a window
let mut dialog = turbo_vision::views::dialog::DialogBuilder::new().bounds(Rect::new(10, 5, 50, 15)).title("My First Dialog").build();
// Create a button and add it to the window
let button = turbo_vision::views::button::Button::new(Rect::new(26, 6, 36, 8), "Quit", turbo_vision::core::command::CM_OK, true);
dialog.add(Box::new(button));
// Create the application and add the dialog to its desktop
let mut app = Application::new()?;
app.desktop.add(Box::new(dialog));
// Event loop
app.running = true;
while app.running {
app.desktop.draw(&mut app.terminal);
app.terminal.flush()?;
if let Ok(Some(mut event)) = app.terminal.poll_event(std::time::Duration::from_millis(50)) {
app.desktop.handle_event(&mut event);
if event.command == CM_OK {
// Handle button click
app.running = false;
}
}
}
Ok(())
}Tip: Capture the screen at any time β
- F12 saves an ASCII (ANSI-colored) dump of the whole screen to
screen-YYYYMMDD-HHMMSS.ans(view it withcatorless -R). - Ctrl+F12 saves a PNG screenshot of the whole screen to
screenshot-YYYYMMDD-HHMMSS.png.
For programmatic use, see Terminal::dump_screen(path), Terminal::dump_region(...), and Terminal::save_screenshot_png(path).
The color palette system accurately replicates Borland Turbo Vision's behavior:
- Context-Aware Remapping: Views automatically remap colors based on their container (Dialog, Window, or Desktop)
- Owner Type Support: Each view tracks its owner type for correct palette inheritance
- Borland-Accurate Colors: All UI elements (menus, buttons, labels, dialogs) match original Borland colors
- Runtime Customization: Change the entire application palette at runtime with
app.set_palette()for custom themes
The palette system uses a three-level mapping chain:
- View palette (e.g., Button, Label) β indices 1-31
- Container palette (Dialog/Window) β remaps to indices 32-63
- Application palette β final RGB colors
You can customize the entire application palette at runtime to create custom themes:
// Create a custom palette (63 bytes, each encoding foreground << 4 | background)
let dark_palette = vec![/* 63 color bytes */];
// Set the palette - redraw happens automatically!
app.set_palette(Some(dark_palette));
// Reset to default Borland palette
app.set_palette(None);See examples/palette_themes_demo.rs for a complete example with multiple themes.
- core: Fundamental types (geometry, events, drawing, colors)
- terminal: Terminal I/O abstraction layer
- views: UI components (dialogs, buttons, menus, etc.)
- app: Application framework and event loop
This project includes extensive documentation for different audiences and use cases. Here's a recommended reading order based on your goals:
If you're new to Turbo Vision frameworks, follow this path:
- Quick Start (above) - Get a minimal example running
- Examples Overview - Browse 30+ working examples
cargo run --example showcase # Comprehensive feature showcase cargo run --bin pascal_ide # Full-featured text editor
- User Guide - Chapter 1 - Learn the basics
- User Guide - Chapter 2 - Handle events and commands
- User Guide - Chapter 3 - Create your first window
Continue with: Chapters 4-18 in the User Guide for comprehensive coverage of all features.
For practical application development:
- Custom Application Example - Complete walkthrough
- Biorhythm Calculator Tutorial - Build a real app step-by-step
- examples/showcase.rs - Study the comprehensive demo
- pascal_ide source - See a production-ready editor
If you're familiar with Borland Turbo Vision:
- Architecture Overview - Understand Rust adaptations
- Rust Implementation Reference - Technical details
- Turbo Vision Design - Complete design document
- Class Diagram - How the core types compose, as a Mermaid diagram
Key Differences: The Rust port uses composition over inheritance, but maintains the same event loop patterns, drawing system, and API structure as Borland's original.
When you need specific functionality:
- Palette & Colors: Palette System, Borland Palette Chart, Chapter 14
- Event Handling: Chapter 9 - Event-Driven Programming
- Forms & Input: Chapter 5 - Data Entry Forms, Chapter 13 - Validation
- Text Editing: Chapter 15 - Editor and Text Views
- Collections & Lists: Chapter 6 - Managing Data Collections
- Persistence: Serialization Guide, Quick Reference
- Application Structure: Chapter 10 - Application Objects
- Windows & Dialogs: Chapter 11 - Window and Dialog Box Objects
For API lookups and function signatures:
- Documentation Index - Master index of all documentation
- Rust API Catalog - Complete API listing
- API Catalog Index - Quick reference guide
- Inline Docs: Run
cargo doc --openfor generated documentation
If you want to modify or extend the codebase:
- Rust Coding Guidelines - Code style and best practices
- Chapter 8 - Views and Groups - Understanding the view hierarchy
- Study existing tests in
src/views/*/testsmodules
docs/
βββ DOCUMENTATION-INDEX.md # Master index
βββ RUST-CODING-GUIDELINES.md # Code style guide
βββ CUSTOM-APPLICATION-RUST-EXAMPLE.md # Complete app walkthrough
βββ BIORHYTHM-CALCULATOR-TUTORIAL.md # Step-by-step tutorial
βββ PALETTE-SYSTEM.md # Color system explained
βββ BORLAND-PALETTE-CHART.md # Color reference
βββ RUST-API-CATALOG.md # API reference
βββ TURBO-VISION-DESIGN.md # Complete design document
βββ CLASS-DIAGRAM.md # Mermaid class diagram of the core types
βββ HOW-TO-BUILD-AND-DEPLOY-WEBSITE.md # Building and deploying the MkDocs site
βββ SERIALIZATION-PERSISTENCE.md # Saving/loading data
βββ user-guide/ # 18-chapter comprehensive guide
βββ Chapter-01-Stepping-into-Turbo-Vision.md
βββ Chapter-02-Responding-to-Commands.md
βββ ... (Chapters 3-17)
βββ Chapter-18-Resources.md
examples/
βββ README.md # Examples index with descriptions
βββ showcase.rs # Comprehensive demo
βββ biorhythm.rs # Complete calculator app
βββ ... (30+ more examples)
demo/
βββ pascal_ide.rs # Production text editor
- Start Coding: Quick Start β Examples
- Learn Concepts: User Guide Chapter 1
- Build an App: Custom Application Example
- Get Help: Documentation Index
- Report Issues: GitHub Issues
Currently implements:
- β Core drawing and event system
- β Dialog boxes with frames and close buttons
- β Buttons with keyboard shortcuts
- β Static text labels (with centered text support)
- β Input fields
- β Menu bar with dropdowns and keyboard shortcut display
- β Status line with hot spots (hover highlighting, context-sensitive hints)
- β Desktop manager
- β Scrollbars (vertical and horizontal)
- β Scroller base class for scrollable views
- β Indicator (position display)
- β Text viewer with scrolling
- β CheckBoxes and RadioButtons (single, or multi-item clusters with one bitmask value)
- β ListBoxes (single selection, or multi-select with Space and Shift+click)
- β Memo (multi-line text editor)
- β ProgressBar (determinate and marquee, three glyph styles)
- β ComboBox (read-only field with a drop-down list)
- β Spinner (numeric field with steppers, range-clamped)
- β Table (grid with header row, sized columns, cell focus)
- β TabbedPane (enclosed tabs over a stack of pages)
- β SplitPane (two panes with a draggable divider)
- β Tooltip (hover hints for a dialog's controls)
- β Mouse support (buttons, menus, status bar, close buttons, hover effects, listbox clicks, scroll wheel, double-click detection)
- β Window dragging and resizing (drag by title bar, resize from bottom-right corner with minimum size constraints)
- β Window closing (non-modal windows close with close button, modal dialogs convert to cancel)
- β File Dialog (fully functional with mouse/keyboard support and directory navigation)
- β ANSI Dump for debugging (dump screen/views to text files with colors)
- β Input Validators (FilterValidator, RangeValidator with hex/octal, LookupValidator)
- β Editor with search/replace and file I/O (load_file, save_file, save_as)
- β EditWindow (ready-to-use editor window wrapper)
- β OS Clipboard integration (cross-platform with arboard)
- β Help System (markdown-based with HelpFile, HelpViewer, HelpWindow, HelpContext)
- β SSH TUI Bridge (optional feature for serving TUI apps over SSH)
Turbo Vision can serve TUI applications over SSH connections, enabling remote terminal access to your application. This is useful for admin consoles, monitoring dashboards, and tools that need to be accessed remotely.
SSH support is behind a feature flag. Enable it in your Cargo.toml:
[dependencies]
turbo-vision = { version = "2.3", features = ["ssh"] }Or build with the feature:
cargo build --features sshuse turbo_vision::prelude::*;
use turbo_vision::terminal::{Backend, SshBackend, SshSessionBuilder};
use turbo_vision::ssh::{SshServer, SshServerConfig};
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = SshServerConfig::default();
let server = SshServer::new(config)?;
server.run("0.0.0.0:2222", |backend| {
// Create Terminal with SSH backend
let terminal = Terminal::with_backend(backend).unwrap();
run_your_tui_app(terminal);
}).await?;
Ok(())
}# Start the SSH server
cargo run --example ssh_server --features ssh
# Connect from another terminal
ssh -p 2222 user@localhost
# Password: any (accepts any password in the example)The SSH support uses a Backend trait abstraction:
- Backend trait: Abstracts terminal I/O operations
- CrosstermBackend: Default implementation for local terminals
- SshBackend: Implementation for SSH channel I/O
- InputParser: Converts raw terminal bytes to turbo-vision events
This allows the same TUI application to run locally or over SSH with no code changes.
This implementation closely follows Borland Turbo Vision's architecture, adapted for Rust:
- Event Loop:
Application::run_withtakes anAppHandlerfor the program's own commands (Borland'sTApplication::handleEventandidleoverrides);Application::execute_modalis the one modal loop behindDialog::execute - Modal Dialogs: Use Borland's
endModal()pattern to exit event loops;CloseOnsays which commands close a dialog - View Hierarchy: Borland's
TView > TGroup > TWindow > TDialogis expressed as layered traits over shared cores: every view owns aViewCore,GroupLikeandWindowLikecarryTGroup's andTWindow's behaviour asgroup_*/window_*default methods, and a window-shaped type gets itsViewimpl fromimpl_view_for_window!with overrides written inline. Overrides are late-bound:Dialog::get_paletteis whatwindow_drawpaints with. See docs/MISSING-INHERITANCE.md for the analysis behind it. - Drawing: Event-driven redraws with Borland's
drawUnderRectpattern for efficient updates - Event System:
- Three-phase processing (PreProcess β Focused β PostProcess) matching Borland's
TGroup::handleEvent() - Event re-queuing via
Terminal::put_event()matching Borland'sTProgram::putEvent() - Owner-aware broadcasts via
Group::broadcast()matching Borland'smessage(owner, ...)pattern
- Three-phase processing (PreProcess β Focused β PostProcess) matching Borland's
A non-exhaustive map of the main types. Traits are marked <<trait>>; dashed hollow arrows are trait implementations, filled diamonds are ownership by value. The full page with notes lives in docs/CLASS-DIAGRAM.md.
classDiagram
direction TB
class View {
<<trait>>
+bounds() Rect
+set_bounds(Rect)
+draw(Terminal)
+handle_event(Event)
+can_focus() bool
+set_focus(bool)
+state() StateFlags
+options() u16
+grow_mode() GrowFlags
}
class IdleView {
<<trait>>
+idle()
}
class Cluster {
<<trait>>
+cluster_state()
}
class ListViewer {
<<trait>>
+list_state()
+item_count() usize
}
class MenuViewer {
<<trait>>
+menu_state()
}
class Editor {
<<trait>>
+undo()
+redo()
+cut() bool
+copy() bool
+paste() bool
}
class FileEditor {
<<trait>>
+load(PathBuf)
+save()
+save_as(PathBuf)
}
View <|-- IdleView
View <|-- Cluster
View <|-- ListViewer
View <|-- MenuViewer
View <|-- Editor
Editor <|-- FileEditor
class Application {
+terminal: Terminal
+desktop: Desktop
+menu_bar: Option~MenuBar~
+status_line: Option~StatusLine~
+running: bool
+run()
+handle_event(Event)
}
class Desktop {
-children: Group
+add(Box~View~)
+cascade()
+tile()
+bring_to_front(ViewId)
}
class Group {
-children: Vec~Box~View~~
-focused: usize
-end_state: CommandId
+add(Box~View~) ViewId
+execute() CommandId
+end_modal(CommandId)
+broadcast(Event, owner)
}
class Window {
-frame: Frame
-interior: Group
-number: Option~u8~
-zoom_rect: Rect
+add(Box~View~) ViewId
+zoom(Rect)
}
class Frame {
-title: String
-resizable: bool
-zoomable: bool
+is_zoomed() bool
}
class Dialog {
-window: Window
-result: CommandId
+execute(Application) CommandId
}
class MenuBar {
-submenus: Vec~SubMenu~
}
class MenuBox
class StatusLine {
-items: Vec~StatusItem~
}
class Button {
-title: String
-command: CommandId
-is_default: bool
}
class InputLine
class StaticText
class Label
class CheckBox
class RadioButton
class ListBox
class ScrollBar
class Scroller
class TextViewer
class Memo
class EditorWindow
class FileEditorWindow
class Event {
+what: EventType
+key_code: u16
+mouse: MouseEvent
+command: CommandId
+clear()
}
class Terminal {
+put_event(Event)
+flush()
}
class Rect
class Palette
Application *-- Desktop
Application *-- Terminal
Application o-- MenuBar
Application o-- StatusLine
Desktop *-- Group
Window *-- Frame
Window *-- Group : interior
Dialog *-- Window
Group o-- "0..*" View : children
Scroller o-- ScrollBar
TextViewer o-- ScrollBar
MenuBar ..> MenuBox : opens
View <|.. Desktop
View <|.. Group
View <|.. Window
View <|.. Frame
View <|.. Dialog
View <|.. MenuBar
View <|.. StatusLine
View <|.. Button
View <|.. InputLine
View <|.. StaticText
View <|.. Label
View <|.. ScrollBar
View <|.. Scroller
View <|.. TextViewer
View <|.. Memo
Cluster <|.. CheckBox
Cluster <|.. RadioButton
ListViewer <|.. ListBox
MenuViewer <|.. MenuBar
MenuViewer <|.. MenuBox
Editor <|.. EditorWindow
FileEditor <|.. FileEditorWindow
View ..> Event : handles
View ..> Terminal : draws to
View ..> Rect : bounds
View ..> Palette : colours from
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
Rust 125 37315 28029 3557 5729
|- Markdown 102 4695 332 3604 759
(Total) 42010 28361 7161 6488
===============================================================================
Generated with tokei - includes inline documentation
226 unit tests - all passing β
MIT License - see LICENSE file for details.





