Compare commits
4 commits
ab39830477
...
7b2ba06035
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b2ba06035 | ||
|
|
b2bcdeae1a | ||
|
|
ae993a0f6f | ||
|
|
b9e7434ef7 |
2 changed files with 50 additions and 17 deletions
|
|
@ -200,16 +200,30 @@ pub const VirtualListState = struct {
|
|||
|
||||
/// Mueve la selección hacia arriba
|
||||
pub fn moveUp(self: *Self) void {
|
||||
const window_offset = self.scroll_offset -| self.window_start;
|
||||
|
||||
if (self.findSelectedInWindow()) |window_idx| {
|
||||
// Calcular posición en pantalla actual
|
||||
const screen_pos = window_idx -| window_offset;
|
||||
|
||||
if (window_idx > 0) {
|
||||
// Hay item anterior en buffer, seleccionarlo
|
||||
self.selectByWindowIndex(window_idx - 1);
|
||||
} else if (self.window_start > 0) {
|
||||
// Necesita scroll up - el widget debe manejar esto
|
||||
self.scroll_offset = if (self.scroll_offset > 0) self.scroll_offset - 1 else 0;
|
||||
|
||||
// Si estábamos en la primera fila visible, hacer scroll
|
||||
if (screen_pos == 0 and self.scroll_offset > 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) {
|
||||
// Sin selección: seleccionar primera fila visible
|
||||
self.selectByWindowIndex(0);
|
||||
self.selectByWindowIndex(window_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -219,8 +233,13 @@ pub const VirtualListState = struct {
|
|||
if (window_idx + 1 < self.current_window.len) {
|
||||
self.selectByWindowIndex(window_idx + 1);
|
||||
|
||||
// Si la nueva selección está cerca del final visible, scroll
|
||||
if (window_idx + 1 >= visible_rows - 1) {
|
||||
// Calcular posición en pantalla de la nueva selección
|
||||
const window_offset = self.scroll_offset -| self.window_start;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ pub fn virtualListRect(
|
|||
|
||||
// Calculate dimensions
|
||||
const header_h: u32 = config.row_height;
|
||||
const footer_h: u32 = if (config.show_count) 20 else 0;
|
||||
const footer_h: u32 = if (config.show_count) 16 else 0; // 16px para footer compacto
|
||||
const content_h = bounds.h -| header_h -| footer_h;
|
||||
const visible_rows: usize = @intCast(content_h / config.row_height);
|
||||
|
||||
|
|
@ -173,7 +173,10 @@ pub fn virtualListRect(
|
|||
drawScrollbar(ctx, bounds, header_h, footer_h, list_state, visible_rows, total_rows, &colors);
|
||||
}
|
||||
|
||||
// Draw focus ring
|
||||
// Draw border around the entire list (always visible)
|
||||
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 (Style.isFancy()) {
|
||||
ctx.pushCommand(Command.focusRing(bounds.x, bounds.y, bounds.w, bounds.h, 4));
|
||||
|
|
@ -259,7 +262,7 @@ fn drawHeader(
|
|||
// Column title
|
||||
ctx.pushCommand(Command.text(
|
||||
x + 4,
|
||||
bounds.y + 4,
|
||||
bounds.y + 3, // Centrado vertical mejorado
|
||||
col.title,
|
||||
colors.text,
|
||||
));
|
||||
|
|
@ -270,7 +273,7 @@ fn drawHeader(
|
|||
const indicator = list_state.sort_direction.symbol();
|
||||
ctx.pushCommand(Command.text(
|
||||
x + @as(i32, @intCast(col.width)) - 20,
|
||||
bounds.y + 4,
|
||||
bounds.y + 3, // Centrado vertical mejorado
|
||||
indicator,
|
||||
colors.text,
|
||||
));
|
||||
|
|
@ -321,12 +324,19 @@ fn drawRows(
|
|||
|
||||
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
|
||||
var row_idx: usize = 0;
|
||||
while (row_idx < visible_rows and row_idx < list_state.current_window.len) : (row_idx += 1) {
|
||||
while (row_idx < visible_rows) : (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 global_idx = list_state.windowToGlobalIndex(row_idx);
|
||||
const row = list_state.current_window[row_idx];
|
||||
const global_idx = list_state.scroll_offset + row_idx; // Índice global real
|
||||
const row = list_state.current_window[data_idx];
|
||||
|
||||
// Determine row background
|
||||
const is_selected = list_state.selected_id != null and row.id == list_state.selected_id.?;
|
||||
|
|
@ -359,7 +369,7 @@ fn drawRows(
|
|||
|
||||
ctx.pushCommand(Command.text(
|
||||
x + 4,
|
||||
row_y + 4,
|
||||
row_y + 3, // Centrado vertical mejorado
|
||||
row.values[col_idx],
|
||||
text_color,
|
||||
));
|
||||
|
|
@ -498,10 +508,14 @@ fn handleMouseClick(
|
|||
// Check if click is in content area (not header)
|
||||
if (mouse.y >= content_y) {
|
||||
const relative_y = mouse.y - content_y;
|
||||
const row_idx = @as(usize, @intCast(relative_y)) / config.row_height;
|
||||
const screen_row = @as(usize, @intCast(relative_y)) / config.row_height;
|
||||
|
||||
if (row_idx < list_state.current_window.len) {
|
||||
list_state.selectByWindowIndex(row_idx);
|
||||
// Convert screen row to buffer index (accounting for scroll)
|
||||
const window_offset = list_state.scroll_offset -| list_state.window_start;
|
||||
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
|
||||
// TODO: implement double click detection with timing
|
||||
|
|
|
|||
Loading…
Reference in a new issue