Compare commits

..

3 commits

Author SHA1 Message Date
63daca0827 refactor(tips): Eliminar sistema de tips de VirtualAdvancedTable
VirtualAdvancedTable ya NO gestiona tips internamente.
El carrusel ahora vive en zsimifactu/StatusLine (v2.0).

Eliminado:
- table_tips[] y TIP_ROTATION_FRAMES de types.zig
- Re-exports de table_core.zig
- frame_count y tip_index de VirtualAdvancedTableState
- current_tip de VirtualAdvancedTableResult
- Lógica de rotación (frame_count % TIP_ROTATION)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 21:00:28 +01:00
4cdc8c44e2 feat(panel): derived_bg en PanelFrameResult
Añade derived_bg al resultado de drawPanelFrame para que los paneles
puedan usar el color exacto del fondo para las tablas (mimetismo visual).

Las tablas deben usar frame_result.derived_bg como row_normal para
integrarse visualmente con el panel.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:07:56 +01:00
cc7c2a00c6 fix(tabs): Procesar eventos ANTES de dibujar
Problema: Al hacer clic en un tab, el dibujo visual mostraba el
tab viejo como activo porque is_selected se calculaba ANTES de
procesar el clic.

Solución: Separar en dos passes:
- Pass 1: Detectar clics y actualizar state.selected
- Pass 2: Dibujar con el estado ya actualizado

Esto elimina el "parpadeo" donde el tab visual no coincidía
con el tab lógico durante un frame.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 22:58:00 +01:00
6 changed files with 56 additions and 65 deletions

View file

@ -728,6 +728,9 @@ pub const Context = struct {
animating: bool,
/// False if panel was suppressed - caller should return immediately
should_draw: bool,
/// The actual background color being drawn (for table mimetism)
/// Tables should use this as row_normal to blend seamlessly with panel
derived_bg: Style.Color,
};
/// Draw a complete panel frame with focus transition and 3D effects.
@ -832,7 +835,12 @@ pub const Context = struct {
}
// should_draw = false indica que el panel debe saltar operaciones costosas (BD, widgets)
return .{ .animating = animating, .should_draw = !burst_suppressed };
// derived_bg = color actual del fondo (para mimetismo de tablas)
return .{
.animating = animating,
.should_draw = !burst_suppressed,
.derived_bg = transition.current,
};
}
/// Resize the context

View file

@ -40,8 +40,6 @@
// Types - Enums, structs, constantes
pub const types = @import("types.zig");
// Re-exports de types
pub const table_tips = types.table_tips;
pub const TIP_ROTATION_FRAMES = types.TIP_ROTATION_FRAMES;
pub const MAX_EDIT_BUFFER_SIZE = types.MAX_EDIT_BUFFER_SIZE;
pub const MAX_PENDING_COLUMNS = types.MAX_PENDING_COLUMNS;
pub const MAX_CELL_VALUE_LEN = types.MAX_CELL_VALUE_LEN;

View file

@ -4,31 +4,10 @@
//! - Enums de estado y dirección
//! - Structs de configuración y colores
//! - Constantes globales
//! - Tips proactivos
const std = @import("std");
const Style = @import("../../core/style.zig");
// =============================================================================
// Tips Proactivos (FASE I)
// =============================================================================
/// Tips de atajos de teclado para mostrar en StatusLine
/// Rotan cada ~10 segundos para enseñar atajos al usuario
pub const table_tips = [_][]const u8{
"Tip: F2 o Space para editar celda",
"Tip: Tab/Shift+Tab navega entre celdas",
"Tip: Ctrl+N crea nuevo registro",
"Tip: Ctrl+Delete o Ctrl+B borra registro",
"Tip: Ctrl+Shift+1..9 ordena por columna",
"Tip: Ctrl+Home/End va al inicio/fin",
"Tip: Enter confirma y baja, Escape cancela",
"Tip: Al editar, tecla directa reemplaza todo",
};
/// Frames entre rotación de tips (~10s @ 60fps)
pub const TIP_ROTATION_FRAMES: u32 = 600;
// =============================================================================
// Constantes globales
// =============================================================================

View file

@ -247,9 +247,53 @@ pub fn tabsRect(
total_width += width;
}
// Draw tabs
// ==========================================================================
// PASS 1: Process input events BEFORE drawing (fix visual lag on click)
// ==========================================================================
var tab_x = bar_rect.x;
for (tab_list, 0..) |tab, i| {
if (i >= tab_widths.len) break;
const tab_width = tab_widths[i];
const tab_rect = Layout.Rect.init(tab_x, bar_rect.y, tab_width, config.tab_height);
const is_hovered_input = tab_rect.contains(mouse.x, mouse.y) and !tab.disabled;
// Handle close button click (pass 1)
if (config.show_close and tab.closable) {
const close_x = tab_x + @as(i32, @intCast(tab_width - config.close_size - 8));
const close_y = bar_rect.y + @as(i32, @intCast((config.tab_height - config.close_size) / 2));
const close_rect = Layout.Rect.init(close_x, close_y, config.close_size, config.close_size);
const close_hovered = close_rect.contains(mouse.x, mouse.y);
if (close_hovered) {
state.close_hovered = @intCast(i);
}
if (mouse_pressed and close_hovered) {
result.closed = true;
result.closed_index = i;
}
}
// Handle tab click (pass 1) - update state BEFORE drawing
if (mouse_pressed and is_hovered_input and state.close_hovered != @as(i32, @intCast(i))) {
ctx.requestFocus(widget_id);
if (state.selected != i) {
state.selected = i;
result.changed = true;
result.selected = i;
}
}
tab_x += @as(i32, @intCast(tab_width));
}
// ==========================================================================
// PASS 2: Draw tabs with UPDATED state
// ==========================================================================
tab_x = bar_rect.x;
for (tab_list, 0..) |tab, i| {
if (i >= tab_widths.len) break;
@ -328,38 +372,20 @@ pub fn tabsRect(
const text_y = bar_rect.y + @as(i32, @intCast((config.tab_height - 8) / 2));
ctx.pushCommand(Command.text(tab_x + @as(i32, @intCast(config.padding_h)), text_y, tab.label, text_color));
// Draw close button
// Draw close button (events already handled in Pass 1)
if (config.show_close and tab.closable) {
const close_x = tab_x + @as(i32, @intCast(tab_width - config.close_size - 8));
const close_y = bar_rect.y + @as(i32, @intCast((config.tab_height - config.close_size) / 2));
const close_rect = Layout.Rect.init(close_x, close_y, config.close_size, config.close_size);
const close_hovered = close_rect.contains(mouse.x, mouse.y);
if (close_hovered) {
state.close_hovered = @intCast(i);
}
const close_color = if (close_hovered) colors.close_hover else colors.close_color;
// Draw X
ctx.pushCommand(Command.text(close_x + 3, close_y + 2, "x", close_color));
// Handle close click
if (mouse_pressed and close_hovered) {
result.closed = true;
result.closed_index = i;
}
}
// Handle tab click
if (mouse_pressed and is_hovered and state.close_hovered != @as(i32, @intCast(i))) {
ctx.requestFocus(widget_id);
if (state.selected != i) {
state.selected = i;
result.changed = true;
result.selected = i;
}
}
// Note: Tab click handling moved to Pass 1 (before drawing)
tab_x += @as(i32, @intCast(tab_width));
}

View file

@ -123,12 +123,6 @@ pub const VirtualAdvancedTableState = struct {
/// Indica si hubo doble click este frame
double_clicked: bool = false,
/// Frame counter para animaciones
frame_count: u32 = 0,
/// Índice del tip actual (para tips proactivos rotativos)
tip_index: u8 = 0,
// =========================================================================
// Buffers persistentes para texto formateado (evitar stack buffer escape)
// =========================================================================
@ -281,7 +275,6 @@ pub const VirtualAdvancedTableState = struct {
self.filter_text_changed = false;
self.chip_changed = false;
self.changed_chip_index = null;
self.frame_count +%= 1;
}
// =========================================================================

View file

@ -106,9 +106,6 @@ pub const VirtualAdvancedTableResult = struct {
edited_value: ?[]const u8 = null,
previous_row: ?usize = null,
// Tips
current_tip: ?[]const u8 = null,
pub fn getRowChanges(self: *const VirtualAdvancedTableResult) []const table_core.PendingCellChange {
return self.row_changes[0..self.row_changes_count];
}
@ -428,16 +425,6 @@ pub fn virtualAdvancedTableRect(
}
}
// Tips
list_state.frame_count +%= 1;
if (has_focus and !list_state.isEditing()) {
if (list_state.frame_count % table_core.TIP_ROTATION_FRAMES == 0) {
list_state.tip_index = @intCast((list_state.tip_index + 1) % table_core.table_tips.len);
}
result.current_tip = table_core.table_tips[list_state.tip_index];
}
return result;
}