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
This commit is contained in:
parent
c2f0fbb19d
commit
27b69cfcde
3 changed files with 271 additions and 104 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
const schema_mod = @import("schema.zig");
|
const schema_mod = @import("schema.zig");
|
||||||
|
const table_core = @import("../table_core.zig");
|
||||||
|
|
||||||
pub const CellValue = types.CellValue;
|
pub const CellValue = types.CellValue;
|
||||||
pub const RowState = types.RowState;
|
pub const RowState = types.RowState;
|
||||||
|
|
@ -827,86 +828,48 @@ pub const AdvancedTableState = struct {
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Navegación Tab Excel-style (con wrap)
|
// Navegación Tab Excel-style (con wrap)
|
||||||
|
// Usa table_core para la lógica común (Norma #7 DRY)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
/// Resultado de navegación Tab
|
/// Re-exporta TabNavigateResult desde table_core para compatibilidad
|
||||||
pub const TabNavigateResult = enum {
|
pub const TabNavigateResult = table_core.TabNavigateResult;
|
||||||
/// Navegó a otra celda dentro del widget
|
|
||||||
navigated,
|
|
||||||
/// Salió del widget (Tab en última celda o Shift+Tab en primera)
|
|
||||||
tab_out,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Navega a siguiente celda (Tab)
|
/// Navega a siguiente celda (Tab)
|
||||||
/// Si está en última columna, va a primera columna de siguiente fila.
|
/// Si está en última columna, va a primera columna de siguiente fila.
|
||||||
/// Si está en última fila, hace wrap a primera fila o retorna tab_out.
|
/// Si está en última fila, hace wrap a primera fila o retorna tab_out.
|
||||||
pub fn tabToNextCell(self: *AdvancedTableState, num_cols: usize, wrap_to_start: bool) TabNavigateResult {
|
pub fn tabToNextCell(self: *AdvancedTableState, num_cols: usize, wrap_to_start: bool) TabNavigateResult {
|
||||||
if (num_cols == 0) return .tab_out;
|
|
||||||
|
|
||||||
const row_count = self.getRowCount();
|
const row_count = self.getRowCount();
|
||||||
if (row_count == 0) return .tab_out;
|
|
||||||
|
|
||||||
const current_col: usize = if (self.selected_col >= 0) @intCast(self.selected_col) else 0;
|
const current_col: usize = if (self.selected_col >= 0) @intCast(self.selected_col) else 0;
|
||||||
const current_row: usize = if (self.selected_row >= 0) @intCast(self.selected_row) else 0;
|
const current_row: usize = if (self.selected_row >= 0) @intCast(self.selected_row) else 0;
|
||||||
|
|
||||||
if (current_col + 1 < num_cols) {
|
// Usar función de table_core
|
||||||
// Siguiente columna en misma fila
|
const pos = table_core.calculateNextCell(current_row, current_col, num_cols, row_count, wrap_to_start);
|
||||||
self.selected_col = @intCast(current_col + 1);
|
|
||||||
return .navigated;
|
if (pos.result == .navigated) {
|
||||||
|
self.selected_row = @intCast(pos.row);
|
||||||
|
self.selected_col = @intCast(pos.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Última columna: ir a primera columna de siguiente fila
|
return pos.result;
|
||||||
self.selected_col = 0;
|
|
||||||
|
|
||||||
if (current_row + 1 < row_count) {
|
|
||||||
// Hay siguiente fila
|
|
||||||
self.selected_row = @intCast(current_row + 1);
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Última fila
|
|
||||||
if (wrap_to_start) {
|
|
||||||
self.selected_row = 0;
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
|
|
||||||
return .tab_out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Navega a celda anterior (Shift+Tab)
|
/// Navega a celda anterior (Shift+Tab)
|
||||||
/// Si está en primera columna, va a última columna de fila anterior.
|
/// Si está en primera columna, va a última columna de fila anterior.
|
||||||
/// Si está en primera fila, hace wrap a última fila o retorna tab_out.
|
/// Si está en primera fila, hace wrap a última fila o retorna tab_out.
|
||||||
pub fn tabToPrevCell(self: *AdvancedTableState, num_cols: usize, wrap_to_end: bool) TabNavigateResult {
|
pub fn tabToPrevCell(self: *AdvancedTableState, num_cols: usize, wrap_to_end: bool) TabNavigateResult {
|
||||||
if (num_cols == 0) return .tab_out;
|
|
||||||
|
|
||||||
const row_count = self.getRowCount();
|
const row_count = self.getRowCount();
|
||||||
if (row_count == 0) return .tab_out;
|
|
||||||
|
|
||||||
const current_col: usize = if (self.selected_col >= 0) @intCast(self.selected_col) else 0;
|
const current_col: usize = if (self.selected_col >= 0) @intCast(self.selected_col) else 0;
|
||||||
const current_row: usize = if (self.selected_row >= 0) @intCast(self.selected_row) else 0;
|
const current_row: usize = if (self.selected_row >= 0) @intCast(self.selected_row) else 0;
|
||||||
|
|
||||||
if (current_col > 0) {
|
// Usar función de table_core
|
||||||
// Columna anterior en misma fila
|
const pos = table_core.calculatePrevCell(current_row, current_col, num_cols, row_count, wrap_to_end);
|
||||||
self.selected_col = @intCast(current_col - 1);
|
|
||||||
return .navigated;
|
if (pos.result == .navigated) {
|
||||||
|
self.selected_row = @intCast(pos.row);
|
||||||
|
self.selected_col = @intCast(pos.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primera columna: ir a última columna de fila anterior
|
return pos.result;
|
||||||
self.selected_col = @intCast(num_cols - 1);
|
|
||||||
|
|
||||||
if (current_row > 0) {
|
|
||||||
// Hay fila anterior
|
|
||||||
self.selected_row = @intCast(current_row - 1);
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primera fila
|
|
||||||
if (wrap_to_end) {
|
|
||||||
self.selected_row = @intCast(row_count - 1);
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
|
|
||||||
return .tab_out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
|
||||||
|
|
@ -382,6 +382,155 @@ pub fn startsWithIgnoreCase(haystack: []const u8, needle: []const u8) bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Navegación Tab Excel-style (compartida por AdvancedTable y VirtualAdvancedTable)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/// Resultado de navegación Tab
|
||||||
|
pub const TabNavigateResult = enum {
|
||||||
|
/// Navegó a otra celda dentro del widget
|
||||||
|
navigated,
|
||||||
|
/// Salió del widget (Tab en última celda o Shift+Tab en primera)
|
||||||
|
tab_out,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Resultado del cálculo de nueva posición de celda
|
||||||
|
pub const CellPosition = struct {
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
result: TabNavigateResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Calcula la siguiente celda después de Tab
|
||||||
|
/// Parámetros genéricos para que funcione con ambos tipos de tabla.
|
||||||
|
pub fn calculateNextCell(
|
||||||
|
current_row: usize,
|
||||||
|
current_col: usize,
|
||||||
|
num_cols: usize,
|
||||||
|
num_rows: usize,
|
||||||
|
wrap_to_start: bool,
|
||||||
|
) CellPosition {
|
||||||
|
if (num_cols == 0 or num_rows == 0) {
|
||||||
|
return .{ .row = current_row, .col = current_col, .result = .tab_out };
|
||||||
|
}
|
||||||
|
|
||||||
|
var new_row = current_row;
|
||||||
|
var new_col = current_col;
|
||||||
|
|
||||||
|
if (current_col + 1 < num_cols) {
|
||||||
|
// Siguiente columna en misma fila
|
||||||
|
new_col = current_col + 1;
|
||||||
|
return .{ .row = new_row, .col = new_col, .result = .navigated };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Última columna: ir a primera columna de siguiente fila
|
||||||
|
new_col = 0;
|
||||||
|
|
||||||
|
if (current_row + 1 < num_rows) {
|
||||||
|
// Hay siguiente fila
|
||||||
|
new_row = current_row + 1;
|
||||||
|
return .{ .row = new_row, .col = new_col, .result = .navigated };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Última fila
|
||||||
|
if (wrap_to_start) {
|
||||||
|
new_row = 0;
|
||||||
|
return .{ .row = new_row, .col = new_col, .result = .navigated };
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .row = current_row, .col = current_col, .result = .tab_out };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calcula la celda anterior después de Shift+Tab
|
||||||
|
pub fn calculatePrevCell(
|
||||||
|
current_row: usize,
|
||||||
|
current_col: usize,
|
||||||
|
num_cols: usize,
|
||||||
|
num_rows: usize,
|
||||||
|
wrap_to_end: bool,
|
||||||
|
) CellPosition {
|
||||||
|
if (num_cols == 0 or num_rows == 0) {
|
||||||
|
return .{ .row = current_row, .col = current_col, .result = .tab_out };
|
||||||
|
}
|
||||||
|
|
||||||
|
var new_row = current_row;
|
||||||
|
var new_col = current_col;
|
||||||
|
|
||||||
|
if (current_col > 0) {
|
||||||
|
// Columna anterior en misma fila
|
||||||
|
new_col = current_col - 1;
|
||||||
|
return .{ .row = new_row, .col = new_col, .result = .navigated };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primera columna: ir a última columna de fila anterior
|
||||||
|
new_col = num_cols - 1;
|
||||||
|
|
||||||
|
if (current_row > 0) {
|
||||||
|
// Hay fila anterior
|
||||||
|
new_row = current_row - 1;
|
||||||
|
return .{ .row = new_row, .col = new_col, .result = .navigated };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primera fila
|
||||||
|
if (wrap_to_end) {
|
||||||
|
new_row = num_rows - 1;
|
||||||
|
return .{ .row = new_row, .col = new_col, .result = .navigated };
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .row = current_row, .col = current_col, .result = .tab_out };
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Ordenación (compartida)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/// Dirección de ordenación
|
||||||
|
pub const SortDirection = enum {
|
||||||
|
none,
|
||||||
|
ascending,
|
||||||
|
descending,
|
||||||
|
|
||||||
|
/// Alterna la dirección: none → asc → desc → none
|
||||||
|
pub fn toggle(self: SortDirection) SortDirection {
|
||||||
|
return switch (self) {
|
||||||
|
.none => .ascending,
|
||||||
|
.ascending => .descending,
|
||||||
|
.descending => .none,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Resultado de toggle de ordenación en columna
|
||||||
|
pub const SortToggleResult = struct {
|
||||||
|
/// Nueva columna de ordenación (null si se desactivó)
|
||||||
|
column: ?usize,
|
||||||
|
/// Nueva dirección
|
||||||
|
direction: SortDirection,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Calcula el nuevo estado de ordenación al hacer click en una columna
|
||||||
|
pub fn toggleSort(
|
||||||
|
current_column: ?usize,
|
||||||
|
current_direction: SortDirection,
|
||||||
|
clicked_column: usize,
|
||||||
|
) SortToggleResult {
|
||||||
|
if (current_column) |col| {
|
||||||
|
if (col == clicked_column) {
|
||||||
|
// Misma columna: ciclar dirección
|
||||||
|
const new_dir = current_direction.toggle();
|
||||||
|
return .{
|
||||||
|
.column = if (new_dir == .none) null else clicked_column,
|
||||||
|
.direction = new_dir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Columna diferente o sin ordenación: empezar ascendente
|
||||||
|
return .{
|
||||||
|
.column = clicked_column,
|
||||||
|
.direction = .ascending,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Tests
|
// Tests
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -420,3 +569,74 @@ test "detectDoubleClick" {
|
||||||
const third = detectDoubleClick(&state, 1400, 0, 0);
|
const third = detectDoubleClick(&state, 1400, 0, 0);
|
||||||
try std.testing.expect(!third);
|
try std.testing.expect(!third);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "calculateNextCell - basic navigation" {
|
||||||
|
// Tabla 3x4 (3 columnas, 4 filas)
|
||||||
|
// Celda (0,0) -> (0,1)
|
||||||
|
const r1 = calculateNextCell(0, 0, 3, 4, false);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), r1.row);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), r1.col);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.navigated, r1.result);
|
||||||
|
|
||||||
|
// Última columna -> primera columna de siguiente fila
|
||||||
|
const r2 = calculateNextCell(0, 2, 3, 4, false);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), r2.row);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), r2.col);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.navigated, r2.result);
|
||||||
|
|
||||||
|
// Última celda sin wrap -> tab_out
|
||||||
|
const r3 = calculateNextCell(3, 2, 3, 4, false);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.tab_out, r3.result);
|
||||||
|
|
||||||
|
// Última celda con wrap -> primera celda
|
||||||
|
const r4 = calculateNextCell(3, 2, 3, 4, true);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), r4.row);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), r4.col);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.navigated, r4.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "calculatePrevCell - basic navigation" {
|
||||||
|
// Celda (0,2) -> (0,1)
|
||||||
|
const r1 = calculatePrevCell(0, 2, 3, 4, false);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), r1.row);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), r1.col);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.navigated, r1.result);
|
||||||
|
|
||||||
|
// Primera columna -> última columna de fila anterior
|
||||||
|
const r2 = calculatePrevCell(1, 0, 3, 4, false);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), r2.row);
|
||||||
|
try std.testing.expectEqual(@as(usize, 2), r2.col);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.navigated, r2.result);
|
||||||
|
|
||||||
|
// Primera celda sin wrap -> tab_out
|
||||||
|
const r3 = calculatePrevCell(0, 0, 3, 4, false);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.tab_out, r3.result);
|
||||||
|
|
||||||
|
// Primera celda con wrap -> última celda
|
||||||
|
const r4 = calculatePrevCell(0, 0, 3, 4, true);
|
||||||
|
try std.testing.expectEqual(@as(usize, 3), r4.row);
|
||||||
|
try std.testing.expectEqual(@as(usize, 2), r4.col);
|
||||||
|
try std.testing.expectEqual(TabNavigateResult.navigated, r4.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toggleSort" {
|
||||||
|
// Sin ordenación -> ascendente en columna 2
|
||||||
|
const r1 = toggleSort(null, .none, 2);
|
||||||
|
try std.testing.expectEqual(@as(?usize, 2), r1.column);
|
||||||
|
try std.testing.expectEqual(SortDirection.ascending, r1.direction);
|
||||||
|
|
||||||
|
// Ascendente en columna 2 -> descendente
|
||||||
|
const r2 = toggleSort(2, .ascending, 2);
|
||||||
|
try std.testing.expectEqual(@as(?usize, 2), r2.column);
|
||||||
|
try std.testing.expectEqual(SortDirection.descending, r2.direction);
|
||||||
|
|
||||||
|
// Descendente -> none (columna null)
|
||||||
|
const r3 = toggleSort(2, .descending, 2);
|
||||||
|
try std.testing.expectEqual(@as(?usize, null), r3.column);
|
||||||
|
try std.testing.expectEqual(SortDirection.none, r3.direction);
|
||||||
|
|
||||||
|
// Click en columna diferente -> ascendente en nueva columna
|
||||||
|
const r4 = toggleSort(2, .ascending, 5);
|
||||||
|
try std.testing.expectEqual(@as(?usize, 5), r4.column);
|
||||||
|
try std.testing.expectEqual(SortDirection.ascending, r4.direction);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
|
const table_core = @import("../table_core.zig");
|
||||||
const RowData = types.RowData;
|
const RowData = types.RowData;
|
||||||
const CountInfo = types.CountInfo;
|
const CountInfo = types.CountInfo;
|
||||||
const SortDirection = types.SortDirection;
|
const SortDirection = types.SortDirection;
|
||||||
|
|
@ -494,78 +495,61 @@ pub const VirtualAdvancedTableState = struct {
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Navegación Tab Excel-style (con wrap)
|
// Navegación Tab Excel-style (con wrap)
|
||||||
|
// Usa table_core para la lógica común (Norma #7 DRY)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
/// Resultado de navegación Tab
|
/// Re-exporta TabNavigateResult desde table_core para compatibilidad
|
||||||
pub const TabNavigateResult = enum {
|
pub const TabNavigateResult = table_core.TabNavigateResult;
|
||||||
/// Navegó a otra celda dentro del widget
|
|
||||||
navigated,
|
|
||||||
/// Salió del widget (Tab en última celda o Shift+Tab en primera)
|
|
||||||
tab_out,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Navega a siguiente celda (Tab)
|
/// Navega a siguiente celda (Tab)
|
||||||
/// Si está en última columna, va a primera columna de siguiente fila.
|
/// Si está en última columna, va a primera columna de siguiente fila.
|
||||||
/// Si está en última fila, hace wrap a primera fila o retorna tab_out.
|
/// Si está en última fila, hace wrap a primera fila o retorna tab_out.
|
||||||
pub fn tabToNextCell(self: *Self, num_cols: usize, visible_rows: usize, wrap_to_start: bool) TabNavigateResult {
|
pub fn tabToNextCell(self: *Self, num_cols: usize, visible_rows: usize, wrap_to_start: bool) TabNavigateResult {
|
||||||
if (num_cols == 0) return .tab_out;
|
// Obtener fila actual
|
||||||
|
const current_row = self.getSelectedRow() orelse 0;
|
||||||
|
const total_rows = self.current_window.len + self.window_start;
|
||||||
|
|
||||||
if (self.active_col + 1 < num_cols) {
|
// Usar función de table_core
|
||||||
// Siguiente columna en misma fila
|
const pos = table_core.calculateNextCell(current_row, self.active_col, num_cols, total_rows, wrap_to_start);
|
||||||
self.active_col += 1;
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Última columna: ir a primera columna de siguiente fila
|
if (pos.result == .navigated) {
|
||||||
self.active_col = 0;
|
self.active_col = pos.col;
|
||||||
|
// Navegar a la nueva fila si cambió
|
||||||
if (self.findSelectedInWindow()) |window_idx| {
|
if (pos.row != current_row) {
|
||||||
if (window_idx + 1 < self.current_window.len) {
|
if (pos.row == 0) {
|
||||||
// Hay siguiente fila
|
|
||||||
self.moveDown(visible_rows);
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Última fila
|
|
||||||
if (wrap_to_start) {
|
|
||||||
self.goToStart();
|
self.goToStart();
|
||||||
return .navigated;
|
} else {
|
||||||
|
self.moveDown(visible_rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return .tab_out;
|
return pos.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Navega a celda anterior (Shift+Tab)
|
/// Navega a celda anterior (Shift+Tab)
|
||||||
/// Si está en primera columna, va a última columna de fila anterior.
|
/// Si está en primera columna, va a última columna de fila anterior.
|
||||||
/// Si está en primera fila, hace wrap a última fila o retorna tab_out.
|
/// Si está en primera fila, hace wrap a última fila o retorna tab_out.
|
||||||
pub fn tabToPrevCell(self: *Self, num_cols: usize, visible_rows: usize, total_rows: usize, wrap_to_end: bool) TabNavigateResult {
|
pub fn tabToPrevCell(self: *Self, num_cols: usize, visible_rows: usize, total_rows: usize, wrap_to_end: bool) TabNavigateResult {
|
||||||
if (num_cols == 0) return .tab_out;
|
// Obtener fila actual
|
||||||
|
const current_row = self.getSelectedRow() orelse 0;
|
||||||
|
|
||||||
if (self.active_col > 0) {
|
// Usar función de table_core
|
||||||
// Columna anterior en misma fila
|
const pos = table_core.calculatePrevCell(current_row, self.active_col, num_cols, total_rows, wrap_to_end);
|
||||||
self.active_col -= 1;
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primera columna: ir a última columna de fila anterior
|
if (pos.result == .navigated) {
|
||||||
self.active_col = num_cols - 1;
|
self.active_col = pos.col;
|
||||||
|
// Navegar a la nueva fila si cambió
|
||||||
if (self.findSelectedInWindow()) |window_idx| {
|
if (pos.row != current_row) {
|
||||||
if (window_idx > 0) {
|
if (pos.row == total_rows - 1) {
|
||||||
// Hay fila anterior
|
|
||||||
self.moveUp();
|
|
||||||
return .navigated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primera fila
|
|
||||||
if (wrap_to_end) {
|
|
||||||
self.goToEnd(visible_rows, total_rows);
|
self.goToEnd(visible_rows, total_rows);
|
||||||
return .navigated;
|
} else {
|
||||||
|
self.moveUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return .tab_out;
|
return pos.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtiene la fila global seleccionada
|
/// Obtiene la fila global seleccionada
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue