ui

package
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package ui is a thin façade over github.com/gogpu/ui (+ desktop, gg) that hides the bootstrap boilerplate (NewApp → ui/app.New → SetRoot → desktop.Run, plus the blank gg/gpu import) behind one small public surface.

It follows the same philosophy as the engine's logx, window and input packages: engine code imports only aqwabor/ui and never reaches into gogpu/ui/... internals.

Two run loops exist in the engine and must not be mixed for the same window:

  • window.Run: raw goGPU vertex drawing (low-level engine render path).
  • ui.Run: widget toolkit driven by desktop.Run (UI shell / HUD path).

See docs/ui.md and docs/window.md for the split between the UI shell and the engine render path.

Index

Constants

View Source
const (
	// CrossStart aligns children to the start (left for Column, top for Row).
	CrossStart = uiprim.CrossAxisStart
	// CrossCenter centers children on the cross axis.
	CrossCenter = uiprim.CrossAxisCenter
	// CrossEnd aligns children to the end (right for Column, bottom for Row).
	CrossEnd = uiprim.CrossAxisEnd
	// CrossStretch stretches children to fill the cross axis (default).
	CrossStretch = uiprim.CrossAxisStretch
)
View Source
const (
	// AlignLeft aligns text to the left (default).
	AlignLeft = widget.TextAlignLeft
	// AlignCenter centers text horizontally.
	AlignCenter = widget.TextAlignCenter
	// AlignRight aligns text to the right.
	AlignRight = widget.TextAlignRight
)

Variables

View Source
var (
	// LightPurple — brand light purple.
	LightPurple = &Theme{
		Primary: widget.Hex(0x6750A4), OnPrimary: widget.Hex(0xFFFFFFFF),
		Secondary: widget.Hex(0x9A7BD0), OnSecondary: widget.Hex(0xFFFFFFFF),
		Background: widget.Hex(0xF6F2FA), Surface: widget.Hex(0xFFFFFFFF),
		OnSurface: widget.Hex(0x2A2433), Error: widget.Hex(0xB00020), OnError: widget.Hex(0xFFFFFFFF),
	}

	// DarkPurple — brand dark purple.
	DarkPurple = &Theme{
		Primary: widget.Hex(0xBB86FC), OnPrimary: widget.Hex(0x1B1622),
		Secondary: widget.Hex(0x9A7BD0), OnSecondary: widget.Hex(0x1B1622),
		Background: widget.Hex(0x1B1622), Surface: widget.Hex(0x251E30),
		OnSurface: widget.Hex(0xE6E1F0), Error: widget.Hex(0xCF6679), OnError: widget.Hex(0x1B1622),
		Dark: true,
	}

	// Light — neutral light (gray) theme.
	Light = &Theme{
		Primary: widget.Hex(0x37474F), OnPrimary: widget.Hex(0xFFFFFFFF),
		Secondary: widget.Hex(0x607D8B), OnSecondary: widget.Hex(0xFFFFFFFF),
		Background: widget.Hex(0xFFFFFF), Surface: widget.Hex(0xF5F5F5),
		OnSurface: widget.Hex(0x101010), Error: widget.Hex(0xB00020), OnError: widget.Hex(0xFFFFFFFF),
	}

	// Dark — neutral dark (gray) theme.
	Dark = &Theme{
		Primary: widget.Hex(0xB0BEC5), OnPrimary: widget.Hex(0x121212),
		Secondary: widget.Hex(0x78909C), OnSecondary: widget.Hex(0x121212),
		Background: widget.Hex(0x121212), Surface: widget.Hex(0x1E1E1E),
		OnSurface: widget.Hex(0xE0E0E0), Error: widget.Hex(0xCF6679), OnError: widget.Hex(0x121212),
		Dark: true,
	}

	// LightBlue — light blue theme.
	LightBlue = &Theme{
		Primary: widget.Hex(0x2196F3), OnPrimary: widget.Hex(0xFFFFFFFF),
		Secondary: widget.Hex(0x64B5F6), OnSecondary: widget.Hex(0xFFFFFFFF),
		Background: widget.Hex(0xEAF2FF), Surface: widget.Hex(0xFFFFFFFF),
		OnSurface: widget.Hex(0x0E1A2B), Error: widget.Hex(0xB00020), OnError: widget.Hex(0xFFFFFFFF),
	}

	// DarkBlue — dark blue theme.
	DarkBlue = &Theme{
		Primary: widget.Hex(0x448AFF), OnPrimary: widget.Hex(0x0A0F1E),
		Secondary: widget.Hex(0x2979FF), OnSecondary: widget.Hex(0x0A0F1E),
		Background: widget.Hex(0x0A0F1E), Surface: widget.Hex(0x121A2E),
		OnSurface: widget.Hex(0xDCE6FF), Error: widget.Hex(0xCF6679), OnError: widget.Hex(0x0A0F1E),
		Dark: true,
	}
)

Six ready-made themes. Each is a plain *Theme you can also tweak, and you can build your own from scratch with &ui.Theme{...}.

Functions

func BackgroundColor

func BackgroundColor(t *Theme) widget.Color

func Hex

func Hex(hex uint32) widget.Color

Color helpers for building widget.Color values without importing gogpu/ui.

func OnPrimary

func OnPrimary(t *Theme) widget.Color

func OnSurfaceColor

func OnSurfaceColor(t *Theme) widget.Color

func Primary

func Primary(t *Theme) widget.Color

Primary Color accessors for the most useful theme roles. Each returns a widget.Color ready to pass to .Background(...) / .Color(...) on a widget builder, e.g.

ui.Column(...).Background(ui.SurfaceColor(app.Theme()))
ui.Label("x").Color(ui.OnSurfaceColor(app.Theme()))

func RGB

func RGB(r, g, b float32) widget.Color

func RGBA

func RGBA(r, g, b, a float32) widget.Color

func SurfaceColor

func SurfaceColor(t *Theme) widget.Color

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App owns a goGPU application and its gogpu/ui App.

func New

func New(cfg Config) (*App, error)

New creates a UI application. It builds a goGPU app window and the matching gogpu/ui App (window/event/platform providers wired from the goGPU app).

func (*App) Button

func (a *App) Button(text string, onClick func()) Widget

Button builds a themed button: its background uses the active theme's primary and its text uses on-primary, with hover/press feedback. Unlike the raw core/button (which hardcodes grey/black), this reflects the chosen theme.

func (*App) Close

func (a *App) Close()

Close requests the UI window to close. Safe to call from a button callback.

func (*App) GogpuApp

func (a *App) GogpuApp() *gogpu.App

GogpuApp returns the underlying goGPU app as an escape hatch (e.g. to wire the input backend or request custom redraws).

func (*App) Images

func (a *App) Images() *ImageManager

Images returns the app's image manager. The same manager is returned on every call, so assets loaded through it are shared across the whole application and released through TryRelease / ForceRelease.

func (*App) Run

func (a *App) Run() error

Run blocks until the window is closed, driving the widget toolkit.

func (*App) SetRoot

func (a *App) SetRoot(root Widget)

SetRoot sets the root widget of the UI tree. The theme's Background is painted as a full-window surface behind the content so changing the theme actually repaints the window background (relying solely on the toolkit's backdrop is fragile and easy to cover with a child widget).

func (*App) SetTheme

func (a *App) SetTheme(t *Theme)

SetTheme swaps the active theme at runtime. The window background is repainted immediately; if the root was already set, it is rebuilt so the new background applies. Rebuild your own widgets too if you want their captured colors (e.g. surfaces, buttons) to follow.

func (*App) Theme

func (a *App) Theme() *Theme

Theme returns the active theme (a mutable *Theme). Mutate its fields then call SetTheme to apply changes.

type BoxWidget

type BoxWidget = *uiprim.BoxWidget

BoxWidget is the builder returned by Box/Column/Row; it supports chaining methods such as Padding, Gap, Background and Rounded.

func Align

func Align(w BoxWidget, cross CrossAxisAlignment) BoxWidget

Align sets a box's cross-axis alignment, letting you choose how children are positioned instead of hardcoding a center. Pick CrossStart (left for a Column, top for a Row), CrossCenter, CrossEnd, or CrossStretch.

Note: the underlying gogpu/ui BoxWidget only supports cross-axis alignment; main-axis (vertical for a Column) alignment is start-only in this version.

func Box

func Box(children ...Widget) BoxWidget

Box lays out children in a vertical column by default.

func CenterX

func CenterX(w BoxWidget) BoxWidget

CenterX centers a box's children on the cross axis (horizontal for a Column, vertical for a Row). Returns w so calls can keep chaining.

func Column

func Column(children ...Widget) BoxWidget

Column lays out children top-to-bottom.

func Row

func Row(children ...Widget) BoxWidget

Row lays out children left-to-right.

