zcatgui/CLAUDE.md
reugenio bd95013ffc fix(advanced_table): Teclado funciona - result.selected_row/col
Bug: Las flechas no movían la selección en AdvancedTable.

Causa raíz:
- handleKeyboard seteaba result.selection_changed = true
- PERO NO seteaba result.selected_row / result.selected_col
- zsimifactu sincroniza selección desde DataManager cada frame
- Sin esos valores, DataManager no se actualizaba
- Siguiente frame: selección se reseteaba al valor anterior

Solución:
- Añadir result.selected_row y result.selected_col a todas
  las teclas de navegación (up, down, left, right, page_up,
  page_down, home, end)

Cambios visuales:
- Celda seleccionada: borde + tinte sutil (15%) en lugar
  de fondo sólido azul

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 20:06:17 +01:00

34 KiB

zcatgui - GUI Library para Zig

IMPORTANTE PARA CLAUDE: Lee la sección "PROTOCOLO DE INICIO" antes de hacer cualquier cosa.


PROTOCOLO DE INICIO (LEER PRIMERO)

Paso 1: Leer normas del equipo

/mnt/cello2/arno/re/recode/teamdocs/LAST_UPDATE.md

Paso 2: Leer normas completas si es necesario

/mnt/cello2/arno/re/recode/teamdocs/normas/NORMAS_TRABAJO_CONSENSUADAS.md
/mnt/cello2/arno/re/recode/teamdocs/QUICK_REFERENCE.md
/mnt/cello2/arno/re/recode/teamdocs/agenda/2025-12_diciembre.md  # Trabajo diario

Paso 3: Leer documentación

REFERENCE.md                                      # ⭐ MANUAL DE REFERENCIA COMPLETO
docs/BUG_ADVANCEDTABLE_KEYBOARD_2025-12-17.md    # ✅ BUG RESUELTO
docs/ADVANCED_TABLE_MERGE_PLAN.md                # Plan merge Table → AdvancedTable
docs/research/DVUI_AUDIT_2025-12-17.md           # Auditoría DVUI
docs/DEVELOPMENT_PLAN.md                          # Plan de desarrollo por fases
docs/MOBILE_WEB_BACKENDS.md                       # Documentación backends mobile/web
docs/research/WIDGET_COMPARISON.md                # Comparativa zcatgui vs DVUI vs Gio
docs/ARCHITECTURE.md                              # Arquitectura y decisiones de diseño

Paso 4: Verificar estado del proyecto

cd /mnt/cello2/arno/re/recode/zig/zcatgui
git status
git log --oneline -3
zig build test

Paso 5: Continuar trabajo

Una vez verificado el estado, continúa desde donde se dejó.


REGLA CRÍTICA: NO EJECUTAR BINARIOS GUI

NUNCA ejecutar programas GUI directamente con ./programa o en background

Los procesos GUI no terminan correctamente desde Claude Code y dejan shells zombie que:

  1. Consumen contexto de la conversación con mensajes "Background Bash running"
  2. Fuerzan compactaciones prematuras del contexto
  3. Degradan severamente la calidad de la sesión de trabajo

Alternativas:

  • Para verificar que compila: zig build (sin ejecutar)
  • Para probar muy brevemente: timeout 2s ./programa 2>&1 || true
  • Mejor opción: Pedir al usuario que lo pruebe y reporte

Esta regla está documentada en teamdocs desde 2025-11-30.


DOCUMENTACIÓN EN TEAMDOCS

Al documentar trabajo en teamdocs/agenda/:

  1. Entrada en agenda: Máximo 5 líneas (QUÉ + CUÁNDO + link)
  2. Detalle técnico: Crear hito en agenda/hitos/
  3. Protocolo completo: Ver teamdocs/ESTRUCTURA_DOCUMENTACION.md

Formato de entrada:

## Fecha - Título ✅

Resumen breve (1-2 frases). Resultado principal.

→ [Detalle técnico](hitos/YYYY-MM-DD_tema.md)

Paridad Visual DVUI - FASES 1+2 COMPLETADAS

Estado: Fases 1 y 2 completadas (2025-12-17) Auditoría original: docs/research/DVUI_AUDIT_2025-12-17.md (570 líneas)

El Problema (RESUELTO)

zcatgui tenía MÁS widgets que DVUI pero DVUI se veía mejor por falta de:

  1. Esquinas redondeadasfillRoundedRect con edge-fade AA
  2. Anti-aliasing en bordes → edge-fade technique implementada
  3. Transiciones suaves → HoverTransition en Button/Select
  4. Sombras en paneles/modales → Panel/Modal con shadow
  5. Focus ring AA → 9 widgets con focus ring

Sistema Dual Implementado

// style.zig
pub const RenderMode = enum { simple, fancy };
var global_render_mode: RenderMode = .fancy;  // Default: bonito

// Uso en widgets
if (Style.isFancy() and config.corner_radius > 0) {
    ctx.pushCommand(Command.roundedRect(...));
} else {
    ctx.pushCommand(Command.rect(...));
}

Widgets Actualizados

Widget corner_radius shadow Notas
Button 4 - Esquinas redondeadas en fancy mode
Panel 6 offset 4px Borde y shadow
TextInput 3 - Esquinas sutiles
Select 3 - Esquinas sutiles
Modal 8 offset 6px Diálogo + botones + input

Código Añadido

  • framebuffer.zig: +350 LOC (fillRoundedRect, drawRoundedRect, edge-fade AA)
  • command.zig: +69 LOC (nuevos comandos rounded_rect, rounded_rect_outline)
  • style.zig: +33 LOC (RenderMode system)
  • Widgets: ~120 LOC entre todos

Total: ~590 líneas nuevas/modificadas

Fase 2: Transiciones + Focus Ring COMPLETADA

HoverTransition helper (animation.zig):

  • update() y updateWithPress() para animar hacia target
  • blend() y blendThree() para interpolar colores
  • Speed configurable (default ~125ms transición)

Focus ring helper (command.zig):

  • focusRing() y focusRingColor() para indicador de foco
  • Dibuja 2px fuera del widget con AA
  • Color primario semi-transparente (alpha 180)

Widgets con focus ring:

Widget Transiciones Focus Ring Esquinas
Button buttonStateful() -
Select Automático
TextInput -
NumberEntry -
Radio - (opción)
Slider - (thumb)
Tabs - (tab)
Table - (borde) -
TextArea -
// Button con transiciones (opcional)
var btn_state = button.ButtonState{};
if (button.buttonStateful(&ctx, &btn_state, "Click me")) { ... }

// Focus ring se dibuja automáticamente cuando widget tiene foco

Fase 3: Efectos Avanzados (OPCIONAL)

  • Mejorar uso de gradientes
  • Blur effect para backdrops

Documentación de Referencia

  • docs/research/DVUI_AUDIT_2025-12-17.md - Auditoría completa
  • docs/research/WIDGET_COMPARISON.md - Comparativa (actualizar después)

TTF Rendering - RESUELTO (2025-12-17)

Estado: COMPLETADO - zcatttf v1.0 integrado y funcionando perfectamente Documentación: /mnt/cello2/arno/re/recode/teamdocs/agenda/hitos/2025-12-17_zcatttf_v1.0.md

El Problema (16-17 Dic)

El texto TTF se renderizaba como garabatos ilegibles. 2 días de debugging con múltiples intentos fallidos.

Solución: zcatttf v1.0

TRADUCCIÓN LITERAL de stb_truetype.h, sin intentar "mejorar" o "reimaginar".

Bug final: y_offset = iy0 (negativo) → y_offset = -iy0 (positivo). El bearing_y debe ser positivo para glyphs encima de la baseline.

Lección Clave

"No reimplementar, TRADUCIR" Si existe código C que funciona, traducirlo literalmente. La humildad técnica es fundamental.

Campo Valor
Librería /mnt/cello2/arno/re/recode/zig/zcatttf/
Versión v1.0
Algoritmo Traducción literal stb_truetype (~1,200 LOC rasterize.zig)
Estado FUNCIONA PERFECTAMENTE en zsimifactu

Archivos clave

  • src/render/ttf.zig - Wrapper sobre zcatttf (API compatible)
  • src/render/embedded_font.zig - Fuente DroidSans embebida
  • build.zig.zon - Dependencia de zcatttf

Uso

var ttf = try TtfFont.initEmbedded(allocator);
defer ttf.deinit();
ttf.setSize(14);
ttf.drawText(fb, x, y, "Hola UTF-8: áéíóú ñ €", color, clip);

Fuentes TTF: Estado Técnico

Estado actual (v0.19.0) - FUNCIONAL

  • Parsing TTF via zcatttf (cmap format 4 y 12)
  • Rasterización con áreas trapezoidales (antialiasing)
  • Fuente embebida (DroidSans)
  • Soporte UTF-8 completo (áéíóú ñ €)
  • Cache de glyphs renderizados

Uso actual

const ttf = @import("render/ttf.zig");

// Opción 1: Fuente embebida
var font = try ttf.TtfFont.initEmbedded(allocator);

// Opción 2: Cargar archivo
var font = try ttf.TtfFont.loadFromFile(allocator, "/path/to/font.ttf");

defer font.deinit();
font.setSize(14);
font.drawText(fb, x, y, "Texto con UTF-8: ñ €", color, clip);

INFORMACIÓN DEL PROYECTO

Campo Valor
Nombre zcatgui
Versión v0.19.0
Fecha inicio 2025-12-09
Estado COMPLETO - 37 widgets, ~35K LOC, 4 backends, TTF funcional
Lenguaje Zig 0.15.2
Paradigma Immediate Mode GUI
Inspiración Gio (Go), microui (C), DVUI (Zig), Dear ImGui (C++)
Proyecto hermano zcatui (TUI library)

Descripción

zcatgui es una librería GUI immediate-mode para Zig con las siguientes características:

  1. Software Rendering por defecto - Funciona en cualquier ordenador sin GPU
  2. Cross-platform - Linux, Windows, macOS, Web (WASM), Android, iOS
  3. SSH compatible - Funciona via X11 forwarding
  4. Sistema de Macros - Grabación/reproducción de acciones (piedra angular)
  5. Sin dependencias pesadas - Solo SDL2 para desktop, nativo para mobile/web

Filosofía

"Máxima compatibilidad, mínimas dependencias, control total del usuario"

  • Funciona en cualquier ordenador (viejo HP, nuevo Lenovo, servidor SSH)
  • Software rendering primero, GPU opcional después
  • Sistema de macros integrado desde el diseño
  • Immediate mode = estado explícito, sin threading hell

RUTAS IMPORTANTES

# Este proyecto
/mnt/cello2/arno/re/recode/zig/zcatgui/

# Proyecto hermano (TUI)
/mnt/cello2/arno/re/recode/zig/zcatui/

# Proyecto de referencia (usa Fyne, queremos replicar funcionalidad)
/mnt/cello2/arno/re/recode/go/simifactu/

# Normas del equipo
/mnt/cello2/arno/re/recode/teamdocs/

# Compilador Zig 0.15.2
/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig

COMANDOS FRECUENTES

# Compilar (desktop)
zig build

# Tests
zig build test

# Ejemplos desktop
zig build hello
zig build macro-demo
zig build widgets-demo
zig build table-demo

# WASM (navegador)
zig build wasm                    # Genera web/zcatgui-demo.wasm
cd web && python3 -m http.server  # Servir y abrir localhost:8000

# Android (requiere NDK)
zig build android                 # ARM64 para dispositivo
zig build android-x86             # x86_64 para emulador

# iOS (requiere Xcode en macOS)
zig build ios                     # ARM64 para dispositivo
zig build ios-sim                 # ARM64 para simulador

# Git
git status
git add -A && git commit -m "mensaje"
git push

ARQUITECTURA

Paradigma: Immediate Mode

┌─────────────────────────────────────────────────────────────┐
│                    IMMEDIATE MODE                           │
├─────────────────────────────────────────────────────────────┤
│  while (running) {                                          │
│      events = pollEvents();     // Input                    │
│      updateState(events);       // TÚ manejas estado        │
│      commands = drawUI(state);  // Genera comandos          │
│      render(commands);          // Dibuja                   │
│  }                                                          │
└─────────────────────────────────────────────────────────────┘

vs Retained Mode (Fyne):
- Framework mantiene árbol de widgets
- Callbacks para cambios
- fyne.Do() para threading
- Estado oculto, sincronización compleja

Capas de la Librería

┌─────────────────────────────────────────────────────────────┐
│  Capa 4: Widgets de alto nivel                              │
│  (Table, Panel, Select, Modal, etc.)                        │
├─────────────────────────────────────────────────────────────┤
│  Capa 3: Sistema de Macros                                  │
│  (Grabación, Reproducción, Inyección de teclas)             │
├─────────────────────────────────────────────────────────────┤
│  Capa 2: Core UI                                            │
│  (Context, Layout, Style, Input, Commands)                  │
├─────────────────────────────────────────────────────────────┤
│  Capa 1: Rendering                                          │
│  (Software Rasterizer, Framebuffer, Fonts)                  │
├─────────────────────────────────────────────────────────────┤
│  Capa 0: Backend                                            │
│  (SDL2 - ventanas, eventos, display)                        │
└─────────────────────────────────────────────────────────────┘

Estructura de Archivos (ACTUAL v0.16.0)

zcatgui/
├── src/
│   ├── zcatgui.zig          # Entry point, re-exports, conditional backend imports
│   │
│   ├── core/
│   │   ├── context.zig      # ✅ Context, ID system, command pool, FrameArena
│   │   ├── layout.zig       # ✅ Rect, Constraint, LayoutState
│   │   ├── style.zig        # ✅ Color, Style, Theme (5 themes)
│   │   ├── input.zig        # ✅ Key, KeyEvent, MouseEvent, InputState
│   │   ├── command.zig      # ✅ DrawCommand list
│   │   ├── clipboard.zig    # ✅ Clipboard support
│   │   ├── dragdrop.zig     # ✅ Drag & drop system
│   │   ├── shortcuts.zig    # ✅ Keyboard shortcuts manager
│   │   ├── focus_group.zig  # ✅ Focus groups
│   │   ├── accessibility.zig # ✅ Accessibility (ARIA roles)
│   │   └── gesture.zig      # ✅ Gesture recognizer (tap, swipe, pinch, rotate)
│   │
│   ├── widgets/             # 37 widgets implementados
│   │   ├── widgets.zig      # Re-exports
│   │   ├── label.zig, button.zig, text_input.zig, checkbox.zig
│   │   ├── select.zig, list.zig, focus.zig, table.zig
│   │   ├── split.zig, panel.zig, modal.zig, autocomplete.zig
│   │   ├── slider.zig, scroll.zig, tabs.zig, radio.zig, menu.zig
│   │   ├── progress.zig, tooltip.zig, toast.zig
│   │   ├── textarea.zig, tree.zig, badge.zig
│   │   ├── number_entry.zig, reorderable.zig
│   │   ├── breadcrumb.zig, image.zig, icon.zig
│   │   ├── color_picker.zig, date_picker.zig, chart.zig
│   │   └── calendar.zig
│   │
│   ├── render/
│   │   ├── software.zig     # ✅ SoftwareRenderer
│   │   ├── framebuffer.zig  # ✅ Framebuffer RGBA (u32 pixels)
│   │   ├── font.zig         # ✅ Bitmap font 8x8
│   │   ├── ttf.zig          # ✅ TTF font support (stb_truetype)
│   │   ├── animation.zig    # ✅ Animation system, easing, springs
│   │   ├── effects.zig      # ✅ Shadows, gradients, blur
│   │   └── antialiasing.zig # ✅ Anti-aliased rendering
│   │
│   ├── backend/
│   │   ├── backend.zig      # ✅ Backend interface (VTable)
│   │   ├── sdl2.zig         # ✅ SDL2 (desktop: Linux/Win/Mac)
│   │   ├── wasm.zig         # ✅ WASM (navegador)
│   │   ├── android.zig      # ✅ Android (ANativeActivity)
│   │   └── ios.zig          # ✅ iOS (UIKit bridge)
│   │
│   ├── macro/
│   │   └── macro.zig        # ✅ MacroRecorder, MacroPlayer, MacroStorage
│   │
│   ├── panels/
│   │   └── panels.zig       # ✅ Lego Panels architecture
│   │
│   └── utils/
│       └── utils.zig        # ✅ FrameArena, ObjectPool, Benchmark
│
├── examples/
│   ├── hello.zig            # Ejemplo básico
│   ├── macro_demo.zig       # Demo macros
│   ├── widgets_demo.zig     # Demo widgets
│   ├── table_demo.zig       # Demo Table/Split/Panel
│   ├── wasm_demo.zig        # ✅ Demo WASM (navegador)
│   └── android_demo.zig     # ✅ Demo Android
│
├── web/                     # ✅ WASM support
│   ├── index.html           # Demo HTML
│   ├── zcatgui.js           # JavaScript glue code
│   └── zcatgui-demo.wasm    # Compiled WASM (~18KB)
│
├── ios/                     # ✅ iOS support
│   ├── ZcatguiBridge.h      # Objective-C header
│   └── ZcatguiBridge.m      # UIKit implementation
│
├── docs/
│   ├── ARCHITECTURE.md
│   ├── DEVELOPMENT_PLAN.md  # ⭐ Plan maestro
│   ├── MOBILE_WEB_BACKENDS.md # ✅ Documentación mobile/web
│   └── research/
│       ├── GIO_UI_ANALYSIS.md
│       ├── IMMEDIATE_MODE_LIBS.md
│       ├── WIDGET_COMPARISON.md
│       └── SIMIFACTU_FYNE_ANALYSIS.md
│
├── build.zig                # Build con targets: wasm, android, ios
├── build.zig.zon
├── CLAUDE.md                # Este archivo
└── REFERENCE.md             # ⭐ Manual de referencia completo (1370 líneas)

