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
This commit is contained in:
reugenio 2025-12-27 21:34:24 +01:00
parent 8e9dd3a475
commit 91570368cc

View file

@ -391,7 +391,7 @@ pub fn virtualAdvancedTableRect(
// Handle keyboard // Handle keyboard
if (has_focus) { if (has_focus) {
handleKeyboard(ctx, list_state, provider, visible_rows, total_rows, max_scroll_x, config.columns.len, &result); handleKeyboard(ctx, list_state, provider, visible_rows, total_rows, max_scroll_x, config.columns, bounds.w, &result);
} }
// Handle mouse clicks on rows // Handle mouse clicks on rows
@ -979,6 +979,46 @@ fn drawScrollbarH(
}); });
} }
// =============================================================================
// Auto-scroll horizontal helper
// =============================================================================
/// Asegura que la columna activa sea visible ajustando scroll_x si es necesario
fn ensureColumnVisible(
list_state: *VirtualAdvancedTableState,
columns: []const types.ColumnDef,
visible_width: u32,
max_scroll_x: i32,
) void {
const active_col = list_state.nav.active_col;
if (active_col >= columns.len) return;
// Calcular posición X de la columna activa
var col_start: i32 = 0;
for (columns, 0..) |col, i| {
if (i == active_col) break;
col_start += @as(i32, @intCast(col.width));
}
const col_end = col_start + @as(i32, @intCast(columns[active_col].width));
// Posición visible (considerando scroll actual)
const visible_start = list_state.nav.scroll_x;
const visible_end = visible_start + @as(i32, @intCast(visible_width));
// Ajustar scroll si la columna está fuera de vista
if (col_start < visible_start) {
// Columna está a la izquierda: scroll para mostrar inicio de columna
list_state.nav.scroll_x = col_start;
} else if (col_end > visible_end) {
// Columna está a la derecha: scroll para mostrar final de columna
list_state.nav.scroll_x = col_end - @as(i32, @intCast(visible_width));
}
// Clamp scroll_x a límites válidos
if (list_state.nav.scroll_x < 0) list_state.nav.scroll_x = 0;
if (list_state.nav.scroll_x > max_scroll_x) list_state.nav.scroll_x = max_scroll_x;
}
// ============================================================================= // =============================================================================
// Handle: Keyboard (Brain-in-Core pattern) // Handle: Keyboard (Brain-in-Core pattern)
// ============================================================================= // =============================================================================
@ -993,12 +1033,14 @@ fn handleKeyboard(
visible_rows: usize, visible_rows: usize,
total_rows: usize, total_rows: usize,
max_scroll_x: i32, max_scroll_x: i32,
num_columns: usize, columns: []const types.ColumnDef,
visible_width: u32,
result: *VirtualAdvancedTableResult, result: *VirtualAdvancedTableResult,
) void { ) void {
_ = provider; _ = provider;
const h_scroll_step: i32 = 40; // Pixels per arrow key press const h_scroll_step: i32 = 40; // Pixels per arrow key press
const num_columns = columns.len;
// ========================================================================= // =========================================================================
// BRAIN-IN-CORE: Delegar toda la lógica de decisión al Core // BRAIN-IN-CORE: Delegar toda la lógica de decisión al Core
@ -1007,6 +1049,9 @@ fn handleKeyboard(
if (!events.handled) return; if (!events.handled) return;
// Guardar columna activa antes del cambio para detectar movimiento
const prev_col = list_state.nav.active_col;
// ========================================================================= // =========================================================================
// Aplicar acciones de navegación // Aplicar acciones de navegación
// ========================================================================= // =========================================================================
@ -1023,6 +1068,13 @@ fn handleKeyboard(
if (events.scroll_left) list_state.scrollLeft(h_scroll_step); if (events.scroll_left) list_state.scrollLeft(h_scroll_step);
if (events.scroll_right) list_state.scrollRight(h_scroll_step, max_scroll_x); if (events.scroll_right) list_state.scrollRight(h_scroll_step, max_scroll_x);
// =========================================================================
// Auto-scroll horizontal: asegurar que la columna activa sea visible
// =========================================================================
if (list_state.nav.active_col != prev_col) {
ensureColumnVisible(list_state, columns, visible_width, max_scroll_x);
}
// ========================================================================= // =========================================================================
// Propagar acciones CRUD al result (el panel las manejará) // Propagar acciones CRUD al result (el panel las manejará)
// ========================================================================= // =========================================================================