Performance Infrastructure: - FrameArena: O(1) per-frame allocator with automatic reset - ObjectPool: Generic object pool for frequently allocated types - CommandPool: Specialized pool for draw commands - RingBuffer: Circular buffer for streaming data - ScopedArena: RAII pattern for temporary allocations Dirty Rectangle System: - Context now tracks dirty regions for partial redraws - Automatic rect merging to reduce overdraw - invalidateRect(), needsRedraw(), getDirtyRects() API - Falls back to full redraw when > 32 dirty rects Benchmark Suite: - Timer: High-resolution timing - Benchmark: Stats collection (avg, min, max, stddev, median) - FrameTimer: FPS and frame time tracking - AllocationTracker: Memory usage monitoring - Pre-built benchmarks for arena, pool, and commands Context Improvements: - Integrated FrameArena for zero-allocation hot paths - frameAllocator() for per-frame widget allocations - FrameStats for performance monitoring - Context.init() now returns error union (breaking change) New Widgets (from previous session): - Slider: Horizontal/vertical with customization - ScrollArea: Scrollable content region - Tabs: Tab container with keyboard navigation - RadioButton: Radio button groups - Menu: Dropdown menus (foundation) Theme System Expansion: - 5 built-in themes: dark, light, high_contrast, nord, dracula - ThemeManager with runtime switching - TTF font support via stb_truetype Documentation: - DEVELOPMENT_PLAN.md: 9-phase roadmap to DVUI/Gio parity - Updated WIDGET_COMPARISON.md with detailed analysis - Lego Panels architecture documented Stats: 17 widgets, 123 tests, 5 themes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1611 lines
42 KiB
Markdown
1611 lines
42 KiB
Markdown
# Plan Maestro de Desarrollo: zcatgui
|
|
|
|
> **Versión**: 1.0
|
|
> **Fecha**: 2025-12-09
|
|
> **Objetivo**: Llevar zcatgui a la perfección - paridad completa con DVUI/Gio + features únicas
|
|
> **Filosofía**: Calidad sobre velocidad. Código óptimo, mínima memoria, máximo rendimiento.
|
|
|
|
---
|
|
|
|
## COMPARATIVA DE PARIDAD
|
|
|
|
### vs DVUI (Target: 100%)
|
|
|
|
| Categoría | DVUI | zcatgui actual | Falta | Post-Plan |
|
|
|-----------|:----:|:--------------:|:-----:|:---------:|
|
|
| Básicos (Label, Button, etc.) | 7 | 7 ✅ | 0 | 7 ✅ |
|
|
| Contenedores (Panel, Split, etc.) | 6 | 6 ✅ | 0 | 6 ✅ |
|
|
| Datos (List, Table, Tree) | 4 | 2 | 2 | 4 ✅ |
|
|
| Input (Text, Number, Editor) | 5 | 3 | 2 | 5 ✅ |
|
|
| Navegación (Menu, Tabs) | 4 | 4 ✅ | 0 | 4 ✅ |
|
|
| Feedback (Tooltip, Toast) | 3 | 0 | 3 | 3 ✅ |
|
|
| Especial (Image, Icon) | 4 | 0 | 4 | 4 ✅ |
|
|
| Rendering (AA, Effects) | ✅ | Básico | ✅ | ✅ |
|
|
| **TOTAL WIDGETS** | **35** | **17** | **18** | **35 ✅** |
|
|
|
|
### vs Gio (Target: ~60% - lo útil)
|
|
|
|
| Feature | Gio | Implementamos | Razón si NO |
|
|
|---------|:---:|:-------------:|-------------|
|
|
| Widgets básicos | ✅ | ✅ | - |
|
|
| Progress/Spinner | ✅ | ✅ | - |
|
|
| Charts | ✅ | ✅ | - |
|
|
| Clipboard | ✅ | ✅ | - |
|
|
| Animaciones | ✅ | ✅ | - |
|
|
| Material Design | ✅ | ❌ | No necesario, tenemos themes |
|
|
| GPU Rendering | ✅ | Opcional | Software-first es objetivo |
|
|
| HarfBuzz/BiDi | ✅ | ❌ | Overkill, no idiomas RTL |
|
|
| System Fonts | ✅ | ❌ | TTF embebido suficiente |
|
|
|
|
### Features ÚNICAS de zcatgui (Ventaja Competitiva)
|
|
|
|
| Feature | DVUI | Gio | zcatgui | Valor |
|
|
|---------|:----:|:---:|:-------:|:-----:|
|
|
| Sistema de Macros | ❌ | ❌ | ✅ | ⭐⭐⭐ |
|
|
| Lego Panels + DataManager | ❌ | ❌ | ✅ | ⭐⭐⭐ |
|
|
| Table Dirty Tracking | ❌ | ❌ | ✅ | ⭐⭐⭐ |
|
|
| Table Validation | ❌ | ❌ | ✅ | ⭐⭐ |
|
|
| Table Sorting | ❌ | ❌ | ✅ | ⭐⭐ |
|
|
| Table Multi-select | ❌ | ❌ | ✅ | ⭐⭐ |
|
|
| High Contrast Theme | ❌ | ❌ | ✅ | ⭐⭐ |
|
|
| SSH-first Design | Parcial | ❌ | ✅ | ⭐⭐⭐ |
|
|
|
|
### Conclusión de Paridad
|
|
|
|
```
|
|
Post-Plan:
|
|
vs DVUI: 100% paridad + features únicas SUPERIORES
|
|
vs Gio: ~60% paridad (lo útil) + features únicas
|
|
|
|
zcatgui será MEJOR que ambas para aplicaciones empresariales
|
|
gracias a: Macros + Lego Panels + Table avanzada + SSH-first
|
|
```
|
|
|
|
---
|
|
|
|
## ÍNDICE
|
|
|
|
1. [Estado Actual](#1-estado-actual)
|
|
2. [Objetivos de Perfección](#2-objetivos-de-perfección)
|
|
3. [Principios de Desarrollo](#3-principios-de-desarrollo)
|
|
4. [Plan por Fases](#4-plan-por-fases)
|
|
5. [Detalles de Implementación](#5-detalles-de-implementación)
|
|
6. [Métricas de Calidad](#6-métricas-de-calidad)
|
|
7. [Checklist Final](#7-checklist-final)
|
|
|
|
---
|
|
|
|
## 1. ESTADO ACTUAL
|
|
|
|
### 1.1 Inventario Completado (v0.5.0)
|
|
|
|
| Categoría | Completado | Items |
|
|
|-----------|:----------:|-------|
|
|
| **Core** | ✅ 100% | Context, Layout, Style, Input, Command |
|
|
| **Render** | ✅ 80% | Framebuffer, SoftwareRenderer, Font, TTF básico |
|
|
| **Backend** | ✅ 100% | SDL2 |
|
|
| **Macros** | ✅ 100% | Recorder, Player, Storage |
|
|
| **Widgets** | ✅ 17/35 | Label, Button, TextInput, Checkbox, Select, List, Focus, Table, Split, Panel, Modal, AutoComplete, Slider, Scroll, Menu, Tabs, Radio |
|
|
| **Panels** | ✅ 100% | AutonomousPanel, Composites, DataManager |
|
|
| **Themes** | ✅ 100% | 5 themes, ThemeManager |
|
|
|
|
### 1.2 LOC Actual
|
|
|
|
```
|
|
Core: ~1,700 LOC
|
|
Render: ~1,300 LOC
|
|
Backend: ~400 LOC
|
|
Macro: ~340 LOC
|
|
Widgets: ~8,000 LOC
|
|
Panels: ~350 LOC
|
|
Entry: ~130 LOC
|
|
─────────────────────
|
|
TOTAL: ~12,220 LOC
|
|
```
|
|
|
|
### 1.3 Tests Actuales
|
|
|
|
- **85+ tests** pasando
|
|
- Cobertura: Core 90%, Widgets 60%, Panels 70%
|
|
|
|
---
|
|
|
|
## 2. OBJETIVOS DE PERFECCIÓN
|
|
|
|
### 2.1 Paridad de Widgets (Target: 35 widgets)
|
|
|
|
```
|
|
Actual: 17 widgets
|
|
Objetivo: 35 widgets (+18)
|
|
Paridad: 100% DVUI, 60% Gio
|
|
```
|
|
|
|
### 2.2 Rendimiento Target
|
|
|
|
| Métrica | Target | Razón |
|
|
|---------|--------|-------|
|
|
| **FPS** | 60+ estable | Fluidez visual |
|
|
| **Startup** | <50ms | Percepción instantánea |
|
|
| **Memoria base** | <10MB | Eficiencia |
|
|
| **Memoria por widget** | <100 bytes | Escalabilidad |
|
|
| **Latencia input** | <16ms | Respuesta inmediata |
|
|
| **Redraw completo** | <5ms | 60fps con margen |
|
|
|
|
### 2.3 Calidad de Código
|
|
|
|
| Métrica | Target |
|
|
|---------|--------|
|
|
| **LOC total** | <20,000 (eficiente) |
|
|
| **Cobertura tests** | >90% |
|
|
| **Complejidad ciclomática** | <10 por función |
|
|
| **Funciones >50 LOC** | 0 |
|
|
| **Comentarios/código** | 15-20% |
|
|
| **Warnings** | 0 |
|
|
| **Memory leaks** | 0 |
|
|
|
|
---
|
|
|
|
## 3. PRINCIPIOS DE DESARROLLO
|
|
|
|
### 3.1 Optimización de Memoria
|
|
|
|
```zig
|
|
// ❌ MAL: Allocaciones innecesarias
|
|
fn process(allocator: Allocator, items: []const Item) ![]Result {
|
|
var results = try allocator.alloc(Result, items.len);
|
|
// ...
|
|
}
|
|
|
|
// ✅ BIEN: Reutilizar buffers, stack allocation cuando sea posible
|
|
fn process(items: []const Item, result_buf: []Result) []Result {
|
|
const count = @min(items.len, result_buf.len);
|
|
// ...
|
|
return result_buf[0..count];
|
|
}
|
|
```
|
|
|
|
**Reglas:**
|
|
1. Preferir stack allocation sobre heap
|
|
2. Usar `comptime` para cálculos en tiempo de compilación
|
|
3. Reutilizar buffers entre frames
|
|
4. Evitar slices dinámicos cuando el tamaño es conocido
|
|
5. Usar `@memset` y `@memcpy` para operaciones bulk
|
|
|
|
### 3.2 Optimización de Rendimiento
|
|
|
|
```zig
|
|
// ❌ MAL: Múltiples pasadas
|
|
for (items) |item| {
|
|
if (item.visible) count += 1;
|
|
}
|
|
for (items) |item| {
|
|
if (item.visible) process(item);
|
|
}
|
|
|
|
// ✅ BIEN: Una sola pasada
|
|
for (items) |item| {
|
|
if (item.visible) {
|
|
count += 1;
|
|
process(item);
|
|
}
|
|
}
|
|
```
|
|
|
|
**Reglas:**
|
|
1. Minimizar iteraciones (single-pass cuando posible)
|
|
2. Early-exit en condiciones frecuentes
|
|
3. Cache locality: acceso secuencial a memoria
|
|
4. Evitar división (usar multiplicación por recíproco)
|
|
5. Usar SIMD implícito via `@Vector` cuando aplique
|
|
|
|
### 3.3 Inmediato y Determinista
|
|
|
|
```zig
|
|
// ❌ MAL: Estado oculto, efectos secundarios
|
|
var global_counter: u32 = 0;
|
|
fn doSomething() void {
|
|
global_counter += 1;
|
|
}
|
|
|
|
// ✅ BIEN: Estado explícito, función pura
|
|
fn doSomething(state: *State) void {
|
|
state.counter += 1;
|
|
}
|
|
```
|
|
|
|
**Reglas:**
|
|
1. Sin globals mutables (excepto ThemeManager/DataManager controlados)
|
|
2. Funciones puras cuando posible
|
|
3. Estado explícito pasado como parámetro
|
|
4. Resultados predecibles dado el mismo input
|
|
|
|
### 3.4 API Consistente
|
|
|
|
Todos los widgets siguen el patrón:
|
|
|
|
```zig
|
|
// Variante simple (defaults)
|
|
pub fn widget(ctx: *Context, ...) Result { ... }
|
|
|
|
// Variante extendida (con config)
|
|
pub fn widgetEx(ctx: *Context, ..., config: Config) Result { ... }
|
|
|
|
// Variante con bounds explícitos
|
|
pub fn widgetRect(ctx: *Context, bounds: Rect, ..., config: Config) Result { ... }
|
|
```
|
|
|
|
---
|
|
|
|
## 4. PLAN POR FASES
|
|
|
|
### FASE 1: FUNDAMENTOS SÓLIDOS
|
|
**Duración estimada**: 1 semana
|
|
**Objetivo**: Optimizar y solidificar el core existente
|
|
|
|
#### 1.1 Optimización del Core
|
|
|
|
| Tarea | Prioridad | LOC Est. | Descripción |
|
|
|-------|:---------:|:--------:|-------------|
|
|
| Arena allocator para Context | ALTA | 150 | Pool de memoria por frame |
|
|
| Object pooling para Commands | ALTA | 100 | Reutilizar command buffers |
|
|
| Optimizar Rect operations | MEDIA | 50 | SIMD para intersecciones |
|
|
| Benchmark suite | ALTA | 200 | Medir rendimiento base |
|
|
|
|
#### 1.2 Optimización del Renderer
|
|
|
|
| Tarea | Prioridad | LOC Est. | Descripción |
|
|
|-------|:---------:|:--------:|-------------|
|
|
| Dirty rectangles | ALTA | 200 | Solo redibujar lo cambiado |
|
|
| Batch draw commands | ALTA | 150 | Agrupar rects del mismo color |
|
|
| Clip optimization | MEDIA | 100 | Skip completo si fuera de clip |
|
|
| Framebuffer double-buffering | MEDIA | 80 | Evitar tearing |
|
|
|
|
#### 1.3 Tests y Benchmarks
|
|
|
|
| Tarea | Prioridad | LOC Est. | Descripción |
|
|
|-------|:---------:|:--------:|-------------|
|
|
| Test coverage 90%+ | ALTA | 500 | Tests para todo el core |
|
|
| Performance benchmarks | ALTA | 300 | Medir todas las operaciones |
|
|
| Memory leak tests | ALTA | 100 | Verificar cero leaks |
|
|
| Stress tests | MEDIA | 200 | 10K widgets, 1M commands |
|
|
|
|
**Entregables Fase 1:**
|
|
- [ ] Arena allocator funcionando
|
|
- [ ] Dirty rectangles implementado
|
|
- [ ] Benchmark suite con métricas base
|
|
- [ ] 90%+ test coverage en core
|
|
- [ ] 0 memory leaks verificado
|
|
|
|
---
|
|
|
|
### FASE 2: WIDGETS DE FEEDBACK
|
|
**Duración estimada**: 1 semana
|
|
**Objetivo**: Completar widgets de feedback visual
|
|
|
|
#### 2.1 Tooltip
|
|
|
|
```zig
|
|
pub const TooltipConfig = struct {
|
|
delay_ms: u32 = 500, // Delay antes de mostrar
|
|
max_width: u16 = 300, // Ancho máximo
|
|
position: Position = .auto, // auto, above, below, left, right
|
|
arrow: bool = true, // Mostrar flecha
|
|
};
|
|
|
|
pub const TooltipState = struct {
|
|
hover_start: i64 = 0, // Timestamp inicio hover
|
|
visible: bool = false,
|
|
target_rect: Rect = .{},
|
|
};
|
|
|
|
pub fn tooltip(ctx: *Context, state: *TooltipState, text: []const u8, config: TooltipConfig) void;
|
|
pub fn tooltipArea(ctx: *Context, bounds: Rect, state: *TooltipState, text: []const u8) void;
|
|
```
|
|
|
|
**Características:**
|
|
- Delay configurable antes de mostrar
|
|
- Posicionamiento inteligente (evitar salir de pantalla)
|
|
- Soporte multi-línea con wrapping
|
|
- Flecha apuntando al elemento
|
|
- Fade in/out suave
|
|
|
|
**LOC estimadas**: 150
|
|
|
|
#### 2.2 ProgressBar
|
|
|
|
```zig
|
|
pub const ProgressStyle = enum { bar, circle, dots };
|
|
|
|
pub const ProgressConfig = struct {
|
|
style: ProgressStyle = .bar,
|
|
show_percentage: bool = true,
|
|
show_label: bool = false,
|
|
label: []const u8 = "",
|
|
animated: bool = true, // Animación de progreso
|
|
indeterminate: bool = false, // Modo indeterminado (loading)
|
|
};
|
|
|
|
pub const ProgressColors = struct {
|
|
track: Color,
|
|
fill: Color,
|
|
text: Color,
|
|
};
|
|
|
|
pub fn progressBar(ctx: *Context, progress: f32, config: ProgressConfig) void;
|
|
pub fn progressCircle(ctx: *Context, progress: f32, config: ProgressConfig) void;
|
|
```
|
|
|
|
**Características:**
|
|
- Barra horizontal/vertical
|
|
- Círculo de progreso
|
|
- Modo indeterminado (spinner)
|
|
- Porcentaje y label opcional
|
|
- Animación suave de transición
|
|
|
|
**LOC estimadas**: 200
|
|
|
|
#### 2.3 Toast/Notification
|
|
|
|
```zig
|
|
pub const ToastType = enum { info, success, warning, error };
|
|
pub const ToastPosition = enum { top, bottom, top_right, bottom_right };
|
|
|
|
pub const ToastConfig = struct {
|
|
duration_ms: u32 = 3000,
|
|
position: ToastPosition = .bottom_right,
|
|
max_visible: u8 = 5,
|
|
animation: bool = true,
|
|
};
|
|
|
|
pub const ToastManager = struct {
|
|
toasts: [MAX_TOASTS]Toast,
|
|
count: usize,
|
|
|
|
pub fn show(self: *ToastManager, message: []const u8, toast_type: ToastType) void;
|
|
pub fn showWithAction(self: *ToastManager, message: []const u8, action: []const u8, callback: ActionFn) void;
|
|
pub fn dismiss(self: *ToastManager, id: u32) void;
|
|
pub fn dismissAll(self: *ToastManager) void;
|
|
pub fn render(self: *ToastManager, ctx: *Context) void;
|
|
};
|
|
```
|
|
|
|
**Características:**
|
|
- Múltiples tipos (info, success, warning, error)
|
|
- Posicionamiento configurable
|
|
- Auto-dismiss con timer
|
|
- Botón de acción opcional
|
|
- Stack de múltiples toasts
|
|
- Animación slide in/out
|
|
|
|
**LOC estimadas**: 250
|
|
|
|
#### 2.4 Spinner/Loader
|
|
|
|
```zig
|
|
pub const SpinnerStyle = enum {
|
|
circular, // Círculo girando
|
|
dots, // Puntos pulsando
|
|
bars, // Barras ecualizador
|
|
ring, // Anillo con gap
|
|
};
|
|
|
|
pub const SpinnerConfig = struct {
|
|
style: SpinnerStyle = .circular,
|
|
size: u16 = 24,
|
|
speed: f32 = 1.0, // Multiplicador de velocidad
|
|
label: ?[]const u8 = null,
|
|
};
|
|
|
|
pub fn spinner(ctx: *Context, config: SpinnerConfig) void;
|
|
pub fn spinnerOverlay(ctx: *Context, bounds: Rect, config: SpinnerConfig) void;
|
|
```
|
|
|
|
**Características:**
|
|
- Múltiples estilos de animación
|
|
- Tamaño configurable
|
|
- Velocidad ajustable
|
|
- Label opcional ("Loading...")
|
|
- Overlay mode para cubrir contenido
|
|
|
|
**LOC estimadas**: 150
|
|
|
|
**Entregables Fase 2:**
|
|
- [ ] Tooltip con posicionamiento inteligente
|
|
- [ ] ProgressBar (bar + circle + indeterminate)
|
|
- [ ] Toast/Notification system
|
|
- [ ] Spinner con 4 estilos
|
|
- [ ] Tests para cada widget
|
|
- [ ] Demo de feedback widgets
|
|
|
|
---
|
|
|
|
### FASE 3: WIDGETS ESPECIALIZADOS
|
|
**Duración estimada**: 2 semanas
|
|
**Objetivo**: Widgets avanzados para aplicaciones complejas
|
|
|
|
#### 3.1 Tree View
|
|
|
|
```zig
|
|
pub const TreeNode = struct {
|
|
id: u64,
|
|
label: []const u8,
|
|
icon: ?Icon = null,
|
|
children: []TreeNode = &.{},
|
|
expanded: bool = false,
|
|
selected: bool = false,
|
|
data: ?*anyopaque = null,
|
|
};
|
|
|
|
pub const TreeConfig = struct {
|
|
indent: u16 = 20,
|
|
show_lines: bool = true,
|
|
show_icons: bool = true,
|
|
multi_select: bool = false,
|
|
drag_drop: bool = false,
|
|
lazy_load: bool = false, // Cargar hijos bajo demanda
|
|
};
|
|
|
|
pub const TreeState = struct {
|
|
selected: std.ArrayList(u64),
|
|
expanded: std.AutoHashMap(u64, bool),
|
|
scroll_offset: i32,
|
|
focused_id: ?u64,
|
|
};
|
|
|
|
pub const TreeResult = struct {
|
|
selection_changed: bool,
|
|
expanded_changed: bool,
|
|
activated: bool, // Double-click o Enter
|
|
activated_node: ?*TreeNode,
|
|
drag_started: bool,
|
|
drop_target: ?*TreeNode,
|
|
};
|
|
|
|
pub fn tree(ctx: *Context, bounds: Rect, state: *TreeState, root: *TreeNode, config: TreeConfig) TreeResult;
|
|
```
|
|
|
|
**Características:**
|
|
- Expand/collapse con animación
|
|
- Selección simple y múltiple
|
|
- Keyboard navigation completo
|
|
- Drag & drop entre nodos
|
|
- Lazy loading para árboles grandes
|
|
- Iconos por tipo de nodo
|
|
- Líneas de conexión opcionales
|
|
- Virtual scrolling para árboles enormes
|
|
|
|
**LOC estimadas**: 400
|
|
|
|
#### 3.2 Image Widget
|
|
|
|
```zig
|
|
pub const ImageFormat = enum { rgba, rgb, grayscale, indexed };
|
|
pub const ImageFit = enum { none, contain, cover, fill, scale_down };
|
|
|
|
pub const ImageData = struct {
|
|
pixels: []const u8,
|
|
width: u32,
|
|
height: u32,
|
|
format: ImageFormat,
|
|
stride: ?u32 = null,
|
|
};
|
|
|
|
pub const ImageConfig = struct {
|
|
fit: ImageFit = .contain,
|
|
alignment: Alignment = .center,
|
|
border_radius: u8 = 0,
|
|
placeholder: ?Color = null, // Color mientras carga
|
|
error_placeholder: ?[]const u8 = null,
|
|
};
|
|
|
|
pub const ImageCache = struct {
|
|
entries: std.AutoHashMap(u64, CachedImage),
|
|
max_size: usize,
|
|
current_size: usize,
|
|
|
|
pub fn get(self: *ImageCache, id: u64) ?*CachedImage;
|
|
pub fn put(self: *ImageCache, id: u64, image: ImageData) !void;
|
|
pub fn evict(self: *ImageCache, bytes: usize) void;
|
|
};
|
|
|
|
pub fn image(ctx: *Context, bounds: Rect, data: ImageData, config: ImageConfig) void;
|
|
pub fn imageFromCache(ctx: *Context, bounds: Rect, cache: *ImageCache, id: u64, config: ImageConfig) void;
|
|
```
|
|
|
|
**Características:**
|
|
- Soporte RGBA, RGB, grayscale
|
|
- Múltiples modos de fit
|
|
- Caché de imágenes con LRU eviction
|
|
- Border radius para esquinas redondeadas
|
|
- Placeholder mientras carga
|
|
- Lazy loading desde archivo
|
|
- Resize eficiente (nearest/bilinear)
|
|
|
|
**LOC estimadas**: 350
|
|
|
|
#### 3.3 ReorderableList
|
|
|
|
```zig
|
|
pub const ReorderableConfig = struct {
|
|
item_height: u16 = 32,
|
|
drag_handle: bool = true, // Mostrar handle de arrastre
|
|
allow_remove: bool = true, // Permitir eliminar items
|
|
allow_add: bool = true, // Permitir añadir items
|
|
animation: bool = true, // Animar reordenamiento
|
|
};
|
|
|
|
pub const ReorderableState = struct {
|
|
dragging_index: ?usize,
|
|
drag_offset: i32,
|
|
target_index: ?usize,
|
|
items_order: []usize, // Índices en orden actual
|
|
};
|
|
|
|
pub const ReorderableResult = struct {
|
|
reordered: bool,
|
|
removed_index: ?usize,
|
|
add_requested: bool,
|
|
new_order: []const usize,
|
|
};
|
|
|
|
pub fn reorderableList(
|
|
ctx: *Context,
|
|
bounds: Rect,
|
|
state: *ReorderableState,
|
|
items: []const []const u8,
|
|
config: ReorderableConfig,
|
|
) ReorderableResult;
|
|
```
|
|
|
|
**Características:**
|
|
- Drag & drop para reordenar
|
|
- Handle visual de arrastre
|
|
- Animación suave de reposicionamiento
|
|
- Botón eliminar por item
|
|
- Botón añadir al final
|
|
- Keyboard reorder (Ctrl+Up/Down)
|
|
- Callback on change
|
|
|
|
**LOC estimadas**: 300
|
|
|
|
#### 3.4 ColorPicker
|
|
|
|
```zig
|
|
pub const ColorPickerMode = enum { rgb, hsl, hex, palette };
|
|
|
|
pub const ColorPickerConfig = struct {
|
|
mode: ColorPickerMode = .rgb,
|
|
show_alpha: bool = true,
|
|
show_preview: bool = true,
|
|
palette: ?[]const Color = null, // Colores predefinidos
|
|
recent_colors: bool = true,
|
|
};
|
|
|
|
pub const ColorPickerState = struct {
|
|
current: Color,
|
|
mode: ColorPickerMode,
|
|
hue: f32,
|
|
saturation: f32,
|
|
lightness: f32,
|
|
recent: [8]Color,
|
|
};
|
|
|
|
pub fn colorPicker(ctx: *Context, bounds: Rect, state: *ColorPickerState, config: ColorPickerConfig) bool;
|
|
pub fn colorPickerPopup(ctx: *Context, anchor: Rect, state: *ColorPickerState, config: ColorPickerConfig) bool;
|
|
```
|
|
|
|
**Características:**
|
|
- Selector visual (cuadrado SL + barra H)
|
|
- Inputs RGB/HSL/Hex
|
|
- Slider de alpha
|
|
- Paleta de colores predefinidos
|
|
- Historial de colores recientes
|
|
- Preview comparativo (nuevo vs actual)
|
|
- Eyedropper (futuro)
|
|
|
|
**LOC estimadas**: 350
|
|
|
|
#### 3.5 DatePicker/Calendar
|
|
|
|
```zig
|
|
pub const DatePickerConfig = struct {
|
|
min_date: ?Date = null,
|
|
max_date: ?Date = null,
|
|
disabled_dates: ?[]const Date = null,
|
|
first_day_of_week: u8 = 1, // 0=Sunday, 1=Monday
|
|
show_week_numbers: bool = false,
|
|
range_selection: bool = false,
|
|
};
|
|
|
|
pub const DatePickerState = struct {
|
|
selected_date: ?Date,
|
|
range_start: ?Date,
|
|
range_end: ?Date,
|
|
view_month: u8,
|
|
view_year: u16,
|
|
open: bool,
|
|
};
|
|
|
|
pub const DatePickerResult = struct {
|
|
changed: bool,
|
|
date: ?Date,
|
|
range: ?struct { start: Date, end: Date },
|
|
};
|
|
|
|
pub fn datePicker(ctx: *Context, state: *DatePickerState, config: DatePickerConfig) DatePickerResult;
|
|
pub fn calendar(ctx: *Context, bounds: Rect, state: *DatePickerState, config: DatePickerConfig) DatePickerResult;
|
|
```
|
|
|
|
**Características:**
|
|
- Vista de mes con navegación
|
|
- Selección de fecha única o rango
|
|
- Fechas deshabilitadas
|
|
- Límites min/max
|
|
- Números de semana opcionales
|
|
- Navegación por teclado
|
|
- Dropdown integrado
|
|
|
|
**LOC estimadas**: 400
|
|
|
|
**Entregables Fase 3:**
|
|
- [ ] Tree View con lazy loading
|
|
- [ ] Image widget con cache
|
|
- [ ] ReorderableList con drag & drop
|
|
- [ ] ColorPicker completo
|
|
- [ ] DatePicker/Calendar
|
|
- [ ] Tests exhaustivos
|
|
- [ ] Demo de widgets especializados
|
|
|
|
---
|
|
|
|
### FASE 4: TEXTO AVANZADO
|
|
**Duración estimada**: 2 semanas
|
|
**Objetivo**: Sistema de texto profesional
|
|
|
|
#### 4.1 MultilineText Editor
|
|
|
|
```zig
|
|
pub const EditorConfig = struct {
|
|
read_only: bool = false,
|
|
word_wrap: bool = true,
|
|
show_line_numbers: bool = false,
|
|
tab_size: u8 = 4,
|
|
max_lines: ?u32 = null,
|
|
placeholder: ?[]const u8 = null,
|
|
};
|
|
|
|
pub const EditorState = struct {
|
|
lines: std.ArrayList([]u8),
|
|
cursor_line: usize,
|
|
cursor_col: usize,
|
|
selection_start: ?Position,
|
|
selection_end: ?Position,
|
|
scroll_offset: i32,
|
|
undo_stack: UndoStack,
|
|
redo_stack: UndoStack,
|
|
};
|
|
|
|
pub const EditorResult = struct {
|
|
text_changed: bool,
|
|
cursor_moved: bool,
|
|
selection_changed: bool,
|
|
};
|
|
|
|
pub fn editor(ctx: *Context, bounds: Rect, state: *EditorState, config: EditorConfig) EditorResult;
|
|
```
|
|
|
|
**Características:**
|
|
- Múltiples líneas con scroll
|
|
- Selección de texto (mouse y teclado)
|
|
- Copy/Cut/Paste (clipboard)
|
|
- Undo/Redo con stack
|
|
- Word wrap opcional
|
|
- Line numbers opcional
|
|
- Tab handling
|
|
- Find & Replace (básico)
|
|
|
|
**LOC estimadas**: 600
|
|
|
|
#### 4.2 NumberEntry
|
|
|
|
```zig
|
|
pub const NumberType = enum { integer, float, currency };
|
|
|
|
pub const NumberConfig = struct {
|
|
number_type: NumberType = .integer,
|
|
min: ?f64 = null,
|
|
max: ?f64 = null,
|
|
step: f64 = 1.0,
|
|
precision: u8 = 2, // Decimales para float/currency
|
|
prefix: ?[]const u8 = null, // "$", "€"
|
|
suffix: ?[]const u8 = null, // "%", "kg"
|
|
thousand_separator: bool = true,
|
|
allow_negative: bool = true,
|
|
spinner: bool = true, // Botones +/-
|
|
};
|
|
|
|
pub const NumberState = struct {
|
|
value: f64,
|
|
text_buf: [64]u8,
|
|
text_len: usize,
|
|
editing: bool,
|
|
cursor: usize,
|
|
};
|
|
|
|
pub const NumberResult = struct {
|
|
changed: bool,
|
|
value: f64,
|
|
valid: bool,
|
|
};
|
|
|
|
pub fn numberEntry(ctx: *Context, state: *NumberState, config: NumberConfig) NumberResult;
|
|
```
|
|
|
|
**Características:**
|
|
- Validación en tiempo real
|
|
- Formateo automático (separadores miles)
|
|
- Spinner buttons (+/-)
|
|
- Arrastrar para cambiar valor
|
|
- Límites min/max
|
|
- Precisión configurable
|
|
- Prefijo/sufijo (moneda, unidades)
|
|
|
|
**LOC estimadas**: 250
|
|
|
|
#### 4.3 Font Atlas y Rendering Mejorado
|
|
|
|
```zig
|
|
pub const FontAtlas = struct {
|
|
texture: []u8,
|
|
width: u32,
|
|
height: u32,
|
|
glyphs: std.AutoHashMap(GlyphKey, GlyphInfo),
|
|
|
|
pub fn getGlyph(self: *FontAtlas, codepoint: u32, size: u16) ?GlyphInfo;
|
|
pub fn renderGlyph(self: *FontAtlas, codepoint: u32, size: u16) !GlyphInfo;
|
|
};
|
|
|
|
pub const GlyphInfo = struct {
|
|
atlas_x: u16,
|
|
atlas_y: u16,
|
|
width: u16,
|
|
height: u16,
|
|
bearing_x: i16,
|
|
bearing_y: i16,
|
|
advance: u16,
|
|
};
|
|
|
|
pub const TextRenderer = struct {
|
|
atlas: *FontAtlas,
|
|
|
|
pub fn measureText(self: *TextRenderer, text: []const u8, size: u16) struct { width: u32, height: u32 };
|
|
pub fn renderText(self: *TextRenderer, fb: *Framebuffer, x: i32, y: i32, text: []const u8, size: u16, color: Color) void;
|
|
pub fn renderTextWrapped(self: *TextRenderer, fb: *Framebuffer, bounds: Rect, text: []const u8, size: u16, color: Color, align: Alignment) void;
|
|
};
|
|
```
|
|
|
|
**Características:**
|
|
- Font atlas dinámico
|
|
- Caché de glyphs renderizados
|
|
- Múltiples tamaños de fuente
|
|
- Text measurement preciso
|
|
- Word wrapping correcto
|
|
- Kerning básico
|
|
- Subpixel rendering (opcional)
|
|
|
|
**LOC estimadas**: 500
|
|
|
|
#### 4.4 Rich Text (básico)
|
|
|
|
```zig
|
|
pub const TextSpan = struct {
|
|
text: []const u8,
|
|
style: TextStyle,
|
|
};
|
|
|
|
pub const TextStyle = struct {
|
|
color: ?Color = null,
|
|
bold: bool = false,
|
|
italic: bool = false,
|
|
underline: bool = false,
|
|
strikethrough: bool = false,
|
|
size: ?u16 = null,
|
|
link: ?[]const u8 = null,
|
|
};
|
|
|
|
pub fn richText(ctx: *Context, bounds: Rect, spans: []const TextSpan) void;
|
|
pub fn richTextInteractive(ctx: *Context, bounds: Rect, spans: []const TextSpan) ?[]const u8; // Returns clicked link
|
|
```
|
|
|
|
**Características:**
|
|
- Múltiples estilos en un texto
|
|
- Bold, italic, underline
|
|
- Links clickables
|
|
- Colores por span
|
|
- Tamaños mixtos
|
|
|
|
**LOC estimadas**: 300
|
|
|
|
**Entregables Fase 4:**
|
|
- [ ] Editor multilinea completo
|
|
- [ ] NumberEntry con validación
|
|
- [ ] Font Atlas funcionando
|
|
- [ ] Rich Text básico
|
|
- [ ] Clipboard integration
|
|
- [ ] Tests de texto
|
|
- [ ] Demo de editores
|
|
|
|
---
|
|
|
|
### FASE 5: SISTEMA DE ICONOS Y GRÁFICOS
|
|
**Duración estimada**: 1 semana
|
|
**Objetivo**: Iconos vectoriales y gráficos básicos
|
|
|
|
#### 5.1 Icon System
|
|
|
|
```zig
|
|
pub const IconSet = enum {
|
|
material, // Material Design icons
|
|
feather, // Feather icons
|
|
custom, // User-defined
|
|
};
|
|
|
|
pub const Icon = struct {
|
|
data: []const u8, // Path data o bitmap
|
|
width: u16,
|
|
height: u16,
|
|
|
|
pub fn render(self: Icon, fb: *Framebuffer, x: i32, y: i32, size: u16, color: Color) void;
|
|
};
|
|
|
|
pub const IconLibrary = struct {
|
|
icons: std.StringHashMap(Icon),
|
|
|
|
pub fn get(self: *IconLibrary, name: []const u8) ?Icon;
|
|
pub fn loadFromSvg(self: *IconLibrary, name: []const u8, svg_data: []const u8) !void;
|
|
};
|
|
|
|
// Built-in icons
|
|
pub const icons = struct {
|
|
pub const check: Icon = ...;
|
|
pub const close: Icon = ...;
|
|
pub const arrow_left: Icon = ...;
|
|
pub const arrow_right: Icon = ...;
|
|
pub const arrow_up: Icon = ...;
|
|
pub const arrow_down: Icon = ...;
|
|
pub const menu: Icon = ...;
|
|
pub const search: Icon = ...;
|
|
pub const settings: Icon = ...;
|
|
pub const user: Icon = ...;
|
|
pub const folder: Icon = ...;
|
|
pub const file: Icon = ...;
|
|
pub const edit: Icon = ...;
|
|
pub const delete: Icon = ...;
|
|
pub const add: Icon = ...;
|
|
pub const remove: Icon = ...;
|
|
// ... 50+ iconos básicos
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 400
|
|
|
|
#### 5.2 Canvas/Drawing Primitives
|
|
|
|
```zig
|
|
pub const Canvas = struct {
|
|
fb: *Framebuffer,
|
|
clip: Rect,
|
|
transform: Transform,
|
|
|
|
// Primitivas básicas
|
|
pub fn drawLine(self: *Canvas, x1: i32, y1: i32, x2: i32, y2: i32, color: Color, thickness: u8) void;
|
|
pub fn drawRect(self: *Canvas, rect: Rect, color: Color) void;
|
|
pub fn drawRectOutline(self: *Canvas, rect: Rect, color: Color, thickness: u8) void;
|
|
pub fn drawRoundedRect(self: *Canvas, rect: Rect, radius: u8, color: Color) void;
|
|
pub fn drawCircle(self: *Canvas, cx: i32, cy: i32, radius: u16, color: Color) void;
|
|
pub fn drawCircleOutline(self: *Canvas, cx: i32, cy: i32, radius: u16, color: Color, thickness: u8) void;
|
|
pub fn drawArc(self: *Canvas, cx: i32, cy: i32, radius: u16, start_angle: f32, end_angle: f32, color: Color) void;
|
|
pub fn drawPolygon(self: *Canvas, points: []const Point, color: Color) void;
|
|
|
|
// Path-based drawing
|
|
pub fn beginPath(self: *Canvas) void;
|
|
pub fn moveTo(self: *Canvas, x: i32, y: i32) void;
|
|
pub fn lineTo(self: *Canvas, x: i32, y: i32) void;
|
|
pub fn quadraticTo(self: *Canvas, cx: i32, cy: i32, x: i32, y: i32) void;
|
|
pub fn closePath(self: *Canvas) void;
|
|
pub fn fill(self: *Canvas, color: Color) void;
|
|
pub fn stroke(self: *Canvas, color: Color, thickness: u8) void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 500
|
|
|
|
#### 5.3 Charts (básicos)
|
|
|
|
```zig
|
|
pub const ChartType = enum { line, bar, pie, donut };
|
|
|
|
pub const ChartData = struct {
|
|
labels: []const []const u8,
|
|
series: []const Series,
|
|
};
|
|
|
|
pub const Series = struct {
|
|
name: []const u8,
|
|
values: []const f64,
|
|
color: Color,
|
|
};
|
|
|
|
pub const ChartConfig = struct {
|
|
chart_type: ChartType,
|
|
show_legend: bool = true,
|
|
show_grid: bool = true,
|
|
show_values: bool = false,
|
|
animated: bool = true,
|
|
};
|
|
|
|
pub fn chart(ctx: *Context, bounds: Rect, data: ChartData, config: ChartConfig) void;
|
|
pub fn lineChart(ctx: *Context, bounds: Rect, data: ChartData) void;
|
|
pub fn barChart(ctx: *Context, bounds: Rect, data: ChartData) void;
|
|
pub fn pieChart(ctx: *Context, bounds: Rect, data: ChartData) void;
|
|
```
|
|
|
|
**LOC estimadas**: 400
|
|
|
|
**Entregables Fase 5:**
|
|
- [ ] 50+ iconos built-in
|
|
- [ ] Canvas con primitivas
|
|
- [ ] Rounded rectangles
|
|
- [ ] Charts básicos (line, bar, pie)
|
|
- [ ] Documentación de iconos
|
|
- [ ] Demo de gráficos
|
|
|
|
---
|
|
|
|
### FASE 6: INPUT AVANZADO
|
|
**Duración estimada**: 1 semana
|
|
**Objetivo**: Clipboard, drag & drop, gestures
|
|
|
|
#### 6.1 Clipboard Integration
|
|
|
|
```zig
|
|
pub const Clipboard = struct {
|
|
pub fn getText(allocator: Allocator) !?[]u8;
|
|
pub fn setText(text: []const u8) !void;
|
|
pub fn hasText() bool;
|
|
pub fn clear() void;
|
|
|
|
// Formatos adicionales (futuro)
|
|
pub fn getImage() ?ImageData;
|
|
pub fn setImage(data: ImageData) !void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 150 (SDL2 clipboard)
|
|
|
|
#### 6.2 Drag & Drop System
|
|
|
|
```zig
|
|
pub const DragData = struct {
|
|
source_id: u64,
|
|
data_type: []const u8,
|
|
data: ?*anyopaque,
|
|
preview: ?DragPreview,
|
|
};
|
|
|
|
pub const DropZone = struct {
|
|
accepts: []const []const u8, // Tipos aceptados
|
|
highlight_on_hover: bool,
|
|
};
|
|
|
|
pub const DragDropManager = struct {
|
|
current_drag: ?DragData,
|
|
drop_zones: std.ArrayList(DropZone),
|
|
|
|
pub fn startDrag(self: *DragDropManager, data: DragData) void;
|
|
pub fn endDrag(self: *DragDropManager) ?DragData;
|
|
pub fn isDragging(self: DragDropManager) bool;
|
|
pub fn registerDropZone(self: *DragDropManager, bounds: Rect, zone: DropZone) void;
|
|
pub fn getHoveredDropZone(self: DragDropManager) ?*DropZone;
|
|
};
|
|
|
|
pub fn draggable(ctx: *Context, bounds: Rect, id: u64, data_type: []const u8) bool;
|
|
pub fn dropZone(ctx: *Context, bounds: Rect, accepts: []const []const u8) ?DragData;
|
|
```
|
|
|
|
**LOC estimadas**: 300
|
|
|
|
#### 6.3 Keyboard Shortcuts System
|
|
|
|
```zig
|
|
pub const Shortcut = struct {
|
|
key: Key,
|
|
modifiers: KeyModifiers,
|
|
action: []const u8,
|
|
};
|
|
|
|
pub const ShortcutManager = struct {
|
|
shortcuts: std.ArrayList(Shortcut),
|
|
|
|
pub fn register(self: *ShortcutManager, shortcut: Shortcut) void;
|
|
pub fn unregister(self: *ShortcutManager, action: []const u8) void;
|
|
pub fn check(self: *ShortcutManager, input: *InputState) ?[]const u8;
|
|
pub fn getShortcutText(shortcut: Shortcut) []const u8; // "Ctrl+S"
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 150
|
|
|
|
#### 6.4 Focus Groups
|
|
|
|
```zig
|
|
pub const FocusGroup = struct {
|
|
id: u64,
|
|
widgets: [MAX_GROUP_SIZE]u64,
|
|
count: usize,
|
|
wrap: bool,
|
|
|
|
pub fn add(self: *FocusGroup, widget_id: u64) void;
|
|
pub fn focusNext(self: *FocusGroup, current: u64) ?u64;
|
|
pub fn focusPrev(self: *FocusGroup, current: u64) ?u64;
|
|
};
|
|
|
|
pub const FocusManagerEx = struct {
|
|
current_focus: ?u64,
|
|
groups: std.AutoHashMap(u64, FocusGroup),
|
|
|
|
pub fn createGroup(self: *FocusManagerEx) u64;
|
|
pub fn addToGroup(self: *FocusManagerEx, group_id: u64, widget_id: u64) void;
|
|
pub fn handleNavigation(self: *FocusManagerEx, input: *InputState) void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 200
|
|
|
|
**Entregables Fase 6:**
|
|
- [ ] Clipboard texto funcionando
|
|
- [ ] Drag & drop básico
|
|
- [ ] Sistema de shortcuts
|
|
- [ ] Focus groups
|
|
- [ ] Tests de input
|
|
- [ ] Demo de drag & drop
|
|
|
|
---
|
|
|
|
### FASE 7: RENDERIZADO AVANZADO
|
|
**Duración estimada**: 2 semanas
|
|
**Objetivo**: Anti-aliasing, efectos visuales, rendimiento
|
|
|
|
#### 7.1 Anti-aliasing
|
|
|
|
```zig
|
|
pub const AAMode = enum {
|
|
none, // Sin AA
|
|
fast, // 2x supersampling
|
|
quality, // 4x supersampling
|
|
};
|
|
|
|
pub const AARenderer = struct {
|
|
mode: AAMode,
|
|
|
|
pub fn drawLineAA(self: *AARenderer, fb: *Framebuffer, x1: f32, y1: f32, x2: f32, y2: f32, color: Color) void;
|
|
pub fn drawCircleAA(self: *AARenderer, fb: *Framebuffer, cx: f32, cy: f32, radius: f32, color: Color) void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 300
|
|
|
|
#### 7.2 Efectos Visuales
|
|
|
|
```zig
|
|
pub const Effect = union(enum) {
|
|
shadow: ShadowEffect,
|
|
blur: BlurEffect,
|
|
gradient: GradientEffect,
|
|
opacity: f32,
|
|
};
|
|
|
|
pub const ShadowEffect = struct {
|
|
offset_x: i8,
|
|
offset_y: i8,
|
|
blur_radius: u8,
|
|
color: Color,
|
|
};
|
|
|
|
pub const GradientEffect = struct {
|
|
start_color: Color,
|
|
end_color: Color,
|
|
direction: GradientDirection,
|
|
};
|
|
|
|
pub fn applyShadow(fb: *Framebuffer, rect: Rect, shadow: ShadowEffect) void;
|
|
pub fn applyGradient(fb: *Framebuffer, rect: Rect, gradient: GradientEffect) void;
|
|
pub fn applyBlur(fb: *Framebuffer, rect: Rect, radius: u8) void;
|
|
```
|
|
|
|
**LOC estimadas**: 400
|
|
|
|
#### 7.3 Animaciones
|
|
|
|
```zig
|
|
pub const EasingFn = *const fn(f32) f32;
|
|
|
|
pub const Easing = struct {
|
|
pub fn linear(t: f32) f32;
|
|
pub fn easeInQuad(t: f32) f32;
|
|
pub fn easeOutQuad(t: f32) f32;
|
|
pub fn easeInOutQuad(t: f32) f32;
|
|
pub fn easeInCubic(t: f32) f32;
|
|
pub fn easeOutCubic(t: f32) f32;
|
|
pub fn easeInOutCubic(t: f32) f32;
|
|
pub fn easeInElastic(t: f32) f32;
|
|
pub fn easeOutElastic(t: f32) f32;
|
|
pub fn easeInBounce(t: f32) f32;
|
|
pub fn easeOutBounce(t: f32) f32;
|
|
};
|
|
|
|
pub const Animation = struct {
|
|
start_value: f32,
|
|
end_value: f32,
|
|
duration_ms: u32,
|
|
easing: EasingFn,
|
|
start_time: i64,
|
|
|
|
pub fn getValue(self: Animation, current_time: i64) f32;
|
|
pub fn isComplete(self: Animation, current_time: i64) bool;
|
|
};
|
|
|
|
pub const AnimationManager = struct {
|
|
animations: std.AutoHashMap(u64, Animation),
|
|
|
|
pub fn start(self: *AnimationManager, id: u64, anim: Animation) void;
|
|
pub fn stop(self: *AnimationManager, id: u64) void;
|
|
pub fn getValue(self: *AnimationManager, id: u64) ?f32;
|
|
pub fn update(self: *AnimationManager, current_time: i64) void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 300
|
|
|
|
#### 7.4 Virtual Scrolling
|
|
|
|
```zig
|
|
pub const VirtualScroller = struct {
|
|
total_items: usize,
|
|
item_height: u16,
|
|
viewport_height: u32,
|
|
scroll_offset: i32,
|
|
|
|
pub fn getVisibleRange(self: VirtualScroller) struct { start: usize, end: usize };
|
|
pub fn getItemY(self: VirtualScroller, index: usize) i32;
|
|
pub fn scrollToItem(self: *VirtualScroller, index: usize) void;
|
|
pub fn handleScroll(self: *VirtualScroller, delta: i32) void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 150
|
|
|
|
#### 7.5 GPU Renderer (Opcional)
|
|
|
|
```zig
|
|
pub const GpuBackend = enum { opengl, vulkan, metal, d3d11 };
|
|
|
|
pub const GpuRenderer = struct {
|
|
backend: GpuBackend,
|
|
|
|
pub fn init(backend: GpuBackend) !GpuRenderer;
|
|
pub fn deinit(self: *GpuRenderer) void;
|
|
pub fn beginFrame(self: *GpuRenderer) void;
|
|
pub fn endFrame(self: *GpuRenderer) void;
|
|
pub fn execute(self: *GpuRenderer, commands: []const DrawCommand) void;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 800 (solo OpenGL básico)
|
|
|
|
**Entregables Fase 7:**
|
|
- [ ] Anti-aliasing para líneas y círculos
|
|
- [ ] Sombras (drop shadow)
|
|
- [ ] Gradientes lineales
|
|
- [ ] Sistema de animaciones con easing
|
|
- [ ] Virtual scrolling para listas
|
|
- [ ] GPU renderer básico (opcional)
|
|
- [ ] Benchmarks de rendimiento
|
|
|
|
---
|
|
|
|
### FASE 8: ACCESIBILIDAD Y TESTING
|
|
**Duración estimada**: 1 semana
|
|
**Objetivo**: Accesibilidad, testing automatizado, documentación
|
|
|
|
#### 8.1 Accesibilidad
|
|
|
|
```zig
|
|
pub const AccessibilityRole = enum {
|
|
button,
|
|
checkbox,
|
|
radio,
|
|
slider,
|
|
textbox,
|
|
listbox,
|
|
tree,
|
|
menu,
|
|
dialog,
|
|
// ...
|
|
};
|
|
|
|
pub const AccessibilityInfo = struct {
|
|
role: AccessibilityRole,
|
|
label: []const u8,
|
|
description: ?[]const u8,
|
|
value: ?[]const u8,
|
|
state: AccessibilityState,
|
|
};
|
|
|
|
pub const AccessibilityState = packed struct {
|
|
disabled: bool = false,
|
|
expanded: bool = false,
|
|
selected: bool = false,
|
|
checked: bool = false,
|
|
focused: bool = false,
|
|
};
|
|
|
|
// Cada widget expone su info de accesibilidad
|
|
pub fn getAccessibilityInfo(widget_id: u64) ?AccessibilityInfo;
|
|
```
|
|
|
|
**LOC estimadas**: 200
|
|
|
|
#### 8.2 Testing Framework
|
|
|
|
```zig
|
|
pub const TestRunner = struct {
|
|
ctx: *Context,
|
|
input: *InputState,
|
|
|
|
pub fn click(self: *TestRunner, x: i32, y: i32) void;
|
|
pub fn typeText(self: *TestRunner, text: []const u8) void;
|
|
pub fn pressKey(self: *TestRunner, key: Key, modifiers: KeyModifiers) void;
|
|
pub fn waitFrames(self: *TestRunner, count: u32) void;
|
|
|
|
pub fn findWidget(self: *TestRunner, label: []const u8) ?WidgetInfo;
|
|
pub fn assertVisible(self: *TestRunner, label: []const u8) !void;
|
|
pub fn assertText(self: *TestRunner, label: []const u8, expected: []const u8) !void;
|
|
pub fn assertEnabled(self: *TestRunner, label: []const u8) !void;
|
|
};
|
|
|
|
pub const SnapshotTest = struct {
|
|
pub fn capture(fb: *Framebuffer, name: []const u8) !void;
|
|
pub fn compare(fb: *Framebuffer, name: []const u8) !bool;
|
|
};
|
|
```
|
|
|
|
**LOC estimadas**: 400
|
|
|
|
#### 8.3 Documentación
|
|
|
|
- API Reference generada automáticamente
|
|
- Ejemplos para cada widget
|
|
- Tutorial de inicio rápido
|
|
- Guía de arquitectura
|
|
- Guía de contribución
|
|
|
|
**Entregables Fase 8:**
|
|
- [ ] Roles de accesibilidad para todos los widgets
|
|
- [ ] Framework de testing
|
|
- [ ] Snapshot testing
|
|
- [ ] Documentación completa
|
|
- [ ] 10+ ejemplos funcionando
|
|
|
|
---
|
|
|
|
### FASE 9: INTEGRACIÓN Y POLISH
|
|
**Duración estimada**: 1 semana
|
|
**Objetivo**: Integración final, pulido, release
|
|
|
|
#### 9.1 Integración Completa
|
|
|
|
- Verificar que todos los widgets funcionan juntos
|
|
- Verificar rendimiento con UI compleja
|
|
- Verificar uso de memoria en escenarios reales
|
|
- Verificar funcionamiento SSH/X11
|
|
|
|
#### 9.2 Polish
|
|
|
|
- Revisar API consistency
|
|
- Optimizar hot paths
|
|
- Eliminar código muerto
|
|
- Reducir allocaciones innecesarias
|
|
|
|
#### 9.3 Release Preparation
|
|
|
|
- Versión 1.0.0
|
|
- Changelog completo
|
|
- Package en zig package manager
|
|
- Anuncio
|
|
|
|
**Entregables Fase 9:**
|
|
- [ ] Integración completa verificada
|
|
- [ ] Rendimiento optimizado
|
|
- [ ] 0 warnings, 0 leaks
|
|
- [ ] v1.0.0 release
|
|
- [ ] Documentación publicada
|
|
|
|
---
|
|
|
|
## 5. DETALLES DE IMPLEMENTACIÓN
|
|
|
|
### 5.1 Estructura Final de Archivos
|
|
|
|
```
|
|
zcatgui/
|
|
├── src/
|
|
│ ├── zcatgui.zig # Entry point
|
|
│ │
|
|
│ ├── core/
|
|
│ │ ├── context.zig # Context + Arena
|
|
│ │ ├── layout.zig # Constraints
|
|
│ │ ├── style.zig # Colors, Themes
|
|
│ │ ├── input.zig # Input state
|
|
│ │ ├── command.zig # Draw commands
|
|
│ │ └── animation.zig # Animation system
|
|
│ │
|
|
│ ├── widgets/
|
|
│ │ ├── basic/
|
|
│ │ │ ├── label.zig
|
|
│ │ │ ├── button.zig
|
|
│ │ │ ├── checkbox.zig
|
|
│ │ │ ├── radio.zig
|
|
│ │ │ └── slider.zig
|
|
│ │ ├── input/
|
|
│ │ │ ├── text_input.zig
|
|
│ │ │ ├── number_entry.zig
|
|
│ │ │ ├── editor.zig # Multiline
|
|
│ │ │ ├── select.zig
|
|
│ │ │ └── autocomplete.zig
|
|
│ │ ├── data/
|
|
│ │ │ ├── list.zig
|
|
│ │ │ ├── table.zig
|
|
│ │ │ ├── tree.zig
|
|
│ │ │ └── reorderable.zig
|
|
│ │ ├── navigation/
|
|
│ │ │ ├── menu.zig
|
|
│ │ │ ├── tabs.zig
|
|
│ │ │ └── breadcrumb.zig
|
|
│ │ ├── container/
|
|
│ │ │ ├── panel.zig
|
|
│ │ │ ├── split.zig
|
|
│ │ │ ├── modal.zig
|
|
│ │ │ └── scroll.zig
|
|
│ │ ├── feedback/
|
|
│ │ │ ├── tooltip.zig
|
|
│ │ │ ├── progress.zig
|
|
│ │ │ ├── toast.zig
|
|
│ │ │ └── spinner.zig
|
|
│ │ ├── special/
|
|
│ │ │ ├── image.zig
|
|
│ │ │ ├── color_picker.zig
|
|
│ │ │ ├── date_picker.zig
|
|
│ │ │ └── chart.zig
|
|
│ │ ├── focus.zig
|
|
│ │ └── widgets.zig # Re-exports
|
|
│ │
|
|
│ ├── panels/
|
|
│ │ ├── panel.zig
|
|
│ │ ├── composite.zig
|
|
│ │ ├── data_manager.zig
|
|
│ │ └── panels.zig
|
|
│ │
|
|
│ ├── render/
|
|
│ │ ├── framebuffer.zig
|
|
│ │ ├── software.zig
|
|
│ │ ├── gpu.zig # Optional GPU
|
|
│ │ ├── font.zig
|
|
│ │ ├── font_atlas.zig
|
|
│ │ ├── ttf.zig
|
|
│ │ ├── canvas.zig
|
|
│ │ ├── effects.zig
|
|
│ │ └── aa.zig # Anti-aliasing
|
|
│ │
|
|
│ ├── backend/
|
|
│ │ ├── backend.zig
|
|
│ │ ├── sdl2.zig
|
|
│ │ └── clipboard.zig
|
|
│ │
|
|
│ ├── macro/
|
|
│ │ └── macro.zig
|
|
│ │
|
|
│ ├── icons/
|
|
│ │ ├── icons.zig
|
|
│ │ └── material.zig
|
|
│ │
|
|
│ └── utils/
|
|
│ ├── pool.zig # Object pools
|
|
│ ├── arena.zig # Arena allocator
|
|
│ └── virtual_scroll.zig
|
|
│
|
|
├── examples/
|
|
│ ├── hello.zig
|
|
│ ├── widgets_demo.zig
|
|
│ ├── table_demo.zig
|
|
│ ├── editor_demo.zig
|
|
│ ├── tree_demo.zig
|
|
│ ├── charts_demo.zig
|
|
│ └── full_app_demo.zig
|
|
│
|
|
├── tests/
|
|
│ ├── core_tests.zig
|
|
│ ├── widget_tests.zig
|
|
│ ├── render_tests.zig
|
|
│ └── integration_tests.zig
|
|
│
|
|
├── docs/
|
|
│ ├── ARCHITECTURE.md
|
|
│ ├── DEVELOPMENT_PLAN.md
|
|
│ ├── API_REFERENCE.md
|
|
│ ├── TUTORIAL.md
|
|
│ └── research/
|
|
│
|
|
├── build.zig
|
|
├── build.zig.zon
|
|
├── CLAUDE.md
|
|
└── README.md
|
|
```
|
|
|
|
### 5.2 Estimación Total de LOC
|
|
|
|
| Módulo | LOC Actual | LOC Final Est. |
|
|
|--------|:----------:|:--------------:|
|
|
| Core | 1,700 | 2,500 |
|
|
| Render | 1,300 | 3,000 |
|
|
| Backend | 400 | 600 |
|
|
| Macro | 340 | 400 |
|
|
| Widgets | 8,000 | 12,000 |
|
|
| Panels | 350 | 500 |
|
|
| Icons | 0 | 500 |
|
|
| Utils | 0 | 500 |
|
|
| Tests | 500 | 2,000 |
|
|
| **TOTAL** | **12,590** | **~22,000** |
|
|
|
|
---
|
|
|
|
## 6. MÉTRICAS DE CALIDAD
|
|
|
|
### 6.1 Performance Benchmarks
|
|
|
|
| Operación | Target |
|
|
|-----------|--------|
|
|
| Widget simple (button) | <50μs |
|
|
| Widget complejo (table 100 rows) | <500μs |
|
|
| Full frame (50 widgets) | <5ms |
|
|
| Text rendering (1000 chars) | <1ms |
|
|
| Command execution (1000 cmds) | <2ms |
|
|
|
|
### 6.2 Memory Benchmarks
|
|
|
|
| Escenario | Target |
|
|
|-----------|--------|
|
|
| Startup (empty) | <5MB |
|
|
| 100 widgets | <15MB |
|
|
| 1000 widgets | <50MB |
|
|
| Table 10K rows | <100MB |
|
|
|
|
### 6.3 Code Quality
|
|
|
|
| Métrica | Target |
|
|
|---------|--------|
|
|
| Test coverage | >90% |
|
|
| Functions >50 LOC | 0 |
|
|
| Cyclomatic complexity | <10 |
|
|
| Duplicate code | <5% |
|
|
| TODO/FIXME | 0 (at release) |
|
|
|
|
---
|
|
|
|
## 7. CHECKLIST FINAL
|
|
|
|
### Pre-Release Checklist
|
|
|
|
#### Core
|
|
- [ ] Arena allocator implementado
|
|
- [ ] Object pooling funcionando
|
|
- [ ] Dirty rectangles optimizado
|
|
- [ ] 0 memory leaks
|
|
|
|
#### Widgets (35 total)
|
|
- [ ] Label ✅
|
|
- [ ] Button ✅
|
|
- [ ] Checkbox ✅
|
|
- [ ] Radio ✅
|
|
- [ ] Slider ✅
|
|
- [ ] TextInput ✅
|
|
- [ ] NumberEntry
|
|
- [ ] Editor (multiline)
|
|
- [ ] Select ✅
|
|
- [ ] AutoComplete ✅
|
|
- [ ] List ✅
|
|
- [ ] Table ✅
|
|
- [ ] Tree
|
|
- [ ] ReorderableList
|
|
- [ ] Menu ✅
|
|
- [ ] Tabs ✅
|
|
- [ ] Breadcrumb
|
|
- [ ] Panel ✅
|
|
- [ ] Split ✅
|
|
- [ ] Modal ✅
|
|
- [ ] Scroll ✅
|
|
- [ ] Tooltip
|
|
- [ ] ProgressBar
|
|
- [ ] Toast
|
|
- [ ] Spinner
|
|
- [ ] Image
|
|
- [ ] ColorPicker
|
|
- [ ] DatePicker
|
|
- [ ] Chart (line)
|
|
- [ ] Chart (bar)
|
|
- [ ] Chart (pie)
|
|
- [ ] Focus ✅
|
|
- [ ] Canvas
|
|
- [ ] Icon
|
|
- [ ] RichText
|
|
|
|
#### Rendering
|
|
- [ ] Font Atlas
|
|
- [ ] Anti-aliasing
|
|
- [ ] Shadows
|
|
- [ ] Gradients
|
|
- [ ] Virtual scrolling
|
|
- [ ] GPU renderer (opcional)
|
|
|
|
#### Input
|
|
- [ ] Clipboard
|
|
- [ ] Drag & Drop
|
|
- [ ] Shortcuts system
|
|
- [ ] Focus groups
|
|
|
|
#### Sistema
|
|
- [ ] Animations
|
|
- [ ] Accessibility info
|
|
- [ ] Testing framework
|
|
- [ ] Snapshot tests
|
|
|
|
#### Documentación
|
|
- [ ] API Reference
|
|
- [ ] Tutorial
|
|
- [ ] 10+ ejemplos
|
|
- [ ] Changelog
|
|
|
|
#### Calidad
|
|
- [ ] 90%+ test coverage
|
|
- [ ] 0 warnings
|
|
- [ ] 0 memory leaks
|
|
- [ ] Performance targets met
|
|
- [ ] Memory targets met
|
|
|
|
---
|
|
|
|
## RESUMEN
|
|
|
|
| Fase | Duración | Widgets | LOC |
|
|
|------|:--------:|:-------:|:---:|
|
|
| 1. Fundamentos | 1 sem | 0 | +1,500 |
|
|
| 2. Feedback | 1 sem | +4 | +750 |
|
|
| 3. Especializados | 2 sem | +5 | +1,800 |
|
|
| 4. Texto | 2 sem | +2 | +1,650 |
|
|
| 5. Iconos/Gráficos | 1 sem | +4 | +1,300 |
|
|
| 6. Input | 1 sem | 0 | +800 |
|
|
| 7. Render | 2 sem | 0 | +1,950 |
|
|
| 8. Testing | 1 sem | 0 | +600 |
|
|
| 9. Polish | 1 sem | 0 | +100 |
|
|
| **TOTAL** | **12 sem** | **+18** | **+10,450** |
|
|
|
|
**Resultado final:**
|
|
- **35 widgets** (paridad DVUI)
|
|
- **~22,000 LOC** (eficiente)
|
|
- **Performance óptimo** (60fps, <16ms latencia)
|
|
- **Memoria mínima** (<50MB típico)
|
|
- **Código perfecto** (0 warnings, 0 leaks, 90%+ coverage)
|
|
|
|
---
|
|
|
|
> **Nota**: Este plan prioriza calidad sobre velocidad. Cada fase debe completarse con todos los tests pasando y métricas cumplidas antes de avanzar a la siguiente.
|