Commit graph

195 commits

Author SHA1 Message Date
d8f04f85bc feat: FilledCircle primitive (v0.24.0)
- Add FilledCircleCommand in command.zig
- Implement drawFilledCircle using Midpoint Circle Algorithm (Bresenham)
- Integer-only arithmetic (efficient, no sqrt/trig)
- Scanline filling with horizontal symmetry
- Add commandBounds for dirty region optimization
- Update CHANGELOG with v0.23.0 (FilledTriangle) and v0.24.0 (FilledCircle)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:29:57 +01:00
de56496803 feat: Añadir filledTriangle (rasterización scanline)
Nueva primitiva de dibujo para gráficos 3D:
- FilledTriangleCommand en command.zig
- Algoritmo scanline en software.zig
- Ordena vértices por Y, interpola bordes
- Soporta clipping correctamente

Base para logos 3D sólidos y widgets avanzados.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 00:51:46 +01:00
ae600f4341 feat: Modo minimal para tabs (estilo Laravel)
- Añadir config.minimal: bool para activar estilo sin fondos
- Añadir config.indicator_height para altura personalizable del underline
- En modo minimal: no dibujar fondos de tabs
- Texto inactivo usa text_secondary, activo usa primary
- Hover en minimal ilumina el texto
- Mantener retrocompatibilidad (minimal=false por defecto)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 00:13:51 +01:00
8b15d3f80f feat: Bisel 3D sutil en botones
- Añadir línea highlight (lighten 15) en borde superior interno
- Añadir línea shadow (darken 15) en borde inferior interno
- Aplicar a buttonRect y buttonStatefulRect
- Deshabilitar bisel en botones disabled
- Solo aplicar si botón tiene al menos 4px de alto/ancho
- Actualizar test para reflejar 2 comandos extra

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 00:11:25 +01:00
d2f99419de feat(text_input): Z-Design soporte para colores de panel
Añadidos campos opcionales a TextInputConfig:
- bg_color: color de fondo (override del theme)
- placeholder_color: color del placeholder

Los paneles ahora pueden pasar sus colores derivados Z-Design
a los widgets hijos para coherencia visual.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 22:39:47 +01:00
8f4336f1f6 feat(widgets): Z-Design usar theme dinámico en todos los widgets
Cambio de Style.Theme.dark (hardcoded) a Style.currentTheme().*
en 5 archivos / 7 ocurrencias:

- text_input.zig (línea 282)
- button.zig (líneas 75, 163)
- list.zig (líneas 124, 131)
- checkbox.zig (línea 61)
- select.zig (línea 102)

Ahora todos los widgets usan el ThemeManager global, permitiendo
cambio de tema en runtime.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 21:30:11 +01:00
9559b14a33 feat(style): Z-Design blend 85/15 para fondos visibles
Cambio en deriveDarkPalette(): 85% negro + 15% color base
(antes era 95/5, imperceptible)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 18:33:45 +01:00
b5a4205c29 feat(style): Mejorar derivePanelPalette con HSL
- Header usa darkenHsl/lightenHsl (preserva tono mejor que RGB)
- Selección sin foco usa desaturate + lightenHsl (más elegante)
- Nueva función contrastTextColor() para texto automático b/n
- Test adicional para contrastTextColor

Z-Design ahora produce paletas más armónicas desde color base.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 15:36:20 +01:00
c330492022 feat(style): Motor HSL para derivación de colores
Añadido espacio de color HSL para transformaciones perceptualmente uniformes:

- Struct Hsl con campos h (0-360), s (0-1), l (0-1)
- Funciones rgbToHsl() y hslToRgb() con algoritmo estándar
- Métodos Hsl: lighten, darken, saturate, desaturate, rotate
- Métodos Color: toHsl, lightenHsl, darkenHsl, saturate, desaturate
- Color.rotateHue, Color.complementary para teoría del color
- 15 tests unitarios para validar conversiones

Esto permite derivar paletas armónicas desde un color base (Z-Design).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 15:33:57 +01:00
b2a4081493 feat: Paridad Excel-style AdvancedTable ↔ VirtualAdvancedTable
Propuesta Gemini: Unificación funcional entre tablas.

1. Modo inserción centralizado en NavigationState (table_core)
   - is_insertion_mode, last_inserted_id
   - enterInsertionMode(), exitInsertionMode(), isInInsertionMode()

2. Auto-edit en Ctrl+N (AdvancedTable)
   - Tras insertar fila, inicia edición inmediatamente en col 0

3. Auto-insert en Tab (Modo Pro)
   - En modo inserción, Tab al final de fila inserta nueva fila
   - Permite meter 50+ líneas sin soltar teclado

4. Fix ghost row clonada
   - Comparar row_id AND row_index en rendering
   - Evita que fila insertada y ghost row compartan buffer

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 14:55:30 +01:00
bb2d6a7be1 fix: Cell editor bugs - buffer corrupción + desincronización
Bug 1: text_input bytes corruptos al editar celda con texto pre-seleccionado
- Causa: slice getTextInput() se corrompía tras deleteSelection
- Fix: Copiar a buffer local antes de modificar edit_buffer

Bug 2: Editor permanecía visible al hacer clic en otra fila
- Causa: Falta commit implícito al abandonar fila
- Fix: handleMouseClick detecta clic en fila diferente → commitEdit()

