Eventos de teclado: - Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind - Soporte para todas las teclas: caracteres, F1-F12, navegación, control - Modificadores: Ctrl, Alt, Shift, Super Eventos de ratón: - MouseEvent, MouseEventKind, MouseButton - Click, release, drag, scroll (up/down/left/right) - Posición (column, row) con modificadores - Protocolos: SGR extended y X10 legacy Parser de escape sequences: - CSI sequences (arrows, F-keys, navigation) - SS3 sequences (F1-F4 alternativo) - SGR mouse protocol (mejores coordenadas) - X10 mouse protocol (compatibilidad) - Focus events, bracketed paste Cursor control: - Visibility: show/hide - Blinking: enable/disable - Styles: block, underline, bar (blinking/steady) - Position: moveTo, moveUp/Down/Left/Right - Save/restore position Terminal integrado: - pollEvent(timeout_ms) - polling con timeout - readEvent() - blocking read - enableMouseCapture/disableMouseCapture - enableFocusChange/disableFocusChange - enableBracketedPaste/disableBracketedPaste Ejemplo interactivo: - examples/events_demo.zig Tests: 47 (29 nuevos para eventos y cursor) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
914 lines
21 KiB
Markdown
914 lines
21 KiB
Markdown
# zcatui - API Reference
|
||
|
||
> Referencia rapida de la API publica de zcatui
|
||
|
||
## Importar la Libreria
|
||
|
||
```zig
|
||
const zcatui = @import("zcatui");
|
||
|
||
// Core types
|
||
const Color = zcatui.Color;
|
||
const Style = zcatui.Style;
|
||
const Modifier = zcatui.Modifier;
|
||
const Cell = zcatui.Cell;
|
||
const Buffer = zcatui.Buffer;
|
||
const Rect = zcatui.Rect;
|
||
const Span = zcatui.Span;
|
||
const Line = zcatui.Line;
|
||
const Text = zcatui.Text;
|
||
const Alignment = zcatui.Alignment;
|
||
|
||
// Layout
|
||
const Layout = zcatui.Layout;
|
||
const Constraint = zcatui.Constraint;
|
||
const Direction = zcatui.Direction;
|
||
|
||
// Terminal
|
||
const Terminal = zcatui.Terminal;
|
||
|
||
// Events (crossterm-style)
|
||
const Event = zcatui.Event;
|
||
const KeyEvent = zcatui.KeyEvent;
|
||
const KeyCode = zcatui.KeyCode;
|
||
const KeyModifiers = zcatui.KeyModifiers;
|
||
const MouseEvent = zcatui.MouseEvent;
|
||
const MouseEventKind = zcatui.MouseEventKind;
|
||
const MouseButton = zcatui.MouseButton;
|
||
|
||
// Cursor
|
||
const Cursor = zcatui.Cursor;
|
||
const CursorStyle = zcatui.CursorStyle;
|
||
|
||
// Widgets
|
||
const widgets = zcatui.widgets;
|
||
const Block = widgets.Block;
|
||
const Paragraph = widgets.Paragraph;
|
||
const List = widgets.List;
|
||
const ListState = widgets.ListState;
|
||
// ... etc
|
||
```
|
||
|
||
---
|
||
|
||
## Core Types
|
||
|
||
### Color
|
||
|
||
```zig
|
||
pub const Color = union(enum) {
|
||
// Reset
|
||
reset,
|
||
|
||
// Basic 16 colors
|
||
black, red, green, yellow, blue, magenta, cyan, white,
|
||
light_black, light_red, light_green, light_yellow,
|
||
light_blue, light_magenta, light_cyan, light_white,
|
||
|
||
// 256 color palette
|
||
indexed: u8,
|
||
|
||
// True color (24-bit)
|
||
rgb: struct { r: u8, g: u8, b: u8 },
|
||
|
||
// Constructor helpers
|
||
pub fn indexed(n: u8) Color;
|
||
pub fn rgb(r: u8, g: u8, b: u8) Color;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
const red = Color.red;
|
||
const gray = Color.indexed(240);
|
||
const custom = Color.rgb(255, 128, 0);
|
||
```
|
||
|
||
### Style
|
||
|
||
```zig
|
||
pub const Style = struct {
|
||
foreground: ?Color = null,
|
||
background: ?Color = null,
|
||
add_modifiers: Modifier = .{},
|
||
sub_modifiers: Modifier = .{},
|
||
|
||
pub const default: Style = .{};
|
||
|
||
// Fluent setters
|
||
pub fn fg(self: Style, color: Color) Style;
|
||
pub fn bg(self: Style, color: Color) Style;
|
||
pub fn bold(self: Style) Style;
|
||
pub fn dim(self: Style) Style;
|
||
pub fn italic(self: Style) Style;
|
||
pub fn underlined(self: Style) Style;
|
||
pub fn slow_blink(self: Style) Style;
|
||
pub fn rapid_blink(self: Style) Style;
|
||
pub fn reversed(self: Style) Style;
|
||
pub fn hidden(self: Style) Style;
|
||
pub fn crossed_out(self: Style) Style;
|
||
|
||
// Remove modifiers
|
||
pub fn notBold(self: Style) Style;
|
||
pub fn notDim(self: Style) Style;
|
||
// ... etc
|
||
|
||
// Combine styles
|
||
pub fn patch(self: Style, other: Style) Style;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
const style1 = Style.default.fg(Color.red).bold();
|
||
const style2 = Style.default.bg(Color.blue).italic();
|
||
const combined = style1.patch(style2); // red fg, blue bg, bold+italic
|
||
```
|
||
|
||
### Modifier
|
||
|
||
```zig
|
||
pub const Modifier = packed struct {
|
||
bold: bool = false,
|
||
dim: bool = false,
|
||
italic: bool = false,
|
||
underlined: bool = false,
|
||
slow_blink: bool = false,
|
||
rapid_blink: bool = false,
|
||
reversed: bool = false,
|
||
hidden: bool = false,
|
||
crossed_out: bool = false,
|
||
|
||
pub const empty: Modifier = .{};
|
||
pub const all: Modifier = .{ .bold = true, ... };
|
||
|
||
pub fn contains(self: Modifier, other: Modifier) bool;
|
||
pub fn insert(self: Modifier, other: Modifier) Modifier;
|
||
pub fn remove(self: Modifier, other: Modifier) Modifier;
|
||
};
|
||
```
|
||
|
||
### Rect
|
||
|
||
```zig
|
||
pub const Rect = struct {
|
||
x: u16,
|
||
y: u16,
|
||
width: u16,
|
||
height: u16,
|
||
|
||
pub fn init(x: u16, y: u16, width: u16, height: u16) Rect;
|
||
|
||
// Getters
|
||
pub fn left(self: Rect) u16; // x
|
||
pub fn right(self: Rect) u16; // x + width
|
||
pub fn top(self: Rect) u16; // y
|
||
pub fn bottom(self: Rect) u16; // y + height
|
||
pub fn area(self: Rect) u32; // width * height
|
||
|
||
// Queries
|
||
pub fn isEmpty(self: Rect) bool;
|
||
pub fn contains(self: Rect, x: u16, y: u16) bool;
|
||
|
||
// Transformations
|
||
pub fn inner(self: Rect, margin: u16) Rect;
|
||
pub fn innerMargins(self: Rect, top: u16, right: u16, bottom: u16, left_: u16) Rect;
|
||
pub fn intersection(self: Rect, other: Rect) Rect;
|
||
pub fn union_(self: Rect, other: Rect) Rect;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
const area = Rect.init(0, 0, 80, 24);
|
||
const inner = area.inner(1); // Rect.init(1, 1, 78, 22)
|
||
```
|
||
|
||
### Symbol
|
||
|
||
Almacenamiento compacto UTF-8 (hasta 4 bytes). Optimizado para evitar conversiones en render.
|
||
|
||
```zig
|
||
pub const Symbol = struct {
|
||
data: [4]u8 = .{ ' ', 0, 0, 0 },
|
||
len: u3 = 1,
|
||
|
||
pub const default_val: Symbol = .{};
|
||
pub const space: Symbol = .{};
|
||
|
||
// Constructores
|
||
pub fn fromSlice(bytes: []const u8) Symbol;
|
||
pub fn fromCodepoint(cp: u21) Symbol;
|
||
|
||
// Acceso
|
||
pub fn slice(self: Symbol) []const u8; // Para output directo
|
||
pub fn eql(self: Symbol, other: Symbol) bool;
|
||
};
|
||
```
|
||
|
||
### Cell
|
||
|
||
```zig
|
||
pub const Cell = struct {
|
||
symbol: Symbol = Symbol.space,
|
||
fg: Color = .reset,
|
||
bg: Color = .reset,
|
||
modifiers: Modifier = .{},
|
||
|
||
pub const empty: Cell = .{};
|
||
|
||
// Constructores
|
||
pub fn init(cp: u21) Cell;
|
||
pub fn fromStr(s: []const u8) Cell;
|
||
|
||
// Modificadores
|
||
pub fn setStyle(self: *Cell, s: Style) void;
|
||
pub fn setChar(self: *Cell, cp: u21) void;
|
||
pub fn setSymbol(self: *Cell, s: []const u8) void;
|
||
pub fn reset(self: *Cell) void;
|
||
|
||
// Comparación (para diff)
|
||
pub fn eql(self: Cell, other: Cell) bool;
|
||
|
||
// Legacy accessor
|
||
pub fn char(self: Cell) u21; // Decodifica symbol a codepoint
|
||
};
|
||
```
|
||
|
||
### Buffer
|
||
|
||
```zig
|
||
pub const Buffer = struct {
|
||
area: Rect,
|
||
cells: []Cell,
|
||
allocator: Allocator,
|
||
|
||
pub fn init(allocator: Allocator, area: Rect) !Buffer;
|
||
pub fn deinit(self: *Buffer) void;
|
||
|
||
// Cell access
|
||
pub fn getPtr(self: *Buffer, x: u16, y: u16) ?*Cell;
|
||
pub fn getCell(self: *Buffer, x: u16, y: u16) ?*Cell; // Alias
|
||
pub fn get(self: *const Buffer, x: u16, y: u16) ?Cell;
|
||
|
||
// Setting content
|
||
pub fn setChar(self: *Buffer, x: u16, y: u16, cp: u21, s: Style) void;
|
||
pub fn setString(self: *Buffer, x: u16, y: u16, text: []const u8, style: Style) u16;
|
||
pub fn setStyle(self: *Buffer, area: Rect, style: Style) void;
|
||
|
||
// Filling
|
||
pub fn fill(self: *Buffer, rect: Rect, cp: u21, s: Style) void;
|
||
pub fn clear(self: *Buffer) void;
|
||
|
||
// Differential rendering (v1.1)
|
||
pub fn diff(self: *const Buffer, other: *const Buffer) DiffIterator;
|
||
pub fn resize(self: *Buffer, new_rect: Rect) !void;
|
||
pub fn merge(self: *Buffer, other: *const Buffer) void;
|
||
|
||
// Legacy (no-op, for compatibility)
|
||
pub fn markDirty(self: *Buffer) void;
|
||
pub fn markClean(self: *Buffer) void;
|
||
};
|
||
|
||
// Iterator para renderizado diferencial
|
||
pub const DiffIterator = struct {
|
||
pub fn next(self: *DiffIterator) ?CellUpdate;
|
||
pub fn countRemaining(self: *DiffIterator) usize;
|
||
};
|
||
|
||
pub const CellUpdate = struct {
|
||
x: u16,
|
||
y: u16,
|
||
cell: Cell,
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
var buf = try Buffer.init(allocator, Rect.init(0, 0, 80, 24));
|
||
defer buf.deinit();
|
||
|
||
_ = buf.setString(10, 5, "Hello, World!", Style.default.fg(Color.green));
|
||
|
||
if (buf.getCell(10, 5)) |cell| {
|
||
cell.setStyle(Style.default.bold());
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Text Types
|
||
|
||
### Span
|
||
|
||
```zig
|
||
pub const Span = struct {
|
||
content: []const u8,
|
||
style: Style,
|
||
|
||
pub fn init(content: []const u8) Span;
|
||
pub fn raw(content: []const u8) Span;
|
||
pub fn styled(content: []const u8, style: Style) Span;
|
||
pub fn setStyle(self: Span, style: Style) Span;
|
||
pub fn width(self: Span) usize;
|
||
};
|
||
```
|
||
|
||
### Line
|
||
|
||
```zig
|
||
pub const Line = struct {
|
||
spans: []const Span,
|
||
alignment: Alignment,
|
||
|
||
pub fn init(spans: []const Span) Line;
|
||
pub fn raw(content: []const u8) Line;
|
||
pub fn styled(content: []const u8, style: Style) Line;
|
||
pub fn setStyle(self: Line, style: Style) Line;
|
||
pub fn setAlignment(self: Line, alignment: Alignment) Line;
|
||
pub fn width(self: Line) usize;
|
||
};
|
||
```
|
||
|
||
### Text
|
||
|
||
```zig
|
||
pub const Text = struct {
|
||
lines: []const Line,
|
||
alignment: Alignment,
|
||
|
||
pub fn init(lines: []const Line) Text;
|
||
pub fn raw(content: []const u8) Text;
|
||
pub fn styled(content: []const u8, style: Style) Text;
|
||
pub fn setStyle(self: Text, style: Style) Text;
|
||
pub fn setAlignment(self: Text, alignment: Alignment) Text;
|
||
pub fn width(self: Text) usize;
|
||
pub fn height(self: Text) usize;
|
||
};
|
||
```
|
||
|
||
### Alignment
|
||
|
||
```zig
|
||
pub const Alignment = enum {
|
||
left,
|
||
center,
|
||
right,
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
// Simple text
|
||
const span = Span.styled("Hello", Style.default.fg(Color.red));
|
||
const line = Line.raw("Simple line");
|
||
|
||
// Multi-span line
|
||
const multi_line = Line.init(&[_]Span{
|
||
Span.styled("Error: ", Style.default.fg(Color.red).bold()),
|
||
Span.raw("Something went wrong"),
|
||
});
|
||
|
||
// Multi-line text
|
||
const text = Text.raw("Line 1\nLine 2\nLine 3");
|
||
```
|
||
|
||
---
|
||
|
||
## Layout
|
||
|
||
### Layout
|
||
|
||
```zig
|
||
pub const Layout = struct {
|
||
direction: Direction,
|
||
constraints: []const Constraint,
|
||
|
||
pub fn horizontal(constraints: []const Constraint) Layout;
|
||
pub fn vertical(constraints: []const Constraint) Layout;
|
||
pub fn init(direction: Direction, constraints: []const Constraint) Layout;
|
||
|
||
pub fn split(self: Layout, area: Rect, result: []Rect) void;
|
||
};
|
||
```
|
||
|
||
### Constraint
|
||
|
||
```zig
|
||
pub const Constraint = union(enum) {
|
||
length: u16, // Exactly N cells
|
||
min: u16, // At least N cells
|
||
max: u16, // At most N cells
|
||
percentage: u16, // N% of available space (0-100)
|
||
ratio: struct { num: u32, den: u32 },
|
||
fill: u16, // Fill remaining space (weight)
|
||
|
||
pub fn length(n: u16) Constraint;
|
||
pub fn min(n: u16) Constraint;
|
||
pub fn max(n: u16) Constraint;
|
||
pub fn percentage(n: u16) Constraint;
|
||
pub fn ratio(num: u32, den: u32) Constraint;
|
||
pub fn fill(weight: u16) Constraint;
|
||
};
|
||
```
|
||
|
||
### Direction
|
||
|
||
```zig
|
||
pub const Direction = enum {
|
||
horizontal,
|
||
vertical,
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
// Vertical layout: header (3 rows), content (rest), footer (1 row)
|
||
const layout = Layout.vertical(&[_]Constraint{
|
||
Constraint.length(3),
|
||
Constraint.min(0),
|
||
Constraint.length(1),
|
||
});
|
||
|
||
var chunks: [3]Rect = undefined;
|
||
layout.split(area, &chunks);
|
||
|
||
// Horizontal split: 30% | 70%
|
||
const h_layout = Layout.horizontal(&[_]Constraint{
|
||
Constraint.percentage(30),
|
||
Constraint.percentage(70),
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Symbols
|
||
|
||
### Line Set
|
||
|
||
```zig
|
||
pub const line = struct {
|
||
pub const Set = struct {
|
||
vertical: []const u8,
|
||
horizontal: []const u8,
|
||
top_right: []const u8,
|
||
top_left: []const u8,
|
||
bottom_right: []const u8,
|
||
bottom_left: []const u8,
|
||
vertical_left: []const u8,
|
||
vertical_right: []const u8,
|
||
horizontal_down: []const u8,
|
||
horizontal_up: []const u8,
|
||
cross: []const u8,
|
||
};
|
||
|
||
pub const NORMAL: Set; // ─│┌┐└┘
|
||
pub const ROUNDED: Set; // ─│╭╮╰╯
|
||
pub const DOUBLE: Set; // ═║╔╗╚╝
|
||
pub const THICK: Set; // ━┃┏┓┗┛
|
||
};
|
||
```
|
||
|
||
### Border Set
|
||
|
||
```zig
|
||
pub const border = struct {
|
||
pub const Set = struct {
|
||
top_left: []const u8,
|
||
top_right: []const u8,
|
||
bottom_left: []const u8,
|
||
bottom_right: []const u8,
|
||
horizontal: []const u8,
|
||
vertical: []const u8,
|
||
};
|
||
|
||
pub const PLAIN: Set;
|
||
pub const ROUNDED: Set;
|
||
pub const DOUBLE: Set;
|
||
pub const THICK: Set;
|
||
};
|
||
```
|
||
|
||
### Block Characters
|
||
|
||
```zig
|
||
pub const block = struct {
|
||
pub const FULL: []const u8 = "█";
|
||
pub const UPPER_HALF: []const u8 = "▀";
|
||
pub const LOWER_HALF: []const u8 = "▄";
|
||
pub const LEFT_HALF: []const u8 = "▌";
|
||
pub const RIGHT_HALF: []const u8 = "▐";
|
||
// ...
|
||
};
|
||
```
|
||
|
||
### Bar Characters
|
||
|
||
```zig
|
||
pub const bar = struct {
|
||
pub const Set = struct {
|
||
full: []const u8,
|
||
seven_eighths: []const u8,
|
||
three_quarters: []const u8,
|
||
five_eighths: []const u8,
|
||
half: []const u8,
|
||
three_eighths: []const u8,
|
||
one_quarter: []const u8,
|
||
one_eighth: []const u8,
|
||
empty: []const u8,
|
||
};
|
||
|
||
pub const NINE_LEVELS: Set;
|
||
pub const THREE_LEVELS: Set;
|
||
};
|
||
```
|
||
|
||
### Braille
|
||
|
||
```zig
|
||
pub const braille = struct {
|
||
pub const BLANK: []const u8 = "⠀"; // U+2800
|
||
|
||
// Bit positions for 2x4 grid:
|
||
// 0 3
|
||
// 1 4
|
||
// 2 5
|
||
// 6 7
|
||
|
||
pub const PATTERNS: [256][3]u8; // Pre-computed UTF-8 patterns
|
||
|
||
pub fn fromPattern(pattern: u8) []const u8;
|
||
};
|
||
```
|
||
|
||
### Marker
|
||
|
||
```zig
|
||
pub const Marker = enum {
|
||
dot,
|
||
block,
|
||
bar,
|
||
braille,
|
||
half_block,
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## Terminal
|
||
|
||
```zig
|
||
pub const Terminal = struct {
|
||
pub fn init(allocator: Allocator) !Terminal;
|
||
pub fn deinit(self: *Terminal) void;
|
||
|
||
pub fn size(self: Terminal) struct { width: u16, height: u16 };
|
||
pub fn area(self: Terminal) Rect;
|
||
|
||
// Rendering
|
||
pub fn draw(self: *Terminal, render_fn: fn(area: Rect, buf: *Buffer) void) !void;
|
||
pub fn drawWithContext(self: *Terminal, ctx: anytype, render_fn: fn(...) void) !void;
|
||
pub fn clear(self: *Terminal) !void;
|
||
pub fn flush(self: *Terminal) !void;
|
||
|
||
// Cursor
|
||
pub fn hideCursor(self: *Terminal) !void;
|
||
pub fn showCursor(self: *Terminal) !void;
|
||
pub fn setCursorPosition(self: *Terminal, x: u16, y: u16) !void;
|
||
|
||
// Events (crossterm-style)
|
||
pub fn pollEvent(self: *Terminal, timeout_ms: ?u32) !?Event;
|
||
pub fn readEvent(self: *Terminal) !Event;
|
||
|
||
// Mouse
|
||
pub fn enableMouseCapture(self: *Terminal) !void;
|
||
pub fn disableMouseCapture(self: *Terminal) !void;
|
||
|
||
// Focus
|
||
pub fn enableFocusChange(self: *Terminal) !void;
|
||
pub fn disableFocusChange(self: *Terminal) !void;
|
||
|
||
// Bracketed paste
|
||
pub fn enableBracketedPaste(self: *Terminal) !void;
|
||
pub fn disableBracketedPaste(self: *Terminal) !void;
|
||
};
|
||
```
|
||
|
||
**Ejemplo interactivo completo:**
|
||
```zig
|
||
pub fn main() !void {
|
||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||
defer _ = gpa.deinit();
|
||
const allocator = gpa.allocator();
|
||
|
||
var term = try Terminal.init(allocator);
|
||
defer term.deinit();
|
||
|
||
// Enable mouse (optional)
|
||
try term.enableMouseCapture();
|
||
|
||
var running = true;
|
||
while (running) {
|
||
try term.draw(render);
|
||
|
||
// Poll for events with 100ms timeout
|
||
if (try term.pollEvent(100)) |event| {
|
||
switch (event) {
|
||
.key => |key| {
|
||
if (key.code == .esc) running = false;
|
||
if (key.code.isChar('q')) running = false;
|
||
},
|
||
.mouse => |mouse| {
|
||
if (mouse.kind == .down) handleClick(mouse.column, mouse.row);
|
||
},
|
||
.resize => |size| try term.resize(size.width, size.height),
|
||
else => {},
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Events (crossterm-style)
|
||
|
||
### Event
|
||
|
||
```zig
|
||
pub const Event = union(enum) {
|
||
key: KeyEvent,
|
||
mouse: MouseEvent,
|
||
resize: ResizeEvent,
|
||
focus_gained,
|
||
focus_lost,
|
||
paste: []const u8,
|
||
};
|
||
```
|
||
|
||
### KeyEvent
|
||
|
||
```zig
|
||
pub const KeyEvent = struct {
|
||
code: KeyCode,
|
||
modifiers: KeyModifiers,
|
||
kind: KeyEventKind,
|
||
|
||
pub fn char(c: u21) KeyEvent;
|
||
pub fn withMod(code: KeyCode, mods: KeyModifiers) KeyEvent;
|
||
pub fn getChar(self: KeyEvent) ?u21;
|
||
pub fn isCtrl(self: KeyEvent) bool;
|
||
pub fn isAlt(self: KeyEvent) bool;
|
||
pub fn isShift(self: KeyEvent) bool;
|
||
};
|
||
```
|
||
|
||
### KeyCode
|
||
|
||
```zig
|
||
pub const KeyCode = union(enum) {
|
||
char: u21, // Any unicode character
|
||
f: u8, // F1-F12
|
||
backspace, enter, tab, backtab,
|
||
left, right, up, down,
|
||
home, end, page_up, page_down,
|
||
insert, delete, esc, null_key,
|
||
caps_lock, scroll_lock, num_lock,
|
||
print_screen, pause, menu,
|
||
media: MediaKeyCode,
|
||
modifier: ModifierKeyCode,
|
||
|
||
pub fn isChar(self: KeyCode, c: u21) bool;
|
||
};
|
||
```
|
||
|
||
### KeyModifiers
|
||
|
||
```zig
|
||
pub const KeyModifiers = packed struct {
|
||
shift: bool = false,
|
||
ctrl: bool = false,
|
||
alt: bool = false,
|
||
super: bool = false,
|
||
|
||
pub const none: KeyModifiers = .{};
|
||
pub const SHIFT: KeyModifiers = .{ .shift = true };
|
||
pub const CTRL: KeyModifiers = .{ .ctrl = true };
|
||
pub const ALT: KeyModifiers = .{ .alt = true };
|
||
|
||
pub fn combine(self: KeyModifiers, other: KeyModifiers) KeyModifiers;
|
||
pub fn any(self: KeyModifiers) bool;
|
||
pub fn isEmpty(self: KeyModifiers) bool;
|
||
};
|
||
```
|
||
|
||
### MouseEvent
|
||
|
||
```zig
|
||
pub const MouseEvent = struct {
|
||
kind: MouseEventKind,
|
||
button: MouseButton,
|
||
column: u16,
|
||
row: u16,
|
||
modifiers: KeyModifiers,
|
||
|
||
pub fn down(button: MouseButton, col: u16, row: u16) MouseEvent;
|
||
pub fn up(button: MouseButton, col: u16, row: u16) MouseEvent;
|
||
pub fn moved(col: u16, row: u16) MouseEvent;
|
||
pub fn isClick(self: MouseEvent) bool;
|
||
pub fn isLeft(self: MouseEvent) bool;
|
||
pub fn isRight(self: MouseEvent) bool;
|
||
};
|
||
```
|
||
|
||
### MouseEventKind
|
||
|
||
```zig
|
||
pub const MouseEventKind = enum {
|
||
down, up, drag, moved,
|
||
scroll_down, scroll_up,
|
||
scroll_left, scroll_right,
|
||
|
||
pub fn isScroll(self: MouseEventKind) bool;
|
||
pub fn isButton(self: MouseEventKind) bool;
|
||
};
|
||
```
|
||
|
||
### MouseButton
|
||
|
||
```zig
|
||
pub const MouseButton = enum {
|
||
left, right, middle, none,
|
||
};
|
||
```
|
||
|
||
**Ejemplo de manejo de eventos:**
|
||
```zig
|
||
if (try term.pollEvent(100)) |event| {
|
||
switch (event) {
|
||
.key => |key| {
|
||
// Ctrl+C
|
||
if (key.code.isChar('c') and key.isCtrl()) {
|
||
break;
|
||
}
|
||
// Arrow keys
|
||
switch (key.code) {
|
||
.up => state.previous(),
|
||
.down => state.next(),
|
||
.enter => state.select(),
|
||
else => {},
|
||
}
|
||
},
|
||
.mouse => |mouse| {
|
||
switch (mouse.kind) {
|
||
.down => {
|
||
if (mouse.isLeft()) selectAt(mouse.column, mouse.row);
|
||
},
|
||
.scroll_up => state.scrollUp(),
|
||
.scroll_down => state.scrollDown(),
|
||
else => {},
|
||
}
|
||
},
|
||
.resize => |size| {
|
||
try term.resize(size.width, size.height);
|
||
},
|
||
.focus_gained => {},
|
||
.focus_lost => {},
|
||
.paste => |text| handlePaste(text),
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Cursor
|
||
|
||
```zig
|
||
pub const CursorStyle = enum {
|
||
default,
|
||
blinking_block,
|
||
steady_block,
|
||
blinking_underline,
|
||
steady_underline,
|
||
blinking_bar,
|
||
steady_bar,
|
||
};
|
||
|
||
pub const Cursor = struct {
|
||
pub fn init() Cursor;
|
||
|
||
// Visibility
|
||
pub fn hide(self: *Cursor) !void;
|
||
pub fn show(self: *Cursor) !void;
|
||
|
||
// Blinking
|
||
pub fn enableBlinking(self: *Cursor) !void;
|
||
pub fn disableBlinking(self: *Cursor) !void;
|
||
|
||
// Style
|
||
pub fn setStyle(self: *Cursor, style: CursorStyle) !void;
|
||
|
||
// Position
|
||
pub fn moveTo(self: *Cursor, column: u16, row: u16) !void;
|
||
pub fn moveUp(self: *Cursor, n: u16) !void;
|
||
pub fn moveDown(self: *Cursor, n: u16) !void;
|
||
pub fn moveLeft(self: *Cursor, n: u16) !void;
|
||
pub fn moveRight(self: *Cursor, n: u16) !void;
|
||
|
||
// Save/Restore
|
||
pub fn savePosition(self: *Cursor) !void;
|
||
pub fn restorePosition(self: *Cursor) !void;
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## Widgets Quick Reference
|
||
|
||
| Widget | Constructor | Stateful | Key Methods |
|
||
|--------|------------|----------|-------------|
|
||
| Block | `Block.init()` | No | `title()`, `borders()`, `borderStyle()` |
|
||
| Paragraph | `Paragraph.init(text)` | No | `setWrap()`, `setAlignment()`, `setScroll()` |
|
||
| List | `List.init(items)` | Yes | `setHighlightStyle()`, `setHighlightSymbol()` |
|
||
| Table | `Table.init(rows, widths)` | Yes | `setHeader()`, `setHighlightStyle()` |
|
||
| Gauge | `Gauge.init()` | No | `setRatio()`, `setPercent()`, `setLabel()` |
|
||
| LineGauge | `LineGauge.init()` | No | `setRatio()`, `setFilledStyle()` |
|
||
| Tabs | `Tabs.init(titles)` | No | `select()`, `setDivider()` |
|
||
| Sparkline | `Sparkline.init()` | No | `setData()`, `setMax()` |
|
||
| Scrollbar | `Scrollbar.init(orientation)` | Yes | `setSymbols()`, `setStyle()` |
|
||
| BarChart | `BarChart.init()` | No | `setData()`, `setBarWidth()` |
|
||
| Canvas | `Canvas.init()` | No | `setXBounds()`, `setYBounds()`, `paint()` |
|
||
| Chart | `Chart.init(datasets)` | No | `setXAxis()`, `setYAxis()` |
|
||
| Monthly | `Monthly.init(date)` | No | `showMonthHeader()`, `showWeekdaysHeader()` |
|
||
| Clear | `Clear.init()` | No | (none) |
|
||
|
||
---
|
||
|
||
## Error Handling
|
||
|
||
zcatui usa el sistema de errores de Zig. Las funciones que pueden fallar retornan `!T`.
|
||
|
||
```zig
|
||
// Errores comunes
|
||
const TerminalError = error{
|
||
InitFailed,
|
||
WriteFailed,
|
||
FlushFailed,
|
||
};
|
||
|
||
const BufferError = error{
|
||
OutOfMemory,
|
||
};
|
||
|
||
// Manejo tipico
|
||
var term = Terminal.init(allocator) catch |err| {
|
||
std.debug.print("Failed to init terminal: {}\n", .{err});
|
||
return err;
|
||
};
|
||
defer term.deinit();
|
||
```
|
||
|
||
---
|
||
|
||
## Patterns
|
||
|
||
### Builder Pattern
|
||
|
||
```zig
|
||
const widget = SomeWidget.init()
|
||
.setOption1(value1)
|
||
.setOption2(value2)
|
||
.setBlock(Block.bordered());
|
||
```
|
||
|
||
### Stateful Rendering
|
||
|
||
```zig
|
||
var state = WidgetState.init();
|
||
|
||
// En el loop de renderizado:
|
||
widget.renderStateful(area, buf, &state);
|
||
|
||
// Actualizar estado basado en input:
|
||
state.selectNext(items.len);
|
||
```
|
||
|
||
### Layout Composition
|
||
|
||
```zig
|
||
const outer = Layout.vertical(&[_]Constraint{
|
||
Constraint.length(3),
|
||
Constraint.min(0),
|
||
});
|
||
|
||
var outer_chunks: [2]Rect = undefined;
|
||
outer.split(area, &outer_chunks);
|
||
|
||
const inner = Layout.horizontal(&[_]Constraint{
|
||
Constraint.percentage(50),
|
||
Constraint.percentage(50),
|
||
});
|
||
|
||
var inner_chunks: [2]Rect = undefined;
|
||
inner.split(outer_chunks[1], &inner_chunks);
|
||
```
|