feat(virtual_advanced_table): Add CRUD Excel-style editing state
- Rename VirtualList → VirtualAdvancedTable - Add CellId and CellGeometry types - Add editing state fields (editing_cell, original_value, escape_count, etc.) - Add editing methods: startEditing, commitEdit, cancelEdit, handleEscape - Add getCellGeometry() for overlay positioning - Add row_dirty flag for change tracking
This commit is contained in:
parent
7f8870d890
commit
66816bcbf1
5 changed files with 297 additions and 61 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
//! DataProvider - Interface genérica para fuentes de datos
|
//! DataProvider - Interface genérica para fuentes de datos
|
||||||
//!
|
//!
|
||||||
//! Permite que VirtualList trabaje con cualquier fuente de datos
|
//! Permite que VirtualAdvancedTable trabaje con cualquier fuente de datos
|
||||||
//! (SQLite, arrays, APIs, etc.) mediante un vtable pattern.
|
//! (SQLite, arrays, APIs, etc.) mediante un vtable pattern.
|
||||||
//!
|
//!
|
||||||
//! Ejemplo de implementación:
|
//! Ejemplo de implementación:
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//! Estado del VirtualList
|
//! Estado del VirtualAdvancedTable
|
||||||
//!
|
//!
|
||||||
//! Mantiene el estado de navegación, selección y caché del widget.
|
//! Mantiene el estado de navegación, selección y caché del widget.
|
||||||
|
|
||||||
|
|
@ -7,9 +7,11 @@ const types = @import("types.zig");
|
||||||
const RowData = types.RowData;
|
const RowData = types.RowData;
|
||||||
const CountInfo = types.CountInfo;
|
const CountInfo = types.CountInfo;
|
||||||
const SortDirection = types.SortDirection;
|
const SortDirection = types.SortDirection;
|
||||||
|
const CellId = types.CellId;
|
||||||
|
const CellGeometry = types.CellGeometry;
|
||||||
|
|
||||||
/// Estado del widget VirtualList
|
/// Estado del widget VirtualAdvancedTable
|
||||||
pub const VirtualListState = struct {
|
pub const VirtualAdvancedTableState = struct {
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Selección
|
// Selección
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
@ -120,6 +122,34 @@ pub const VirtualListState = struct {
|
||||||
footer_display_buf: [96]u8 = undefined,
|
footer_display_buf: [96]u8 = undefined,
|
||||||
footer_display_len: usize = 0,
|
footer_display_len: usize = 0,
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Estado de edición CRUD Excel-style
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/// Celda actualmente en edición (null = no editando)
|
||||||
|
editing_cell: ?CellId = null,
|
||||||
|
|
||||||
|
/// Valor original de la celda (para Escape revertir)
|
||||||
|
original_value: [256]u8 = undefined,
|
||||||
|
original_value_len: usize = 0,
|
||||||
|
|
||||||
|
/// Contador de Escapes (1 = revertir celda, 2 = descartar fila)
|
||||||
|
escape_count: u8 = 0,
|
||||||
|
|
||||||
|
/// Fila actual tiene cambios sin guardar en BD
|
||||||
|
row_dirty: bool = false,
|
||||||
|
|
||||||
|
/// Última fila editada (para detectar cambio de fila)
|
||||||
|
last_edited_row: ?usize = null,
|
||||||
|
|
||||||
|
/// Buffer de edición (texto actual en el editor)
|
||||||
|
edit_buffer: [256]u8 = undefined,
|
||||||
|
edit_buffer_len: usize = 0,
|
||||||
|
edit_cursor: usize = 0,
|
||||||
|
|
||||||
|
/// Flag: celda requiere commit al terminar edición
|
||||||
|
cell_value_changed: bool = false,
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
@ -403,6 +433,192 @@ pub const VirtualListState = struct {
|
||||||
pub fn goToEndX(self: *Self, max_scroll: i32) void {
|
pub fn goToEndX(self: *Self, max_scroll: i32) void {
|
||||||
self.scroll_offset_x = max_scroll;
|
self.scroll_offset_x = max_scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Métodos de edición CRUD Excel-style
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/// Verifica si hay una celda en edición
|
||||||
|
pub fn isEditing(self: *const Self) bool {
|
||||||
|
return self.editing_cell != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inicia edición de una celda
|
||||||
|
/// initial_char: si viene de tecla alfanumérica, el caracter inicial (null = mostrar valor actual)
|
||||||
|
pub fn startEditing(self: *Self, cell: CellId, current_value: []const u8, initial_char: ?u8) void {
|
||||||
|
// Guardar valor original (para Escape)
|
||||||
|
const len = @min(current_value.len, self.original_value.len);
|
||||||
|
@memcpy(self.original_value[0..len], current_value[0..len]);
|
||||||
|
self.original_value_len = len;
|
||||||
|
|
||||||
|
// Inicializar buffer de edición
|
||||||
|
if (initial_char) |c| {
|
||||||
|
// Tecla alfanumérica: empezar con ese caracter
|
||||||
|
self.edit_buffer[0] = c;
|
||||||
|
self.edit_buffer_len = 1;
|
||||||
|
self.edit_cursor = 1;
|
||||||
|
} else {
|
||||||
|
// Doble-click/Space: mostrar valor actual
|
||||||
|
@memcpy(self.edit_buffer[0..len], current_value[0..len]);
|
||||||
|
self.edit_buffer_len = len;
|
||||||
|
self.edit_cursor = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.editing_cell = cell;
|
||||||
|
self.escape_count = 0;
|
||||||
|
self.cell_value_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Obtiene el texto actual del editor
|
||||||
|
pub fn getEditText(self: *const Self) []const u8 {
|
||||||
|
return self.edit_buffer[0..self.edit_buffer_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Establece el texto del editor
|
||||||
|
pub fn setEditText(self: *Self, text: []const u8) void {
|
||||||
|
const len = @min(text.len, self.edit_buffer.len);
|
||||||
|
@memcpy(self.edit_buffer[0..len], text[0..len]);
|
||||||
|
self.edit_buffer_len = len;
|
||||||
|
self.edit_cursor = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Obtiene el valor original (antes de editar)
|
||||||
|
pub fn getOriginalValue(self: *const Self) []const u8 {
|
||||||
|
return self.original_value[0..self.original_value_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifica si el valor ha cambiado respecto al original
|
||||||
|
pub fn hasValueChanged(self: *const Self) bool {
|
||||||
|
const current = self.getEditText();
|
||||||
|
const original = self.getOriginalValue();
|
||||||
|
return !std.mem.eql(u8, current, original);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finaliza edición guardando cambios (retorna true si hubo cambios)
|
||||||
|
pub fn commitEdit(self: *Self) bool {
|
||||||
|
if (self.editing_cell == null) return false;
|
||||||
|
|
||||||
|
const changed = self.hasValueChanged();
|
||||||
|
if (changed) {
|
||||||
|
self.row_dirty = true;
|
||||||
|
self.cell_value_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualizar última fila editada
|
||||||
|
self.last_edited_row = self.editing_cell.?.row;
|
||||||
|
|
||||||
|
self.editing_cell = null;
|
||||||
|
self.escape_count = 0;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finaliza edición descartando cambios
|
||||||
|
pub fn cancelEdit(self: *Self) void {
|
||||||
|
self.editing_cell = null;
|
||||||
|
self.escape_count = 0;
|
||||||
|
self.cell_value_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Revierte el texto de la celda al valor original (Escape 1)
|
||||||
|
pub fn revertCellText(self: *Self) void {
|
||||||
|
const original = self.getOriginalValue();
|
||||||
|
@memcpy(self.edit_buffer[0..original.len], original);
|
||||||
|
self.edit_buffer_len = original.len;
|
||||||
|
self.edit_cursor = original.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maneja la tecla Escape (retorna acción a tomar)
|
||||||
|
pub const EscapeAction = enum {
|
||||||
|
/// Texto revertido, mantener edición
|
||||||
|
reverted,
|
||||||
|
/// Descartar cambios de fila
|
||||||
|
discard_row,
|
||||||
|
/// No estaba editando
|
||||||
|
none,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn handleEscape(self: *Self) EscapeAction {
|
||||||
|
if (self.editing_cell == null) return .none;
|
||||||
|
|
||||||
|
self.escape_count += 1;
|
||||||
|
|
||||||
|
if (self.escape_count == 1) {
|
||||||
|
// Escape 1: Revertir texto a valor original
|
||||||
|
self.revertCellText();
|
||||||
|
return .reverted;
|
||||||
|
} else {
|
||||||
|
// Escape 2+: Descartar cambios de fila
|
||||||
|
self.cancelEdit();
|
||||||
|
self.row_dirty = false;
|
||||||
|
return .discard_row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifica si cambió de fila (para auto-save)
|
||||||
|
pub fn isRowChange(self: *const Self, new_row: usize) bool {
|
||||||
|
if (self.last_edited_row) |last| {
|
||||||
|
return last != new_row;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marca la fila como guardada (limpia dirty flag)
|
||||||
|
pub fn markRowSaved(self: *Self) void {
|
||||||
|
self.row_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resetea el estado de edición completamente
|
||||||
|
pub fn resetEditState(self: *Self) void {
|
||||||
|
self.editing_cell = null;
|
||||||
|
self.escape_count = 0;
|
||||||
|
self.row_dirty = false;
|
||||||
|
self.last_edited_row = null;
|
||||||
|
self.edit_buffer_len = 0;
|
||||||
|
self.edit_cursor = 0;
|
||||||
|
self.cell_value_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Geometría de celdas
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/// Calcula la geometría (posición y tamaño) de una celda visible
|
||||||
|
/// Retorna null si la celda no está visible en pantalla
|
||||||
|
pub fn getCellGeometry(
|
||||||
|
self: *const Self,
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
columns: []const types.ColumnDef,
|
||||||
|
row_height: u32,
|
||||||
|
bounds_x: i32,
|
||||||
|
bounds_y: i32,
|
||||||
|
header_height: u32,
|
||||||
|
filter_bar_height: u32,
|
||||||
|
) ?CellGeometry {
|
||||||
|
// Verificar si la fila está en la ventana visible
|
||||||
|
if (row < self.scroll_offset) return null;
|
||||||
|
const visible_row = row - self.scroll_offset;
|
||||||
|
|
||||||
|
// Calcular Y (después de filter bar + header)
|
||||||
|
const content_start_y = bounds_y + @as(i32, @intCast(filter_bar_height)) + @as(i32, @intCast(header_height));
|
||||||
|
const y = content_start_y + @as(i32, @intCast(visible_row * row_height));
|
||||||
|
|
||||||
|
// Verificar columna válida
|
||||||
|
if (col >= columns.len) return null;
|
||||||
|
|
||||||
|
// Calcular X (sumando anchos de columnas anteriores, menos scroll horizontal)
|
||||||
|
var x: i32 = bounds_x - self.scroll_offset_x;
|
||||||
|
for (columns[0..col]) |c| {
|
||||||
|
x += @as(i32, @intCast(c.width));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CellGeometry{
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
.w = columns[col].width,
|
||||||
|
.h = row_height,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -411,8 +627,8 @@ pub const VirtualListState = struct {
|
||||||
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
test "VirtualListState selection" {
|
test "VirtualAdvancedTableState selection" {
|
||||||
var state = VirtualListState{};
|
var state = VirtualAdvancedTableState{};
|
||||||
|
|
||||||
// Initial state
|
// Initial state
|
||||||
try testing.expectEqual(@as(?i64, null), state.selected_id);
|
try testing.expectEqual(@as(?i64, null), state.selected_id);
|
||||||
|
|
@ -437,8 +653,8 @@ test "VirtualListState selection" {
|
||||||
try testing.expect(state.selection_changed);
|
try testing.expect(state.selection_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "VirtualListState filter" {
|
test "VirtualAdvancedTableState filter" {
|
||||||
var state = VirtualListState{};
|
var state = VirtualAdvancedTableState{};
|
||||||
|
|
||||||
state.setFilter("test");
|
state.setFilter("test");
|
||||||
try testing.expectEqualStrings("test", state.getFilter());
|
try testing.expectEqualStrings("test", state.getFilter());
|
||||||
|
|
@ -448,8 +664,8 @@ test "VirtualListState filter" {
|
||||||
try testing.expectEqualStrings("", state.getFilter());
|
try testing.expectEqualStrings("", state.getFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
test "VirtualListState sort" {
|
test "VirtualAdvancedTableState sort" {
|
||||||
var state = VirtualListState{};
|
var state = VirtualAdvancedTableState{};
|
||||||
|
|
||||||
// Initial: no sort
|
// Initial: no sort
|
||||||
try testing.expectEqual(@as(?[]const u8, null), state.sort_column);
|
try testing.expectEqual(@as(?[]const u8, null), state.sort_column);
|
||||||
|
|
@ -475,8 +691,8 @@ test "VirtualListState sort" {
|
||||||
try testing.expectEqual(SortDirection.ascending, state.sort_direction);
|
try testing.expectEqual(SortDirection.ascending, state.sort_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "VirtualListState window index conversion" {
|
test "VirtualAdvancedTableState window index conversion" {
|
||||||
var state = VirtualListState{};
|
var state = VirtualAdvancedTableState{};
|
||||||
state.window_start = 100;
|
state.window_start = 100;
|
||||||
|
|
||||||
const values = [_][]const u8{"test"};
|
const values = [_][]const u8{"test"};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//! Tipos para VirtualList
|
//! Tipos para VirtualAdvancedTable
|
||||||
//!
|
//!
|
||||||
//! Tipos genéricos para listas virtualizadas que trabajan con cualquier
|
//! Tipos genéricos para listas virtualizadas que trabajan con cualquier
|
||||||
//! fuente de datos (WHO, DOC, etc.)
|
//! fuente de datos (WHO, DOC, etc.)
|
||||||
|
|
@ -29,6 +29,24 @@ pub const SortDirection = enum {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Identificador de celda (fila + columna)
|
||||||
|
pub const CellId = struct {
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
|
||||||
|
pub fn eql(self: CellId, other: CellId) bool {
|
||||||
|
return self.row == other.row and self.col == other.col;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Geometría de una celda (posición y tamaño en pixels)
|
||||||
|
pub const CellGeometry = struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
w: u32,
|
||||||
|
h: u32,
|
||||||
|
};
|
||||||
|
|
||||||
/// Datos genéricos de una fila
|
/// Datos genéricos de una fila
|
||||||
/// El DataProvider convierte sus datos específicos a este formato
|
/// El DataProvider convierte sus datos específicos a este formato
|
||||||
pub const RowData = struct {
|
pub const RowData = struct {
|
||||||
|
|
@ -152,11 +170,11 @@ pub const FilterBarConfig = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// VirtualListConfig
|
// VirtualAdvancedTableConfig
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Configuración del VirtualList
|
/// Configuración del VirtualAdvancedTable
|
||||||
pub const VirtualListConfig = struct {
|
pub const VirtualAdvancedTableConfig = struct {
|
||||||
/// Altura de cada fila en pixels
|
/// Altura de cada fila en pixels
|
||||||
row_height: u16 = 24,
|
row_height: u16 = 24,
|
||||||
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
//! VirtualList - Widget de lista virtualizada
|
//! VirtualAdvancedTable - Widget de lista virtualizada
|
||||||
//!
|
//!
|
||||||
//! Lista escalable que solo carga en memoria los registros visibles + buffer.
|
//! Lista escalable que solo carga en memoria los registros visibles + buffer.
|
||||||
//! Diseñada para trabajar con bases de datos grandes (100k+ registros).
|
//! Diseñada para trabajar con bases de datos grandes (100k+ registros).
|
||||||
//!
|
//!
|
||||||
//! ## Uso
|
//! ## Uso
|
||||||
//! ```zig
|
//! ```zig
|
||||||
//! const result = virtualList(ctx, rect, &state, provider, .{
|
//! const result = virtualAdvancedTable(ctx, rect, &state, provider, .{
|
||||||
//! .columns = &columns,
|
//! .columns = &columns,
|
||||||
//! .virtualization_threshold = 500,
|
//! .virtualization_threshold = 500,
|
||||||
//! });
|
//! });
|
||||||
|
|
@ -31,16 +31,18 @@ pub const ColumnDef = types.ColumnDef;
|
||||||
pub const SortDirection = types.SortDirection;
|
pub const SortDirection = types.SortDirection;
|
||||||
pub const LoadState = types.LoadState;
|
pub const LoadState = types.LoadState;
|
||||||
pub const CountInfo = types.CountInfo;
|
pub const CountInfo = types.CountInfo;
|
||||||
pub const VirtualListConfig = types.VirtualListConfig;
|
pub const VirtualAdvancedTableConfig = types.VirtualAdvancedTableConfig;
|
||||||
pub const FilterBarConfig = types.FilterBarConfig;
|
pub const FilterBarConfig = types.FilterBarConfig;
|
||||||
pub const FilterChipDef = types.FilterChipDef;
|
pub const FilterChipDef = types.FilterChipDef;
|
||||||
pub const ChipSelectMode = types.ChipSelectMode;
|
pub const ChipSelectMode = types.ChipSelectMode;
|
||||||
|
pub const CellId = types.CellId;
|
||||||
|
pub const CellGeometry = types.CellGeometry;
|
||||||
|
|
||||||
pub const DataProvider = data_provider.DataProvider;
|
pub const DataProvider = data_provider.DataProvider;
|
||||||
pub const VirtualListState = state_mod.VirtualListState;
|
pub const VirtualAdvancedTableState = state_mod.VirtualAdvancedTableState;
|
||||||
|
|
||||||
/// Resultado de renderizar el VirtualList
|
/// Resultado de renderizar el VirtualAdvancedTable
|
||||||
pub const VirtualListResult = struct {
|
pub const VirtualAdvancedTableResult = struct {
|
||||||
/// La selección cambió este frame
|
/// La selección cambió este frame
|
||||||
selection_changed: bool = false,
|
selection_changed: bool = false,
|
||||||
|
|
||||||
|
|
@ -81,26 +83,26 @@ pub const VirtualListResult = struct {
|
||||||
// Widget principal
|
// Widget principal
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/// Renderiza un VirtualList
|
/// Renderiza un VirtualAdvancedTable
|
||||||
pub fn virtualList(
|
pub fn virtualAdvancedTable(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
provider: DataProvider,
|
provider: DataProvider,
|
||||||
config: VirtualListConfig,
|
config: VirtualAdvancedTableConfig,
|
||||||
) VirtualListResult {
|
) VirtualAdvancedTableResult {
|
||||||
const bounds = ctx.layout.nextRect();
|
const bounds = ctx.layout.nextRect();
|
||||||
return virtualListRect(ctx, bounds, list_state, provider, config);
|
return virtualAdvancedTableRect(ctx, bounds, list_state, provider, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renderiza un VirtualList en un rectángulo específico
|
/// Renderiza un VirtualAdvancedTable en un rectángulo específico
|
||||||
pub fn virtualListRect(
|
pub fn virtualAdvancedTableRect(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
bounds: Layout.Rect,
|
bounds: Layout.Rect,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
provider: DataProvider,
|
provider: DataProvider,
|
||||||
config: VirtualListConfig,
|
config: VirtualAdvancedTableConfig,
|
||||||
) VirtualListResult {
|
) VirtualAdvancedTableResult {
|
||||||
var result = VirtualListResult{};
|
var result = VirtualAdvancedTableResult{};
|
||||||
|
|
||||||
if (bounds.isEmpty() or config.columns.len == 0) return result;
|
if (bounds.isEmpty() or config.columns.len == 0) return result;
|
||||||
|
|
||||||
|
|
@ -108,7 +110,7 @@ pub fn virtualListRect(
|
||||||
list_state.resetFrameFlags();
|
list_state.resetFrameFlags();
|
||||||
|
|
||||||
// Get colors
|
// Get colors
|
||||||
const colors = config.colors orelse VirtualListConfig.Colors{};
|
const colors = config.colors orelse VirtualAdvancedTableConfig.Colors{};
|
||||||
|
|
||||||
// Generate unique ID for focus system
|
// Generate unique ID for focus system
|
||||||
const widget_id: u64 = @intFromPtr(list_state);
|
const widget_id: u64 = @intFromPtr(list_state);
|
||||||
|
|
@ -284,7 +286,7 @@ pub fn virtualListRect(
|
||||||
// Helper: Check if refetch needed
|
// Helper: Check if refetch needed
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
fn needsRefetch(list_state: *const VirtualListState, visible_rows: usize, buffer_size: usize) bool {
|
fn needsRefetch(list_state: *const VirtualAdvancedTableState, visible_rows: usize, buffer_size: usize) bool {
|
||||||
// First load
|
// First load
|
||||||
if (list_state.current_window.len == 0) return true;
|
if (list_state.current_window.len == 0) return true;
|
||||||
|
|
||||||
|
|
@ -309,9 +311,9 @@ fn drawFilterBar(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
bounds: Layout.Rect,
|
bounds: Layout.Rect,
|
||||||
config: FilterBarConfig,
|
config: FilterBarConfig,
|
||||||
colors: *const VirtualListConfig.Colors,
|
colors: *const VirtualAdvancedTableConfig.Colors,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
result: *VirtualListResult,
|
result: *VirtualAdvancedTableResult,
|
||||||
) void {
|
) void {
|
||||||
const padding: i32 = 6;
|
const padding: i32 = 6;
|
||||||
const chip_h: u32 = 22;
|
const chip_h: u32 = 22;
|
||||||
|
|
@ -541,10 +543,10 @@ fn drawHeaderAt(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
bounds: Layout.Rect,
|
bounds: Layout.Rect,
|
||||||
header_y: i32,
|
header_y: i32,
|
||||||
config: VirtualListConfig,
|
config: VirtualAdvancedTableConfig,
|
||||||
colors: *const VirtualListConfig.Colors,
|
colors: *const VirtualAdvancedTableConfig.Colors,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
result: *VirtualListResult,
|
result: *VirtualAdvancedTableResult,
|
||||||
scroll_offset_x: i32,
|
scroll_offset_x: i32,
|
||||||
) void {
|
) void {
|
||||||
const header_h = config.row_height;
|
const header_h = config.row_height;
|
||||||
|
|
@ -621,11 +623,11 @@ fn drawHeaderAt(
|
||||||
fn drawRows(
|
fn drawRows(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
content_bounds: Layout.Rect,
|
content_bounds: Layout.Rect,
|
||||||
config: VirtualListConfig,
|
config: VirtualAdvancedTableConfig,
|
||||||
colors: *const VirtualListConfig.Colors,
|
colors: *const VirtualAdvancedTableConfig.Colors,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
visible_rows: usize,
|
visible_rows: usize,
|
||||||
result: *VirtualListResult,
|
result: *VirtualAdvancedTableResult,
|
||||||
scroll_offset_x: i32,
|
scroll_offset_x: i32,
|
||||||
) void {
|
) void {
|
||||||
_ = result;
|
_ = result;
|
||||||
|
|
@ -698,8 +700,8 @@ fn drawRows(
|
||||||
fn drawFooter(
|
fn drawFooter(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
bounds: Layout.Rect,
|
bounds: Layout.Rect,
|
||||||
colors: *const VirtualListConfig.Colors,
|
colors: *const VirtualAdvancedTableConfig.Colors,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
) void {
|
) void {
|
||||||
// Background
|
// Background
|
||||||
ctx.pushCommand(Command.rect(
|
ctx.pushCommand(Command.rect(
|
||||||
|
|
@ -748,10 +750,10 @@ fn drawScrollbar(
|
||||||
bounds: Layout.Rect,
|
bounds: Layout.Rect,
|
||||||
header_h: u32,
|
header_h: u32,
|
||||||
footer_h: u32,
|
footer_h: u32,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
visible_rows: usize,
|
visible_rows: usize,
|
||||||
total_rows: usize,
|
total_rows: usize,
|
||||||
colors: *const VirtualListConfig.Colors,
|
colors: *const VirtualAdvancedTableConfig.Colors,
|
||||||
) void {
|
) void {
|
||||||
const scrollbar_w: u32 = 12;
|
const scrollbar_w: u32 = 12;
|
||||||
const content_h = bounds.h -| header_h -| footer_h;
|
const content_h = bounds.h -| header_h -| footer_h;
|
||||||
|
|
@ -785,7 +787,7 @@ fn drawScrollbarH(
|
||||||
scroll_offset_x: i32,
|
scroll_offset_x: i32,
|
||||||
max_scroll_x: i32,
|
max_scroll_x: i32,
|
||||||
available_width: u32,
|
available_width: u32,
|
||||||
colors: *const VirtualListConfig.Colors,
|
colors: *const VirtualAdvancedTableConfig.Colors,
|
||||||
) void {
|
) void {
|
||||||
const scrollbar_v_w: u32 = 12; // Width of vertical scrollbar area
|
const scrollbar_v_w: u32 = 12; // Width of vertical scrollbar area
|
||||||
|
|
||||||
|
|
@ -817,12 +819,12 @@ fn drawScrollbarH(
|
||||||
|
|
||||||
fn handleKeyboard(
|
fn handleKeyboard(
|
||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
provider: DataProvider,
|
provider: DataProvider,
|
||||||
visible_rows: usize,
|
visible_rows: usize,
|
||||||
total_rows: usize,
|
total_rows: usize,
|
||||||
max_scroll_x: i32,
|
max_scroll_x: i32,
|
||||||
result: *VirtualListResult,
|
result: *VirtualAdvancedTableResult,
|
||||||
) void {
|
) void {
|
||||||
_ = provider;
|
_ = provider;
|
||||||
_ = result;
|
_ = result;
|
||||||
|
|
@ -860,9 +862,9 @@ fn handleMouseClick(
|
||||||
bounds: Layout.Rect,
|
bounds: Layout.Rect,
|
||||||
filter_bar_h: u32,
|
filter_bar_h: u32,
|
||||||
header_h: u32,
|
header_h: u32,
|
||||||
config: VirtualListConfig,
|
config: VirtualAdvancedTableConfig,
|
||||||
list_state: *VirtualListState,
|
list_state: *VirtualAdvancedTableState,
|
||||||
result: *VirtualListResult,
|
result: *VirtualAdvancedTableResult,
|
||||||
) void {
|
) void {
|
||||||
_ = result;
|
_ = result;
|
||||||
|
|
||||||
|
|
@ -892,15 +894,15 @@ fn handleMouseClick(
|
||||||
// Tests
|
// Tests
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
test "virtual_list module imports" {
|
test "virtual_advanced_table module imports" {
|
||||||
_ = types;
|
_ = types;
|
||||||
_ = data_provider;
|
_ = data_provider;
|
||||||
_ = state_mod;
|
_ = state_mod;
|
||||||
_ = RowData;
|
_ = RowData;
|
||||||
_ = ColumnDef;
|
_ = ColumnDef;
|
||||||
_ = DataProvider;
|
_ = DataProvider;
|
||||||
_ = VirtualListState;
|
_ = VirtualAdvancedTableState;
|
||||||
_ = VirtualListResult;
|
_ = VirtualAdvancedTableResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
|
@ -41,7 +41,7 @@ pub const canvas = @import("canvas.zig");
|
||||||
pub const chart = @import("chart.zig");
|
pub const chart = @import("chart.zig");
|
||||||
pub const icon = @import("icon.zig");
|
pub const icon = @import("icon.zig");
|
||||||
pub const virtual_scroll = @import("virtual_scroll.zig");
|
pub const virtual_scroll = @import("virtual_scroll.zig");
|
||||||
pub const virtual_list = @import("virtual_list/virtual_list.zig");
|
pub const virtual_advanced_table = @import("virtual_advanced_table/virtual_advanced_table.zig");
|
||||||
|
|
||||||
// Gio parity widgets (Phase 1)
|
// Gio parity widgets (Phase 1)
|
||||||
pub const switch_widget = @import("switch.zig");
|
pub const switch_widget = @import("switch.zig");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue