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>
6.9 KiB
Propuesta: Widgets Browser Especializados
Fecha: 2025-12-17 Origen: Conversación zsimifactu sobre extracción de patrones reutilizables Estado: PROPUESTA - Pendiente de implementación
Resumen Ejecutivo
Se propone crear widgets especializados para navegación de datos tabulares que encapsulen patrones comunes identificados en zsimifactu. Estos widgets combinarían tabla + controles de navegación + filtros en componentes cohesivos.
Widgets Propuestos
1. TableBrowser
Widget compuesto que integra:
- Tabla con scroll y selección
- Barra de estado con posición (ej: "15/520")
- Botones de navegación (|< < > >|)
- Soporte para filtros (opcional)
┌─────────────────────────────────────────────┐
│ [Filtro: ___________] [Tipo: v] │ ← Zona filtros (opcional)
├─────────────────────────────────────────────┤
│ Codigo │ Nombre │ Ciudad │ ← Header tabla
├────────┼─────────────────┼─────────────────┤
│ C0001 │ Empresa ABC │ Valencia │
│ C0002 │ Empresa XYZ │ Madrid │
│ ... │ ... │ ... │
├─────────────────────────────────────────────┤
│ [|<] [<] 15/520 [>] [>|] │ ← Navegación integrada
└─────────────────────────────────────────────┘
Caso de uso: Panel de lista en aplicaciones CRUD (WhoListPanel, DocListPanel, etc.)
2. ConfigBrowser
Widget especializado para visualizar/editar configuración:
- Lista de variables agrupadas por categoría
- Editor inline según tipo (checkbox, input, color picker)
- Búsqueda/filtro de variables
- Indicador de cambios pendientes
┌─────────────────────────────────────────────┐
│ [Buscar: ___________] │
├─────────────────────────────────────────────┤
│ ▼ General │
│ auto_guardar_cada [15 ] minutos │
│ backup_automatico [✓] │
├─────────────────────────────────────────────┤
│ ▼ Apariencia │
│ color_azul_empresa [■] RGB(40,80,120) │
│ font_size [14 ] │
├─────────────────────────────────────────────┤
│ ▶ Comportamiento (click para expandir) │
└─────────────────────────────────────────────┘
Caso de uso: Panel de configuración de aplicación
Justificación Técnica
Patrón Repetido en zsimifactu
En WhoListPanel y futuros paneles de lista se repite:
- Tabla con datos
- Callback para obtener celdas
- Botones navegación (First/Prev/Next/Last)
- Indicador posición
- Manejo de selección → DataManager
Este código se duplicaría en cada panel de lista (DocListPanel, ProdListPanel, etc.).
Beneficios de Encapsular
| Aspecto | Sin widget | Con TableBrowser |
|---|---|---|
| Líneas por panel | ~200 | ~50 |
| Bugs de navegación | Duplicados | Corregidos una vez |
| Consistencia UX | Manual | Automática |
| Nuevos paneles | Copy-paste | Instanciar widget |
API Propuesta
TableBrowser
const TableBrowser = struct {
table_state: widgets.table.TableState,
nav_state: NavState,
filter_state: ?FilterState,
pub const Config = struct {
columns: []const Column,
show_navigation: bool = true,
show_filters: bool = false,
row_height: u16 = 18,
};
pub const Callbacks = struct {
getCellData: *const fn (row: usize, col: usize) []const u8,
getRowCount: *const fn () usize,
onSelectionChanged: ?*const fn (row: usize) void = null,
};
pub fn init(config: Config) TableBrowser;
pub fn draw(self: *Self, ctx: *Context, rect: Rect, callbacks: Callbacks) DrawResult;
pub fn handleEvent(self: *Self, event: Event) bool;
// Navegación programática
pub fn goFirst(self: *Self) void;
pub fn goPrev(self: *Self) void;
pub fn goNext(self: *Self) void;
pub fn goLast(self: *Self) void;
pub fn getPosition(self: *Self) struct { current: usize, total: usize };
};
ConfigBrowser
const ConfigBrowser = struct {
pub const Config = struct {
variables: []const ConfigVariable, // De zcatconfig
show_search: bool = true,
group_by_category: bool = true,
};
pub fn init(config: Config) ConfigBrowser;
pub fn draw(self: *Self, ctx: *Context, rect: Rect, config_ptr: anytype) DrawResult;
pub fn handleEvent(self: *Self, event: Event) bool;
// Estado
pub fn hasChanges(self: *Self) bool;
pub fn getChangedVariables(self: *Self) []const []const u8;
};
Integración con zcatconfig
El ConfigBrowser se integraría naturalmente con la nueva librería zcatconfig:
const zcatconfig = @import("zcatconfig");
const ConfigBrowser = zcatgui.widgets.ConfigBrowser;
// En el proyecto consumidor:
const variables = @import("config/variables.zig");
const Config = @import("config/structures.zig").Config;
var config = Config{};
var browser = ConfigBrowser.init(.{
.variables = &variables.config_variables,
});
// En draw:
const result = browser.draw(ctx, rect, &config);
if (result.value_changed) {
try zcatconfig.save(&variables.config_variables, Config, &config, allocator, "config.txt");
}
Priorización Sugerida
| Widget | Prioridad | Razón |
|---|---|---|
| TableBrowser | Alta | Necesario para DocListPanel, ProdListPanel |
| ConfigBrowser | Media | Panel config es nice-to-have, no bloqueante |
Dependencias
- TableBrowser: Ninguna externa, usa widgets existentes (table, button)
- ConfigBrowser: Requiere
zcatconfigcomo dependencia opcional
Siguiente Paso
- Revisar esta propuesta
- Decidir si proceder con implementación
- Crear issue/tarea en zcatgui
Documento generado desde conversación zsimifactu 2025-12-17