feat(window): Unificar tipos Panel con Input.KeyEvent

- Event.KeyEvent ahora re-exporta Input.KeyEvent (unificación tipos)
- Añadir burst_sensitive a PanelInfo (para supresión ráfagas)
- Exportar Panel, PanelInfo, Zone, Event, makePanel desde raíz
- Mantener aliases WindowPanel/WindowPanelInfo para compatibilidad

Esta unificación permite que zsimifactu use WindowState de zcatgui
directamente, ya que Panel y Event son ahora el mismo tipo.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
R.Eugenio 2026-01-04 22:31:47 +01:00
parent 067bac47fd
commit cead6bf26f
2 changed files with 48 additions and 34 deletions

View file

@ -11,6 +11,7 @@ const std = @import("std");
const Context = @import("context.zig").Context; const Context = @import("context.zig").Context;
const Layout = @import("layout.zig"); const Layout = @import("layout.zig");
const Rect = Layout.Rect; const Rect = Layout.Rect;
const Input = @import("input.zig");
// ============================================================================= // =============================================================================
// Panel Interface (con contexto opaco) // Panel Interface (con contexto opaco)
@ -32,6 +33,9 @@ pub const PanelInfo = struct {
preferred_zone: Zone = .center, preferred_zone: Zone = .center,
/// Tecla de acceso rápido: Ctrl+focus_key (1-9, null = sin atajo) /// Tecla de acceso rápido: Ctrl+focus_key (1-9, null = sin atajo)
focus_key: ?u8 = null, focus_key: ?u8 = null,
/// Sensibilidad a ráfagas: si true, el panel se auto-suprime durante navegación rápida
/// Paneles de navegación principal (who_list, who_detail) deben ser false
burst_sensitive: bool = true,
}; };
/// Zonas de layout disponibles /// Zonas de layout disponibles
@ -45,19 +49,14 @@ pub const Zone = enum {
}; };
/// Evento simplificado para paneles /// Evento simplificado para paneles
/// Usa Input.KeyEvent de core/input.zig para compatibilidad
pub const Event = union(enum) { pub const Event = union(enum) {
key: KeyEvent, key: Input.KeyEvent,
mouse: MouseEvent, mouse: MouseEvent,
resize: ResizeEvent, resize: ResizeEvent,
text_input: TextInputEvent, text_input: TextInputEvent,
quit, quit,
pub const KeyEvent = struct {
key: u32,
pressed: bool,
modifiers: Modifiers,
};
pub const MouseEvent = struct { pub const MouseEvent = struct {
x: i32, x: i32,
y: i32, y: i32,
@ -77,11 +76,8 @@ pub const Event = union(enum) {
pub const MouseButton = enum { left, middle, right }; pub const MouseButton = enum { left, middle, right };
pub const Modifiers = struct { // Re-export KeyEvent para acceso uniforme
ctrl: bool = false, pub const KeyEvent = Input.KeyEvent;
shift: bool = false,
alt: bool = false,
};
}; };
/// Interface Panel con contexto opaco (desacoplado de aplicación) /// Interface Panel con contexto opaco (desacoplado de aplicación)
@ -199,8 +195,9 @@ pub const WindowState = struct {
/// Identificador de la ventana /// Identificador de la ventana
id: []const u8, id: []const u8,
/// Lista de paneles (BoundedArray - sin allocations dinámicas) /// Lista de paneles (array estático + contador - sin allocations dinámicas)
panels: std.BoundedArray(Panel, MAX_PANELS), panels_arr: [MAX_PANELS]Panel,
panels_len: usize,
/// Rectángulos para cada panel (actualizados externamente por layout) /// Rectángulos para cada panel (actualizados externamente por layout)
rects: [MAX_PANELS]Rect, rects: [MAX_PANELS]Rect,
@ -217,7 +214,8 @@ pub const WindowState = struct {
pub fn init(id: []const u8, base_focus_group: u64) Self { pub fn init(id: []const u8, base_focus_group: u64) Self {
return .{ return .{
.id = id, .id = id,
.panels = .{}, .panels_arr = undefined,
.panels_len = 0,
.rects = [_]Rect{.{ .x = 0, .y = 0, .w = 0, .h = 0 }} ** MAX_PANELS, .rects = [_]Rect{.{ .x = 0, .y = 0, .w = 0, .h = 0 }} ** MAX_PANELS,
.focused_idx = 0, .focused_idx = 0,
.base_focus_group = base_focus_group, .base_focus_group = base_focus_group,
@ -226,12 +224,19 @@ pub const WindowState = struct {
/// Añade un panel a la ventana /// Añade un panel a la ventana
pub fn addPanel(self: *Self, panel: Panel) error{Overflow}!void { pub fn addPanel(self: *Self, panel: Panel) error{Overflow}!void {
try self.panels.append(panel); if (self.panels_len >= MAX_PANELS) return error.Overflow;
self.panels_arr[self.panels_len] = panel;
self.panels_len += 1;
}
/// Obtiene slice de paneles
pub fn panels(self: *Self) []Panel {
return self.panels_arr[0..self.panels_len];
} }
/// Actualiza los rectángulos de los paneles (llamado por layout externo) /// Actualiza los rectángulos de los paneles (llamado por layout externo)
pub fn updateRects(self: *Self, rects: []const Rect) void { pub fn updateRects(self: *Self, rects: []const Rect) void {
const len = @min(rects.len, self.panels.len); const len = @min(rects.len, self.panels_len);
for (0..len) |i| { for (0..len) |i| {
self.rects[i] = rects[i]; self.rects[i] = rects[i];
} }
@ -240,7 +245,7 @@ pub const WindowState = struct {
/// Dibuja todos los paneles - EL ID VIAJA CON EL PANEL /// Dibuja todos los paneles - EL ID VIAJA CON EL PANEL
/// Elimina errores de mismatch de IDs por construcción /// Elimina errores de mismatch de IDs por construcción
pub fn draw(self: *Self, ctx: *Context, app_ctx: ?*anyopaque) void { pub fn draw(self: *Self, ctx: *Context, app_ctx: ?*anyopaque) void {
for (self.panels.slice(), 0..) |panel, i| { for (self.panels(), 0..) |panel, i| {
const info = panel.getInfo(); const info = panel.getInfo();
const rect = self.rects[i]; const rect = self.rects[i];
@ -256,17 +261,17 @@ pub const WindowState = struct {
/// Mueve el foco al siguiente panel (F6) /// Mueve el foco al siguiente panel (F6)
pub fn focusNext(self: *Self, ctx: *Context) void { pub fn focusNext(self: *Self, ctx: *Context) void {
if (self.panels.len == 0) return; if (self.panels_len == 0) return;
// Notificar blur al panel actual // Notificar blur al panel actual
const current = self.panels.slice()[self.focused_idx]; const current = self.panels()[self.focused_idx];
current.onBlur(null); current.onBlur(null);
// Mover al siguiente // Mover al siguiente
self.focused_idx = (self.focused_idx + 1) % self.panels.len; self.focused_idx = (self.focused_idx + 1) % self.panels_len;
// Notificar focus al nuevo panel // Notificar focus al nuevo panel
const next = self.panels.slice()[self.focused_idx]; const next = self.panels()[self.focused_idx];
next.onFocus(null); next.onFocus(null);
// Actualizar focus group activo // Actualizar focus group activo
@ -275,17 +280,17 @@ pub const WindowState = struct {
/// Mueve el foco al panel anterior (Shift+F6) /// Mueve el foco al panel anterior (Shift+F6)
pub fn focusPrev(self: *Self, ctx: *Context) void { pub fn focusPrev(self: *Self, ctx: *Context) void {
if (self.panels.len == 0) return; if (self.panels_len == 0) return;
// Notificar blur al panel actual // Notificar blur al panel actual
const current = self.panels.slice()[self.focused_idx]; const current = self.panels()[self.focused_idx];
current.onBlur(null); current.onBlur(null);
// Mover al anterior // Mover al anterior
self.focused_idx = if (self.focused_idx == 0) self.panels.len - 1 else self.focused_idx - 1; self.focused_idx = if (self.focused_idx == 0) self.panels_len - 1 else self.focused_idx - 1;
// Notificar focus al nuevo panel // Notificar focus al nuevo panel
const prev = self.panels.slice()[self.focused_idx]; const prev = self.panels()[self.focused_idx];
prev.onFocus(null); prev.onFocus(null);
// Actualizar focus group activo // Actualizar focus group activo
@ -294,17 +299,17 @@ pub const WindowState = struct {
/// Enfoca un panel por índice (Ctrl+1, Ctrl+2, etc.) /// Enfoca un panel por índice (Ctrl+1, Ctrl+2, etc.)
pub fn focusByIndex(self: *Self, ctx: *Context, idx: usize) void { pub fn focusByIndex(self: *Self, ctx: *Context, idx: usize) void {
if (idx >= self.panels.len) return; if (idx >= self.panels_len) return;
// Notificar blur al panel actual // Notificar blur al panel actual
const current = self.panels.slice()[self.focused_idx]; const current = self.panels()[self.focused_idx];
current.onBlur(null); current.onBlur(null);
// Cambiar índice // Cambiar índice
self.focused_idx = idx; self.focused_idx = idx;
// Notificar focus al nuevo panel // Notificar focus al nuevo panel
const target = self.panels.slice()[self.focused_idx]; const target = self.panels()[self.focused_idx];
target.onFocus(null); target.onFocus(null);
// Actualizar focus group activo // Actualizar focus group activo
@ -313,19 +318,19 @@ pub const WindowState = struct {
/// Obtiene el panel actualmente enfocado /// Obtiene el panel actualmente enfocado
pub fn getFocusedPanel(self: *Self) ?Panel { pub fn getFocusedPanel(self: *Self) ?Panel {
if (self.panels.len == 0) return null; if (self.panels_len == 0) return null;
return self.panels.slice()[self.focused_idx]; return self.panels()[self.focused_idx];
} }
/// Despacha un evento al panel enfocado /// Despacha un evento al panel enfocado
pub fn handleEvent(self: *Self, event: Event, app_ctx: ?*anyopaque) bool { pub fn handleEvent(self: *Self, event: Event, app_ctx: ?*anyopaque) bool {
if (self.panels.len == 0) return false; if (self.panels_len == 0) return false;
const focused = self.panels.slice()[self.focused_idx]; const focused = self.panels()[self.focused_idx];
return focused.handleEvent(event, app_ctx); return focused.handleEvent(event, app_ctx);
} }
/// Número de paneles en la ventana /// Número de paneles en la ventana
pub fn panelCount(self: *const Self) usize { pub fn panelCount(self: *const Self) usize {
return self.panels.len; return self.panels_len;
} }
}; };

View file

@ -69,6 +69,15 @@ pub const SwipeDirection = gesture.SwipeDirection;
// Window system (paneles dinámicos) // Window system (paneles dinámicos)
pub const window = @import("core/window.zig"); pub const window = @import("core/window.zig");
pub const WindowState = window.WindowState; pub const WindowState = window.WindowState;
// Panel types - usados por aplicaciones para definir paneles
pub const Panel = window.Panel;
pub const PanelInfo = window.PanelInfo;
pub const Zone = window.Zone;
pub const Event = window.Event;
pub const makePanel = window.makePanel;
// Aliases legacy (deprecated - usar los de arriba)
pub const WindowPanel = window.Panel; pub const WindowPanel = window.Panel;
pub const WindowPanelInfo = window.PanelInfo; pub const WindowPanelInfo = window.PanelInfo;
pub const makeWindowPanel = window.makePanel; pub const makeWindowPanel = window.makePanel;