Diagnóstico: Gemini | Implementación: Claude

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 14:31:49 +01:00
1ae07812bd refactor(icon): Modularizar en carpeta (805→515 LOC hub, -36%) 2025-12-29 11:41:40 +01:00
50a6d3ca60 chore: Eliminar archivos residuales textarea.zig y progress.zig
Estos archivos quedaron fuera de sus carpetas modulares.
Ya se importan desde textarea/textarea.zig y progress/progress.zig.
2025-12-29 11:33:30 +01:00
61f0524bd3 refactor(autocomplete): Modularizar en carpeta (910→571 LOC hub)
- Extraer state.zig: AutoCompleteState (200 LOC)
- Extraer types.zig: MatchMode, Config, Colors, Result (89 LOC)
- Extraer filtering.zig: matchesFilter, prefix, contains, fuzzy (106 LOC)
- autocomplete.zig: hub principal con widget y convenience functions (571 LOC)
- Actualizar widgets.zig con nueva ruta import
2025-12-29 11:27:45 +01:00
7d4d4190b8 refactor(advanced_table): Extraer result.zig y state_helpers.zig de state.zig
- Extraer AdvancedTableResult a result.zig (73 LOC)
- Extraer funciones de map shifting a state_helpers.zig (141 LOC con tests)
- Reducir state.zig de 1235 LOC a 1123 LOC
- Añadir swapMapEntries para operaciones de move row
- Mantener re-exports para compatibilidad
2025-12-29 10:23:41 +01:00
042ff96141 refactor(advanced_table): Modularizar en drawing, input, helpers, sorting
- Extraer drawing.zig: drawHeader, drawScrollbar, drawEditingOverlay
- Extraer input.zig: handleRowClicks, handleKeyboard, handleEditingKeyboard
- Extraer helpers.zig: commitEdit, parseValue, detectCRUDAction, invokeCallbacks
- Extraer sorting.zig: sortRows, swapRowStates, startsWithIgnoreCase
- Reducir advanced_table.zig de 1443 LOC a ~380 LOC
- Mantener re-exports para compatibilidad con código existente
2025-12-29 10:04:39 +01:00
b9f412b64f refactor(virtual_advanced_table): Extraer drawing.zig e input.zig
Modularización del archivo principal (1367 LOC → 468 LOC):
- drawing.zig (495 LOC): FilterBar, Header, Rows, Footer, Scrollbars
- input.zig (232 LOC): Keyboard, MouseClick, helpers

Archivos sin cambios: state.zig (847 LOC - candidato futuro)
2025-12-29 09:48:01 +01:00
fa5854fa21 refactor(table_core): Modularizar en 10 archivos (<300 LOC cada uno)
BREAKING: table_core.zig ahora es carpeta table_core/

Módulos creados:
- types.zig: Enums, structs, constantes
- state.zig: CellEditState, NavigationState
- datasource.zig: TableDataSource interface
- row_buffer.zig: Excel-style commit logic
- keyboard.zig: Manejo de teclado
- navigation.zig: Tab, sorting, double-click
- rendering.zig: Funciones de dibujo
- scrollbars.zig: Scrollbars vertical/horizontal
- utils.zig: blendColor, startsWithIgnoreCase
- table_core.zig: Hub de re-exports

Beneficios:
- 2115 LOC → 10 archivos de ~100-270 LOC
- Debugging focalizado por módulo
- Imports actualizados en 7 archivos de widgets
2025-12-29 01:41:59 +01:00
4648138bfc cleanup: Remove debug print from Ctrl+N handler (v0.2.39) 2025-12-29 00:10:57 +01:00
c9bdf56a80 refactor: Remove injection logic, prepare for Modo Inserción Cronológico
- Remove injected_row_idx, injected_committed from VirtualAdvancedTableState
- Remove is_injected, injection_index from RowEditBuffer and RowCommitInfo
- Remove startInjectedEdit() method
- Simplify PagedDataSource (no injection offset)
- Simplify drawRowsWithDataSource (no injection handling)
- Add is_insertion_mode, insertion_session_active to State
- Add enterInsertionMode(), exitInsertionMode(), isInInsertionMode() methods
- Ctrl+N now emits insert_row_requested for Panel to handle

Part of Modo Inserción Cronológico implementation.
2025-12-28 22:01:28 +01:00
3a6398e90d fix(virtual_table): PagedDataSource en frameAllocator
- PagedDataSource ahora se crea en ctx.frameAllocator()
- Memoria estable durante todo el frame de rendering
- Eliminado cached_paged_datasource del state (punteros auto-ref peligrosos)
- Fix secundario para estabilidad (no era causa del crash Ctrl+N)
2025-12-28 20:28:31 +01:00
b3a33ec4f3 fix(virtual_table): RowIdGetter now handles injected rows
Bug: Tab within injected row was triggering immediate row commit.
This happened because RowIdGetter.getRowId() returned the REAL row ID
for the injected row index, instead of NEW_ROW_ID.

Fix:
- RowIdGetter now takes injected_idx parameter
- Returns NEW_ROW_ID for injected row
- Adjusts indices for rows after injection (row-1)
- num_rows calculation now accounts for injection (+1)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 12:50:30 +01:00
4b61c2a119 fix(virtual_table): Use correct startEditing method name 2025-12-28 02:30:49 +01:00
ca187e743e feat(virtual_table): Auto-reload when injected row leaves viewport
When an injected row has been committed (injected_committed=true)
and scrolling moves it out of the visible area:
- Sets needs_reload=true in result
- Clears injection state

This triggers the panel to refetch data from DB, where the
new row will appear in its proper sorted position.
2025-12-28 02:28:55 +01:00
08b10486d2 feat(table_core,virtual_table): Propagate injection info on commit
RowCommitInfo now includes:
- is_injected: bool (was this an injected row)
- injection_index: ?usize (where it was injected)

buildCommitInfo() copies these from RowEditBuffer.

VirtualAdvancedTable sets result.injection_committed and
result.injection_row_idx when committing an injected row,
for both Tab navigation and selection change commits.

This allows the panel to know when to INSERT vs UPDATE and
handle the special case of locally injected rows.
2025-12-28 02:27:44 +01:00
47146b75c9 feat(virtual_table): Implement Ctrl+N local injection handler
- Ctrl+N creates injected row below current selection
- Uses startInjection() to initialize injection state
- Automatically starts editing first column
- Updates selection to show injected row as selected
- Adjusts visible row count when injection is active

No longer emits insert_row_requested - injection is handled
internally by the widget.
2025-12-28 02:25:44 +01:00
5800d01a67 feat(paged_datasource): Handle injected rows in data access
When an injected row exists (Ctrl+N between lines):
- getRowCount(): adds 1 to total count
- getCellValueInto(): returns edit buffer values for injected row,
  shifts indices for rows after injection
- getRowId(): returns injected_row_id for injected row,
  shifts indices for rows after injection

This enables transparent rendering of injected rows without
modifying the drawing code.
2025-12-28 02:24:14 +01:00
712466adc8 feat(virtual_table): Add injection state for Ctrl+N between rows
State fields:
- injected_row_idx: visual index of injected row
- injected_row_id: ID after commit (NEW_ROW_ID until saved)
- injected_committed: true when saved to DB

