Compare commits

..

No commits in common. "7b2ba0603511e7faf2336d59446fc68e90ca1397" and "ab398304779c6962b9c3319f444b05917b93c75a" have entirely different histories.

2 changed files with 17 additions and 50 deletions

View file

@ -200,30 +200,16 @@ pub const VirtualListState = struct {
/// Mueve la selección hacia arriba /// Mueve la selección hacia arriba
pub fn moveUp(self: *Self) void { pub fn moveUp(self: *Self) void {
const window_offset = self.scroll_offset -| self.window_start;
if (self.findSelectedInWindow()) |window_idx| { if (self.findSelectedInWindow()) |window_idx| {
// Calcular posición en pantalla actual
const screen_pos = window_idx -| window_offset;
if (window_idx > 0) { if (window_idx > 0) {
// Hay item anterior en buffer, seleccionarlo
self.selectByWindowIndex(window_idx - 1); self.selectByWindowIndex(window_idx - 1);
} else if (self.window_start > 0) {
// Si estábamos en la primera fila visible, hacer scroll // Necesita scroll up - el widget debe manejar esto
if (screen_pos == 0 and self.scroll_offset > 0) { self.scroll_offset = if (self.scroll_offset > 0) self.scroll_offset - 1 else 0;
self.scroll_offset -= 1;
}
} else {
// Estamos en el inicio del buffer
// Scroll up para cargar más datos (si es posible)
if (self.scroll_offset > 0) {
self.scroll_offset -= 1;
}
} }
} else if (self.current_window.len > 0) { } else if (self.current_window.len > 0) {
// Sin selección: seleccionar primera fila visible // Sin selección: seleccionar primera fila visible
self.selectByWindowIndex(window_offset); self.selectByWindowIndex(0);
} }
} }
@ -233,13 +219,8 @@ pub const VirtualListState = struct {
if (window_idx + 1 < self.current_window.len) { if (window_idx + 1 < self.current_window.len) {
self.selectByWindowIndex(window_idx + 1); self.selectByWindowIndex(window_idx + 1);
// Calcular posición en pantalla de la nueva selección // Si la nueva selección está cerca del final visible, scroll
const window_offset = self.scroll_offset -| self.window_start; if (window_idx + 1 >= visible_rows - 1) {
const new_screen_pos = (window_idx + 1) -| window_offset;
// Scroll cuando la nueva posición llega a la ÚLTIMA fila visible
// (visible_rows - 1 es el índice de la última fila, 0-indexed)
if (new_screen_pos >= visible_rows) {
self.scroll_offset += 1; self.scroll_offset += 1;
} }
} }

View file

@ -116,7 +116,7 @@ pub fn virtualListRect(
// Calculate dimensions // Calculate dimensions
const header_h: u32 = config.row_height; const header_h: u32 = config.row_height;
const footer_h: u32 = if (config.show_count) 16 else 0; // 16px para footer compacto const footer_h: u32 = if (config.show_count) 20 else 0;
const content_h = bounds.h -| header_h -| footer_h; const content_h = bounds.h -| header_h -| footer_h;
const visible_rows: usize = @intCast(content_h / config.row_height); const visible_rows: usize = @intCast(content_h / config.row_height);
@ -173,10 +173,7 @@ pub fn virtualListRect(
drawScrollbar(ctx, bounds, header_h, footer_h, list_state, visible_rows, total_rows, &colors); drawScrollbar(ctx, bounds, header_h, footer_h, list_state, visible_rows, total_rows, &colors);
} }
// Draw border around the entire list (always visible) // Draw focus ring
ctx.pushCommand(Command.rectOutline(bounds.x, bounds.y, bounds.w, bounds.h, colors.border));
// Draw focus ring (additional highlight when focused)
if (has_focus) { if (has_focus) {
if (Style.isFancy()) { if (Style.isFancy()) {
ctx.pushCommand(Command.focusRing(bounds.x, bounds.y, bounds.w, bounds.h, 4)); ctx.pushCommand(Command.focusRing(bounds.x, bounds.y, bounds.w, bounds.h, 4));
@ -262,7 +259,7 @@ fn drawHeader(
// Column title // Column title
ctx.pushCommand(Command.text( ctx.pushCommand(Command.text(
x + 4, x + 4,
bounds.y + 3, // Centrado vertical mejorado bounds.y + 4,
col.title, col.title,
colors.text, colors.text,
)); ));
@ -273,7 +270,7 @@ fn drawHeader(
const indicator = list_state.sort_direction.symbol(); const indicator = list_state.sort_direction.symbol();
ctx.pushCommand(Command.text( ctx.pushCommand(Command.text(
x + @as(i32, @intCast(col.width)) - 20, x + @as(i32, @intCast(col.width)) - 20,
bounds.y + 3, // Centrado vertical mejorado bounds.y + 4,
indicator, indicator,
colors.text, colors.text,
)); ));
@ -324,19 +321,12 @@ fn drawRows(
const row_h = config.row_height; const row_h = config.row_height;
// Calculate offset within the window buffer
// scroll_offset es la posición global, window_start es donde empieza el buffer
const window_offset = list_state.scroll_offset -| list_state.window_start;
// Draw each visible row // Draw each visible row
var row_idx: usize = 0; var row_idx: usize = 0;
while (row_idx < visible_rows) : (row_idx += 1) { while (row_idx < visible_rows and row_idx < list_state.current_window.len) : (row_idx += 1) {
const data_idx = window_offset + row_idx;
if (data_idx >= list_state.current_window.len) break;
const row_y = content_bounds.y + @as(i32, @intCast(row_idx * row_h)); const row_y = content_bounds.y + @as(i32, @intCast(row_idx * row_h));
const global_idx = list_state.scroll_offset + row_idx; // Índice global real const global_idx = list_state.windowToGlobalIndex(row_idx);
const row = list_state.current_window[data_idx]; const row = list_state.current_window[row_idx];
// Determine row background // Determine row background
const is_selected = list_state.selected_id != null and row.id == list_state.selected_id.?; const is_selected = list_state.selected_id != null and row.id == list_state.selected_id.?;
@ -369,7 +359,7 @@ fn drawRows(
ctx.pushCommand(Command.text( ctx.pushCommand(Command.text(
x + 4, x + 4,
row_y + 3, // Centrado vertical mejorado row_y + 4,
row.values[col_idx], row.values[col_idx],
text_color, text_color,
)); ));
@ -508,14 +498,10 @@ fn handleMouseClick(
// Check if click is in content area (not header) // Check if click is in content area (not header)
if (mouse.y >= content_y) { if (mouse.y >= content_y) {
const relative_y = mouse.y - content_y; const relative_y = mouse.y - content_y;
const screen_row = @as(usize, @intCast(relative_y)) / config.row_height; const row_idx = @as(usize, @intCast(relative_y)) / config.row_height;
// Convert screen row to buffer index (accounting for scroll) if (row_idx < list_state.current_window.len) {
const window_offset = list_state.scroll_offset -| list_state.window_start; list_state.selectByWindowIndex(row_idx);
const data_idx = window_offset + screen_row;
if (data_idx < list_state.current_window.len) {
list_state.selectById(list_state.current_window[data_idx].id);
// Check for double click // Check for double click
// TODO: implement double click detection with timing // TODO: implement double click detection with timing