Terminal User Interfaces (TUIs)
Graphix includes a comprehensive TUI library built on top of the popular Rust ratatui crate. This allows you to build rich, interactive terminal applications with:
Core Components
The TUI library provides all the essential building blocks:
- Layout: Flexible container system with horizontal/vertical arrangement and various sizing constraints
- Block: Wrapper component that adds borders, titles, and styling to other components
- Text: Rich text rendering with styling, colors, and formatting
- Paragraph: Multi-line text with scrolling and word wrapping
Interactive Widgets
- Table: Selectable data tables with custom styling
- List: Scrollable lists with selection and highlighting
- Tabs: Tabbed interface for organizing content
- Browser: Netidx browser component
- Calendar: Month calendar with highlighted dates and events
- Line edit and Form: Single-line text editing and modal forms (see Text Entry)
Data Visualization
- Chart: Line charts with multiple datasets, custom axes, and styling
- Bar Chart: Grouped and individual bar charts with labels
- Sparkline: Compact inline charts perfect for dashboards
- Gauge: Progress indicators and meters
- Canvas: Low-level drawing surface for custom graphics
Input Handling
Interactive components wrap a widget in an input_handler to handle
UI events that flow through the widget graph from parent to child.
Parents can choose to pass on events they receive or not. See
Input Handling for details.
Building Your First TUI
Here’s a simple example that demonstrates the core concepts:
use tui::{line, style, block::block, text::text};
let counter = count(sys::time::timer(duration:1.s, true));
let content = text(&"Counter: [counter]");
block(
#border: &`All,
#title: &line("My First TUI"),
#style: &style(#fg: `Green),
&content
)
This creates a bordered block with a counter that increments every second. The key insight is that when counter changes, the text automatically updates because of Graphix’s reactive nature.

Styling and Theming
Graphix TUIs support rich styling with:
- Colors: Named colors (
Red,Green,Blue), indexed colors (Indexed(202)), and RGB (Rgb({r: 255, g: 100, b: 50})) - Text Effects: Bold, dim, italic, underlined, reversed, crossed out, and the other modifiers on the style page
- Background Colors: Set background colors for any component
- Conditional Styling: Use
selectexpressions to change styles based on state
Many widgets take optional style arguments, allowing styling to be applied at many levels.
use tui::{style, paragraph::paragraph};
let is_selected = true;
paragraph(
#style: &style(
#fg: select is_selected { true => `Yellow, false => `White },
#bg: `DarkGray,
#add_modifier: [`Bold]
),
&"a styled paragraph"
)
Layout System
The layout system provides flexible component arrangement:
- Direction:
HorizontalorVertical - Constraints:
Percentage(50),Length(20),Min(10),Max(100),Ratio(1, 3),Fill(1) - Flex: how leftover space is distributed:
Start,End,Center,SpaceBetween,SpaceEvenly,SpaceAround - Focus Management: Built-in focus handling for interactive components
use tui::{layout::{child, layout}, text::text};
let selected_pane = 0;
let sidebar = text(&"Sidebar");
let main_content = text(&"Main");
layout(
#direction: &`Horizontal,
#focused: &selected_pane,
&[
child(#constraint: `Percentage(30), sidebar),
child(#constraint: `Percentage(70), main_content)
]
)
State Management
In Graphix, UI state is just regular program state. Use variables to track:
- Selection states in lists and tables
- Input field contents
- Window/pane focus
- Application modes (normal, edit, command)
State changes automatically trigger UI updates:
use tui::{line, input_handler::{Event, input_handler, on_press}, list::list};
let selected_item = 0;
let items = [line("Item 1"), line("Item 2"), line("Item 3")];
let handle = |e: Event| on_press(e, |k| select k.code {
d@ `Down => {
selected_item <- d ~ (selected_item + 1) % array::len(items);
`Stop
},
_ => `Continue
});
// UI automatically reflects the change
input_handler(
#handle: &handle,
&list(#highlight_symbol: &"> ", #selected: &selected_item, &items)
)
Real-time Data Integration
Graphix TUIs excel at displaying real-time data. Connect to data sources via netidx and the UI updates automatically:
use tui::{span, style, gauge::gauge};
use core::math;
use sys::time;
// Self-contained: publish a simulated temperature reading once a
// second, then subscribe to it for display. Drop the publish to
// point the gauge at any other publisher.
//
// The gauge below renders `temperature / 100.0` as its ratio, so
// `temperature` is published in the 0–100 range (the gauge clamps
// anything outside [0, 1] and warns).
let tick = time::timer(duration:1.s, true);
let t = cast<f64>(count(tick))$;
let temp_source = 50.0;
temp_source <- tick ~ 50.0 + 25.0 * math::sin(t / 5.0);
sys::net::publish("/local/graphix/overview_realtime/temperature", temp_source);
let temperature: f64 = sys::net::subscribe("/local/graphix/overview_realtime/temperature")$;
// Will display updates automatically when data changes
gauge(
#gauge_style: &style(#fg: `Red),
#label: &span("Temperature"),
&(temperature / 100.0)
)