type Config

type Config struct {
	Title     string
	W, H      int
	Resizable bool
	// Theme, if set, replaces the default theme (LightPurple). Use one of the
	// pre-made themes (ui.DarkBlue, ...) or build your own with &ui.Theme{...}.
	Theme *Theme
}

Config configures a UI application window.

type CrossAxisAlignment

type CrossAxisAlignment = uiprim.CrossAxisAlignment

CrossAxisAlignment selects how a box aligns its children on the cross axis. For a Column the cross axis is horizontal; for a Row it is vertical.

type ImageAsset

type ImageAsset struct {
	// contains filtered or unexported fields
}

ImageAsset is an opaque handle to a loaded image resource. It is returned by ImageManager.Load and consumed by Image / ImageButton / Clickable. Treat it as an opaque token: never reach into its fields and never hold a raw copy of the underlying pixel data past the asset's lifetime.

Asset lifetime is explicit and deterministic:

asset, err := images.Load("logo.png")
root  = ui.Image(asset)            // asset now has 1 active user
images.TryRelease(asset)           // refuses while still used
// ...remove the widget from the tree (Unmount)...
images.TryRelease(asset)           // ok: resource freed

func (*ImageAsset) Acquire

func (a *ImageAsset) Acquire()

Acquire registers an active consumer of the asset (e.g. a widget that will render it). The asset is not released by TryRelease while any user remains.

func (*ImageAsset) IsReleased

func (a *ImageAsset) IsReleased() bool

IsReleased reports whether the asset's resource has been released (via TryRelease or ForceRelease). A released asset must not be rendered.

func (*ImageAsset) Path

func (a *ImageAsset) Path() string

Path returns the normalized source path the asset was loaded from.

func (*ImageAsset) ReleaseUser

func (a *ImageAsset) ReleaseUser() int

ReleaseUser unregisters one active consumer. It returns the remaining user count. When the count reaches zero the asset becomes eligible for release.

func (*ImageAsset) Size

func (a *ImageAsset) Size() (int, int)

Size returns the natural pixel dimensions of the asset.

func (*ImageAsset) Take

func (a *ImageAsset) Take() (image.Image, bool)

Take returns the pixel data and whether it is still valid (not released). It is the only supported way to read the image, so that a concurrent ForceRelease cannot be observed mid-draw as a use-after-free.

func (*ImageAsset) Users

func (a *ImageAsset) Users() int

Users returns the current number of active consumers referencing the asset.

type ImageFit

type ImageFit int

ImageFit controls how an image is scaled to fit its allocated bounds.

const (
	// Fill stretches the image to exactly fill the bounds (may distort aspect ratio).
	Fill ImageFit = iota
	// Contain fits the image fully inside the bounds, preserving aspect ratio.
	Contain
	// Cover fills the bounds, preserving aspect ratio and cropping overflow.
	Cover
	// None draws the image at its natural size (top-left anchored, may overflow).
	None
)

type ImageManager

type ImageManager struct {
	// contains filtered or unexported fields
}

ImageManager loads, caches and owns image assets. It is the single owner of image resources; widgets only consume assets handed out by a manager.

Typical integration: app.Images(). A standalone manager can also be created with ui.NewImageManager().

func NewImageManager

func NewImageManager() *ImageManager

NewImageManager creates an empty image manager. Decoding is CPU-only, so a manager can be constructed before any window/GPU context exists.

func (*ImageManager) ForceRelease

func (m *ImageManager) ForceRelease(asset *ImageAsset)

ForceRelease destroys the asset's resource immediately, even if active users still reference it. This is intentionally unsafe: widgets that keep using the released asset will render nothing (deterministic), but they are now holding a dead reference. The caller is responsible for removing/replacing those users.

Calling ForceRelease twice (or after TryRelease) is a no-op and never frees a resource twice.

func (*ImageManager) Load

func (m *ImageManager) Load(path string) (*ImageAsset, error)

Load reads, decodes and uploads the image at path. Repeated loads of the same normalized source return the same canonical asset without re-decoding or duplicating the resource. Use TryRelease / ForceRelease to free it.

Supported formats are PNG, JPEG (.jpg/.jpeg) and SVG (.svg/.svgz). SVG is rasterized once at load time (see decodeSVG) into a fixed-resolution bitmap, so it behaves like any other raster image from the widget's point of view. Malformed or missing files return an error.

func (*ImageManager) TryRelease

func (m *ImageManager) TryRelease(asset *ImageAsset) bool

