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
This commit is contained in:
reugenio 2025-12-27 12:09:39 +01:00
parent e8b4c98d4a
commit 49cf12f7b9

View file

@ -210,24 +210,34 @@ pub fn detectDoubleClick(
// Manejo de teclado para edición // 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 /// Resultado de procesar teclado en modo edición
pub const EditKeyboardResult = struct { pub const EditKeyboardResult = struct {
/// Se confirmó la edición (Enter) /// Se confirmó la edición (Enter, Tab, flechas)
committed: bool = false, committed: bool = false,
/// Se canceló la edición (Escape) /// Se canceló la edición (Escape 2x)
cancelled: bool = false, cancelled: bool = false,
/// Se revirtió al valor original (primer Escape) /// Se revirtió al valor original (Escape 1x)
reverted: bool = false, reverted: bool = false,
/// Se debe navegar a siguiente celda (Tab) /// Dirección de navegación después de commit
navigate_next: bool = false, navigate: NavigateDirection = .none,
/// Se debe navegar a celda anterior (Shift+Tab)
navigate_prev: bool = false,
/// El buffer de edición cambió /// El buffer de edición cambió
text_changed: bool = false, 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 /// Procesa teclado en modo edición
/// Modifica edit_buffer, edit_len, edit_cursor según las teclas /// 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( pub fn handleEditingKeyboard(
ctx: *Context, ctx: *Context,
edit_buffer: []u8, edit_buffer: []u8,
@ -238,108 +248,124 @@ pub fn handleEditingKeyboard(
) EditKeyboardResult { ) EditKeyboardResult {
var result = EditKeyboardResult{}; var result = EditKeyboardResult{};
// Escape: cancelar o revertir // Procesar eventos de tecla
if (ctx.input.keyPressed(.escape)) { for (ctx.input.getKeyEvents()) |event| {
escape_count.* += 1; if (!event.pressed) continue;
if (escape_count.* >= 2 or original_text == null) {
result.cancelled = true; switch (event.key) {
} else { .escape => {
// Revertir al valor original escape_count.* += 1;
if (original_text) |orig| { if (escape_count.* >= 2 or original_text == null) {
const len = @min(orig.len, edit_buffer.len); result.cancelled = true;
@memcpy(edit_buffer[0..len], orig[0..len]); } else {
edit_len.* = len; // Revertir al valor original
edit_cursor.* = len; if (original_text) |orig| {
result.reverted = true; 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 // Procesar texto ingresado (caracteres imprimibles)
escape_count.* = 0; const text_input = ctx.input.getTextInput();
if (text_input.len > 0) {
// Enter: confirmar for (text_input) |ch| {
if (ctx.input.keyPressed(.enter)) { if (edit_len.* < edit_buffer.len - 1) {
result.committed = true; // Hacer espacio moviendo caracteres hacia la derecha
return result; if (edit_cursor.* < edit_len.*) {
} var i = edit_len.*;
// 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.*;
while (i > edit_cursor.*) : (i -= 1) { while (i > edit_cursor.*) : (i -= 1) {
edit_buffer[i] = edit_buffer[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; return result;