-
Notifications
You must be signed in to change notification settings - Fork 1
State Management
Go-gui's state model has two layers: a per-window typed slot for application state, and
an internal per-widget state map used by the framework itself. Both live in the Window
— there are no globals, no singletons, and no hidden shared mutable state.
Each window holds exactly one typed state slot. Declare the struct that represents your application's state, pass a pointer to it when creating the window, and retrieve it anywhere with a generic accessor:
type App struct {
Count int
Query string
Results []string
}
w := gui.NewWindow(gui.WindowCfg{
Title: "My App",
State: &App{},
})Inside any view function or event callback:
a := gui.State[App](w)
a.Count++gui.State[T](w) is a type-assertion — it panics if the wrong type is passed. This is
intentional: it catches mismatches at startup during development, not silently at runtime.
Rules:
- One type per window. All state for that window goes into that struct.
- The view function reads from the struct; callbacks write to it; the next frame reflects the new values. No notify/subscribe step is needed.
- Multiple windows each have their own independent slot — no cross-window shared state unless you manage it yourself (a shared pointer in the structs is fine).
Each window is self-contained. Tests can create windows with different state without
interfering with each other. Multi-window applications are straightforward: each window
has its own State[T] slot and the two can communicate only through explicit shared
pointers, channels, or callbacks — never through hidden framework machinery.
The framework uses a keyed map per window to store widget-internal state that persists across frames: scroll offsets, input cursor positions, animation progress, and so on.
// Internal framework usage (illustration):
sy := StateMap[uint32, float32](w, nsScrollY, capScroll)
offset, ok := sy.Get(idScroll)
sy.Set(idScroll, newOffset)StateMap[K, V](w, namespace, capacity) returns a bounded map scoped to a string
namespace. The capacity is a hard ceiling — the map evicts the oldest entry when full,
preventing unbounded memory growth in long-running applications with dynamically-created
widget IDs.
Framework namespaces (nsScrollX, nsScrollY, nsInput, etc.) are internal and
unexported. You can use StateMap in your own code with your own namespace strings:
type HoverState struct{ HoverTime float32 }
// Per-row hover tracking in a list:
hm := gui.StateMap[string, HoverState](w, "my-hover", 256)
hs, _ := hm.Get(rowID)In practice, most application code never touches StateMap directly — gui.State[T]
covers nearly all use cases. StateMap is useful when you need per-widget-instance state
that is indexed by a dynamic key (row IDs, tab IDs, etc.) rather than a single top-level
struct.
Getting Started
Widgets
Layout & Interaction
Visuals
Reference