Result fields:
- injection_committed: panel should INSERT
- injection_row_idx: where it was injected
- needs_reload: table should refetch from DB

Helper methods:
- hasInjection(), startInjection(), clearInjection()
- markInjectionCommitted(), isInjectionVisible()
2025-12-28 02:22:06 +01:00
c6b9bd080a feat(advanced_table): Ctrl+N inserts row BELOW current
- Insert at selected_row + 1 instead of at selected_row
- Use startInjectedEdit() for proper injection tracking
- Row appears below cursor, more intuitive UX
2025-12-28 02:19:49 +01:00
40743b98d2 feat(table_core): Add injection support to RowEditBuffer
- Add is_injected: bool to distinguish injected rows
- Add injection_index: ?usize for insertion position
- Add startInjectedEdit() method for Ctrl+N between lines
- Update startEdit/clear to reset new fields
2025-12-28 02:19:04 +01:00
6dbaecc485 fix(advanced_table): Init row_edit_buffer on Ctrl+N insert
Start edit buffer for new row immediately after Ctrl+N insertion,
enabling Excel-style editing from the first keystroke.
2025-12-28 02:00:50 +01:00
454803fe03 feat(advanced_table): Unify Excel-style editing with VirtualAdvancedTable
- Add row_edit_buffer to AdvancedTableState
- Connect edit_buffer to rendering via drawRowsWithDataSource
- Use DRY planTabNavigation for Tab navigation + auto-commit
- Add Excel-style result fields: row_committed, row_changes, etc.
- Both widgets now share identical commit-on-row-change behavior
2025-12-28 01:59:31 +01:00
2a92c7530c feat(table_core): DRY planTabNavigation for Excel-style Tab commit
- Add planTabNavigation() in table_core.zig: central function for Tab navigation with auto-commit
- Uses row_id comparison (not indices) to detect row changes - robust for virtual tables
- Returns TabAction enum: move, move_with_commit, exit, exit_with_commit
- Integrates in virtual_advanced_table.zig with RowIdGetter wrapper
- Removes obsolete tab_out commit logic
- Fix: Tab at end of ghost row now commits before wrap

🤖 Generated with Claude Code
2025-12-28 01:50:22 +01:00
51705f8fc7 fix(virtual_table): Commit pending changes on tab_out
When user tabs out of the table with pending changes in RowEditBuffer,
commit them before exiting. Prevents data loss when leaving ghost row.
2025-12-27 23:36:34 +01:00
ef30cc7d1b fix(table_core): Show pending values from RowEditBuffer in render
Fix Tab showing empty cell after editing:
- Add edit_buffer field to DrawRowsConfig
- drawRowsWithDataSource now checks RowEditBuffer before DataSource
- VirtualAdvancedTable passes row_edit_buffer to render

Priority: RowEditBuffer (user typed) > DataSource (DB/memory)
2025-12-27 23:00:09 +01:00
9c9c53afea feat(style): Z-Design panel color derivation system
Laravel-inspired color system for semantic panel coloring:

- Add blendTowards(target, percent) for color washing
- Add Laravel color constants (red, blue, green, amber, cyan, etc.)
- Add soft_black/soft_white for better aesthetics
- Add ThemeMode enum (dark/light)
- Add PanelColorScheme with 10 documented fields
- Implement derivePanelPalette(base, mode) to derive full palette
- deriveDarkPalette: 5% tint on dark background
- deriveLightPalette: 3% tint on light background
- Tests for blendTowards and derivePanelPalette

This enables deriving a complete 10-color panel palette from
a single base color, achieving Laravel Forge/Nova aesthetics.
2025-12-27 22:23:58 +01:00
5c7964bacc feat(tables): Tips proactivos cada ~10s
- Añade table_tips[] con 8 tips de atajos
- Añade tip_index a VirtualAdvancedTableState
- Rota tip cada 600 frames (~10s @ 60fps)
- result.current_tip contiene tip a mostrar
- Solo muestra tips con focus y sin edición activa
2025-12-27 21:47:47 +01:00
dc82340381 feat(table_core): Selection on focus Excel-style
- Añade selection_start/selection_end a CellEditState
- F2/Space selecciona todo el texto al entrar en edición
- Typing con selección reemplaza texto seleccionado
- Backspace/Delete borra selección si existe
- Flechas/Home/End limpian selección
- Dibuja highlight azul en ambas tablas (Advanced + Virtual)
2025-12-27 21:41:42 +01:00
91570368cc feat(virtual_table): Auto-scroll horizontal en navegación Tab
- Añade ensureColumnVisible() para mantener columna activa visible
- Ajusta scroll_x automáticamente al navegar con Tab/Shift+Tab
- Respeta límites max_scroll_x
2025-12-27 21:34:37 +01:00
8e9dd3a475 feat(virtual_table): deleted_row_id en result para Ctrl+Delete
- Añadido deleted_row_id: i64 a VirtualAdvancedTableResult
- handleKeyboard setea el ID de la fila seleccionada
- El panel puede usar esto para eliminar de BD
2025-12-27 21:30:10 +01:00
b73ee76872 feat(tables): Indicador ordenación ▴/▾ Unicode en headers
- SortDirection.symbol() ahora retorna ▴/▾ en vez de ^/v
- AdvancedTable usa los mismos glifos Unicode
- VirtualAdvancedTable ya usaba symbol()
2025-12-27 21:28:13 +01:00
0ca97c2ba3 refactor(advanced_table): Brain-in-Core pattern - usar processTableEvents()
Completa la limpieza del patrón Brain-in-Core:
- AdvancedTable ahora usa table_core.processTableEvents() igual que VirtualAdvancedTable
- Eliminada lógica duplicada de navegación (flechas, Home, End, PageUp/Down)
- Eliminada lógica duplicada de atajos (Ctrl+Home/End, Ctrl+N, Ctrl+Delete)
- Ctrl+B ahora funciona en ambas tablas (alias de Ctrl+Delete)
- Mantiene lógica específica: búsqueda incremental, Ctrl+A select all

Checklist Gemini completado:
[x] Manejo de flechas en Core
[x] Manejo de Ctrl+N en Core
[x] Ctrl+B implementado
[x] Ctrl+Shift+1 activa ordenación
2025-12-27 21:16:06 +01:00
aed811a102 feat(table_core): Brain-in-Core - processTableEvents() unifica toda lógica de teclado
Arquitectura diseñada por Gemini:
- TODA la lógica de decisión en table_core.zig
- Widgets solo pasan eventos y reaccionan a flags
- Cualquier tabla nueva hereda automáticamente

Cambios:
- TableEventResult: struct con TODOS los flags de acciones
- processTableEvents(): función maestra que procesa teclado
- Soporta: navegación, CRUD (Ctrl+N/B/Del), ordenación (Ctrl+Shift+1-9), edición
- VirtualAdvancedTable refactorizado al patrón Brain-in-Core
- Nuevos campos result: insert_row_requested, delete_row_requested, sort_column_index
2025-12-27 21:07:17 +01:00
7642ffe7f7 feat(table_core): Dirty tracking visual - blend naranja para filas con cambios pendientes
- Añadido dirty_row_id: ?i64 a DrawRowsConfig
- drawRowsWithDataSource aplica blendColor(state_modified, 0.25) si dirty
- VirtualAdvancedTable pasa row_edit_buffer.row_id cuando has_changes
2025-12-27 20:54:53 +01:00
a9caa522a1 refactor(tables): FASE 6 - Unificar scrollbars en table_core
- Añadido VerticalScrollbarParams y drawVerticalScrollbar
- Añadido HorizontalScrollbarParams y drawHorizontalScrollbar
- AdvancedTable y VirtualAdvancedTable ahora usan funciones unificadas
- Elimina duplicación de código de renderizado de scrollbars
2025-12-27 19:52:05 +01:00
253c9b2449 refactor(tables): FASE 5 - Embeber NavigationState en AdvancedTableState y VirtualAdvancedTableState
- Añadido nav: table_core.NavigationState en ambos estados
- Eliminados campos duplicados (scroll_row, scroll_x, active_col, double_click)
- Actualizado todas las referencias a usar nav.*
- Conservado scroll_offset_pixels en Virtual (específico smooth scroll)
2025-12-27 19:47:43 +01:00
08ffcdbac5 refactor(tables): FASE 4.5 - AdvancedTable usa drawRowsWithDataSource
- Añadir RowState enum a table_core.zig
- Añadir getRowState a TableDataSource.VTable (opcional)
- Añadir colores de estado a RowRenderColors
- Añadir draw_row_borders a DrawRowsConfig
- Añadir getRowState a MemoryDataSource
- Nueva función handleRowClicks() separando input de rendering
- AdvancedTable usa drawRowsWithDataSource (sin bucle for propio)
- Eliminar drawRow() y drawStateIndicator() locales (~160 líneas)

Objetivo cumplido: un solo bloque de código para renderizar filas
2025-12-27 18:52:31 +01:00
b8199aec38 refactor(tables): FASE 4 - Add unified drawRowsWithDataSource
Add unified row rendering function to table_core.zig that uses
TableDataSource interface for data access.

Changes:
- Add ColumnRenderDef, RowRenderColors, DrawRowsConfig types
- Add drawRowsWithDataSource() unified rendering function
- Update VirtualAdvancedTable.drawRows to use unified function
  with PagedDataSource

Note: AdvancedTable not yet integrated due to additional complexity
(state indicators, click handling interleaved with drawing).
See PLAN_REFACTOR_TABLES_CONTINUIDAD.md for details.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 18:02:45 +01:00
cf2f91f8bc refactor(tables): FASE 4 - Add DataSource adapters
Add MemoryDataSource for AdvancedTable (in-memory ArrayList) and
PagedDataSource for VirtualAdvancedTable (paged DB data).

Both implement TableDataSource interface from table_core.zig,
enabling unified rendering patterns while respecting memory ownership.

New files:
- advanced_table/datasource.zig - MemoryDataSource
- virtual_advanced_table/paged_datasource.zig - PagedDataSource

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 17:37:04 +01:00
473bbdb648 feat(table_core): Add TableDataSource interface (FASE 3)
- TableDataSource: vtable interface for data abstraction
- getCellValueInto: buffer-based pattern to avoid memory issues
- getRowCount, getRowId: basic data access methods
- isCellEditable, invalidate: optional methods
- makeTableDataSource: helper to create from concrete types
- isGhostRow: convenience method for new row detection

This interface enables unified rendering for both memory and
paginated tables while enforcing safe memory patterns.
2025-12-27 17:13:38 +01:00
37e3b61aca refactor(states): Embed CellEditState in AdvancedTableState and VirtualAdvancedTableState
FASE 2 del refactor de tablas:
- AdvancedTableState: Embed cell_edit, delegate editing methods
- VirtualAdvancedTableState: Embed cell_edit, replace editing_cell/edit_buffer
- Update advanced_table.zig to use isEditing() and cell_edit.*
- Update virtual_advanced_table.zig to use getEditingCell()
- Update cell_editor.zig to use cell_edit.*

Reduces code duplication, centralizes editing logic in table_core
2025-12-27 16:45:58 +01:00
6819919060 refactor(table_core): Add CellEditState + NavigationState for composition
- Delete obsolete 'table_core (conflicted).zig'
- Add memory ownership protocol documentation
- Add CellEditState: embeddable edit state with buffer, cursor, escape handling
- Add NavigationState: embeddable nav state with active_col, scroll, Tab methods
- Maintains backward compatibility with existing EditState
2025-12-27 16:11:24 +01:00
d16019d54f feat(table_core): RowEditBuffer + commit al abandonar fila (Excel-style)
- RowEditBuffer: acumula cambios de fila antes de commit
- checkRowChangeAndCommit(): detecta cambio fila + commit automático
- buildCommitInfo(), isGhostRow(), NEW_ROW_ID
- VirtualAdvancedTableState: row_edit_buffer field
- VirtualAdvancedTableResult: row_committed, row_changes[], etc.
- Comportamiento: Tab entre celdas acumula, cambiar fila hace commit
2025-12-27 14:58:01 +01:00
60c3f9d456 refactor(advanced_table): Use table_core.handleEditingKeyboard (DRY)
- Remove 160 lines of duplicated keyboard handling code
- Use shared table_core.handleEditingKeyboard() for edit buffer operations
- Export NavigateDirection from table_core for external use
- Keep AdvancedTable-specific navigation logic (cell movement, auto-edit)
2025-12-27 12:24:50 +01:00
91969cb728 fix(virtual_advanced_table): Prevent double Tab processing
- Check navigate_direction before setting tab_out in handleKeyboard
- Export NavigateDirection from virtual_advanced_table module
- Use cell_editor.NavigateDirection in VirtualAdvancedTableResult

This fixes the bug where Tab was processed twice: once by CellEditor
(for cell navigation) and again by handleKeyboard (for tab_out).
2025-12-27 12:13:51 +01:00
9b2cf2a3dd refactor(cell_editor): Use table_core.handleEditingKeyboard instead of duplicated code
- Import and use table_core for keyboard handling
- Re-export NavigateDirection from table_core
- Map table_core.EditKeyboardResult to CellEditorResult
- Remove ~100 lines of duplicated keyboard handling code
- Add 'handled' field to CellEditorResult
2025-12-27 12:10:59 +01:00
49cf12f7b9 refactor(table_core): Unify EditKeyboardResult with NavigateDirection and handled flag
- Add NavigateDirection enum (none, next_cell, prev_cell, next_row, prev_row)
- Replace navigate_next/navigate_prev bools with single navigate field
- Add 'handled' flag to prevent double processing of Tab
- Add Up/Down arrow handling for row navigation
- Use getKeyEvents() loop instead of keyPressed() for consistency
2025-12-27 12:09:47 +01:00
27b69cfcde refactor(table_core): Move Tab navigation logic to shared module (Norma #7 DRY)
ANTES: calculateNextCell/calculatePrevCell duplicados en:
  - AdvancedTableState
  - VirtualAdvancedTableState

AHORA: Lógica común en table_core.zig:
  - calculateNextCell() - calcula siguiente celda (Tab)
  - calculatePrevCell() - calcula celda anterior (Shift+Tab)
  - toggleSort() - alterna ordenación de columna
  - TabNavigateResult, CellPosition, SortDirection, SortToggleResult

Ambos widgets usan table_core, adaptando el resultado a su modelo:
  - AdvancedTable: selected_row/selected_col (índices)
  - VirtualAdvancedTable: selected_id + active_col (ID + columna)

Tests añadidos para calculateNextCell, calculatePrevCell, toggleSort
2025-12-27 01:49:56 +01:00
c2f0fbb19d refactor(tables): Add tabToNextCell/tabToPrevCell to both AdvancedTable and VirtualAdvancedTable
Norma #6: Abstract to library level
- Tab navigation with wrap now in library, not application
- AdvancedTableState.tabToNextCell/tabToPrevCell for in-memory data
- VirtualAdvancedTableState.tabToNextCell/tabToPrevCell for paginated data
- DRY: same logic available in both table widgets
2025-12-27 01:28:32 +01:00
702c33c13a feat(virtual_table): Tab navigation + cursor fixes + cell editing
- Tab/Shift+Tab with wrap navigation in editing mode
- tab_out/tab_shift result fields for application handling
- Cursor position, blinking, background color fixes
- markRowSaved() to clear dirty state after save
- last_edited_row only set when actual changes made
2025-12-27 01:18:54 +01:00
47fc5b28f7 refactor(tables): Add table_core.zig with shared rendering functions
- New module: table_core.zig with common table rendering logic
- drawCellActiveIndicator(): visual indicator for selected cell  
- detectDoubleClick(): timing-based double-click detection
- handleEditingKeyboard(): common keyboard handling for editing
- blendColor(), startsWithIgnoreCase(): utilities

VirtualAdvancedTable now uses table_core:
- Active cell indicator in drawRows (visible highlight on selected cell)
- Double-click detection in handleMouseClick
- Added state fields: last_click_time, last_click_row, last_click_col

AdvancedTable changes:
- Improved cell active indicator (alpha 0.35, double border)
- Added double-click fields to state
- Space starts editing with empty value
- Alphanumeric keys start editing in editable cells
2025-12-26 17:53:16 +01:00
65f6782d24 feat(virtual_advanced_table): Add keyboard/mouse editing triggers (F2, chars, column nav) 2025-12-26 14:54:24 +01:00
97ddf28c15 feat(virtual_advanced_table): Integrate CellEditor in draw loop with result handling 2025-12-26 14:51:03 +01:00
93836aef50 feat(virtual_advanced_table): Add CellEditor widget for inline editing 2025-12-26 14:49:04 +01:00
66816bcbf1 feat(virtual_advanced_table): Add CRUD Excel-style editing state
- Rename VirtualList → VirtualAdvancedTable
- Add CellId and CellGeometry types
- Add editing state fields (editing_cell, original_value, escape_count, etc.)
- Add editing methods: startEditing, commitEdit, cancelEdit, handleEscape
- Add getCellGeometry() for overlay positioning
- Add row_dirty flag for change tracking
2025-12-26 14:45:32 +01:00
7f8870d890 fix(advanced_table): Use std.mem.swap for Row sorting + doc warnings
- Replace manual temp variable swap with std.mem.swap (more explicit)
- Add documentation warning about pointer invalidation after sort/setRows
- Row contains StringHashMap with internal pointers - swap is safe but
  pointers obtained via getRow() are invalidated after mutations

Based on INFORME_AUDITORIA_PROFUNDA_20251225.md §1.2
2025-12-25 23:04:01 +01:00
1c284ed0f6 fix(virtual_list): Move footer display buffer to state struct
- Added footer_display_buf and footer_display_len to VirtualListState
- Fixes use-after-return bug: stack buffer passed to pushCommand() was
  invalidated when function returned, causing corrupted display in
  deferred rendering
2025-12-25 22:40:14 +01:00
ae55ea5488 CLAUDE.md: jj + NORMAS_ESENCIALES 2025-12-25 19:24:00 +01:00
R.Eugenio
b0b8346355 feat(virtual_list): FilterBar visual + click offset fix
- FilterBar chips con forma pill (border-radius completo)
- Esquinas redondeadas en TextInput del filtro
- Fix click offset: ahora cuenta filter_bar_h + header_h
- Corrección selección de fila por click

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 00:09:57 +01:00
R.Eugenio
7b2ba06035 fix(virtual_list): Borde completo + centrado texto
- Añadir borde alrededor de toda la lista (siempre visible)
- Mejorar centrado vertical del texto (y+4 → y+3)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 14:41:56 +01:00
R.Eugenio
b2bcdeae1a fix(virtual_list): Scroll arriba + footer compacto
- moveUp: Calcular screen position para scroll correcto
- footer_h: Reducir de 20 a 16 pixels para más filas visibles

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 14:31:12 +01:00
R.Eugenio
ae993a0f6f fix(virtual_list): Scroll en última fila y posición correcta
- moveDown: Calcular screen position antes de decidir scroll
- Scroll ahora ocurre cuando llega a última fila visible (no penúltima)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 14:18:47 +01:00
R.Eugenio
b9e7434ef7 fix(virtual_list): Scroll visual y click con offset correcto
- drawRows: Calcular window_offset para dibujar desde scroll_offset
- handleMouseClick: Convertir screen_row a data_idx con offset
- Antes siempre dibujaba desde índice 0 del buffer

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 14:11:12 +01:00
R.Eugenio
edba1cc7e5 fix(virtual_list): Soportar key repeat con navKeyPressed
Cambiar de keyPressed() a navKeyPressed() permite que mantener
pulsada la flecha arriba/abajo mueva la selección continuamente.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 13:12:54 +01:00
R.Eugenio
206a997628 fix(virtual_list): Usar Style.Color y Command.rect
- VirtualListConfig.Colors ahora usa Style.Color en vez de u32
- Reemplazar Command.fill() por Command.rect() (fill no existe)
- Corregir tipo bg_color en drawRows

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 13:00:20 +01:00
R.Eugenio
2abb8547a5 feat(virtual_list): Fase 3 - Widget completo con renderizado
Implementación del widget VirtualList (~530 LOC):

virtualListRect():
- Registra focusable, maneja mouse/keyboard
- Calcula filas visibles y buffer size
- Detecta si necesita refetch (needsRefetch)
- Llama a DataProvider.fetchWindow() cuando necesario
- Actualiza counts desde provider

Renderizado:
- drawHeader(): títulos columnas, indicadores sort (^/v), click para ordenar
- drawRows(): filas con alternancia, selección con/sin focus
- drawFooter(): contador "pos de total" con soporte para "..."
- drawScrollbar(): thumb proporcional al scroll

Interacción:
- handleKeyboard(): ↑↓, PgUp/Dn, Home/End
- handleMouseClick(): click en fila selecciona

Características:
- Colores configurables (row_selected, row_selected_unfocus, etc.)
- Focus ring (fancy o simple)
- Clipping para contenido
- Footer muestra "15 de 500+..." → "15 de 1,234"

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 12:46:50 +01:00
R.Eugenio
7d1919969f feat(virtual_list): Fase 2 - DataProvider interface + tipos + state
Nuevo módulo virtual_list para listas virtualizadas:

types.zig:
- RowData: datos genéricos de fila con ID persistente
- ColumnDef: definición de columnas (name, title, width)
- SortDirection: enum con toggle()
- CountInfo: conteo con estado (loading, partial, ready)
- VirtualListConfig: configuración con umbral configurable

data_provider.zig:
- DataProvider: interface vtable para fuentes de datos
- Métodos: fetchWindow, getTotalCount, setFilter, setSort
- MockProvider para tests
- Tests completos

state.zig:
- VirtualListState: estado de navegación y selección
- Selección por ID (no índice)
- Conversión global ↔ window index
- Navegación: moveUp/Down, pageUp/Down, goToStart/End
- Tests completos

virtual_list.zig:
- Re-exports de módulos
- Documentación de arquitectura
- VirtualListResult struct
- TODO: widget principal (Fase 3)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 12:27:23 +01:00
R.Eugenio
59d102315d fix(memory): Deep clone en Row + CellValue para evitar dangling pointers
- CellValue.clone(): duplica strings en lugar de copiar punteros
- CellValue.deinit(): libera strings clonados
- Row.owns_data: flag para indicar propiedad de memoria
- Row.clone(): ahora hace deep copy completo
- Row.deinit(): libera strings si owns_data=true

Soluciona crash al guardar cliente sin población/provincia/país,
donde loadWhoList() liberaba strings que Row clonada seguía referenciando.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 13:16:59 +01:00
3f442bf8b9 feat(autocomplete): Sistema overlay para dropdowns + mejoras UX
OVERLAY SYSTEM:
- Context: nuevo campo overlay_commands para capa superior
- Context: nueva función pushOverlayCommand()
- mainloop: renderiza overlay_commands DESPUÉS de commands
- autocomplete: dropdown usa overlay (se dibuja encima de otros widgets)

MEJORAS AUTOCOMPLETE:
- Dropdown se abre inmediatamente al escribir (sin delay de 1 frame)
- Dropdown se abre al borrar con backspace/delete
- Click en flecha del dropdown hace toggle abrir/cerrar
- Área clicable de flecha: 20px

ESTADO: En progreso - funcionalidad básica operativa, pendiente:
- Keyboard handlers completos
- Más testing de casos edge

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 19:07:44 +01:00
fdda6ba1a4 fix(autocomplete): Cursor igual que TextInput - altura completa + parpadeo
- Altura del cursor: inner.h (toda la altura del campo, no 8px fijos)
- Posición Y: inner.y (no centrado en el texto)
- Parpadeo: usa CURSOR_BLINK_PERIOD_MS y CURSOR_IDLE_TIMEOUT_MS
- Lógica idéntica a TextInput para consistencia visual
2025-12-20 17:26:31 +01:00
fc2dc83e6c fix(autocomplete): Sync last_filter en setText/clear + auto-cierre dropdown vacío
Cambios de Gemini para estabilidad IMGUI:
- setText(): Sincroniza last_filter para evitar falsos text_changed
- clear(): Resetea last_filter_len
- autocompleteRect(): Cierra dropdown si options.len == 0

Parte de la solución para corrupción de memoria en cascade AutoComplete.
2025-12-20 00:13:43 +01:00
f077c87dfc feat(v0.22.2): AutoComplete focus + Text Metrics + cursor 300ms
AutoComplete:
- Integración sistema focus (registerFocusable, requestFocus, hasFocus)
- Fix input: event.char → ctx.input.getTextInput()
- Fix dropdown al iniciar: is_first_frame guard

Text Metrics:
- Nuevo ctx.measureText() y ctx.measureTextToCursor()
- text_measure_fn callback para fuentes TTF
- char_width fallback para bitmap (8px)

Cursor:
- text_input.zig y autocomplete.zig usan métricas reales
- Blink rate: 500ms → 300ms (más responsive)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 20:08:11 +01:00
a377a00803 cleanup: Eliminar prints de debug de investigación fondo azul
Eliminados std.debug.print con números mágicos 99999 y debug de
focus/colores añadidos durante investigación del bug.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 12:51:54 +01:00
3d44631cc3 fix: Eliminar código olvidado en drawRoundedRect que rellenaba área
Bug crítico: Al dar focus a cualquier widget, TODO el fondo se pintaba
de azul semitransparente, no solo el borde de focus.

Causa: En drawRoundedRect() había código de una implementación anterior
que hacía fillRoundedRect() antes de dibujar el outline. Cuando focusRing
llamaba a drawRoundedRect con color azul, primero rellenaba todo el área.

Fix: Eliminadas 8 líneas de código obsoleto (comentarios de estrategia
abandonada + la llamada a fillRoundedRect).

También: Limpieza de código debug en advanced_table.zig.

Crédito: Bug encontrado por Gemini tras descripción del problema.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 12:48:30 +01:00
ab63d5a7f8 feat(AdvancedTable): Color selección según focus del panel
Cambios:
- Añadir selected_row_unfocus a TableColors
- drawRow ahora recibe has_focus para elegir color
- Con focus: usa selected_row (color accent)
- Sin focus: usa selected_row_unfocus (gris sutil)

BasicColors ahora acepta selected_row y selected_row_unfocus
opcionales para permitir override desde PanelColorScheme.

Esto permite que el usuario vea claramente:
- Qué panel tiene focus (fila con color accent)
- Qué fila está seleccionada en panel sin focus (gris)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 23:04:11 +01:00
48ab2b749b feat(advanced_table): BasicColors helper para colores configurables
- BasicColors struct: background, foreground, accent, header_bg opcionales
- TableColors.fromBasic(): deriva 26 colores desde 3-4 básicos
- BasicColors.toColor(): convierte cualquier tipo con r,g,b a Style.Color
- Detecta automáticamente tema claro/oscuro para derivar colores
- Presets dark()/light() y withAccent() para personalización

Permite que las aplicaciones pasen colores configurables desde sus
sistemas de config propios (como zsimifactu con resolveColor()).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 11:33:34 +01:00
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
af1bb76aab feat(advanced_table): Multi-select, search, sorting, keyboard fixes
Bugs corregidos:
- Bug 1: Navegación teclado - cambio de keyPressed() a navKeyPressed()
- Bug 2: Sorting real - implementado sortRows() con bubble sort estable

Funcionalidades añadidas de Table:
- Multi-row selection (bit array 1024 rows, Ctrl+click, Shift+click, Ctrl+A)
- Incremental search (type-to-search con timeout 1000ms)
- Cell validation tracking (256 celdas con mensajes de error)

Nuevas funciones en AdvancedTableState:
- isRowSelected, addRowToSelection, removeRowFromSelection
- toggleRowSelection, clearRowSelection, selectAllRows
- selectRowRange, getSelectedRowCount, getSelectedRows, selectSingleRow
- addSearchChar, getSearchTerm, clearSearch, startsWithIgnoreCase
- hasCellError, addCellError, clearCellError, clearAllCellErrors
- hasAnyCellErrors, getLastValidationMessage

Cambios en types.zig:
- CellValue.compare() para ordenación
- allow_multi_select en TableConfig

Tests: 379 passing

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 18:34:34 +01:00
6287231cee feat: AdvancedTable Fases 7-8 - Lookup & Callbacks
Fase 7 - Lookup & Auto-fill:
- performLookupAndAutoFill() en commitEdit
- Busca en DataStore.lookup() al editar columna lookup
- Auto-rellena columnas según auto_fill_columns mapping
- Indicador visual "?" en header para columnas lookup
- Campo lookup_success en AdvancedTableResult

Fase 8 - Callbacks + Debounce:
- invokeCallbacks() con sistema de debounce (150ms default)
- on_row_selected: al cambiar selección
- on_cell_changed: al confirmar edición
- on_active_row_changed: al cambiar de fila (para paneles detalle)
- Campos last_callback_time_ms, last_notified_row en state

Tests: 373/373 (+3 nuevos)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 17:26:53 +01:00
2dccddeab0 feat: Paridad Visual DVUI Fase 3 - Sombras y Gradientes
Nuevas capacidades de rendering:
- ShadowCommand: sombras multi-capa con blur simulado
  - Helpers: shadow(), shadowDrop(), shadowFloat()
  - Quadratic alpha falloff para bordes suaves
- GradientCommand: gradientes suaves pixel a pixel
  - Direcciones: vertical, horizontal, diagonal
  - Helpers: gradientV/H(), gradientButton(), gradientProgress()
  - Soporte esquinas redondeadas

Widgets actualizados:
- Panel/Modal: sombras en fancy mode
- Select/Menu: dropdown con sombra + rounded corners
- Tooltip/Toast: sombra sutil + rounded corners
- Button: gradiente 3D (lighten top, darken bottom)
- Progress: gradientes suaves vs 4 bandas

IMPORTANTE: Compila y pasa tests (370/370) pero NO probado visualmente

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 13:27:48 +01:00
83049a99be feat: AdvancedTable widget - Fases 1-6 IMPLEMENTADO (pendiente aprobacion)
Widget AdvancedTable portado de Go (simifactu-fyne) a Zig.
2,526 LOC en 4 archivos, 370 tests pasan.

Archivos:
- types.zig (369 LOC): CellValue, ColumnType, RowState, TableColors
- schema.zig (373 LOC): ColumnDef, TableSchema, DataStore interface
- state.zig (762 LOC): Selection, editing, dirty tracking, snapshots
- advanced_table.zig (1,022 LOC): Widget, rendering, keyboard

Fases implementadas:
1. Core (types, schema, state)
2. Navigation (arrows, Tab, PgUp/Dn, Home/End, Ctrl+Home/End)
3. Cell Editing (F2/Enter start, Escape cancel, text input)
4. Sorting (header click, visual indicators)
5. Auto-CRUD (CREATE/UPDATE/DELETE detection on row change)
6. Row Operations (Ctrl+N insert, Ctrl+Delete remove)

Fases diferidas (7-8): Lookup & Auto-fill, Callbacks avanzados

ESTADO: Compilado y tests pasan. NO probado en uso real.
REQUIERE: Aprobacion antes de tag de version.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 11:25:48 +01:00
e0cbbf6413 feat: Focus ring AA para todos los widgets focusables
Widgets actualizados:
- NumberEntry: esquinas redondeadas + focus ring
- Radio: esquinas redondeadas para círculos + focus ring en opción
- Slider: esquinas redondeadas en track/thumb + focus ring
- Tabs: esquinas redondeadas en tab seleccionado + focus ring
- Table: focus ring alrededor de toda la tabla
- TextArea: esquinas redondeadas + focus ring

Nuevos campos:
- TableColors.focus_ring para consistencia

Total: +135 LOC en 7 archivos

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 09:24:50 +01:00
ed0e3e8e5b feat: Focus ring con anti-aliasing
Command helpers:
- focusRing(x, y, w, h, radius) - focus indicator con AA
- focusRingColor() - versión con color custom

Características:
- Dibuja 2px fuera del widget (offset)
- Color semi-transparente (primary alpha 180)
- Radio +2 para mantener proporciones
- Thickness 2px para visibilidad
- Anti-aliasing habilitado

Widgets actualizados:
- TextInput: focus ring cuando has_focus
- Select: focus ring cuando has_focus (no cuando dropdown abierto)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 09:18:53 +01:00
74e83d2334 feat: Transiciones hover en Select widget
SelectState ahora incluye:
- hover: HoverTransition para transiciones suaves
- last_time_ms: tracking de tiempo para delta

El color de fondo del botón principal del Select ahora
transiciona suavemente entre normal y hover (lighten 5%).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 01:12:21 +01:00
25728c151c feat: Paridad Visual DVUI Fase 2 - transiciones hover/press
HoverTransition helper:
- animation.zig: HoverTransition struct para widgets
- Métodos update(), updateWithPress() para animar hacia target
- blend() y blendThree() para interpolar colores
- Speed configurable (default 0.008/ms = ~125ms transición)

Button con transiciones:
- ButtonState struct opcional para transiciones suaves
- buttonStateful(), buttonStatefulEx(), buttonStatefulRect()
- Mantiene retrocompatibilidad (button() sigue siendo instantáneo)
- Test buttonStateful transitions

Uso:
```zig
var btn_state = button.ButtonState{};
if (button.buttonStateful(&ctx, &btn_state, "Click me")) {
    // clicked
}
```

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 01:10:58 +01:00
364a7d963f feat: Paridad visual DVUI - RenderMode dual (simple/fancy)
Sistema de rendering dual para zcatgui:

Core:
- RenderMode enum (simple/fancy) en style.zig
- global_render_mode con helpers: isFancy(), setRenderMode()
- fillRoundedRect con edge-fade AA en framebuffer.zig (~350 LOC)
- Nuevos comandos: rounded_rect, rounded_rect_outline

Widgets actualizados:
- Button: corner_radius=4, usa roundedRect en fancy mode
- Panel: corner_radius=6, show_shadow=true, sombra offset 4px
- TextInput: corner_radius=3
- Select: corner_radius=3
- Modal: corner_radius=8, show_shadow=true, sombra offset 6px
  - Botones y input field del modal también redondeados

Técnica edge-fade (de DVUI):
- Anti-aliasing por gradiente alfa en bordes
- Sin supersampling, mínimo impacto en rendimiento
- Bordes suaves sin multisampling

+589 líneas, 9 archivos modificados

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 01:02:46 +01:00
8b90a1b285 feat: Integrar zcatttf para renderizado TTF
- build.zig.zon: Añadir zcatttf como dependencia local
- build.zig: Importar módulo zcatttf en todos los targets
- ttf.zig: Reescribir como wrapper de zcatttf (991→561 LOC)

Cambios en ttf.zig:
- Usa zcatttf.Font para parsing y rasterización
- Mantiene API pública compatible (TtfFont, drawText, etc.)
- Añade soporte UTF-8 completo en drawText
- Elimina código de rasterización propio (buggy)

Eliminado:
- cmap_debug.zig del build (herramienta de diagnóstico obsoleta)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 23:14:16 +01:00
0cdd44b8a0 fix: TTF ABGR format + herramienta diagnóstico cmap
Cambios:
- ttf.zig: Fix formato pixel ABGR (era RGBA invertido)
- cmap_debug.zig: Herramienta diagnóstico tabla cmap
- build.zig: Target cmap-debug para ejecutar diagnóstico
- docs/research/TTF_DEBUG_SESSION: Documentación sesión debug

Nota: El código base TTF funciona (cmap_debug lo confirma).
El bug de rendering sigue sin resolver en integración.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 22:00:54 +01:00
105e3c63d1 fix: UTF-8 support in TTF drawText
- drawText now decodes UTF-8 codepoints instead of iterating bytes
- Fixes rendering of accented characters (á, é, í, ó, ú, ñ, etc.)
- Uses std.unicode.utf8ByteSequenceLength + utf8Decode
- Invalid UTF-8 sequences are gracefully skipped

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:25:17 +01:00
222c4e1542 fix: DroidSans reemplaza AdwaitaSans (variable) + Y-flip TTF
- AdwaitaSans era fuente variable (fvar/gvar) incompatible con parser
- DroidSans.ttf: fuente estática 187KB (Apache 2.0)
- Y-flip en rasterización: TTF Y crece arriba, bitmap Y crece abajo
- Pendiente: UTF-8 multibyte en drawText

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:19:40 +01:00