From d3443d4be9f5622d24298f0ec76f443237f00d41 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 20:31:56 +0000 Subject: [PATCH] chore(gui): add AX usage examples --- pkg/display/display.go | 4 ++++ pkg/display/interfaces.go | 2 ++ pkg/display/messages.go | 3 +++ pkg/screen/messages.go | 6 +++++ pkg/screen/platform.go | 4 ++++ pkg/screen/service.go | 5 ++++ pkg/webview/service.go | 3 +++ pkg/window/messages.go | 50 +++++++++++++++++++++++++++++++++++++++ pkg/window/platform.go | 4 ++++ pkg/window/register.go | 1 + pkg/window/service.go | 4 ++++ pkg/window/state.go | 15 ++++++++++++ pkg/window/window.go | 13 ++++++++++ 13 files changed, 114 insertions(+) diff --git a/pkg/display/display.go b/pkg/display/display.go index 59c9b80..7286722 100644 --- a/pkg/display/display.go +++ b/pkg/display/display.go @@ -30,6 +30,7 @@ import ( ) // Options holds configuration for the display service. +// Use: svc, err := display.NewService() type Options struct{} // WindowInfo is an alias for window.WindowInfo (backward compatibility). @@ -41,6 +42,7 @@ type LayoutSuggestion = window.LayoutSuggestion // Service manages windowing, dialogs, and other visual elements. // It orchestrates sub-services (window, systray, menu) via IPC and bridges // IPC actions to WebSocket events for TypeScript apps. +// Use: svc, err := display.NewService() type Service struct { *core.ServiceRuntime[Options] wailsApp *application.App @@ -64,6 +66,7 @@ func NewService() (*Service, error) { } // Deprecated: use NewService. +// Use: svc, err := display.New() func New() (*Service, error) { return NewService() } @@ -1436,6 +1439,7 @@ func (s *Service) GetSavedWindowStates() map[string]window.WindowState { } // CreateWindowOptions contains options for creating a new window. +// Use: opts := display.CreateWindowOptions{Name: "editor", URL: "/editor"} type CreateWindowOptions struct { Name string `json:"name"` Title string `json:"title,omitempty"` diff --git a/pkg/display/interfaces.go b/pkg/display/interfaces.go index 80dd1f8..ccb96bf 100644 --- a/pkg/display/interfaces.go +++ b/pkg/display/interfaces.go @@ -5,12 +5,14 @@ import "github.com/wailsapp/wails/v3/pkg/application" // App abstracts the Wails application for the display orchestrator. // The service uses Logger() for diagnostics and Quit() for shutdown. +// Use: var app display.App type App interface { Logger() Logger Quit() } // Logger wraps Wails logging. +// Use: var logger display.Logger type Logger interface { Info(message string, args ...any) } diff --git a/pkg/display/messages.go b/pkg/display/messages.go index 632e04a..3cd9044 100644 --- a/pkg/display/messages.go +++ b/pkg/display/messages.go @@ -4,14 +4,17 @@ package display // ActionIDECommand is broadcast when a menu handler triggers an IDE command // (save, run, build). Replaces direct s.app.Event().Emit("ide:*") calls. // Listeners (e.g. editor windows) handle this via HandleIPCEvents. +// Use: _ = c.ACTION(display.ActionIDECommand{Command: "save"}) type ActionIDECommand struct { Command string `json:"command"` // "save", "run", "build" } // EventIDECommand is the WS event type for IDE commands. +// Use: eventType := display.EventIDECommand const EventIDECommand EventType = "ide.command" // Theme is the display-level theme summary exposed by the service API. +// Use: theme := display.Theme{IsDark: true} type Theme struct { IsDark bool `json:"isDark"` } diff --git a/pkg/screen/messages.go b/pkg/screen/messages.go index 07cc071..cd9195d 100644 --- a/pkg/screen/messages.go +++ b/pkg/screen/messages.go @@ -2,19 +2,25 @@ package screen // QueryAll returns all screens. Result: []Screen +// Use: result, _, err := c.QUERY(screen.QueryAll{}) type QueryAll struct{} // QueryPrimary returns the primary screen. Result: *Screen (nil if not found) +// Use: result, _, err := c.QUERY(screen.QueryPrimary{}) type QueryPrimary struct{} // QueryByID returns a screen by ID. Result: *Screen (nil if not found) +// Use: result, _, err := c.QUERY(screen.QueryByID{ID: "display-1"}) type QueryByID struct{ ID string } // QueryAtPoint returns the screen containing a point. Result: *Screen (nil if none) +// Use: result, _, err := c.QUERY(screen.QueryAtPoint{X: 100, Y: 100}) type QueryAtPoint struct{ X, Y int } // QueryWorkAreas returns work areas for all screens. Result: []Rect +// Use: result, _, err := c.QUERY(screen.QueryWorkAreas{}) type QueryWorkAreas struct{} // ActionScreensChanged is broadcast when displays change. +// Use: _ = c.ACTION(screen.ActionScreensChanged{Screens: screens}) type ActionScreensChanged struct{ Screens []Screen } diff --git a/pkg/screen/platform.go b/pkg/screen/platform.go index 97d950d..59c6324 100644 --- a/pkg/screen/platform.go +++ b/pkg/screen/platform.go @@ -2,12 +2,14 @@ package screen // Platform abstracts the screen/display backend. +// Use: var p screen.Platform type Platform interface { GetAll() []Screen GetPrimary() *Screen } // Screen describes a display/monitor. +// Use: scr := screen.Screen{ID: "display-1"} type Screen struct { ID string `json:"id"` Name string `json:"name"` @@ -20,6 +22,7 @@ type Screen struct { } // Rect represents a rectangle with position and dimensions. +// Use: rect := screen.Rect{X: 0, Y: 0, Width: 1920, Height: 1080} type Rect struct { X int `json:"x"` Y int `json:"y"` @@ -28,6 +31,7 @@ type Rect struct { } // Size represents dimensions. +// Use: size := screen.Size{Width: 1920, Height: 1080} type Size struct { Width int `json:"width"` Height int `json:"height"` diff --git a/pkg/screen/service.go b/pkg/screen/service.go index 29db455..e81fc18 100644 --- a/pkg/screen/service.go +++ b/pkg/screen/service.go @@ -8,15 +8,18 @@ import ( ) // Options holds configuration for the screen service. +// Use: svc, err := screen.Register(platform)(core.New()) type Options struct{} // Service is a core.Service providing screen/display queries via IPC. +// Use: svc, err := screen.Register(platform)(core.New()) type Service struct { *core.ServiceRuntime[Options] platform Platform } // Register creates a factory closure that captures the Platform adapter. +// Use: core.WithService(screen.Register(platform)) func Register(p Platform) func(*core.Core) (any, error) { return func(c *core.Core) (any, error) { return &Service{ @@ -27,12 +30,14 @@ func Register(p Platform) func(*core.Core) (any, error) { } // OnStartup registers IPC handlers. +// Use: _ = svc.OnStartup(context.Background()) func (s *Service) OnStartup(ctx context.Context) error { s.Core().RegisterQuery(s.handleQuery) return nil } // HandleIPCEvents is auto-discovered by core.WithService. +// Use: _ = svc.HandleIPCEvents(core, msg) func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error { return nil } diff --git a/pkg/webview/service.go b/pkg/webview/service.go index 792f5fd..9bfccde 100644 --- a/pkg/webview/service.go +++ b/pkg/webview/service.go @@ -49,6 +49,7 @@ type connector interface { } // Options holds configuration for the webview service. +// Use: svc, err := webview.Register()(core.New()) type Options struct { DebugURL string // Chrome debug endpoint (default: "http://localhost:9222") Timeout time.Duration // Operation timeout (default: 30s) @@ -56,6 +57,7 @@ type Options struct { } // Service is a core.Service managing webview interactions via IPC. +// Use: svc, err := webview.Register()(core.New()) type Service struct { *core.ServiceRuntime[Options] opts Options @@ -67,6 +69,7 @@ type Service struct { } // Register creates a factory closure with the given options. +// Use: core.WithService(webview.Register()) func Register(opts ...func(*Options)) func(*core.Core) (any, error) { o := Options{ DebugURL: "http://localhost:9222", diff --git a/pkg/window/messages.go b/pkg/window/messages.go index 8482db8..8ffdaf9 100644 --- a/pkg/window/messages.go +++ b/pkg/window/messages.go @@ -2,6 +2,7 @@ package window // WindowInfo contains information about a window. +// Use: info := window.WindowInfo{Name: "editor", Title: "Core Editor"} type WindowInfo struct { Name string `json:"name"` Title string `json:"title"` @@ -16,6 +17,7 @@ type WindowInfo struct { } // Bounds describes the position and size of a window. +// Use: bounds := window.Bounds{X: 10, Y: 10, Width: 1280, Height: 800} type Bounds struct { X int `json:"x"` Y int `json:"y"` @@ -26,19 +28,24 @@ type Bounds struct { // --- Queries (read-only) --- // QueryWindowList returns all tracked windows. Result: []WindowInfo +// Use: result, _, err := c.QUERY(window.QueryWindowList{}) type QueryWindowList struct{} // QueryWindowByName returns a single window by name. Result: *WindowInfo (nil if not found) +// Use: result, _, err := c.QUERY(window.QueryWindowByName{Name: "editor"}) type QueryWindowByName struct{ Name string } // QueryConfig requests this service's config section from the display orchestrator. // Result: map[string]any +// Use: result, _, err := c.QUERY(window.QueryConfig{}) type QueryConfig struct{} // QueryWindowBounds returns the current bounds for a window. +// Use: result, _, err := c.QUERY(window.QueryWindowBounds{Name: "editor"}) type QueryWindowBounds struct{ Name string } // QueryFindSpace returns a suggested free placement for a new window. +// Use: result, _, err := c.QUERY(window.QueryFindSpace{Width: 1280, Height: 800}) type QueryFindSpace struct { Width int Height int @@ -47,6 +54,7 @@ type QueryFindSpace struct { } // QueryLayoutSuggestion returns a layout recommendation for the current screen. +// Use: result, _, err := c.QUERY(window.QueryLayoutSuggestion{WindowCount: 2}) type QueryLayoutSuggestion struct { WindowCount int ScreenWidth int @@ -56,6 +64,7 @@ type QueryLayoutSuggestion struct { // --- Tasks (side-effects) --- // TaskOpenWindow creates a new window. Result: WindowInfo +// Use: _, _, err := c.PERFORM(window.TaskOpenWindow{Opts: []window.WindowOption{window.WithName("editor")}}) type TaskOpenWindow struct { Window *Window Opts []WindowOption @@ -63,15 +72,18 @@ type TaskOpenWindow struct { // TaskCloseWindow closes a window after persisting state. // Platform close events emit ActionWindowClosed through the tracked window handler. +// Use: _, _, err := c.PERFORM(window.TaskCloseWindow{Name: "editor"}) type TaskCloseWindow struct{ Name string } // TaskSetPosition moves a window. +// Use: _, _, err := c.PERFORM(window.TaskSetPosition{Name: "editor", X: 160, Y: 120}) type TaskSetPosition struct { Name string X, Y int } // TaskSetSize resizes a window. +// Use: _, _, err := c.PERFORM(window.TaskSetSize{Name: "editor", Width: 1280, Height: 800}) type TaskSetSize struct { Name string Width, Height int @@ -79,30 +91,37 @@ type TaskSetSize struct { } // TaskMaximise maximises a window. +// Use: _, _, err := c.PERFORM(window.TaskMaximise{Name: "editor"}) type TaskMaximise struct{ Name string } // TaskMinimise minimises a window. +// Use: _, _, err := c.PERFORM(window.TaskMinimise{Name: "editor"}) type TaskMinimise struct{ Name string } // TaskFocus brings a window to the front. +// Use: _, _, err := c.PERFORM(window.TaskFocus{Name: "editor"}) type TaskFocus struct{ Name string } // TaskRestore restores a maximised or minimised window to its normal state. +// Use: _, _, err := c.PERFORM(window.TaskRestore{Name: "editor"}) type TaskRestore struct{ Name string } // TaskSetTitle changes a window's title. +// Use: _, _, err := c.PERFORM(window.TaskSetTitle{Name: "editor", Title: "Core Editor"}) type TaskSetTitle struct { Name string Title string } // TaskSetAlwaysOnTop pins a window above others. +// Use: _, _, err := c.PERFORM(window.TaskSetAlwaysOnTop{Name: "editor", AlwaysOnTop: true}) type TaskSetAlwaysOnTop struct { Name string AlwaysOnTop bool } // TaskSetBackgroundColour updates the window background colour. +// Use: _, _, err := c.PERFORM(window.TaskSetBackgroundColour{Name: "editor", Red: 0, Green: 0, Blue: 0, Alpha: 0}) type TaskSetBackgroundColour struct { Name string Red uint8 @@ -112,18 +131,21 @@ type TaskSetBackgroundColour struct { } // TaskSetOpacity updates the window opacity as a value between 0 and 1. +// Use: _, _, err := c.PERFORM(window.TaskSetOpacity{Name: "editor", Opacity: 0.85}) type TaskSetOpacity struct { Name string Opacity float32 } // TaskSetVisibility shows or hides a window. +// Use: _, _, err := c.PERFORM(window.TaskSetVisibility{Name: "editor", Visible: false}) type TaskSetVisibility struct { Name string Visible bool } // TaskFullscreen enters or exits fullscreen mode. +// Use: _, _, err := c.PERFORM(window.TaskFullscreen{Name: "editor", Fullscreen: true}) type TaskFullscreen struct { Name string Fullscreen bool @@ -132,47 +154,57 @@ type TaskFullscreen struct { // --- Layout Queries --- // QueryLayoutList returns summaries of all saved layouts. Result: []LayoutInfo +// Use: result, _, err := c.QUERY(window.QueryLayoutList{}) type QueryLayoutList struct{} // QueryLayoutGet returns a layout by name. Result: *Layout (nil if not found) +// Use: result, _, err := c.QUERY(window.QueryLayoutGet{Name: "coding"}) type QueryLayoutGet struct{ Name string } // --- Layout Tasks --- // TaskSaveLayout saves the current window arrangement as a named layout. Result: bool +// Use: _, _, err := c.PERFORM(window.TaskSaveLayout{Name: "coding"}) type TaskSaveLayout struct{ Name string } // TaskRestoreLayout restores a saved layout by name. +// Use: _, _, err := c.PERFORM(window.TaskRestoreLayout{Name: "coding"}) type TaskRestoreLayout struct{ Name string } // TaskDeleteLayout removes a saved layout by name. +// Use: _, _, err := c.PERFORM(window.TaskDeleteLayout{Name: "coding"}) type TaskDeleteLayout struct{ Name string } // TaskTileWindows arranges windows in a tiling mode. +// Use: _, _, err := c.PERFORM(window.TaskTileWindows{Mode: "grid"}) type TaskTileWindows struct { Mode string // "left-right", "grid", "left-half", "right-half", etc. Windows []string // window names; empty = all } // TaskSnapWindow snaps a window to a screen edge/corner. +// Use: _, _, err := c.PERFORM(window.TaskSnapWindow{Name: "editor", Position: "left"}) type TaskSnapWindow struct { Name string // window name Position string // "left", "right", "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right", "center" } // TaskArrangePair places two windows side-by-side in a balanced split. +// Use: _, _, err := c.PERFORM(window.TaskArrangePair{First: "editor", Second: "terminal"}) type TaskArrangePair struct { First string Second string } // TaskBesideEditor places a target window beside an editor/IDE window. +// Use: _, _, err := c.PERFORM(window.TaskBesideEditor{Editor: "editor", Window: "terminal"}) type TaskBesideEditor struct { Editor string Window string } // TaskStackWindows cascades windows with a shared offset. +// Use: _, _, err := c.PERFORM(window.TaskStackWindows{Windows: []string{"editor", "terminal"}}) type TaskStackWindows struct { Windows []string OffsetX int @@ -180,31 +212,47 @@ type TaskStackWindows struct { } // TaskApplyWorkflow applies a predefined workflow layout to windows. +// Use: _, _, err := c.PERFORM(window.TaskApplyWorkflow{Workflow: window.WorkflowCoding}) type TaskApplyWorkflow struct { Workflow WorkflowLayout Windows []string } // TaskSaveConfig persists this service's config section via the display orchestrator. +// Use: _, _, err := c.PERFORM(window.TaskSaveConfig{Value: map[string]any{"default_width": 1280}}) type TaskSaveConfig struct{ Value map[string]any } // --- Actions (broadcasts) --- +// ActionWindowOpened is broadcast when a window is created. +// Use: _ = c.ACTION(window.ActionWindowOpened{Name: "editor"}) type ActionWindowOpened struct{ Name string } + +// ActionWindowClosed is broadcast when a window is closed. +// Use: _ = c.ACTION(window.ActionWindowClosed{Name: "editor"}) type ActionWindowClosed struct{ Name string } +// ActionWindowMoved is broadcast when a window is moved. +// Use: _ = c.ACTION(window.ActionWindowMoved{Name: "editor", X: 160, Y: 120}) type ActionWindowMoved struct { Name string X, Y int } +// ActionWindowResized is broadcast when a window is resized. +// Use: _ = c.ACTION(window.ActionWindowResized{Name: "editor", Width: 1280, Height: 800}) type ActionWindowResized struct { Name string Width, Height int W, H int } +// ActionWindowFocused is broadcast when a window gains focus. +// Use: _ = c.ACTION(window.ActionWindowFocused{Name: "editor"}) type ActionWindowFocused struct{ Name string } + +// ActionWindowBlurred is broadcast when a window loses focus. +// Use: _ = c.ACTION(window.ActionWindowBlurred{Name: "editor"}) type ActionWindowBlurred struct{ Name string } type ActionFilesDropped struct { @@ -214,6 +262,7 @@ type ActionFilesDropped struct { } // SpaceInfo describes a suggested empty area on the screen. +// Use: info := window.SpaceInfo{X: 160, Y: 120, Width: 1280, Height: 800} type SpaceInfo struct { X int `json:"x"` Y int `json:"y"` @@ -225,6 +274,7 @@ type SpaceInfo struct { } // LayoutSuggestion describes a recommended layout for a screen. +// Use: suggestion := window.LayoutSuggestion{Mode: "side-by-side"} type LayoutSuggestion struct { Mode string `json:"mode"` Columns int `json:"columns"` diff --git a/pkg/window/platform.go b/pkg/window/platform.go index d277231..be58dc0 100644 --- a/pkg/window/platform.go +++ b/pkg/window/platform.go @@ -2,12 +2,14 @@ package window // Platform abstracts the windowing backend (Wails v3). +// Use: var p window.Platform type Platform interface { CreateWindow(opts PlatformWindowOptions) PlatformWindow GetWindows() []PlatformWindow } // PlatformWindowOptions are the backend-specific options passed to CreateWindow. +// Use: opts := window.PlatformWindowOptions{Name: "editor"} type PlatformWindowOptions struct { Name string Title string @@ -25,6 +27,7 @@ type PlatformWindowOptions struct { } // PlatformWindow is a live window handle from the backend. +// Use: var w window.PlatformWindow type PlatformWindow interface { // Identity Name() string @@ -68,6 +71,7 @@ type PlatformWindow interface { } // WindowEvent is emitted by the backend for window state changes. +// Use: evt := window.WindowEvent{Type: "focus", Name: "editor"} type WindowEvent struct { Type string // "focus", "blur", "move", "resize", "close" Name string // window name diff --git a/pkg/window/register.go b/pkg/window/register.go index 63812f1..a00bc17 100644 --- a/pkg/window/register.go +++ b/pkg/window/register.go @@ -4,6 +4,7 @@ import "forge.lthn.ai/core/go/pkg/core" // Register creates a factory closure that captures the Platform adapter. // The returned function has the signature WithService requires: func(*Core) (any, error). +// Use: core.WithService(window.Register(platform)) func Register(p Platform) func(*core.Core) (any, error) { return func(c *core.Core) (any, error) { return &Service{ diff --git a/pkg/window/service.go b/pkg/window/service.go index 0e17015..b631202 100644 --- a/pkg/window/service.go +++ b/pkg/window/service.go @@ -11,11 +11,13 @@ import ( ) // Options holds configuration for the window service. +// Use: svc, err := window.Register(platform)(core.New()) type Options struct{} // Service is a core.Service managing window lifecycle via IPC. // Use: core.WithService(window.Register(window.NewMockPlatform())) // It embeds ServiceRuntime for Core access and composes Manager for platform operations. +// Use: svc, err := window.Register(platform)(core.New()) type Service struct { *core.ServiceRuntime[Options] manager *Manager @@ -23,6 +25,7 @@ type Service struct { } // OnStartup queries config from the display orchestrator and registers IPC handlers. +// Use: _ = svc.OnStartup(context.Background()) func (s *Service) OnStartup(ctx context.Context) error { // Query config — display registers its handler before us (registration order guarantee). // If display is not registered, handled=false and we skip config. @@ -60,6 +63,7 @@ func (s *Service) applyConfig(cfg map[string]any) { } // HandleIPCEvents is auto-discovered and registered by core.WithService. +// Use: _ = svc.HandleIPCEvents(core, msg) func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error { return nil } diff --git a/pkg/window/state.go b/pkg/window/state.go index 91c6c81..f222f24 100644 --- a/pkg/window/state.go +++ b/pkg/window/state.go @@ -11,6 +11,7 @@ import ( // WindowState holds the persisted position/size of a window. // JSON tags match existing window_state.json format for backward compat. +// Use: state := window.WindowState{X: 10, Y: 20, Width: 1280, Height: 800} type WindowState struct { X int `json:"x,omitempty"` Y int `json:"y,omitempty"` @@ -23,6 +24,7 @@ type WindowState struct { } // StateManager persists window positions to ~/.config/Core/window_state.json. +// Use: sm := window.NewStateManager() type StateManager struct { configDir string statePath string @@ -32,6 +34,7 @@ type StateManager struct { } // NewStateManager creates a StateManager loading from the default config directory. +// Use: sm := window.NewStateManager() func NewStateManager() *StateManager { sm := &StateManager{ states: make(map[string]WindowState), @@ -46,6 +49,7 @@ func NewStateManager() *StateManager { // NewStateManagerWithDir creates a StateManager loading from a custom config directory. // Useful for testing or when the default config directory is not appropriate. +// Use: sm := window.NewStateManagerWithDir(t.TempDir()) func NewStateManagerWithDir(configDir string) *StateManager { sm := &StateManager{ configDir: configDir, @@ -70,6 +74,7 @@ func (sm *StateManager) dataDir() string { } // SetPath overrides the persisted state file path. +// Use: sm.SetPath(filepath.Join(t.TempDir(), "window_state.json")) func (sm *StateManager) SetPath(path string) { if path == "" { return @@ -120,6 +125,7 @@ func (sm *StateManager) scheduleSave() { } // GetState returns the saved state for a window name. +// Use: state, ok := sm.GetState("editor") func (sm *StateManager) GetState(name string) (WindowState, bool) { sm.mu.RLock() defer sm.mu.RUnlock() @@ -128,6 +134,7 @@ func (sm *StateManager) GetState(name string) (WindowState, bool) { } // SetState saves state for a window name (debounced disk write). +// Use: sm.SetState("editor", window.WindowState{Width: 1280, Height: 800}) func (sm *StateManager) SetState(name string, state WindowState) { state.UpdatedAt = time.Now().UnixMilli() sm.mu.Lock() @@ -137,6 +144,7 @@ func (sm *StateManager) SetState(name string, state WindowState) { } // UpdatePosition updates only the position fields. +// Use: sm.UpdatePosition("editor", 160, 120) func (sm *StateManager) UpdatePosition(name string, x, y int) { sm.mu.Lock() s := sm.states[name] @@ -149,6 +157,7 @@ func (sm *StateManager) UpdatePosition(name string, x, y int) { } // UpdateSize updates only the size fields. +// Use: sm.UpdateSize("editor", 1280, 800) func (sm *StateManager) UpdateSize(name string, width, height int) { sm.mu.Lock() s := sm.states[name] @@ -161,6 +170,7 @@ func (sm *StateManager) UpdateSize(name string, width, height int) { } // UpdateMaximized updates the maximized flag. +// Use: sm.UpdateMaximized("editor", true) func (sm *StateManager) UpdateMaximized(name string, maximized bool) { sm.mu.Lock() s := sm.states[name] @@ -172,6 +182,7 @@ func (sm *StateManager) UpdateMaximized(name string, maximized bool) { } // CaptureState snapshots the current state from a PlatformWindow. +// Use: sm.CaptureState(pw) func (sm *StateManager) CaptureState(pw PlatformWindow) { x, y := pw.Position() w, h := pw.Size() @@ -182,6 +193,7 @@ func (sm *StateManager) CaptureState(pw PlatformWindow) { } // ApplyState restores saved position/size to a Window descriptor. +// Use: sm.ApplyState(&window.Window{Name: "editor"}) func (sm *StateManager) ApplyState(w *Window) { s, ok := sm.GetState(w.Name) if !ok { @@ -198,6 +210,7 @@ func (sm *StateManager) ApplyState(w *Window) { } // ListStates returns all stored window names. +// Use: names := sm.ListStates() func (sm *StateManager) ListStates() []string { sm.mu.RLock() defer sm.mu.RUnlock() @@ -209,6 +222,7 @@ func (sm *StateManager) ListStates() []string { } // Clear removes all stored states. +// Use: sm.Clear() func (sm *StateManager) Clear() { sm.mu.Lock() sm.states = make(map[string]WindowState) @@ -217,6 +231,7 @@ func (sm *StateManager) Clear() { } // ForceSync writes state to disk immediately. +// Use: sm.ForceSync() func (sm *StateManager) ForceSync() { if sm.saveTimer != nil { sm.saveTimer.Stop() diff --git a/pkg/window/window.go b/pkg/window/window.go index 071c67f..6589646 100644 --- a/pkg/window/window.go +++ b/pkg/window/window.go @@ -26,6 +26,7 @@ type Window struct { } // ToPlatformOptions converts a Window to PlatformWindowOptions for the backend. +// Use: opts := spec.ToPlatformOptions() func (w *Window) ToPlatformOptions() PlatformWindowOptions { return PlatformWindowOptions{ Name: w.Name, Title: w.Title, URL: w.URL, @@ -73,6 +74,7 @@ func NewManagerWithDir(platform Platform, configDir string) *Manager { } // SetDefaultWidth overrides the fallback width used when a window is created without one. +// Use: mgr.SetDefaultWidth(1280) func (m *Manager) SetDefaultWidth(width int) { if width > 0 { m.defaultWidth = width @@ -80,6 +82,7 @@ func (m *Manager) SetDefaultWidth(width int) { } // SetDefaultHeight overrides the fallback height used when a window is created without one. +// Use: mgr.SetDefaultHeight(800) func (m *Manager) SetDefaultHeight(height int) { if height > 0 { m.defaultHeight = height @@ -136,6 +139,7 @@ func (m *Manager) Create(w *Window) (PlatformWindow, error) { } // Get returns a tracked window by name. +// Use: pw, ok := mgr.Get("editor") func (m *Manager) Get(name string) (PlatformWindow, bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -144,6 +148,7 @@ func (m *Manager) Get(name string) (PlatformWindow, bool) { } // List returns all tracked window names. +// Use: names := mgr.List() func (m *Manager) List() []string { m.mu.RLock() defer m.mu.RUnlock() @@ -155,6 +160,7 @@ func (m *Manager) List() []string { } // Remove stops tracking a window by name. +// Use: mgr.Remove("editor") func (m *Manager) Remove(name string) { m.mu.Lock() delete(m.windows, name) @@ -162,21 +168,25 @@ func (m *Manager) Remove(name string) { } // Platform returns the underlying platform for direct access. +// Use: platform := mgr.Platform() func (m *Manager) Platform() Platform { return m.platform } // State returns the state manager for window persistence. +// Use: state := mgr.State() func (m *Manager) State() *StateManager { return m.state } // Layout returns the layout manager. +// Use: layouts := mgr.Layout() func (m *Manager) Layout() *LayoutManager { return m.layout } // SuggestLayout returns a simple layout recommendation for the given screen. +// Use: suggestion := mgr.SuggestLayout(1920, 1080, 2) func (m *Manager) SuggestLayout(screenW, screenH, windowCount int) LayoutSuggestion { if windowCount <= 1 { return LayoutSuggestion{ @@ -224,6 +234,7 @@ func (m *Manager) SuggestLayout(screenW, screenH, windowCount int) LayoutSuggest } // FindSpace returns a free placement suggestion for a new window. +// Use: info := mgr.FindSpace(1920, 1080, 1280, 800) func (m *Manager) FindSpace(screenW, screenH, width, height int) SpaceInfo { if width <= 0 { width = screenW / 2 @@ -273,6 +284,7 @@ func (m *Manager) FindSpace(screenW, screenH, width, height int) SpaceInfo { } // ArrangePair places two windows side-by-side with a balanced split. +// Use: _ = mgr.ArrangePair("editor", "terminal", 1920, 1080) func (m *Manager) ArrangePair(first, second string, screenW, screenH int) error { left, ok := m.Get(first) if !ok { @@ -293,6 +305,7 @@ func (m *Manager) ArrangePair(first, second string, screenW, screenH int) error } // BesideEditor places a target window beside an editor window, using a 70/30 split. +// Use: _ = mgr.BesideEditor("editor", "terminal", 1920, 1080) func (m *Manager) BesideEditor(editorName, windowName string, screenW, screenH int) error { editor, ok := m.Get(editorName) if !ok {