feat(virtual_advanced_table): Add keyboard/mouse editing triggers (F2, chars, column nav)
This commit is contained in:
parent
97ddf28c15
commit
65f6782d24
2 changed files with 122 additions and 9 deletions
|
|
@ -23,6 +23,10 @@ pub const VirtualAdvancedTableState = struct {
|
|||
/// Índice de la fila con hover
|
||||
hover_index: ?usize = null,
|
||||
|
||||
/// Columna activa (para edición)
|
||||
/// Cuando el usuario navega con flechas o hace click, se actualiza
|
||||
active_col: usize = 0,
|
||||
|
||||
// =========================================================================
|
||||
// Scroll y ventana
|
||||
// =========================================================================
|
||||
|
|
@ -434,6 +438,51 @@ pub const VirtualAdvancedTableState = struct {
|
|||
self.scroll_offset_x = max_scroll;
|
||||
}
|
||||
|
||||
/// Mueve a columna anterior
|
||||
pub fn moveToPrevCol(self: *Self) void {
|
||||
if (self.active_col > 0) {
|
||||
self.active_col -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Mueve a columna siguiente
|
||||
pub fn moveToNextCol(self: *Self, max_cols: usize) void {
|
||||
if (self.active_col + 1 < max_cols) {
|
||||
self.active_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Va a primera columna
|
||||
pub fn goToFirstCol(self: *Self) void {
|
||||
self.active_col = 0;
|
||||
}
|
||||
|
||||
/// Va a última columna
|
||||
pub fn goToLastCol(self: *Self, max_cols: usize) void {
|
||||
if (max_cols > 0) {
|
||||
self.active_col = max_cols - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtiene la fila global seleccionada
|
||||
pub fn getSelectedRow(self: *const Self) ?usize {
|
||||
if (self.selected_id == null) return null;
|
||||
|
||||
// Buscar en la ventana actual
|
||||
if (self.findSelectedInWindow()) |window_idx| {
|
||||
return self.windowToGlobalIndex(window_idx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Obtiene la celda activa (fila seleccionada + columna activa)
|
||||
pub fn getActiveCell(self: *const Self) ?CellId {
|
||||
if (self.getSelectedRow()) |row| {
|
||||
return .{ .row = row, .col = self.active_col };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Métodos de edición CRUD Excel-style
|
||||
// =========================================================================
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ pub fn virtualAdvancedTableRect(
|
|||
|
||||
// Handle keyboard
|
||||
if (has_focus) {
|
||||
handleKeyboard(ctx, list_state, provider, visible_rows, total_rows, max_scroll_x, &result);
|
||||
handleKeyboard(ctx, list_state, provider, visible_rows, total_rows, max_scroll_x, config.columns.len, &result);
|
||||
}
|
||||
|
||||
// Handle mouse clicks on rows
|
||||
|
|
@ -906,10 +906,13 @@ fn handleKeyboard(
|
|||
visible_rows: usize,
|
||||
total_rows: usize,
|
||||
max_scroll_x: i32,
|
||||
num_columns: usize,
|
||||
result: *VirtualAdvancedTableResult,
|
||||
) void {
|
||||
_ = provider;
|
||||
_ = result;
|
||||
|
||||
// Si hay edición activa, el CellEditor maneja las teclas
|
||||
if (list_state.isEditing()) return;
|
||||
|
||||
const h_scroll_step: i32 = 40; // Pixels per arrow key press
|
||||
|
||||
|
|
@ -918,21 +921,70 @@ fn handleKeyboard(
|
|||
switch (key) {
|
||||
.up => list_state.moveUp(),
|
||||
.down => list_state.moveDown(visible_rows),
|
||||
.left => list_state.scrollLeft(h_scroll_step),
|
||||
.right => list_state.scrollRight(h_scroll_step, max_scroll_x),
|
||||
.left => {
|
||||
// Con Ctrl: scroll horizontal
|
||||
// Sin Ctrl: cambiar columna activa
|
||||
if (ctx.input.modifiers.ctrl) {
|
||||
list_state.scrollLeft(h_scroll_step);
|
||||
} else {
|
||||
list_state.moveToPrevCol();
|
||||
}
|
||||
},
|
||||
.right => {
|
||||
if (ctx.input.modifiers.ctrl) {
|
||||
list_state.scrollRight(h_scroll_step, max_scroll_x);
|
||||
} else {
|
||||
list_state.moveToNextCol(num_columns);
|
||||
}
|
||||
},
|
||||
.page_up => list_state.pageUp(visible_rows),
|
||||
.page_down => list_state.pageDown(visible_rows, total_rows),
|
||||
.home => {
|
||||
list_state.goToStart();
|
||||
list_state.goToStartX();
|
||||
if (ctx.input.modifiers.ctrl) {
|
||||
list_state.goToStart();
|
||||
list_state.goToFirstCol();
|
||||
} else {
|
||||
list_state.goToFirstCol();
|
||||
}
|
||||
},
|
||||
.end => {
|
||||
list_state.goToEnd(visible_rows, total_rows);
|
||||
list_state.goToEndX(max_scroll_x);
|
||||
if (ctx.input.modifiers.ctrl) {
|
||||
list_state.goToEnd(visible_rows, total_rows);
|
||||
list_state.goToLastCol(num_columns);
|
||||
} else {
|
||||
list_state.goToLastCol(num_columns);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// F2 o Space: iniciar edición de celda activa
|
||||
for (ctx.input.getKeyEvents()) |event| {
|
||||
if (!event.pressed) continue;
|
||||
|
||||
switch (event.key) {
|
||||
.f2, .space => {
|
||||
// Iniciar edición de celda activa
|
||||
if (list_state.getActiveCell()) |cell| {
|
||||
// El panel debe proveer el valor actual via callback
|
||||
// Por ahora iniciamos con texto vacío - el panel debería llamar startEditing
|
||||
result.cell_committed = false; // Flag especial: indica que se solicitó edición
|
||||
result.edited_cell = cell;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Teclas alfanuméricas: iniciar edición con ese caracter
|
||||
const char_input = ctx.input.getTextInput();
|
||||
if (char_input.len > 0 and !list_state.isEditing()) {
|
||||
if (list_state.getActiveCell()) |cell| {
|
||||
// Iniciar edición con el primer caracter
|
||||
list_state.startEditing(cell, "", char_input[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -966,8 +1018,20 @@ fn handleMouseClick(
|
|||
if (data_idx < list_state.current_window.len) {
|
||||
list_state.selectById(list_state.current_window[data_idx].id);
|
||||
|
||||
// Check for double click
|
||||
// Detect which column was clicked
|
||||
const relative_x = mouse.x - bounds.x + list_state.scroll_offset_x;
|
||||
var col_start: i32 = 0;
|
||||
for (config.columns, 0..) |col, col_idx| {
|
||||
const col_end = col_start + @as(i32, @intCast(col.width));
|
||||
if (relative_x >= col_start and relative_x < col_end) {
|
||||
list_state.active_col = col_idx;
|
||||
break;
|
||||
}
|
||||
col_start = col_end;
|
||||
}
|
||||
|
||||
// TODO: implement double click detection with timing
|
||||
// For now, double click is not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue