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>
This commit is contained in:
parent
f17104c08b
commit
cc7c2a00c6
1 changed files with 47 additions and 21 deletions
|
|
@ -247,9 +247,53 @@ pub fn tabsRect(
|
||||||
total_width += width;
|
total_width += width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw tabs
|
// ==========================================================================
|
||||||
|
// PASS 1: Process input events BEFORE drawing (fix visual lag on click)
|
||||||
|
// ==========================================================================
|
||||||
var tab_x = bar_rect.x;
|
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| {
|
for (tab_list, 0..) |tab, i| {
|
||||||
if (i >= tab_widths.len) break;
|
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));
|
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));
|
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) {
|
if (config.show_close and tab.closable) {
|
||||||
const close_x = tab_x + @as(i32, @intCast(tab_width - config.close_size - 8));
|
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_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_rect = Layout.Rect.init(close_x, close_y, config.close_size, config.close_size);
|
||||||
|
|
||||||
const close_hovered = close_rect.contains(mouse.x, mouse.y);
|
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;
|
const close_color = if (close_hovered) colors.close_hover else colors.close_color;
|
||||||
|
|
||||||
// Draw X
|
// Draw X
|
||||||
ctx.pushCommand(Command.text(close_x + 3, close_y + 2, "x", close_color));
|
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
|
// Note: Tab click handling moved to Pass 1 (before drawing)
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tab_x += @as(i32, @intCast(tab_width));
|
tab_x += @as(i32, @intCast(tab_width));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue