# 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 ```bash 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: ```markdown ## 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 redondeadas** → `fillRoundedRect` 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 ```zig // 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 | - | ✅ | ✅ | ```zig // 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 ```zig 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 ```zig 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 ```bash # 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 ```bash # 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 ```zig 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) ```zig 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 - [x] Crear estructura de directorios - [x] build.zig con SDL2 - [x] CLAUDE.md - [x] Documentación de investigación ### Fase 1: Core + Macros ✅ COMPLETADA - [x] Context con event loop - [x] Sistema de macros (grabación/reproducción teclas) - [x] Software rasterizer básico (rects, text, lines) - [x] SDL2 backend - [x] Framebuffer RGBA ### Fase 2: Widgets Esenciales ✅ COMPLETADA - [x] Label (static text) - [x] Button (clickable, importance levels) - [x] TextInput (editable text, cursor, selection) - [x] Checkbox (boolean toggle) - [x] Select (dropdown) - [x] List (scrollable selection) - [x] 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 ### Links externos - [microui GitHub](https://github.com/rxi/microui) - [DVUI GitHub](https://github.com/david-vanderson/dvui) - [Gio UI](https://gioui.org/) - [Dear ImGui](https://github.com/ocornut/imgui) --- ## 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 ```zig // 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: ```bash 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 ```zig // 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 - [microui](https://github.com/rxi/microui) - Arquitectura mínima - [DVUI](https://github.com/david-vanderson/dvui) - Zig GUI reference - [Gio](https://gioui.org/) - Go immediate-mode - [Dear ImGui](https://github.com/ocornut/imgui) - C++ reference