pub const UnknownTabError = error.UnknownTab; pub const AppState = struct { allocator: std.mem.Allocator, currentTab: *Tab = undefined, tabs: std.ArrayList(*Tab), currentTabChanged: Observable(*Tab), tabChildrenLoaded: Observable(*Tab), pub fn init(allocator: std.mem.Allocator) AppState { return .{ .allocator = allocator, .tabs = std.ArrayList(*Tab).init(allocator), .currentTabChanged = Observable(*Tab).init(allocator), .tabChildrenLoaded = Observable(*Tab).init(allocator), }; } pub fn addTab(self: *AppState, tab: *Tab) !void { try self.tabs.append(tab); const tabChildrenLoadedHandlerObserver = try tab.childrenLoaded.allocator.create(Observer(*Tab)); tabChildrenLoadedHandlerObserver.* = Observer(*Tab){ .ctx = @ptrCast(@alignCast(self)), .update = tabChildrenLoadedHandler, }; try tab.childrenLoaded.attach(tabChildrenLoadedHandlerObserver); } pub fn setCurrentTab(self: *AppState, newTab: *Tab) !void { blk: { for (self.tabs.items) |item| { if (item == newTab) break :blk; } return UnknownTabError; } self.currentTab = newTab; self.currentTabChanged.notify(newTab); } pub fn removeTab(self: *AppState, tab: *Tab) void { const index = for (tab.childrenLoaded.observers, 0..) |observer, i| { if (observer.ctx == self) break i; } else null; if (index) |i| { tab.childrenLoaded.observers.swapRemove(i); } //TODO: remove from tabs } pub fn deinit(self: *AppState) void { self.tabChildrenLoaded.deinit(); self.currentTabChanged.deinit(); for (self.tabs.items) |tab| { tab.deinit(); } self.tabs.deinit(); } fn tabChildrenLoadedHandler(ctx: *anyopaque, tab: *Tab) void { const self: *AppState = @ptrCast(@alignCast(ctx)); self.tabChildrenLoaded.notify(tab); } }; const std = @import("std"); const Tab = @import("tab/tab.zig").Tab; const Observable = @import("observable.zig").Observable; const Observer = @import("observable.zig").Observer;