Commit graph

122 commits

Author SHA1 Message Date
ded8946702 feat(widgets): Add focus_border_color to text_input and select
Z-Design V2: Allow panels to specify custom focus ring color.
- TextInputConfig.focus_border_color: overrides theme.primary
- SelectConfig.focus_border_color: same pattern
- Uses Command.focusRingColor() instead of focusRing()

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 20:09:08 +01:00
dd249d2b2d fix(buttons): Completar efecto bisel 3D con 4 lados
- Añadir líneas verticales (izquierda + derecha) al bisel
- Antes: solo 2 líneas horizontales (arriba + abajo)
- Ahora: 4 líneas formando marco 3D completo

Z-Design V2: Bisel con las 4 esquinas completas.
Normal: claro arriba/izquierda, oscuro abajo/derecha.
Pressed: invierte colores para efecto "hundido".

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 20:01:10 +01:00
8f577e02b0 fix(buttons): Centrar texto V+H usando métricas del contexto
- button.zig: Usar ctx.measureText() y ctx.char_width para centrado
- label.zig: Mismo fix para centrado de labels
- animation.zig: Actualizar test ColorTransition para duration 500ms

Z-Design V2: El centrado ahora funciona correctamente con TTF fonts.
Antes usaba 8px hardcodeado, ahora usa métricas dinámicas del contexto.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 19:58:45 +01:00
0e913cda55 style(chips): Reducir radio chips para consistencia con botones
Z-Design V2: Chips de filtro con corner_radius: 4 (igual que botones)
en lugar de 11 (pill-like).

Esto hace que chips y botones tengan el mismo lenguaje visual.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 18:25:47 +01:00
6eae44dcfd style(scrollbar): Aumentar ancho scrollbars (8/12→14px)
Z-Design V2: Scrollbars más anchos para mejor usabilidad.
- list.zig: 8→14px
- grid.zig: 8→14px
- advanced_table/drawing.zig: 12→14px
- virtual_advanced_table/drawing.zig: 12→14px
- virtual_scroll.zig: 12→14px (default config)
- table/render.zig: 12→14px

El bisel interno Laravel ya estaba implementado en drawBeveledRect.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 18:24:46 +01:00
9772d33b06 fix(AdvancedTable): Pintar fondo área contenido (Z-Design V2)
Añade rectángulo de fondo con row_normal color ANTES de dibujar
las filas. Esto asegura que:
- Tablas vacías muestren color de fondo correcto (no negro)
- Áreas debajo de las últimas filas no queden sin pintar

VirtualAdvancedTable ya tenía este comportamiento.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 18:20:23 +01:00
b5073dcbe3 feat(button): Micro-interacciones al pulsar botón
Acabado Espectacular mejora #5:
- Bisel invertido cuando pressed (oscuro arriba = "hundido")
- Texto desplazado +1px abajo/derecha cuando pressed
- Aplicado a buttonRect y buttonStatefulRect
- Botones se sienten "físicos" al pulsarlos

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 15:38:02 +01:00
c657583e06 style(ui): Padding +20% en tablas, botones, inputs
El Lujo del Espacio (Acabado Espectacular mejora #3):
- table_core/rendering.zig: padding celdas 4px → 5px
- button.zig: padding botones 8px → 10px
- text_input.zig: padding inputs 4px → 5px

UI más "respirada" y profesional estilo Laravel.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 15:31:16 +01:00
3af97f6174 feat: IdleCompanion widget (v0.25.0)
Mascota animada reutilizable que aparece tras inactividad:
- Se asoma por bordes de paneles aleatorios
- Clipping correcto (respeta límites del panel)
- Ojos que miran izq/der, salto de pánico
- Estados: hidden → peeking → watching → hiding
- Diseño gato: orejas puntiagudas, pupilas verticales, mejillas

Uso:
  const IdleCompanion = zcatgui.widgets.idle_companion;
  var state: IdleCompanion.State = .{};
  IdleCompanion.draw(ctx, &panels, &state, last_activity, color);

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 15:01:44 +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
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
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