SISTEMA DE MACROS (PIEDRA ANGULAR)

Concepto

El sistema de macros permite grabar y reproducir todas las acciones del usuario.

Principio: Grabar teclas raw, no comandos abstractos.

Usuario pulsa: Tab, Tab, Enter, "texto", Escape
Grabamos:      [Tab, Tab, Enter, t, e, x, t, o, Escape]
Reproducimos:  Inyectamos exactamente esas teclas

Por qué teclas raw (no comandos)

Enfoque Pros Contras
Teclas raw Simple, mínima memoria, reproducción exacta Depende del estado inicial
Comandos semánticos Más robusto Complejo, más memoria, traducción bidireccional

Decisión: Teclas raw (como Vim). Razones:

  1. KISS - menos código = menos bugs
  2. Vim lo hace así y funciona
  3. El estado inicial es controlable

Manejo del ratón

Casi todo lo que hace el ratón se puede expresar como teclado:

Acción ratón Equivalente teclado
Click en botón Tab hasta focus + Enter
Click en fila 5 Flechas hasta fila 5
Scroll down PageDown o flechas
Drag splitter Ctrl+flechas

Estrategia:

  1. Fase 1: Solo teclado (macros de teclas)
  2. Fase 2: Mouse → traducir a teclas equivalentes

API Propuesta

pub const MacroRecorder = struct {
    events: ArrayList(KeyEvent),
    recording: bool,

    pub fn start(self: *MacroRecorder) void;
    pub fn stop(self: *MacroRecorder) []const KeyEvent;
    pub fn record(self: *MacroRecorder, key: KeyEvent) void;
    pub fn save(self: *MacroRecorder, path: []const u8) !void;
    pub fn load(allocator: Allocator, path: []const u8) !MacroRecorder;
};

pub const MacroPlayer = struct {
    pub fn play(
        events: []const KeyEvent,
        inject_fn: *const fn(KeyEvent) void,
        delay_ms: u32,
    ) void;
};

Casos de Uso

  1. Testing automatizado: Grabar sesión → convertir en test
  2. Tutoriales: Macros que se ejecutan paso a paso
  3. Repetición: Grabar tarea repetitiva, asignar a hotkey
  4. Debugging: "¿Cómo llegaste a este bug?" → envía el macro
  5. Demos: Grabar demos que se reproducen en la app

WIDGETS PRIORITARIOS

Basado en análisis de Simifactu (ver docs/research/SIMIFACTU_FYNE_ANALYSIS.md):

# Widget Prioridad Descripción
1 Table CRÍTICA Edición in-situ, navegación teclado, dirty tracking
2 Input CRÍTICA Text entry con validación
3 Select CRÍTICA Dropdown selection
4 Panel ALTA Container con título y bordes
5 Split ALTA HSplit/VSplit draggable
6 Button ALTA Con estados disabled, importance
7 Modal MEDIA Diálogos modales
8 List MEDIA Lista seleccionable
9 Checkbox MEDIA Toggle boolean
10 Label BAJA Texto estático

RENDERING

Software Rasterizer (Command List approach)

pub const DrawCommand = union(enum) {
    rect: struct {
        x: i32,
        y: i32,
        w: u32,
        h: u32,
        color: Color,
    },
    text: struct {
        x: i32,
        y: i32,
        text: []const u8,
        color: Color,
        font: *Font,
    },
    line: struct {
        x1: i32,
        y1: i32,
        x2: i32,
        y2: i32,
        color: Color,
    },
    clip: struct {
        x: i32,
        y: i32,
        w: u32,
        h: u32,
    },
    clip_end,
};

Flujo:

Widgets → Commands → Software Rasterizer → Framebuffer → SDL_Texture → Display

Por qué Software Rendering

  1. Funciona SIEMPRE - No depende de drivers GPU
  2. SSH compatible - X11 forwarding funciona
  3. Máxima compatibilidad - Desde HP viejo hasta Lenovo nuevo
  4. Simple de debugear - Es solo un array de pixels

Fonts

Dos opciones soportadas:

  1. Bitmap fonts (embebidos) - Siempre funcionan, rápidos
  2. TTF (stb_truetype) - Más flexible, opcional

PLAN DE DESARROLLO

Fase 0: Setup COMPLETADA

  • Crear estructura de directorios
  • build.zig con SDL2
  • CLAUDE.md
  • Documentación de investigación

Fase 1: Core + Macros COMPLETADA

  • Context con event loop
  • Sistema de macros (grabación/reproducción teclas)
  • Software rasterizer básico (rects, text, lines)
  • SDL2 backend
  • Framebuffer RGBA

Fase 2: Widgets Esenciales COMPLETADA

  • Label (static text)
  • Button (clickable, importance levels)
  • TextInput (editable text, cursor, selection)
  • Checkbox (boolean toggle)
  • Select (dropdown)
  • List (scrollable selection)
  • Focus management (FocusManager, FocusRing)

Fase 3: Widgets Avanzados (PENDIENTE)

  • Table con edición (CRÍTICO)
  • Split panels (HSplit/VSplit draggable)
  • Panel (container con título)
  • Modal/Popup

Fase 4: Pulido (PENDIENTE)

  • Themes hot-reload
  • TTF fonts (stb_truetype)
  • Documentación completa
  • Más examples

REFERENCIAS Y RECURSOS

Librerías estudiadas

Librería Lenguaje LOC Valor para nosotros
microui C 1,100 Referencia arquitectura mínima
DVUI Zig 15,000 Único ejemplo Zig native
Dear ImGui C++ 60,000 API design, features
Gio Go - Immediate mode moderno
Nuklear C 30,000 Vertex buffer approach

Documentación detallada

  • docs/research/GIO_UI_ANALYSIS.md - Análisis completo de Gio
  • docs/research/IMMEDIATE_MODE_LIBS.md - Comparativa de librerías
  • docs/research/SIMIFACTU_FYNE_ANALYSIS.md - Requisitos de Simifactu
  • docs/ARCHITECTURE.md - Decisiones de arquitectura

DECISIONES DE DISEÑO CONSENSUADAS

1. Immediate Mode vs Retained Mode

Decisión: Immediate Mode Razón: Control total, sin threading hell (fyne.Do()), estado explícito

2. Software Rendering vs GPU

Decisión: Software por defecto, GPU opcional futuro Razón: Máxima compatibilidad (SSH, HP viejo, cualquier driver)

3. Sistema de Macros

Decisión: Teclas raw, no comandos abstractos Razón: Simple, como Vim, menos código = menos bugs

4. Backend inicial

Decisión: SDL2 Razón: Cross-platform probado, fácil de usar

5. Fonts

Decisión: Bitmap embebido + TTF opcional Razón: Bitmap siempre funciona, TTF para flexibilidad

6. Enfoque de desarrollo

Decisión: Híbrido (estudiar DVUI/microui, implementar desde cero) Razón: Aprender haciendo, control total, sin dependencias no deseadas


RELACIÓN CON ZCATUI

zcatui (TUI) y zcatgui (GUI) son proyectos hermanos:

Aspecto zcatui zcatgui
Target Terminal (ANSI) Ventana gráfica
Rendering Escape codes Software rasterizer
Paradigma Immediate mode Immediate mode
Layout Constraint-based Constraint-based (reusar)
Style Color/Modifier Color/Style (reusar)
Widgets 35 widgets En desarrollo

Código a reutilizar de zcatui:

  • Sistema de Layout (Constraint, Flex)
  • Sistema de Style (Color, Style)
  • Conceptos de Focus
  • Patterns de widgets

EQUIPO

  • Usuario (R.Eugenio): Desarrollador principal
  • Claude: Asistente de programación (Claude Code / Opus 4.5)

NOTAS ZIG 0.15.2

// Sleep
std.Thread.sleep(ns)  // NO std.time.sleep

// ArrayList - CAMBIÓ en 0.15
// VIEJO: std.ArrayList(T).init(allocator)
// NUEVO: std.ArrayListUnmanaged(T) + pasar allocator a cada operación
var list: std.ArrayListUnmanaged(T) = .{};
defer list.deinit(allocator);
try list.append(allocator, item);  // allocator en cada append

// HashMap
var map = std.AutoHashMap(K, V).init(allocator);
defer map.deinit();

// Error handling
fn foo() !T { ... }
const result = try foo();
const result = foo() catch |err| { ... };

// File I/O - cambió en 0.15
const file = try std.fs.cwd().createFile(path, .{});
_ = try file.write("data");  // Directo

// stdout - cambió en 0.15
const stdout = std.fs.File.stdout();  // NO std.io.getStdOut()
// O usar std.debug.print() que es más simple

// build.zig.zon - requiere fingerprint
.{
    .fingerprint = 0x...,
    .name = .proyecto,  // enum literal, no string
    ...
}

HISTORIAL

Fecha Versión Cambios
2025-12-09 v0.1.0 Proyecto creado, estructura base, documentación
2025-12-09 v0.2.0 Widgets Fase 2 completados (Label, Button, TextInput, Checkbox, Select, List, Focus)
2025-12-09 v0.3.0 Widgets Fase 3 completados (Table editable, Split panels, Panel container)
2025-12-09 v0.3.5 Keyboard integration: InputState ahora trackea teclas, Table responde a flechas/Enter/Escape/Tab/F2
2025-12-09 v0.4.0 Modal widget: diálogos modales (alert, confirm, input), plan extendido documentado
2025-12-09 v0.5.0 AutoComplete widget, comparativa DVUI/Gio/zcatui en WIDGET_COMPARISON.md
2025-12-09 v0.6.0 FASE 1 Optimización: FrameArena, ObjectPool, dirty rectangles, Benchmark suite
2025-12-09 v0.7.0 FASE 2: Progress, Tooltip, Toast, Spinner
2025-12-09 v0.8.0 FASE 2: TextArea, Tree, Badge/TagGroup
2025-12-09 v0.9.0 FASE 3: Image, ReorderableList, ColorPicker, DatePicker
2025-12-09 v0.10.0 FASE 4: NumberEntry, RichText, Breadcrumb
2025-12-09 v0.11.0 FASE 5: Canvas, Charts (line/bar/pie), Icon system (60+ icons)
2025-12-09 v0.12.0 FASE 6: Clipboard, DragDrop, Shortcuts, FocusGroups
2025-12-09 v0.13.0 FASE 7: Animation/Easing, Effects (shadow/gradient/blur), VirtualScroll, AA rendering
2025-12-09 v0.14.0 FASE 8: Accessibility system, Testing framework, 274 tests
2025-12-09 v0.14.1 FASE 9: Gio parity - 12 widgets + gesture system
2025-12-09 v0.15.0 FASE 10: Mobile/Web - WASM, Android, iOS backends
2025-12-09 v0.15.0 Documentación: REFERENCE.md completo (1370 líneas)
2025-12-11 v0.15.1 FocusSystem rediseñado: registration_group/active_group, focus implícito
2025-12-11 v0.15.2 Widgets adaptados a FocusSystem: numberentry, textarea, select, radio, slider, tabs
2025-12-16 v0.16.0 TTF rasterization con antialiasing (supersampling 2x)
2025-12-16 v0.16.1 Fuente embebida: TtfFont.initEmbedded()
2025-12-16 v0.16.2 Fix TTF: DroidSans (187KB) reemplaza AdwaitaSans (variable). Y-flip rasterización.
2025-12-17 v0.17.0 Integración zcatttf v1.0 - TTF FUNCIONA PERFECTAMENTE
2025-12-17 v0.18.0 Paridad Visual DVUI Fase 1: RenderMode dual, esquinas redondeadas, sombras
2025-12-17 v0.19.0 Paridad Visual DVUI Fase 2: HoverTransition, Focus Ring AA en 9 widgets
2025-12-17 v0.20.0 AdvancedTable: 8 fases completas (~2,700 LOC) - Schema, CRUD, Sorting, Lookup
2025-12-17 v0.21.0 AdvancedTable: +990 LOC (multi-select, search, validation)
2025-12-17 v0.21.1 Fix: AdvancedTable teclado - result.selected_row/col en handleKeyboard

BUG RESUELTO: AdvancedTable Teclado

Estado: RESUELTO (2025-12-17 19:30) Documentación: docs/BUG_ADVANCEDTABLE_KEYBOARD_2025-12-17.md

Causa raíz

handleKeyboard seteaba result.selection_changed = true pero NO seteaba result.selected_row / result.selected_col. zsimifactu sincroniza selección desde DataManager cada frame, y sin esos valores no actualizaba DataManager → reset al valor anterior.

Solución

Añadir result.selected_row y result.selected_col a todas las teclas de navegación (up, down, left, right, page_up, page_down, home, end).


ESTADO ACTUAL

PROYECTO COMPLETADO - v0.21.1

Para detalles técnicos completos, ver REFERENCE.md (1370 líneas de documentación)

Widgets (37 total):

Básicos (7): Label, Button, Checkbox, Radio, Slider, TextInput, NumberEntry

Contenedores (6): Panel, Split, Modal, Scroll, Tabs, Menu

Datos (5): List, Table, Tree, ReorderableList, VirtualScroll

Feedback (4): Progress, Tooltip, Toast, Spinner

Input avanzado (5): AutoComplete, Select, TextArea, ColorPicker, DatePicker

Especial (5): Image, Icon, Canvas, Chart, RichText

Navegación (2): Breadcrumb, Focus

Sistema (1): Badge/TagGroup

Backends (5 plataformas):

  • SDL2: Desktop (Linux, Windows, macOS)
  • WASM: Navegadores web (Canvas 2D)
  • Android: ANativeActivity + ANativeWindow
  • iOS: UIKit bridge (Objective-C)

Core Systems:

  • Context: FrameArena (O(1) reset), dirty rectangles, ID system
  • Input: Keyboard, mouse, touch, shortcuts, focus groups, gestures
  • Rendering: Software renderer, anti-aliasing, effects (shadow, gradient, blur)
  • Animation: Easing functions (20+), AnimationManager, Springs
  • Accessibility: Roles, states, announcements, live regions
  • Testing: TestRunner, SnapshotTester, Assertions
  • Macros: Recording, playback, storage
  • Themes: 5 themes (dark, light, high_contrast, nord, dracula)
  • Clipboard: SDL2 clipboard integration
  • Drag & Drop: Type-filtered drop zones
  • Gestures: Tap, double-tap, long-press, swipe, pinch, rotate

Métricas:

  • ~35,000 LOC en 81 archivos fuente
  • 0 warnings, 0 memory leaks
  • WASM: ~18KB compilado

Verificar que funciona:

cd /mnt/cello2/arno/re/recode/zig/zcatgui

# Tests
/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig build test

# Desktop
/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig build

# WASM (genera web/zcatgui-demo.wasm)
/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig build wasm

# Android (requiere NDK)
/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig build android

# iOS (requiere macOS + Xcode)
/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig build ios

DOCUMENTACIÓN DISPONIBLE

Documento Descripción
REFERENCE.md Manual de referencia completo (1370 líneas)
docs/DEVELOPMENT_PLAN.md Plan de desarrollo por fases (10 fases completadas)
docs/MOBILE_WEB_BACKENDS.md Guía de backends WASM/Android/iOS
docs/ARCHITECTURE.md Decisiones de arquitectura
docs/research/ Análisis de librerías de referencia

SISTEMA DE FOCUS - RESUELTO (2025-12-11)

El sistema de focus fue rediseñado y ahora funciona correctamente.

Documentación completa

/mnt/cello2/arno/re/recode/zig/zcatgui/docs/FOCUS_TRANSITION_2025-12-11.md

Arquitectura final

                    FocusSystem
                         |
         +---------------+---------------+
         |                               |
    FocusGroup 1                    FocusGroup 2
    (Panel Lista)                   (Panel Detalle)
         |                               |
    Table widget                   TextInput widgets
         |                               |
    - registerFocusable()          - registerFocusable()
    - hasFocus() -> true/false     - hasFocus() -> true/false

Conceptos clave

  • registration_group: Grupo donde se registran widgets durante draw
  • active_group: Grupo con focus de teclado (solo cambia con F6/clic)
  • Focus implícito: Primer widget del grupo activo tiene focus si focused_index == null

API para widgets

// 1. Generar ID único basado en dirección del state
const widget_id: u64 = @intFromPtr(state);

// 2. Registrar en el grupo de focus activo
ctx.registerFocusable(widget_id);

// 3. Al hacer clic, solicitar focus
if (clicked) {
    ctx.requestFocus(widget_id);
}

// 4. Verificar si tiene focus
const has_focus = ctx.hasFocus(widget_id);
state.focused = has_focus;

Widgets integrados con FocusSystem

Widget Estado
Table Adaptado - inicializa selected_row/col a 0
TextInput Correcto
NumberEntry Adaptado
TextArea Adaptado
Select Adaptado
Radio Adaptado
Slider Adaptado
Tabs Adaptado

Widgets sin FocusSystem (no lo necesitan)

  • Modales: Menu, Modal, Tooltip, Toast
  • Acción única: Button, Checkbox, Switch
  • Solo visualización: Label, Progress, Badge, Icon, Image

PROYECTOS RELACIONADOS

Proyecto Ruta Descripción
zcatttf /mnt/cello2/arno/re/recode/zig/zcatttf/ Librería TTF v1.0 - COMPLETA (dependencia de zcatgui)
zsimifactu /mnt/cello2/arno/re/recode/zig/zsimifactu/ App de facturación Zig (consumidor principal)
zcatui /mnt/cello2/arno/re/recode/zig/zcatui/ TUI library (proyecto hermano)
zcatp2p /mnt/cello2/arno/re/recode/zig/zcatp2p/ Librería P2P (v1.0.0 completa)
simifactu /mnt/cello2/arno/re/recode/go/simifactu/ App de referencia (Fyne/Go)

REFERENCIAS EXTERNAS