diff --git a/src/core/window.zig b/src/core/window.zig index c20342e..6b0385a 100644 --- a/src/core/window.zig +++ b/src/core/window.zig @@ -11,6 +11,7 @@ const std = @import("std"); const Context = @import("context.zig").Context; const Layout = @import("layout.zig"); const Rect = Layout.Rect; +const Input = @import("input.zig"); // ============================================================================= // Panel Interface (con contexto opaco) @@ -32,6 +33,9 @@ pub const PanelInfo = struct { preferred_zone: Zone = .center, /// Tecla de acceso rápido: Ctrl+focus_key (1-9, null = sin atajo) 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 @@ -45,19 +49,14 @@ pub const Zone = enum { }; /// Evento simplificado para paneles +/// Usa Input.KeyEvent de core/input.zig para compatibilidad pub const Event = union(enum) { - key: KeyEvent, + key: Input.KeyEvent, mouse: MouseEvent, resize: ResizeEvent, text_input: TextInputEvent, quit, - pub const KeyEvent = struct { - key: u32, - pressed: bool, - modifiers: Modifiers, - }; - pub const MouseEvent = struct { x: i32, y: i32, @@ -77,11 +76,8 @@ pub const Event = union(enum) { pub const MouseButton = enum { left, middle, right }; - pub const Modifiers = struct { - ctrl: bool = false, - shift: bool = false, - alt: bool = false, - }; + // Re-export KeyEvent para acceso uniforme + pub const KeyEvent = Input.KeyEvent; }; /// Interface Panel con contexto opaco (desacoplado de aplicación) @@ -199,8 +195,9 @@ pub const WindowState = struct { /// Identificador de la ventana id: []const u8, - /// Lista de paneles (BoundedArray - sin allocations dinámicas) - panels: std.BoundedArray(Panel, MAX_PANELS), + /// Lista de paneles (array estático + contador - sin allocations dinámicas) + panels_arr: [MAX_PANELS]Panel, + panels_len: usize, /// Rectángulos para cada panel (actualizados externamente por layout) rects: [MAX_PANELS]Rect, @@ -217,7 +214,8 @@ pub const WindowState = struct { pub fn init(id: []const u8, base_focus_group: u64) Self { return .{ .id = id, - .panels = .{}, + .panels_arr = undefined, + .panels_len = 0, .rects = [_]Rect{.{ .x = 0, .y = 0, .w = 0, .h = 0 }} ** MAX_PANELS, .focused_idx = 0, .base_focus_group = base_focus_group, @@ -226,12 +224,19 @@ pub const WindowState = struct { /// Añade un panel a la ventana 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) 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| { self.rects[i] = rects[i]; } @@ -240,7 +245,7 @@ pub const WindowState = struct { /// Dibuja todos los paneles - EL ID VIAJA CON EL PANEL /// Elimina errores de mismatch de IDs por construcción 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 rect = self.rects[i]; @@ -256,17 +261,17 @@ pub const WindowState = struct { /// Mueve el foco al siguiente panel (F6) 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 - const current = self.panels.slice()[self.focused_idx]; + const current = self.panels()[self.focused_idx]; current.onBlur(null); // 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 - const next = self.panels.slice()[self.focused_idx]; + const next = self.panels()[self.focused_idx]; next.onFocus(null); // Actualizar focus group activo @@ -275,17 +280,17 @@ pub const WindowState = struct { /// Mueve el foco al panel anterior (Shift+F6) 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 - const current = self.panels.slice()[self.focused_idx]; + const current = self.panels()[self.focused_idx]; current.onBlur(null); // 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 - const prev = self.panels.slice()[self.focused_idx]; + const prev = self.panels()[self.focused_idx]; prev.onFocus(null); // Actualizar focus group activo @@ -294,17 +299,17 @@ pub const WindowState = struct { /// Enfoca un panel por índice (Ctrl+1, Ctrl+2, etc.) 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 - const current = self.panels.slice()[self.focused_idx]; + const current = self.panels()[self.focused_idx]; current.onBlur(null); // Cambiar índice self.focused_idx = idx; // Notificar focus al nuevo panel - const target = self.panels.slice()[self.focused_idx]; + const target = self.panels()[self.focused_idx]; target.onFocus(null); // Actualizar focus group activo @@ -313,19 +318,19 @@ pub const WindowState = struct { /// Obtiene el panel actualmente enfocado pub fn getFocusedPanel(self: *Self) ?Panel { - if (self.panels.len == 0) return null; - return self.panels.slice()[self.focused_idx]; + if (self.panels_len == 0) return null; + return self.panels()[self.focused_idx]; } /// Despacha un evento al panel enfocado pub fn handleEvent(self: *Self, event: Event, app_ctx: ?*anyopaque) bool { - if (self.panels.len == 0) return false; - const focused = self.panels.slice()[self.focused_idx]; + if (self.panels_len == 0) return false; + const focused = self.panels()[self.focused_idx]; return focused.handleEvent(event, app_ctx); } /// Número de paneles en la ventana pub fn panelCount(self: *const Self) usize { - return self.panels.len; + return self.panels_len; } }; diff --git a/src/zcatgui.zig b/src/zcatgui.zig index 3adcfb7..efe5b61 100644 --- a/src/zcatgui.zig +++ b/src/zcatgui.zig @@ -69,6 +69,15 @@ pub const SwipeDirection = gesture.SwipeDirection; // Window system (paneles dinámicos) pub const window = @import("core/window.zig"); 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 WindowPanelInfo = window.PanelInfo; pub const makeWindowPanel = window.makePanel;