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:
parent
e8b4c98d4a
commit
49cf12f7b9
1 changed files with 126 additions and 100 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue