From 49cf12f7b97e015b72e50ddbcae86e299b8c87fb Mon Sep 17 00:00:00 2001 From: reugenio Date: Sat, 27 Dec 2025 12:09:39 +0100 Subject: [PATCH] refactor(table_core): Unify EditKeyboardResult with NavigateDirection and handled flag - Add NavigateDirection enum (none, next_cell, prev_cell, next_row, prev_row) - Replace navigate_next/navigate_prev bools with single navigate field - Add 'handled' flag to prevent double processing of Tab - Add Up/Down arrow handling for row navigation - Use getKeyEvents() loop instead of keyPressed() for consistency --- src/widgets/table_core.zig | 226 +++++++++++++++++++++---------------- 1 file changed, 126 insertions(+), 100 deletions(-) diff --git a/src/widgets/table_core.zig b/src/widgets/table_core.zig index 32bb5a3..6aa1f5b 100644 --- a/src/widgets/table_core.zig +++ b/src/widgets/table_core.zig @@ -210,24 +210,34 @@ pub fn detectDoubleClick( // Manejo de teclado para edición // ============================================================================= +/// Dirección de navegación después de edición +pub const NavigateDirection = enum { + none, + next_cell, // Tab + prev_cell, // Shift+Tab + next_row, // Enter o ↓ + prev_row, // ↑ +}; + /// Resultado de procesar teclado en modo edición pub const EditKeyboardResult = struct { - /// Se confirmó la edición (Enter) + /// Se confirmó la edición (Enter, Tab, flechas) committed: bool = false, - /// Se canceló la edición (Escape) + /// Se canceló la edición (Escape 2x) cancelled: bool = false, - /// Se revirtió al valor original (primer Escape) + /// Se revirtió al valor original (Escape 1x) reverted: bool = false, - /// Se debe navegar a siguiente celda (Tab) - navigate_next: bool = false, - /// Se debe navegar a celda anterior (Shift+Tab) - navigate_prev: bool = false, + /// Dirección de navegación después de commit + navigate: NavigateDirection = .none, /// El buffer de edición cambió text_changed: bool = false, + /// Indica que se procesó un evento de teclado (para evitar doble procesamiento) + handled: bool = false, }; /// Procesa teclado en modo edición /// Modifica edit_buffer, edit_len, edit_cursor según las teclas +/// Retorna resultado con flags de navegación y si se procesó algún evento pub fn handleEditingKeyboard( ctx: *Context, edit_buffer: []u8, @@ -238,108 +248,124 @@ pub fn handleEditingKeyboard( ) EditKeyboardResult { var result = EditKeyboardResult{}; - // Escape: cancelar o revertir - if (ctx.input.keyPressed(.escape)) { - escape_count.* += 1; - if (escape_count.* >= 2 or original_text == null) { - result.cancelled = true; - } else { - // Revertir al valor original - if (original_text) |orig| { - const len = @min(orig.len, edit_buffer.len); - @memcpy(edit_buffer[0..len], orig[0..len]); - edit_len.* = len; - edit_cursor.* = len; - result.reverted = true; - } + // Procesar eventos de tecla + for (ctx.input.getKeyEvents()) |event| { + if (!event.pressed) continue; + + switch (event.key) { + .escape => { + escape_count.* += 1; + if (escape_count.* >= 2 or original_text == null) { + result.cancelled = true; + } else { + // Revertir al valor original + if (original_text) |orig| { + const len = @min(orig.len, edit_buffer.len); + @memcpy(edit_buffer[0..len], orig[0..len]); + edit_len.* = len; + edit_cursor.* = len; + result.reverted = true; + } + } + result.handled = true; + return result; + }, + .enter => { + result.committed = true; + result.navigate = .next_row; + result.handled = true; + return result; + }, + .tab => { + result.committed = true; + result.navigate = if (event.modifiers.shift) .prev_cell else .next_cell; + result.handled = true; + return result; + }, + .up => { + result.committed = true; + result.navigate = .prev_row; + result.handled = true; + return result; + }, + .down => { + result.committed = true; + result.navigate = .next_row; + result.handled = true; + return result; + }, + .left => { + if (edit_cursor.* > 0) edit_cursor.* -= 1; + result.handled = true; + // Reset escape count + escape_count.* = 0; + }, + .right => { + if (edit_cursor.* < edit_len.*) edit_cursor.* += 1; + result.handled = true; + escape_count.* = 0; + }, + .home => { + edit_cursor.* = 0; + result.handled = true; + escape_count.* = 0; + }, + .end => { + edit_cursor.* = edit_len.*; + result.handled = true; + escape_count.* = 0; + }, + .backspace => { + if (edit_cursor.* > 0 and edit_len.* > 0) { + // Shift characters left + const pos = edit_cursor.* - 1; + var i: usize = pos; + while (i < edit_len.* - 1) : (i += 1) { + edit_buffer[i] = edit_buffer[i + 1]; + } + edit_len.* -= 1; + edit_cursor.* -= 1; + result.text_changed = true; + } + result.handled = true; + escape_count.* = 0; + }, + .delete => { + if (edit_cursor.* < edit_len.*) { + var i: usize = edit_cursor.*; + while (i < edit_len.* - 1) : (i += 1) { + edit_buffer[i] = edit_buffer[i + 1]; + } + edit_len.* -= 1; + result.text_changed = true; + } + result.handled = true; + escape_count.* = 0; + }, + else => {}, } - return result; } - // Reset escape count en cualquier otra tecla - escape_count.* = 0; - - // Enter: confirmar - if (ctx.input.keyPressed(.enter)) { - result.committed = true; - return result; - } - - // Tab: confirmar y navegar - if (ctx.input.keyPressed(.tab)) { - result.committed = true; - if (ctx.input.modifiers.shift) { - result.navigate_prev = true; - } else { - result.navigate_next = true; - } - return result; - } - - // Movimiento del cursor - if (ctx.input.keyPressed(.left)) { - if (edit_cursor.* > 0) edit_cursor.* -= 1; - return result; - } - if (ctx.input.keyPressed(.right)) { - if (edit_cursor.* < edit_len.*) edit_cursor.* += 1; - return result; - } - if (ctx.input.keyPressed(.home)) { - edit_cursor.* = 0; - return result; - } - if (ctx.input.keyPressed(.end)) { - edit_cursor.* = edit_len.*; - return result; - } - - // Backspace - if (ctx.input.keyPressed(.backspace)) { - if (edit_cursor.* > 0) { - // Shift characters left - var i: usize = edit_cursor.* - 1; - while (i < edit_len.* - 1) : (i += 1) { - edit_buffer[i] = edit_buffer[i + 1]; - } - edit_len.* -= 1; - edit_cursor.* -= 1; - result.text_changed = true; - } - return result; - } - - // Delete - if (ctx.input.keyPressed(.delete)) { - if (edit_cursor.* < edit_len.*) { - var i: usize = edit_cursor.*; - while (i < edit_len.* - 1) : (i += 1) { - edit_buffer[i] = edit_buffer[i + 1]; - } - edit_len.* -= 1; - result.text_changed = true; - } - return result; - } - - // Character input - if (ctx.input.text_input_len > 0) { - const text = ctx.input.text_input[0..ctx.input.text_input_len]; - for (text) |ch| { - if (ch >= 32 and ch < 127) { - if (edit_len.* < edit_buffer.len - 1) { - // Shift characters right - var i: usize = edit_len.*; + // Procesar texto ingresado (caracteres imprimibles) + const text_input = ctx.input.getTextInput(); + if (text_input.len > 0) { + for (text_input) |ch| { + if (edit_len.* < edit_buffer.len - 1) { + // Hacer espacio moviendo caracteres hacia la derecha + if (edit_cursor.* < edit_len.*) { + var i = edit_len.*; while (i > edit_cursor.*) : (i -= 1) { edit_buffer[i] = edit_buffer[i - 1]; } - edit_buffer[edit_cursor.*] = ch; - edit_len.* += 1; - edit_cursor.* += 1; - result.text_changed = true; } + edit_buffer[edit_cursor.*] = ch; + edit_len.* += 1; + edit_cursor.* += 1; + result.text_changed = true; + result.handled = true; } } + escape_count.* = 0; } return result;