TryRelease releases the asset only if it has no active users. It returns true on success. If the asset is still used by one or more widgets, or has already been released, or is owned by another manager, it returns false and leaves the resource intact.

type ImageWidget

type ImageWidget = *imageWidget

ImageWidget is the builder returned by Image. It supports fluent configuration (Size / Width / Height / Fit / Opacity) and composes with the existing layout widgets (Row, Column, Box, Clickable, ...).

func Image

func Image(asset *ImageAsset) ImageWidget

Image creates an image widget that consumes the given asset. The asset must be loaded via ImageManager.Load; widgets never perform I/O or decoding.

func (ImageWidget) Fit

func (w ImageWidget) Fit(fit ImageFit) ImageWidget

Fit sets how the image is scaled within its bounds.

func (ImageWidget) Height

func (w ImageWidget) Height(height int) ImageWidget

Height sets an explicit height in logical pixels.

func (ImageWidget) OnClick

func (w ImageWidget) OnClick(fn func()) Widget

OnClick makes the image directly clickable. It is a convenience shorthand for ui.Clickable(image, fn): clicks anywhere within the image's bounds invoke fn. The returned Widget is no longer an ImageWidget, so chain OnClick last.

func (ImageWidget) Opacity

func (w ImageWidget) Opacity(alpha float32) ImageWidget

Opacity sets the image opacity in [0,1]. Values < 1 are baked into a derived copy at draw time.

func (ImageWidget) Size

func (w ImageWidget) Size(width, height int) ImageWidget

Size sets explicit width and height (in logical pixels). Zero keeps the natural dimension on that axis.

func (ImageWidget) Width

func (w ImageWidget) Width(width int) ImageWidget

Width sets an explicit width in logical pixels.

type LabelWidget

type LabelWidget = *uiprim.TextWidget

LabelWidget is the builder returned by Label; it supports chaining methods such as FontSize and Bold.

func CenterText

func CenterText(l LabelWidget) LabelWidget

CenterText centers a label's text horizontally. Returns l so calls can keep chaining.

func Label

func Label(text string) LabelWidget

Label creates a text label. Chain .FontSize(n), .Bold(), .Color(c), etc.

func LabelFn

func LabelFn(fn func() string) LabelWidget

LabelFn creates a reactive text label whose content is recomputed on every draw from fn. Use it for live readouts (e.g. a camera HUD) without rebuilding the widget tree.

type TextAlign

type TextAlign = widget.TextAlign

TextAlign selects horizontal text alignment within a label.

type Theme

type Theme struct {
	Primary     widget.Color
	OnPrimary   widget.Color
	Secondary   widget.Color
	OnSecondary widget.Color
	Background  widget.Color
	Surface     widget.Color
	OnSurface   widget.Color
	Error       widget.Color
	OnError     widget.Color

	// Dark selects the dark color scheme (affects default shadows/mode). Set it
	// when you want a dark look, typically together with dark Background/Surface.
	Dark bool
}

Theme is a plain, editable color scheme. Fill the roles you care about and apply it with app.SetTheme. Because widgets capture their colors when the tree is built, re-call app.SetTheme — and rebuild the root (or the subtree) — after mutating fields to reskin a live UI.

type Widget

type Widget = widget.Widget

Widget is the gogpu/ui widget interface, re-exported so engine code never imports gogpu/ui/widget directly.

func Button

func Button(text string, onClick func()) Widget

Button creates a clickable button painted with the engine brand theme's primary/on-primary colors. For an app-specific theme, use App.Button.

func Clickable

func Clickable(content Widget, onClick func()) Widget

Clickable wraps any widget so a click anywhere inside its bounds invokes onClick. It is a thin interaction layer over the toolkit's gesture pipeline (the same one core/button uses) and introduces no separate input system.

ui.Clickable(ui.Image(play), startGame)
ui.Clickable(ui.Row(ui.Image(play).Size(20, 20), ui.Label("Play")), startGame)

func ImageButton

func ImageButton(asset *ImageAsset, onClick func()) Widget

ImageButton is a clickable image. It is a thin, unopinionated wrapper over Clickable + Image: the image keeps its natural/default sizing and the caller is free to size it explicitly (e.g. ui.Image(icon).Size(32, 32)). No fixed dimensions or fit mode are baked in.

ui.ImageButton(play, startGame)
ui.Clickable(ui.Image(play).Size(32, 32), startGame) // explicit sizing

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL