gui

package module
v0.0.0-...-dc36e85 Latest Latest
Warning

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

Go to latest
Published: Feb 7, 2026 License: MIT Imports: 10 Imported by: 0

README

gui

Immediate-mode GUI library for Go with an OpenGL 4.1 backend. Built for go-theft-auto, usable as a standalone library.

Features

  • Immediate-mode API — no persistent widget objects, draw everything every frame
  • Built-in widget set: buttons, sliders, tables, lists, comboboxes, panels, graphs, toasts, and more
  • Gamepad/keyboard focus navigation with double-buffered focus registry
  • OpenGL 4.1 renderer with built-in monospace font
  • GLFW input adapter
  • Drag-and-drop, clipboard, and scroll support
  • GTA-inspired default style

Install

go get github.com/go-theft-auto/gui

Requires CGO and OpenGL/X11 development headers (see Development below).

Usage

package main

import (
    "github.com/go-gl/gl/v4.1-core/gl"
    "github.com/go-gl/glfw/v3.3/glfw"

    "github.com/go-theft-auto/gui"
    "github.com/go-theft-auto/gui/backend/opengl"
)

func main() {
    // ... initialize GLFW window and OpenGL context ...

    renderer, _ := opengl.NewRenderer(800, 600)
    defer renderer.Delete()

    inputAdapter := opengl.NewGLFWInputAdapter(window)

    ui := gui.New(renderer, gui.WithStyle(gui.GTAStyle()))

    for !window.ShouldClose() {
        glfw.PollEvents()
        inputAdapter.Update()

        gl.ClearColor(0.1, 0.1, 0.1, 1)
        gl.Clear(gl.COLOR_BUFFER_BIT)

        ctx := ui.Begin(inputAdapter.Input(), gui.Vec2{X: 800, Y: 600}, 1.0/60.0)

        ctx.Panel("My Panel", gui.Width(300))(func() {
            ctx.Text("Hello!")
            if ctx.Button("Click me") {
                // handle click
            }
        })

        ui.End()
        window.SwapBuffers()
    }
}

See example/main.go for a complete runnable example.

Development

This package uses CGO for OpenGL. Install Devbox to get a reproducible environment with Go, OpenGL headers, X11 libraries, formatters, and linters:

devbox shell       # enter the dev environment
task fmt           # format code (gci + gofumpt)
task lint          # run golangci-lint
task test          # run tests
task build         # verify compilation
task deps          # tidy and vendor dependencies

See CONTRIBUTING.md for more details.

Architecture

gui/                    Core library (no OpenGL dependency)
  backend/opengl/       OpenGL 4.1 renderer + GLFW input adapter
  example/              Runnable example

The core gui package defines interfaces (Renderer, FontProvider) and all widgets. The backend/opengl package provides concrete implementations. This split means you could implement a different rendering backend (Vulkan, software, etc.) without touching the core.

License

MIT

Documentation

Overview

Package gui provides an immediate-mode GUI library inspired by Dear ImGui, designed as idiomatic Go with a dedicated Context type.

Overview

This package implements an immediate-mode GUI where the UI is rebuilt every frame. Unlike retained-mode GUIs, there's no need to manage widget state or handle callbacks. The UI code is simply called each frame, and widgets return interaction results directly.

Quick Start

// Setup
renderer, _ := opengl.NewRenderer(1920, 1080)
ui := gui.New(renderer, gui.WithStyle(gui.GTAStyle()))

// Game loop
for !window.ShouldClose() {
    input := pollInput(window)

    ctx := ui.Begin(input, gui.Vec2{1920, 1080}, deltaTime)

    ctx.Panel("Menu", gui.Gap(8), gui.Padding(12))(func() {
        ctx.Text("Hello World")
        if ctx.Button("Click Me") {
            // Button was clicked
        }
    })

    ui.End()
    window.SwapBuffers()
}

Keyboard Shortcuts Reference

This section documents all keyboard shortcuts available in the GUI system.

## InputText Widget Shortcuts

Navigation:

Left Arrow       Move cursor one character left
Right Arrow      Move cursor one character right
Ctrl+Left        Move cursor one word left
Ctrl+Right       Move cursor one word right
Home             Jump to start of text
End              Jump to end of text

Selection:

Shift+Left       Extend selection one character left
Shift+Right      Extend selection one character right
Ctrl+Shift+Left  Extend selection one word left
Ctrl+Shift+Right Extend selection one word right
Shift+Home       Select from cursor to start
Shift+End        Select from cursor to end
Ctrl+A           Select all text

Clipboard Operations:

Ctrl+C           Copy selected text to clipboard
Ctrl+X           Cut selected text to clipboard
Ctrl+V           Paste from clipboard

Undo/Redo:

Ctrl+Z           Undo last change
Ctrl+Y           Redo (alternative 1)
Ctrl+Shift+Z     Redo (alternative 2)

Control:

Enter            Confirm input and unfocus
Escape           Cancel and unfocus
Backspace        Delete character before cursor (or delete selection)
Delete           Delete character after cursor (or delete selection)

## Scrollable Areas (ListBox, Scrollable, List)

Mouse Wheel      Scroll vertically
Shift+Wheel      Scroll horizontally (when enabled)
Page Up          Scroll up by 80% of viewport height
Page Down        Scroll down by 80% of viewport height
Home             Scroll to top (when focused)
End              Scroll to bottom (when focused)

## ComboBox Widget

Click            Open/close dropdown menu
Escape           Close dropdown menu
Mouse Wheel      Scroll dropdown items
Type characters  Filter items (when WithSearchable() is set)
Backspace        Delete filter character

## Slider Widgets (SliderFloat, SliderInt)

Click+Drag       Adjust value by dragging
Mouse Wheel      Increment/decrement value (when hovered)

## NumberInput Widgets (NumberInputFloat, NumberInputInt)

Click+Drag       Adjust value by dragging left/right
Click (release)  Enter text edit mode (if drag distance < 3px)
Enter            Confirm text edit
Escape           Cancel text edit
0-9, ., -        Input digits/decimal/negative
Backspace        Delete digit

## Collapsing Headers / Tree Nodes

Click            Toggle expanded/collapsed state

## Panel Focus (requires PanelRegistry)

Ctrl+Tab         Cycle to next panel
Ctrl+Shift+Tab   Cycle to previous panel

Complete Component List

All components are organized by category. When using the component registry, components use the "component_*" naming prefix.

## Text Components

ctx.Text(text string)
    Draws basic text at current cursor position.
    Component name: component_text

ctx.TextColored(text string, color uint32)
    Draws text with a specific color.
    Component name: component_text_colored

ctx.TextDisabled(text string)
    Draws text with the disabled/grayed out color.

ctx.TextWrapped(text string, maxWidth float32)
    Draws text with automatic word wrapping.
    Use maxWidth=0 for current layout width.
    Component name: component_text_wrapped

ctx.LabelText(label, value string)
    Draws a label and value side by side.

ctx.BulletText(text string)
    Draws a bullet point followed by text.

## Button Components

ctx.Button(label string, opts ...Option) bool
    Draws a clickable button. Returns true when clicked.
    Options: WithID, WithDisabled, WithWidth, WithHeight
    Component name: component_button

ctx.SmallButton(label string, opts ...Option) bool
    Draws a smaller button without extra padding.
    Component name: component_button_small

## Input Components

ctx.InputText(label string, value *string, opts ...Option) bool
    Full-featured text input with cursor, selection, clipboard, undo/redo.
    Returns true when value changes.
    Options: WithID, WithDisabled, WithWidth
    Component name: component_input_text

ctx.SliderFloat(label string, value *float32, min, max float32, opts ...Option) bool
    Horizontal slider for float values. Returns true when value changes.
    Options: WithID, WithWidth, WithFormat, WithStep
    Component name: component_slider

ctx.SliderInt(label string, value *int, min, max int, opts ...Option) bool
    Horizontal slider for integer values. Returns true when value changes.
    Options: WithID, WithWidth, WithFormat, WithStep
    Component name: component_slider_int

ctx.NumberInputFloat(label string, value *float32, opts ...Option) bool
    Numeric input with drag-to-adjust. Click to type, drag to adjust.
    Options: WithID, WithWidth, WithFormat, WithStep, WithRange,
             WithDragSpeed, WithPrefix, WithSuffix
    Component name: component_number_input

ctx.NumberInputInt(label string, value *int, opts ...Option) bool
    Integer variant of NumberInputFloat.

ctx.Checkbox(label string, value *bool, opts ...Option) bool
    Checkbox with label. Returns true when toggled.
    Options: WithID, WithDisabled
    Component name: component_checkbox

ctx.RadioButton(label string, active bool, opts ...Option) bool
    Radio button. Returns true when clicked.
    Options: WithID, WithDisabled
    Component name: component_radio_button

ctx.ComboBox(label string, selectedIndex *int, items []string, opts ...Option) bool
    Dropdown selection widget. Returns true when selection changes.
    Options: WithID, WithWidth, WithSearchable, WithMaxDropdownHeight
    Component name: component_combobox

ctx.ProgressBar(fraction float32, opts ...Option)
    Displays a progress bar. Fraction should be 0.0 to 1.0.
    Options: WithWidth, WithHeight
    Component name: component_progress_bar

## Selection Components

ctx.Selectable(label string, selected bool, opts ...Option) bool
    Selectable list item. Returns true when clicked.
    Options: WithID, WithDisabled
    Component name: component_selectable

## Layout Components

ctx.Panel(title string, opts ...LayoutOption) func(func())
    Container with background and optional title.
    Options: Gap, GapX, GapY, Padding, PaddingXY, Width, Height, Align, Justify
    Component name: component_panel

ctx.CenteredPanel(id string, opts ...LayoutOption) func(func())
    Panel centered on screen using cached size from previous frame.
    Solves ImGui's "can't center without knowing size" issue.

ctx.VStack(opts ...LayoutOption) func(func())
    Vertical layout container (items stack top to bottom).
    Options: Gap, GapX, GapY, Padding, Width, Height, Align, Justify
    Component name: component_vstack

ctx.HStack(opts ...LayoutOption) func(func())
    Horizontal layout container (items stack left to right).
    Options: Gap, GapX, GapY, Padding, Width, Height, Align, Justify
    Component name: component_hstack

ctx.Row(contents func())
    Alias for HStack with default options.

ctx.ListBox(id string, height float32, opts ...LayoutOption) func(func())
    Scrollable list area with smooth scrolling.
    Component name: component_listbox

ctx.Scrollable(id string, height float32, opts ...Option) func(func())
    Generic scrollable wrapper for any content.
    Options: ShowScrollbar, ScrollbarPosition, EnableHorizontal, ClampToContent
    Component name: component_scrollable

ctx.List(id string, height float32, opts ...Option) *ListBuilder
    Advanced list with sections, search filter, and nested widgets.
    Returns a builder for fluent configuration.
    Options: ShowScrollbar, WithFilter, WithMultiSelect, DefaultOpen
    Component name: component_list

## Table Component

ctx.BeginTable(id string, columns []TableColumn, flags TableFlags, width, height float32) *Table
    Starts a table. Returns nil if table should be skipped.
    Component name: component_table

ctx.BeginTableVirtualized(id string, columns []TableColumn, flags TableFlags, width, height float32, totalRows int) *Table
    Virtualized table for large datasets (1000+ rows).

Table methods:
    t.TableHeadersRow()                    Draw column headers
    t.TableNextRow()                       Start new row
    t.TableNextColumn() Vec2               Move to next column
    t.TableText(text string)               Draw text in current column
    t.TableTextColored(text, color)        Draw colored text
    t.TableIsRowHovered() bool             Check if row is hovered
    t.TableIsRowClicked() bool             Check if row was clicked
    t.EndTable()                           Finish table

TableFlags:
    TableFlagsResizable        Enable column resizing
    TableFlagsSortable         Enable sorting indicators
    TableFlagsRowSelect        Enable row selection
    TableFlagsScrollY          Enable vertical scrolling
    TableFlagsStickyHeader     Keep header visible when scrolling
    TableFlagsAutoSizeColumns  Auto-size columns to content
    TableFlagsBordersInner     Inner borders (H+V)
    TableFlagsBordersOuter     Outer borders (H+V)
    TableFlagsBorders          All borders
    TableFlagsRowBg            Alternate row backgrounds
    TableFlagsHighlightHover   Highlight hovered row

## Tree/Collapsing Components

ctx.CollapsingHeader(label string, opts ...Option) bool
    Collapsible header. Returns true if section is expanded.
    Options: WithID
    Component name: component_collapsing_header

ctx.TreeNode(label string, opts ...Option) bool
    Tree node with indent. Call TreePop() after contents.
    Returns true if expanded.
    Component name: component_tree_node

ctx.TreePop()
    End a tree node started with TreeNode().

## Misc Components

ctx.Separator()
    Draws a horizontal separator line.
    Component name: component_separator

ctx.Spacing(pixels float32)
    Adds vertical space.

ctx.Bullet()
    Draws a bullet point (inline element).

ctx.Indent(pixels float32)
    Increases cursor X position.

ctx.Unindent(pixels float32)
    Decreases cursor X position.

ctx.SameLine()
    Places next widget on same line as previous.

ctx.Tooltip(text string)
    Shows tooltip at mouse position.

Widget Options Reference

Common options available for widgets:

WithID(id string)              Explicit ID (use in loops)
WithDisabled(disabled bool)    Disable widget interaction
WithWidth(width float32)       Set widget width
WithHeight(height float32)     Set widget height
WithFormat(format string)      Printf-style format (e.g., "%.2f")
WithStep(step float32)         Value increment step
WithRange(min, max float32)    Value range constraints
WithDragSpeed(speed float32)   Drag sensitivity
WithPrefix(prefix string)      Text prefix (e.g., "X:")
WithSuffix(suffix string)      Text suffix (e.g., "px")
WithSearchable()               Enable typing to filter (ComboBox)
WithMaxDropdownHeight(h)       Limit dropdown height
WithColumns(n int)             Multi-column layout
ShowScrollbar(always bool)     Control scrollbar visibility
ScrollbarPosition(side)        Scrollbar side (left/right)
EnableHorizontal()             Enable horizontal scroll
ClampToContent()               Don't scroll past content
WithFilter(placeholder)        Enable search filter (List)
WithMultiSelect()              Allow multiple selection
DefaultOpen()                  Start sections expanded

Layout Options Reference

Options for Panel, VStack, HStack, and other layout containers:

Gap(pixels float32)            Space between all children
GapX(pixels float32)           Horizontal spacing override
GapY(pixels float32)           Vertical spacing override
Padding(pixels float32)        Inner padding on all sides
PaddingXY(x, y float32)        Separate X/Y padding
Width(w float32)               Fixed width
Height(h float32)              Fixed height
Align(alignment Alignment)     Cross-axis alignment
Justify(just Justification)    Main-axis alignment

Alignment values: AlignStart, AlignCenter, AlignEnd, AlignStretch Justification values: JustifyStart, JustifyCenter, JustifyEnd, JustifyBetween

Spacing Constants

Use these instead of magic numbers:

SpaceNone  = 0   // No spacing
SpaceXS    = 2   // Extra small
SpaceSM    = 4   // Small (default item spacing)
SpaceMD    = 8   // Medium (default padding)
SpaceLG    = 12  // Large
SpaceXL    = 16  // Extra large
Space2XL   = 24  // 2x extra large
Space3XL   = 32  // 3x extra large
Space4XL   = 48  // 4x extra large

State Types

Widget state types for GetState/SetState:

ScrollState           Scroll position for ListBox
InputTextState        Cursor, selection, undo stack for InputText
TreeNodeState         Expanded state for TreeNode
CollapsingHeaderState Collapsed state for CollapsingHeader
SliderState           Drag state for Slider
ComboBoxState         Open/scroll state for ComboBox
ScrollableState       Full scroll state for Scrollable
ListState             Scroll/filter/selection for List
NumberInputState      Edit/drag state for NumberInput
TableState            Column widths, sort, selection for Table

Component Interface

For creating custom components:

type Component interface {
    Render(ctx *Context)
}

// Register custom component
gui.RegisterComponent("component_my_widget", func() gui.Component {
    return &MyWidget{}
})

// Use registered component
gui.RenderComponent(ctx, "component_my_widget", func(c gui.Component) {
    w := c.(*MyWidget)
    w.Value = &myValue
})

Clipboard Integration

To enable clipboard support, implement ClipboardProvider:

type ClipboardProvider interface {
    GetText() string
    SetText(text string)
}

// GLFW example:
type GLFWClipboard struct {
    window *glfw.Window
}

func (c *GLFWClipboard) GetText() string {
    return c.window.GetClipboardString()
}

func (c *GLFWClipboard) SetText(text string) {
    c.window.SetClipboardString(text)
}

// Register during init:
gui.SetClipboardProvider(&GLFWClipboard{window: window})

Text Utilities

For advanced text handling:

// Wrap text with mode selection
lines := gui.WrapText(ctx, text, maxWidth, gui.WrapModeAuto)

// Smart wrap (auto-detects CJK)
lines := gui.WrapTextSmart(ctx, text, maxWidth)

// Truncate with ellipsis
truncated := gui.TruncateText(ctx, text, maxWidth)

// Measure wrapped text
size := gui.MeasureWrappedText(ctx, text, maxWidth, gui.WrapModeWord)

WrapMode values: WrapModeWord, WrapModeChar, WrapModeAuto

Performance Optimizations

Built-in optimizations:

  • sync.Pool for DrawList buffer reuse
  • Batched rendering by texture
  • Pre-allocated glyph buffer for text
  • Per-frame text measurement cache
  • ListClipper for virtualizing large lists
  • Table row virtualization

For large datasets, use:

// Virtualized table (only renders visible rows)
table := ctx.BeginTableVirtualized("data", cols, flags, w, h, 10000)
for i := table.FirstVisibleRow(); i < table.LastVisibleRow(); i++ {
    if table.TableNextRowVirtualized(i) {
        table.TableTextVirtualized(data[i].Name)
    }
}
table.EndTable()

// ListClipper for custom lists
clipper := gui.NewListClipper(totalItems, itemHeight, visibleHeight, scrollY)
for i := clipper.StartIdx; i < clipper.EndIdx; i++ {
    y := clipper.ItemY(i, baseY, scrollY)
    // Draw item at y
}

Differences from Dear ImGui

This implementation addresses known ImGui issues:

  • Layout centering: CenteredPanel uses two-pass layout
  • ID conflicts: Auto-ID generation prevents loop bugs
  • Text wrapping: Built-in TextWrapped with CJK support
  • Hidden state: Explicit StateStore interface
  • Type safety: Go generics instead of void*
  • Memory: sync.Pool instead of manual management
  • InputText: Full cursor, selection, clipboard, undo/redo
  • Virtualization: Built-in ListClipper and table virtualization
  • Smooth scrolling: Interpolated scroll positions

Package gui provides an immediate-mode GUI library inspired by Dear ImGui. It uses a dedicated Context type (not context.Context) for better performance and type safety.

Index

Constants

View Source
const (
	KeyRepeatDelay    float32 = 0.4  // Initial delay before repeat starts (seconds)
	KeyRepeatInterval float32 = 0.03 // Repeat interval once repeating (seconds)
)

Key repeat timing constants

View Source
const (
	SpaceNone float32 = 0
	SpaceXS   float32 = 2  // Extra small
	SpaceSM   float32 = 4  // Small (default item spacing)
	SpaceMD   float32 = 8  // Medium (default padding)
	SpaceLG   float32 = 12 // Large
	SpaceXL   float32 = 16 // Extra large
	Space2XL  float32 = 24 // 2x extra large
	Space3XL  float32 = 32 // 3x extra large
	Space4XL  float32 = 48 // 4x extra large
)

Spacing constants for consistent layout (similar to Tailwind spacing scale). Use these instead of raw numbers for maintainability.

View Source
const (
	ColorWhite       uint32 = 0xFFFFFFFF
	ColorBlack       uint32 = 0xFF000000
	ColorRed         uint32 = 0xFF0000FF
	ColorGreen       uint32 = 0xFF00FF00
	ColorBlue        uint32 = 0xFFFF0000
	ColorYellow      uint32 = 0xFF00FFFF
	ColorCyan        uint32 = 0xFFFFFF00
	ColorMagenta     uint32 = 0xFFFF00FF
	ColorGray        uint32 = 0xFF808080
	ColorDarkGray    uint32 = 0xFF404040
	ColorLightGray   uint32 = 0xFFC0C0C0
	ColorTransparent uint32 = 0x00000000
)

Color constants (RGBA packed as 0xAABBGGRR for OpenGL compatibility)

View Source
const DefaultToastDuration float32 = 3.0

DefaultToastDuration is the default duration for toast messages.

View Source
const ToastMaxVisible = 5

ToastMaxVisible is the maximum number of visible toasts at once.

Variables

View Source
var (
	OptID         = NewOptKey("id", "")
	OptDisabled   = NewOptKey("disabled", false)
	OptFocused    = NewOptKey("focused", false)
	OptForceFocus = NewOptKey("forceFocus", false) // Actually grab keyboard focus
	OptWidth      = NewOptKey[float32]("width", 0)
	OptHeight     = NewOptKey[float32]("height", 0)
)

--- Core Options ---

View Source
var (
	OptFormat    = NewOptKey("format", "")
	OptStep      = NewOptKey[float32]("step", 0)
	OptRange     = NewOptKey("range", RangeValue{})
	OptDragSpeed = NewOptKey[float32]("dragSpeed", 0)
	OptPrefix    = NewOptKey("prefix", "")
	OptSuffix    = NewOptKey("suffix", "")
)

--- Slider/NumberInput Options ---

View Source
var (
	OptSearchable        = NewOptKey("searchable", false)
	OptMaxDropdownHeight = NewOptKey[float32]("maxDropdownHeight", 0)
)

--- ComboBox Options ---

View Source
var (
	OptScrollbarVisibility = NewOptKey("scrollbarVisibility", ScrollbarAuto)
	OptScrollbarSide       = NewOptKey("scrollbarSide", ScrollbarRight)
	OptHorizontalScroll    = NewOptKey("horizontalScroll", false)
	OptClampToContent      = NewOptKey("clampToContent", false)
	OptFocus               = NewOptKey("focus", FocusValue{})
)

--- Scrollable Options ---

View Source
var (
	OptFilterPlaceholder = NewOptKey("filterPlaceholder", "")
	OptMultiSelect       = NewOptKey("multiSelect", false)
	OptDefaultOpen       = NewOptKey("defaultOpen", false)
)

--- List Options ---

View Source
var (
	OptIndentSize = NewOptKey[float32]("indentSize", 0) // Custom indent (0 = use default)
	OptNoIndent   = NewOptKey("noIndent", false)        // Skip indentation entirely
	OptOpen       = NewOptKey("open", OpenValue{})      // Controlled open state via pointer
)

--- Section Options ---

View Source
var (
	OptGraphYMin      = NewOptKey[float32]("graphYMin", 0)
	OptGraphYMax      = NewOptKey[float32]("graphYMax", 0)
	OptGraphGridLines = NewOptKey("graphGridLines", 0)
	OptGraphLegend    = NewOptKey("graphLegend", false)
)

--- Graph Options ---

View Source
var (
	OptHistogramYMin       = NewOptKey[float32]("histogramYMin", 0)
	OptHistogramYMax       = NewOptKey[float32]("histogramYMax", 0)
	OptHistogramShowValues = NewOptKey("histogramShowValues", false)
	OptHistogramHorizontal = NewOptKey("histogramHorizontal", false)
)

--- Histogram Options ---

View Source
var BuiltinComponents = struct {
	// Text components
	Text        string // component_text
	TextWrapped string // component_text_wrapped
	TextColored string // component_text_colored

	// Button components
	Button      string // component_button
	SmallButton string // component_button_small

	// Input components
	InputText   string // component_input_text
	Slider      string // component_slider
	SliderInt   string // component_slider_int
	NumberInput string // component_number_input
	Checkbox    string // component_checkbox
	RadioButton string // component_radio_button
	ComboBox    string // component_combobox

	// Layout components
	Panel      string // component_panel
	ListBox    string // component_listbox
	Scrollable string // component_scrollable
	Table      string // component_table
	VStack     string // component_vstack
	HStack     string // component_hstack

	// Selection components
	Selectable string // component_selectable
	List       string // component_list

	// Misc components
	ProgressBar      string // component_progress_bar
	Separator        string // component_separator
	CollapsingHeader string // component_collapsing_header
	TreeNode         string // component_tree_node
}{
	Text:        "component_text",
	TextWrapped: "component_text_wrapped",
	TextColored: "component_text_colored",

	Button:      "component_button",
	SmallButton: "component_button_small",

	InputText:   "component_input_text",
	Slider:      "component_slider",
	SliderInt:   "component_slider_int",
	NumberInput: "component_number_input",
	Checkbox:    "component_checkbox",
	RadioButton: "component_radio_button",
	ComboBox:    "component_combobox",

	Panel:      "component_panel",
	ListBox:    "component_listbox",
	Scrollable: "component_scrollable",
	Table:      "component_table",
	VStack:     "component_vstack",
	HStack:     "component_hstack",

	Selectable: "component_selectable",
	List:       "component_list",

	ProgressBar:      "component_progress_bar",
	Separator:        "component_separator",
	CollapsingHeader: "component_collapsing_header",
	TreeNode:         "component_tree_node",
}

BuiltinComponents contains the standard component implementations. These use the "component_" prefix naming convention.

View Source
var DebugFocusBorderColor = RGBA(255, 50, 50, 255)

DebugFocusBorderColor is the border color for debug focus highlighting (bright red, thick).

View Source
var DebugFocusColor = RGBA(255, 0, 0, 180)

DebugFocusColor is the color used for debug focus highlighting (bright red, more visible).

View Source
var (
	OptColumns = NewOptKey("columns", 0)
)

--- RadioGroup Options ---

View Source
var (
	OptSequencerControls = NewOptKey("sequencerControls", false)
)

--- Sequencer Options ---

Functions

func ApplyAndCheck

func ApplyAndCheck[T any](opts []Option, key OptKey[T]) (T, bool)

ApplyAndCheck returns the option value and whether it was explicitly set.

func ApplyAndGet

func ApplyAndGet[T any](opts []Option, key OptKey[T]) T

ApplyAndGet applies options and returns a single value. Use this in external packages to create custom widgets.

func ClipboardAvailable

func ClipboardAvailable() bool

ClipboardAvailable returns true if a clipboard provider is configured.

func ClipboardGetText

func ClipboardGetText() string

ClipboardGetText retrieves text from the clipboard. Returns empty string if no clipboard provider is set or clipboard is empty.

func ClipboardSetText

func ClipboardSetText(text string)

ClipboardSetText copies text to the clipboard. Does nothing if no clipboard provider is set.

func CurrentFrameCount

func CurrentFrameCount() uint64

CurrentFrameCount returns the current frame counter. Useful for debugging or advanced use cases.

func DeleteState

func DeleteState(ctx *Context, id ID)

DeleteState removes state from the context.

func DrawFocusRing

func DrawFocusRing(dl *DrawList, x, y, w, h float32, style Style)

DrawFocusRing draws a focus indicator ring around the given rectangle. Uses the style's FocusColor for theming support.

func DrawFocusRingDebug

func DrawFocusRingDebug(dl *DrawList, x, y, w, h float32, style Style, debugHighlight bool)

DrawFocusRingDebug draws a focus indicator ring with optional debug highlighting. When debugHighlight is true, uses red color instead of the style's FocusColor.

func EnsureScrollVisible

func EnsureScrollVisible(ctx *Context, scrollID string, targetY, viewportHeight, padding float32)

EnsureScrollVisible scrolls a Scrollable to keep the given Y position visible. Call this when selection changes to auto-scroll to the selected item.

Parameters:

  • ctx: GUI context
  • scrollID: The ID used when creating the Scrollable (e.g., "my_scroll")
  • targetY: Y position relative to scrollable content (e.g., rowIndex * rowHeight)
  • viewportHeight: Height of the scrollable viewport
  • padding: Extra padding around target (e.g., rowHeight for one row margin)

Usage:

// When selection changes via keyboard:
if selectionChanged {
    targetY := float32(selectedIndex) * rowHeight
    gui.EnsureScrollVisible(ctx, "items_scroll", targetY, scrollHeight, rowHeight)
}

func GetOpt

func GetOpt[T any](o options, key OptKey[T]) T

GetOpt retrieves an option value with type safety. Returns the key's default value if not set.

func GetState

func GetState[T any](ctx *Context, id ID, defaultVal T) T

GetState retrieves typed state from the context. Returns defaultVal if the state doesn't exist or has wrong type.

func HasOpt

func HasOpt[T any](o options, key OptKey[T]) bool

HasOpt returns true if the option was explicitly set.

func IsSectionOpen

func IsSectionOpen(ctx *Context, id ID) bool

IsSectionOpen returns whether a section is currently open.

func KeyName

func KeyName(k Key) string

KeyName returns a human-readable name for a key.

func ListComponents

func ListComponents() []string

ListComponents returns a list of all registered component names.

func NextFrame

func NextFrame()

NextFrame advances the frame counter and cleans all registered stores. Call this once at the start of each GUI frame (typically in Context.Reset). Stale entries (not accessed in the previous frame) are removed automatically.

func RGBA

func RGBA(r, g, b, a uint8) uint32

RGBA creates a packed color from individual components (0-255).

func RGBAf

func RGBAf(r, g, b, a float32) uint32

RGBAf creates a packed color from float components (0.0-1.0).

func RegisterBuiltinComponents

func RegisterBuiltinComponents()

RegisterBuiltinComponents registers all builtin components. Call this during initialization if you want to use the component registry.

func RegisterComponent

func RegisterComponent(name string, factory ComponentFactory)

RegisterComponent registers a custom component with the given name. Use the "component_" prefix for custom components to avoid naming conflicts.

Example:

gui.RegisterComponent("component_color_wheel", func() gui.Component {
    return &ColorWheel{}
})

func ReleaseDrawList

func ReleaseDrawList(dl *DrawList)

ReleaseDrawList returns a DrawList to the pool for reuse.

func RenderComponent

func RenderComponent(ctx *Context, name string, config func(Component)) bool

RenderComponent renders a registered component by name. Returns false if the component is not registered.

func SetClipboardProvider

func SetClipboardProvider(cp ClipboardProvider)

SetClipboardProvider sets the global clipboard provider. Call this during application initialization with a platform-specific implementation.

Example with GLFW:

gui.SetClipboardProvider(&GLFWClipboard{window: window})

func SetSectionOpen

func SetSectionOpen(ctx *Context, id ID, open bool)

SetSectionOpen sets the open/closed state of a section. Use this for external control (e.g., keyboard shortcuts).

func SetState

func SetState[T any](ctx *Context, id ID, value T)

SetState stores typed state in the context.

func SetVerbose

func SetVerbose(v bool)

SetVerbose enables or disables verbose/debug logging for GUI components. Call this from main() after parsing flags.

func TextWidthEllipsis

func TextWidthEllipsis(ctx *Context, text string, maxWidth float32) string

TextWidthEllipsis returns text that fits within maxWidth, with ellipsis. Unlike TruncateText, this also works with very small widths.

func ToggleSectionState

func ToggleSectionState(ctx *Context, id ID)

ToggleSectionState toggles the open/closed state of a section. Use this for external control (e.g., keyboard shortcuts).

Usage:

sectionID := ctx.GetID("my_section")
gui.ToggleSectionState(ctx, sectionID)

func TruncateText

func TruncateText(ctx *Context, text string, maxWidth float32) string

TruncateText truncates text to fit within maxWidth, adding ellipsis if needed.

func TruncateTextWithSuffix

func TruncateTextWithSuffix(ctx *Context, text string, maxWidth float32, suffix string) string

TruncateTextWithSuffix truncates text and adds a custom suffix.

func UnpackRGBA

func UnpackRGBA(c uint32) (r, g, b, a uint8)

UnpackRGBA extracts RGBA components from a packed color.

func UnregisterComponent

func UnregisterComponent(name string)

UnregisterComponent removes a component from the registry.

func WrapText

func WrapText(ctx *Context, text string, maxWidth float32, mode TextWrapMode) []string

WrapText wraps text to fit within maxWidth using the specified mode. Returns a slice of lines.

func WrapTextSmart

func WrapTextSmart(ctx *Context, text string, maxWidth float32) []string

WrapTextSmart wraps text using smart word/character detection. Latin text wraps at word boundaries, CJK text wraps at character boundaries. Mixed text handles each segment appropriately.

Types

type ActionCondition

type ActionCondition func() bool

ActionCondition returns true if the action can be executed.

type ActionEntry

type ActionEntry struct {
	Name        string          // Action name for debugging
	CheckHotkey HotkeyCheck     // Returns true if hotkey is pressed
	Handler     ActionHandler   // Called when hotkey triggered
	Condition   ActionCondition // Optional: must return true to execute (nil = always)
	BlockedBy   []string        // Panel names that block this action
}

ActionEntry holds a registered action with its hotkey and handler.

type ActionHandler

type ActionHandler func()

ActionHandler is called when an action's hotkey is triggered.

type ActionRegistry

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

ActionRegistry manages hotkey-triggered actions. Use this for global shortcuts that aren't panel toggles.

func NewActionRegistry

func NewActionRegistry(panels *PanelRegistry) *ActionRegistry

NewActionRegistry creates a new action registry. Pass the panel registry to enable BlockedBy checking.

func (*ActionRegistry) Clear

func (r *ActionRegistry) Clear()

Clear removes all registered actions.

func (*ActionRegistry) HandleActions

func (r *ActionRegistry) HandleActions() bool

HandleActions checks all registered actions and executes matching handlers. Returns true if any action was triggered.

func (*ActionRegistry) Register

func (r *ActionRegistry) Register(name string, checkHotkey HotkeyCheck, handler ActionHandler)

Register adds an action with a hotkey check and handler.

func (*ActionRegistry) RegisterBlocked

func (r *ActionRegistry) RegisterBlocked(name string, checkHotkey HotkeyCheck, handler ActionHandler, blockedBy ...string)

RegisterBlocked adds an action that's blocked when certain panels are open.

func (*ActionRegistry) RegisterFull

func (r *ActionRegistry) RegisterFull(name string, checkHotkey HotkeyCheck, handler ActionHandler, condition ActionCondition, blockedBy ...string)

RegisterFull adds an action with all options.

func (*ActionRegistry) RegisterWithCondition

func (r *ActionRegistry) RegisterWithCondition(name string, checkHotkey HotkeyCheck, handler ActionHandler, condition ActionCondition)

RegisterWithCondition adds an action with a condition that must be true to execute.

func (*ActionRegistry) Unregister

func (r *ActionRegistry) Unregister(name string)

Unregister removes an action by name.

type Alignment

type Alignment uint8

Alignment values (like Tailwind items-*)

const (
	AlignStart   Alignment = iota // items-start
	AlignCenter                   // items-center
	AlignEnd                      // items-end
	AlignStretch                  // items-stretch (default)
)

type Cleanable

type Cleanable interface {
	Cleanup(currentFrame uint64)
}

Cleanable is implemented by stores that need frame-based cleanup. Each frame, stale entries (not accessed this frame) are removed.

type ClipboardProvider

type ClipboardProvider interface {
	// GetText retrieves text from the system clipboard.
	// Returns empty string if clipboard is empty or contains non-text data.
	GetText() string

	// SetText copies text to the system clipboard.
	SetText(text string)
}

ClipboardProvider abstracts system clipboard access. Implement this interface with platform-specific clipboard APIs.

For GLFW:

type GLFWClipboard struct {
    window *glfw.Window
}

func (c *GLFWClipboard) GetText() string {
    return c.window.GetClipboardString()
}

func (c *GLFWClipboard) SetText(text string) {
    c.window.SetClipboardString(text)
}

func GetClipboardProvider

func GetClipboardProvider() ClipboardProvider

GetClipboardProvider returns the current clipboard provider, or nil if not set.

type CollapsingHeaderState

type CollapsingHeaderState struct {
	Open bool
}

CollapsingHeaderState tracks collapsed state for collapsing headers.

type ComboBoxState

type ComboBoxState struct {
	Open          bool    // True when dropdown is open
	ScrollY       float32 // Scroll position in dropdown
	HoveredIndex  int     // Currently hovered item index (-1 = none)
	KeyboardIndex int     // Currently keyboard-selected index (-1 = none)
	SearchText    string  // Text typed for filtering (when searchable)
}

ComboBoxState tracks state for combo box widgets.

type Component

type Component interface {
	// Render draws the component using the provided context.
	Render(ctx *Context)
}

Component is the interface that all GUI components implement. This allows users to extend the library with custom components without modifying the core package.

Usage (custom component):

type MyCustomComponent struct {
    label string
    value *float32
}

func (c *MyCustomComponent) Render(ctx *gui.Context) {
    pos := ctx.ItemPos()
    ctx.Text(c.label)
    // ... custom rendering
}

// Register and use:
gui.RegisterComponent("component_custom_slider", func() gui.Component {
    return &MyCustomComponent{}
})

type ComponentButtonWrapper

type ComponentButtonWrapper struct {
	Label   string
	Options []Option
	Clicked bool // Set after Render if button was clicked
}

ComponentButtonWrapper wraps the Button widget as a Component.

func (*ComponentButtonWrapper) HandleInput

func (c *ComponentButtonWrapper) HandleInput(ctx *Context, input *InputState) bool

HandleInput implements InteractiveComponent.

func (*ComponentButtonWrapper) Render

func (c *ComponentButtonWrapper) Render(ctx *Context)

Render implements Component.

type ComponentCheckboxWrapper

type ComponentCheckboxWrapper struct {
	Label   string
	Value   *bool
	Options []Option
	Changed bool // Set after Render if value changed
}

ComponentCheckboxWrapper wraps the Checkbox widget as a Component.

func (*ComponentCheckboxWrapper) HandleInput

func (c *ComponentCheckboxWrapper) HandleInput(ctx *Context, input *InputState) bool

HandleInput implements InteractiveComponent.

func (*ComponentCheckboxWrapper) Render

func (c *ComponentCheckboxWrapper) Render(ctx *Context)

Render implements Component.

type ComponentFactory

type ComponentFactory func() Component

ComponentFactory creates a new instance of a component.

func GetComponent

func GetComponent(name string) ComponentFactory

GetComponent retrieves a component factory by name. Returns nil if the component is not registered.

type ComponentInputTextWrapper

type ComponentInputTextWrapper struct {
	Label   string
	Value   *string
	Options []Option
	Changed bool // Set after Render if value changed
}

ComponentInputTextWrapper wraps the InputText widget as a Component.

func (*ComponentInputTextWrapper) HandleInput

func (c *ComponentInputTextWrapper) HandleInput(ctx *Context, input *InputState) bool

HandleInput implements InteractiveComponent.

func (*ComponentInputTextWrapper) Render

func (c *ComponentInputTextWrapper) Render(ctx *Context)

Render implements Component.

type ComponentSliderWrapper

type ComponentSliderWrapper struct {
	Label   string
	Value   *float32
	Min     float32
	Max     float32
	Options []Option
	Changed bool // Set after Render if value changed
}

ComponentSliderWrapper wraps the SliderFloat widget as a Component.

func (*ComponentSliderWrapper) HandleInput

func (c *ComponentSliderWrapper) HandleInput(ctx *Context, input *InputState) bool

HandleInput implements InteractiveComponent.

func (*ComponentSliderWrapper) Render

func (c *ComponentSliderWrapper) Render(ctx *Context)

Render implements Component.

type ComponentTextWrapper

type ComponentTextWrapper struct {
	Text  string
	Color uint32 // 0 = use default color
}

ComponentTextWrapper wraps the Text widget as a Component.

func (*ComponentTextWrapper) Render

func (c *ComponentTextWrapper) Render(ctx *Context)

Render implements Component.

type ComponentWithID

type ComponentWithID interface {
	Component
	// ID returns the unique identifier for this component instance.
	ID() string
}

ComponentWithID is a component that has a unique identifier.

type ComponentWithState

type ComponentWithState interface {
	Component
	// GetState returns the component's current state.
	GetState() any
	// SetState sets the component's state (used for serialization).
	SetState(state any)
}

ComponentWithState is a component that maintains state between frames.

type Context

type Context struct {
	// Drawing output
	DrawList           *DrawList
	ForegroundDrawList *DrawList // For popups, dropdowns, tooltips (drawn on top)

	// Input (read-only during frame)
	Input *InputState

	// Screen
	DisplaySize Vec2
	DPIScale    float32

	// Frame info
	FrameCount uint64
	DeltaTime  float32

	// Font texture ID (set by renderer) - legacy field for built-in font
	FontTextureID uint32

	// Input capture flags (output from GUI to application)
	// These tell the application whether GUI wants to consume input.
	WantCaptureMouse    bool // True if mouse is over any GUI element
	WantCaptureKeyboard bool // True if a text input has focus

	// Debug visualization
	DebugFocusHighlight bool // When true, draw red overlays on all focused elements
	// contains filtered or unexported fields
}

Context holds all state for UI rendering in a single frame. This is NOT context.Context - it's a dedicated GUI context type. Using a dedicated type avoids type assertions and map lookups, providing better performance and type safety.

func NewContext

func NewContext() *Context

NewContext creates a new GUI context with default settings.

func (*Context) ActiveDragPanel

func (ctx *Context) ActiveDragPanel() *DraggablePanel

ActiveDragPanel returns the panel currently being dragged, or nil.

func (*Context) ActivePopupID

func (ctx *Context) ActivePopupID() ID

ActivePopupID returns the ID of the currently active popup, or 0 if none.

func (*Context) AddText

func (ctx *Context) AddText(x, y float32, text string, color uint32)

AddText draws text with current style (public API). Uses the font provider if available, otherwise falls back to built-in monospace font.

func (*Context) AddTextTo

func (ctx *Context) AddTextTo(dl *DrawList, x, y float32, text string, color uint32)

AddTextTo draws text to a specific DrawList (public API). This is useful for drawing to foreground/overlay layers.

func (*Context) AdvanceCursor

func (ctx *Context) AdvanceCursor(size Vec2)

AdvanceCursor moves the cursor after drawing an item (public API).

func (*Context) BeginFocusGroup

func (ctx *Context) BeginFocusGroup(id ID, name string, rect Rect)

BeginFocusGroup starts a focus scope for a container widget. All focusables registered until EndFocusGroup are considered children of this scope.

func (*Context) BeginFocusScope

func (ctx *Context) BeginFocusScope(id ID, name string, typ FocusType, rect Rect)

BeginFocusScope starts a focusable container scope. Call this when entering a widget that can contain focusable children. Must be paired with EndFocusScope.

Parameters:

  • id: Widget ID for state lookup
  • name: Debug-friendly identifier
  • typ: Widget category (Container, Section, List, etc.)
  • rect: Bounds for hit testing

Usage:

ctx.BeginFocusScope(id, "my_section", FocusTypeSection, rect)
defer ctx.EndFocusScope()
// ... draw focusable children ...

func (*Context) BeginSection

func (ctx *Context) BeginSection(label string, opts ...Option) bool

BeginSection starts a collapsible section. Returns true if the section is expanded and content should be drawn. Must call EndSection() after content if this returns true.

This is the manual-control API for cases where the closure pattern doesn't fit:

if ctx.BeginSection("Settings") {
    ctx.Text("Content")
    ctx.EndSection()
}

func (*Context) BeginTable

func (ctx *Context) BeginTable(id string, columns []TableColumn, flags TableFlags, width, height float32) *Table

BeginTable starts a new table. Returns nil if table should be skipped. columns define the table structure. flags control table behavior. width/height specify outer dimensions (0 = auto).

func (*Context) BeginTableEx

func (ctx *Context) BeginTableEx(id string, columns []TableColumn, flags TableFlags, width, height float32, opts TableOptions) *Table

BeginTableEx starts a new table with additional options.

func (*Context) BeginTableVirtualized

func (ctx *Context) BeginTableVirtualized(id string, columns []TableColumn, flags TableFlags, width, height float32, totalRows int) *Table

BeginTableVirtualized starts a virtualized table for large datasets. Unlike BeginTable, this version only renders visible rows for performance.

Parameters:

  • id: Unique table identifier
  • columns: Column definitions
  • flags: Table behavior flags (must include TableFlagsScrollY)
  • width, height: Table dimensions (height required for virtualization)
  • totalRows: Total number of rows in the dataset

Usage:

table := ctx.BeginTableVirtualized("large_table", columns, flags, 0, 400, 10000)
if table != nil {
    table.TableHeadersRow()
    for i := table.FirstVisibleRow(); i < table.LastVisibleRow(); i++ {
        table.TableNextRowVirtualized(i)
        table.TableText(data[i].Name)
        // ... more columns
    }
    table.EndTable()
}

func (*Context) Bullet

func (ctx *Context) Bullet()

Bullet draws a bullet point.

func (*Context) BulletText

func (ctx *Context) BulletText(text string)

BulletText draws a bullet point with text.

func (*Context) Button

func (ctx *Context) Button(label string, opts ...Option) bool

Button draws a button and returns true if clicked.

func (*Context) CenteredPanel

func (ctx *Context) CenteredPanel(id string, opts ...LayoutOption) func(func())

CenteredPanel draws a panel centered on screen. Uses cached size from previous frame for accurate centering.

This fixes ImGui's "can't center without knowing size" flaw.

func (*Context) Checkbox

func (ctx *Context) Checkbox(label string, value *bool, opts ...Option) bool

Checkbox draws a checkbox with label. Returns true if the value changed.

func (*Context) ClearFocus

func (ctx *Context) ClearFocus()

ClearFocus removes keyboard focus.

func (*Context) ClearRegistryFocus

func (ctx *Context) ClearRegistryFocus()

ClearRegistryFocus removes focus from all widgets in the registry.

func (*Context) CollapsingHeader

func (ctx *Context) CollapsingHeader(label string, opts ...Option) bool

CollapsingHeader draws a collapsible header. Returns true if the section is expanded.

func (*Context) ComboBox

func (ctx *Context) ComboBox(label string, selectedIndex *int, items []string, opts ...Option) bool

ComboBox draws a dropdown selection widget. Returns true if the selection changed.

Usage:

items := []string{"Low", "Medium", "High"}
if ctx.ComboBox("Quality", &selectedIndex, items) {
    applyQuality(selectedIndex)
}

func (*Context) ConsumeScrollFocus

func (ctx *Context) ConsumeScrollFocus() (y, padding float32, ok bool)

ConsumeScrollFocus returns the scroll focus if set, and clears it. Called by Scrollable to get the focus Y that widgets registered. Returns (y, padding, ok) where ok is false if no focus was set.

func (*Context) CurrentID

func (ctx *Context) CurrentID() ID

CurrentID returns the current parent ID (top of stack).

func (*Context) CurrentLayoutWidth

func (ctx *Context) CurrentLayoutWidth() float32

CurrentLayoutWidth returns the available width in the current layout (public API).

func (*Context) DrawDebugFocusForID

func (ctx *Context) DrawDebugFocusForID(id ID, x, y, w, h float32)

DrawDebugFocusForID draws a debug focus highlight if the given ID is registry-focused. Use this in widgets that track focus by ID.

func (*Context) DrawDebugFocusRect

func (ctx *Context) DrawDebugFocusRect(x, y, w, h float32)

DrawDebugFocusRect draws a debug focus highlight on the given rectangle. Only draws if DebugFocusHighlight is enabled. Use this in widgets to visualize focus state during debugging.

func (*Context) DrawDebugFocusRectIf

func (ctx *Context) DrawDebugFocusRectIf(focused bool, x, y, w, h float32)

DrawDebugFocusRectIf draws a debug focus highlight if the condition is true. Convenience method for widgets that check focus state.

func (*Context) DrawToasts

func (ctx *Context) DrawToasts(ts *ToastState)

DrawToasts renders all active toast notifications. Toasts appear in the bottom-right corner, stacked vertically. Call this at the end of your frame, after all other UI.

func (*Context) EndFocusGroup

func (ctx *Context) EndFocusGroup() FocusScopeEntry

EndFocusGroup ends the current focus scope. Returns info about which child had focus.

func (*Context) EndFocusScope

func (ctx *Context) EndFocusScope() FocusInfo

EndFocusScope ends a focusable container scope and returns focus info. The returned FocusInfo tells the parent whether any child had focus and where that focus was (for auto-scroll purposes).

Usage:

ctx.BeginFocusScope(id, "list", FocusTypeList, rect)
// ... draw items, some may call ReportChildFocus ...
info := ctx.EndFocusScope()
if info.HasFocusedChild {
    // Auto-scroll to info.FocusedChildY
}

func (*Context) EndSection

func (ctx *Context) EndSection()

EndSection ends a section started with BeginSection. Must be called after BeginSection returns true.

func (*Context) FocusFirstWidget

func (ctx *Context) FocusFirstWidget() bool

FocusFirstWidget sets focus to the first focusable widget.

func (*Context) FocusLastWidget

func (ctx *Context) FocusLastWidget() bool

FocusLastWidget sets focus to the last focusable widget.

func (*Context) FocusPath

func (ctx *Context) FocusPath() *FocusPath

FocusPath returns the current focus path for inspection. Do not modify the returned path - it's the internal state.

func (*Context) FocusRegistry

func (ctx *Context) FocusRegistry() *FocusRegistry

FocusRegistry returns the focus registry for advanced usage. Most widgets should use the higher-level methods instead.

func (*Context) FocusWidgetByIndex

func (ctx *Context) FocusWidgetByIndex(idx int) bool

FocusWidgetByIndex sets focus to the widget at the given registration index.

func (*Context) FocusedItem

func (ctx *Context) FocusedItem() *FocusableItem

FocusedItem returns the currently focused item from the registry. Returns nil if no widget has focus.

func (*Context) FontProvider

func (ctx *Context) FontProvider() FontProvider

FontProvider returns the current font provider, or nil if not set.

func (*Context) GetCursorPos

func (ctx *Context) GetCursorPos() Vec2

GetCursorPos returns the current cursor position.

func (*Context) GetFocusDepth

func (ctx *Context) GetFocusDepth(id ID) int

GetFocusDepth returns the depth of the given ID in the focus path. Returns -1 if the ID is not in the focus path.

Depth 0 is the root (topmost focused container), increasing toward the leaf.

func (*Context) GetID

func (ctx *Context) GetID(label string) ID

GetID generates a stable ID from a string label. The ID is unique within the current ID stack context. Uses an auto-incrementing counter to differentiate same labels in loops.

func (*Context) GetIDFromInt

func (ctx *Context) GetIDFromInt(n int) ID

GetIDFromInt generates an ID from an integer. Useful for items in arrays/slices.

func (*Context) Graph

func (ctx *Context) Graph(id string, data []GraphData, height float32, opts ...Option)

Graph draws a line graph for time-series data. height specifies the graph height in pixels.

Usage:

data := []gui.GraphData{
    {Label: "FPS", Values: fpsHistory, Color: gui.ColorGreen},
    {Label: "Frame Time", Values: frameTimeHistory, Color: gui.ColorYellow},
}
ctx.Graph("perf_graph", data, 100, gui.WithGraphGridLines(4))

func (*Context) HStack

func (ctx *Context) HStack(opts ...LayoutOption) func(func())

HStack creates a horizontal layout container.

Usage:

ctx.HStack(Gap(8))(func() {
    ctx.Text("Label:")
    ctx.InputText("", &value)
})

func (*Context) HasActivePopup

func (ctx *Context) HasActivePopup() bool

HasActivePopup returns true if a popup is currently open.

func (*Context) HasWidgetFocus

func (ctx *Context) HasWidgetFocus() bool

HasWidgetFocus returns true if any widget has keyboard focus (edit mode). This is different from registry focus (navigation focus).

func (*Context) HintComingSoon

func (ctx *Context) HintComingSoon()

HintComingSoon draws a "coming soon" placeholder.

func (*Context) HintEmpty

func (ctx *Context) HintEmpty(text string)

HintEmpty draws an empty state message. Use when a list or section has no content.

Usage:

if len(items) == 0 {
    ctx.HintEmpty("No items found")
}

func (*Context) HintFooter

func (ctx *Context) HintFooter(hints ...HintAction)

HintFooter draws a consistent footer with keyboard hints. Automatically adds a separator before the hints.

Usage:

ctx.HintFooter(
    gui.Hint(gui.HintKeyUpDown, "Navigate"),
    gui.Hint(gui.HintKeyEnter, "Select"),
    gui.Hint(gui.HintKeyEscape, "Close"),
)

Renders as: "[↑↓] Navigate [Enter] Select [Esc] Close"

func (*Context) HintFooterClose

func (ctx *Context) HintFooterClose()

HintFooterClose draws a simple close hint: [Esc] Close

func (*Context) HintFooterConfirm

func (ctx *Context) HintFooterConfirm()

HintFooterConfirm draws confirmation hints: [Enter] Confirm [Esc] Cancel

func (*Context) HintFooterNav

func (ctx *Context) HintFooterNav()

HintFooterNav draws navigation hints: [↑↓] Navigate [Enter] Select [Esc] Close

func (*Context) HintFooterSearch

func (ctx *Context) HintFooterSearch()

HintFooterSearch draws search hints: [Type] Search [Backspace] Clear [Esc] Close

func (*Context) HintFooterToggle

func (ctx *Context) HintFooterToggle()

HintFooterToggle draws toggle hints: [Enter] Toggle [Esc] Close

func (*Context) HintHeader

func (ctx *Context) HintHeader(text string)

HintHeader draws a hint at the top of a section (before content). Use for instructions like "Type to search..." or "Drag to reorder".

Usage:

ctx.HintHeader("Type to search...")

func (*Context) HintScroll

func (ctx *Context) HintScroll(offset, visible, total int) *ScrollHints

HintScroll creates scroll indicators for a list. Call Before() before drawing items and After() after.

Usage:

scroll := ctx.HintScroll(scrollOffset, visibleItems, totalItems)
scroll.Before() // Draws "^ more above" if needed
for i := startIdx; i < endIdx; i++ {
    // draw items
}
scroll.After() // Draws "v more below" if needed

func (*Context) HintStatus

func (ctx *Context) HintStatus(format string, args ...any)

HintStatus draws a status line showing counts or state.

Usage:

ctx.HintStatus("%d/%d visible", enabledCount, totalCount)

func (*Context) Histogram

func (ctx *Context) Histogram(id string, bars []HistogramBar, height float32, opts ...Option)

Histogram draws a bar chart for comparing values. height specifies the histogram height in pixels.

Usage:

bars := []gui.HistogramBar{
    {Label: "Core 0", Value: 75, Color: gui.ColorGreen},
    {Label: "Core 1", Value: 45, Color: gui.ColorYellow},
    {Label: "Core 2", Value: 90, Color: gui.ColorRed},
}
ctx.Histogram("cpu_usage", bars, 100, gui.WithHistogramShowValues())

func (*Context) Indent

func (ctx *Context) Indent(pixels float32)

Indent increases the cursor X position.

func (*Context) InputText

func (ctx *Context) InputText(label string, value *string, opts ...Option) bool

InputText draws a text input field with full editing support. Features: cursor positioning, text selection, clipboard (Ctrl+C/V/X), undo/redo (Ctrl+Z/Y), and keyboard navigation (arrows, Home/End). Returns true if the value changed.

func (*Context) IsClicked

func (ctx *Context) IsClicked(id ID, rect Rect) bool

IsClicked returns true if the widget was clicked this frame (public API).

func (*Context) IsDraggingPanel

func (ctx *Context) IsDraggingPanel() bool

IsDraggingPanel returns true if any panel is currently being dragged.

func (*Context) IsFocusAncestor

func (ctx *Context) IsFocusAncestor(id ID) bool

IsFocusAncestor returns true if the given ID is anywhere in the current focus path. Use this to determine if a container has focus somewhere within its children.

Example: A section can draw a highlight if any of its children are focused.

func (*Context) IsFocusVisible

func (ctx *Context) IsFocusVisible() bool

IsFocusVisible returns true if focus indicator rings should be drawn. Returns false if no panel registry is set or focus is not active.

func (*Context) IsFocused

func (ctx *Context) IsFocused(id ID) bool

IsFocused returns true if the widget has keyboard focus.

func (*Context) IsHovered

func (ctx *Context) IsHovered(id ID, rect Rect) bool

IsHovered returns true if the widget area is under the mouse cursor (public API).

func (*Context) IsInsideScrollableViewport

func (ctx *Context) IsInsideScrollableViewport(y, h float32) bool

IsInsideScrollableViewport checks if a Y coordinate is inside the current scrollable's visible viewport. Items drawn outside the viewport (clipped) should not respond to mouse events. Returns true if not inside a scrollable (no clipping) or if inside the visible area.

func (*Context) IsPanelFocused

func (ctx *Context) IsPanelFocused(panel Panel) bool

IsPanelFocused returns true if the given panel is currently focused. Returns false if no panel registry is set.

func (*Context) IsRegistryFocused

func (ctx *Context) IsRegistryFocused(id ID) bool

IsRegistryFocused returns true if the given ID has focus in the registry.

func (*Context) ItemPos

func (ctx *Context) ItemPos() Vec2

ItemPos returns the position for the next widget with gap applied. This is the recommended way for widgets to get their drawing position. It handles layout gaps automatically.

func (*Context) LabelText

func (ctx *Context) LabelText(label, value string)

LabelText draws a label and value side by side.

func (*Context) LineHeight

func (ctx *Context) LineHeight() float32

LineHeight returns the height of a single line of text (public API).

func (*Context) List

func (ctx *Context) List(id string, height float32, opts ...Option) *ListBuilder

List creates a new list component with search, collapsible sections, and nested widgets. Returns a ListBuilder for fluent configuration.

Usage:

list := ctx.List("objects", 400, ShowScrollbar(true), WithFilter("Search..."))

list.Section("Vehicles", DefaultOpen()).
    Item("Infernus", selected == 1).
    ItemFunc("Custom", selected == 2, func() {
        ctx.SliderFloat("Speed", &speed, 0, 100)
    }).
    End()

list.Section("Settings").
    ItemFunc("Scale", false, func() {
        ctx.HStack()(func() {
            ctx.NumberInputFloat("", &x, WithPrefix("X:"))
        })
    }).
    End()

list.End()

func (*Context) ListBox

func (ctx *Context) ListBox(id string, height float32, opts ...LayoutOption) func(func())

ListBox draws a scrollable list area with smooth scrolling. height specifies the visible height; contents can be larger.

Usage:

ctx.ListBox("items", 200, Gap(4))(func() {
    for i, item := range items {
        ctx.Selectable(item.Name, i == selected, WithID(item.ID))
    }
})

func (*Context) MarkKeyboardNavigated

func (ctx *Context) MarkKeyboardNavigated()

MarkKeyboardNavigated signals that keyboard navigation occurred this frame. Call this from panels that use custom navigation (not NavigateFocus) to enable auto-scroll when navigating via keyboard. This is automatically called by NavigateFocus, but panels with manual navigation (e.g., custom row selection) should call this explicitly.

func (*Context) MeasureText

func (ctx *Context) MeasureText(text string) Vec2

MeasureText returns the size of rendered text. Uses the font provider if available, otherwise falls back to monospace calculation. Results are cached per-frame to avoid redundant measurements.

func (*Context) NavigateFocus

func (ctx *Context) NavigateFocus(dir NavDirection) bool

NavigateFocus moves focus in the given direction. Returns true if focus moved, false if at boundary or no focusable widgets.

Usage (in panel HandleInput):

if input.KeyPressed(KeyUp) {
    ctx.NavigateFocus(NavUp)
}

func (*Context) NumberInputFloat

func (ctx *Context) NumberInputFloat(label string, value *float32, opts ...Option) bool

NumberInputFloat draws a numeric input field for float32 values. Click to enter text edit mode, or drag left/right to adjust the value. Returns true if the value was changed.

Usage:

ctx.HStack()(func() {
    ctx.NumberInputFloat("", &scaleX, WithPrefix("X:"), WithWidth(60))
    ctx.NumberInputFloat("", &scaleY, WithPrefix("Y:"), WithWidth(60))
    ctx.NumberInputFloat("", &scaleZ, WithPrefix("Z:"), WithWidth(60))
})

func (*Context) NumberInputInt

func (ctx *Context) NumberInputInt(label string, value *int, opts ...Option) bool

NumberInputInt draws a numeric input field for int values. Returns true if the value was changed.

func (*Context) Panel

func (ctx *Context) Panel(title string, opts ...LayoutOption) func(func())

Panel draws a panel with a title and content. Returns a function that should be called with the content closure.

Usage:

ctx.Panel("Menu", Gap(8), Padding(12))(func() {
    ctx.Text("Hello")
    ctx.Button("Click")
})

// With hotkey display:
ctx.Panel("Model Menu", WithHotkey("T"))(func() {
    // Renders header as "Model Menu [T]"
})

func (*Context) PanelRegistry

func (ctx *Context) PanelRegistry() *PanelRegistry

PanelRegistry returns the associated panel registry, or nil if not set.

func (*Context) PopID

func (ctx *Context) PopID()

PopID removes the last ID from the stack.

func (*Context) PopStyle

func (ctx *Context) PopStyle()

PopStyle restores the previous style.

func (*Context) ProgressBar

func (ctx *Context) ProgressBar(fraction float32, opts ...Option)

ProgressBar draws a progress bar. fraction should be between 0.0 and 1.0.

func (*Context) PushID

func (ctx *Context) PushID(label string)

PushID pushes an ID onto the stack for nested widgets. All GetID calls will be relative to this parent ID.

func (*Context) PushIDInt

func (ctx *Context) PushIDInt(n int)

PushIDInt pushes an integer-based ID onto the stack.

func (*Context) PushStyle

func (ctx *Context) PushStyle(style Style)

PushStyle temporarily overrides the style.

func (*Context) PushStyleColor

func (ctx *Context) PushStyleColor(field StyleColorField, color uint32)

PushStyleColor temporarily overrides a single color.

func (*Context) RadioButton

func (ctx *Context) RadioButton(label string, active bool, opts ...Option) bool

RadioButton draws a radio button. Returns true if this option was selected.

func (*Context) RadioGroup

func (ctx *Context) RadioGroup(label string, selectedIndex *int, items []string, opts ...Option) bool

RadioGroup draws a group of radio buttons arranged vertically. Returns true if the selection changed.

Usage:

items := []string{"Low", "Medium", "High"}
if ctx.RadioGroup("Quality", &selectedIndex, items) {
    applyQuality(selectedIndex)
}

func (*Context) RadioGroupHorizontal

func (ctx *Context) RadioGroupHorizontal(label string, selectedIndex *int, items []string, opts ...Option) bool

RadioGroupHorizontal draws a group of radio buttons arranged horizontally. Returns true if the selection changed.

Usage:

items := []string{"On", "Off"}
if ctx.RadioGroupHorizontal("Status", &selectedIndex, items) {
    applyStatus(selectedIndex)
}

func (*Context) RegisterFocusable

func (ctx *Context) RegisterFocusable(id ID, name string, rect Rect, typ FocusType) *FocusableHandle

RegisterFocusable registers a widget as focusable for this frame. Returns a FocusableHandle that can be used to check focus state and handle navigation. The debug focus highlight is drawn automatically if the widget is focused.

Usage:

func (ctx *Context) MyWidget(label string) {
    id := ctx.GetID(label)
    rect := Rect{X: pos.X, Y: pos.Y, W: w, H: h}
    focusable := ctx.RegisterFocusable(id, label, rect, FocusTypeLeaf)
    // Debug highlight is drawn automatically
    if focusable.IsFocused() {
        // Apply focused styling
    }
}

func (*Context) RegisterFocusableDisabled

func (ctx *Context) RegisterFocusableDisabled(id ID, name string, rect Rect, typ FocusType) *FocusableHandle

RegisterFocusableDisabled registers a widget that cannot receive focus. It's still tracked for navigation purposes (e.g., skipped when navigating).

func (*Context) ReportChildFocus

func (ctx *Context) ReportChildFocus(y, height float32)

ReportChildFocus is called by focused children to inform their parent container. The parent's EndFocusScope will receive this information in FocusInfo.

Parameters:

  • y: Y position of the focused child (screen coordinates or content-relative)
  • height: Height of the focused child

Usage (from a list item that's selected):

if isSelected {
    ctx.ReportChildFocus(itemY, itemHeight)
}

func (*Context) Reset

func (ctx *Context) Reset(displaySize Vec2, deltaTime float32)

Reset prepares the context for a new frame.

func (*Context) Row

func (ctx *Context) Row(contents func())

Row creates a horizontal layout for its contents (alias for HStack).

func (*Context) SameLine

func (ctx *Context) SameLine()

SameLine places the next widget on the same line as the previous.

func (*Context) ScrollTo

func (ctx *Context) ScrollTo(screenY float32, padding float32)

ScrollTo registers the current cursor position as the focus for the parent Scrollable. Call this from any widget inside a Scrollable to make it scroll to keep the widget visible. The coordinate translation from screen position to content-relative is automatic.

Usage (inside a Scrollable):

ctx.Scrollable("list", 300)(func() {
    for i, item := range items {
        if i == selectedIndex {
            ctx.ScrollTo(ctx.cursor.Y, rowHeight) // Just pass cursor.Y!
        }
        ctx.Text(item.Name)
    }
})

The Scrollable will auto-scroll to keep this Y visible when it changes between frames.

func (*Context) Scrollable

func (ctx *Context) Scrollable(id string, height float32, opts ...Option) func(func())

Scrollable creates a scrollable area that can wrap any content. Returns a function that should be called with the content closure.

Usage:

ctx.Scrollable("my_scroll", 300, ShowScrollbar(true))(func() {
    // Any widgets here become scrollable
    ctx.Text("Line 1")
    ctx.Text("Line 2")
    ctx.Button("Click me")
    ctx.SliderFloat("Volume", &vol, 0, 1)
    // ... unlimited content
})

func (*Context) Section

func (ctx *Context) Section(label string, opts ...Option) func(func())

Section creates a collapsible section that can contain any widgets, including nested sections. Returns a function that should be called with the content closure.

The Section widget provides: - Click to expand/collapse - Arrow indicator (► collapsed, ▼ expanded) - Auto-indentation of content - Keyboard focus support (cyan highlight when focused) - Auto-scroll to focused section via ctx.ScrollTo()

Usage:

ctx.Section("Settings")(func() {
    ctx.SliderFloat("Volume", &vol, 0, 1)
    ctx.Section("Advanced")(func() {  // Nesting supported
        ctx.Text("Nested content")
    })
})

With options:

ctx.Section("Graphics", DefaultOpen(), Focused())(func() {
    ctx.Text("Content")
})

func (*Context) Selectable

func (ctx *Context) Selectable(label string, selected bool, opts ...Option) bool

Selectable draws a selectable list item. Returns true if clicked.

func (*Context) SelectableRow

func (ctx *Context) SelectableRow(selected bool, rowWidth float32) func(func())

SelectableRow wraps content with selection highlighting. Use this to create custom selectable rows with consistent styling. The content function renders the row's contents. Pass rowWidth to specify the highlight width (0 = use default 200px).

Example:

ctx.SelectableRow(isSelected, 180)(func() {
    ctx.Text("Label:")
    ctx.InputText("", &value, gui.WithID("input"))
})

func (*Context) Separator

func (ctx *Context) Separator()

Separator draws a horizontal line.

func (*Context) Sequencer

func (ctx *Context) Sequencer(id string, config SequencerConfig, height float32, opts ...Option) bool

Sequencer draws an animation timeline with tracks and keyframes. height specifies the total sequencer height in pixels. Returns true if the current time changed due to user interaction.

Layout:

+------------------------------------------+
| [>] [||]    | 0:00      0:30      1:00  |  <- Controls + time ruler
+------------------------------------------+
| v Root      |    o----o-------o----     |  <- Track with keyframes
|   Pelvis    |      o-------o--------    |
| > L_Leg     |    ---------------        |  <- Collapsed track
+------------------------------------------+
                   ^
                   | Playhead (red line)

func (*Context) SetActiveDragPanel

func (ctx *Context) SetActiveDragPanel(dp *DraggablePanel)

SetActiveDragPanel sets the panel currently being dragged. Only one panel can be dragged at a time.

func (*Context) SetActivePopup

func (ctx *Context) SetActivePopup(id ID)

SetActivePopup marks a popup (dropdown, menu) as open. While a popup is active, focus navigation should stay within it. Call with id=0 to close the popup.

func (*Context) SetCursorPos

func (ctx *Context) SetCursorPos(x, y float32)

SetCursorPos sets the cursor position for the next widget.

func (*Context) SetFocusChildIdx

func (ctx *Context) SetFocusChildIdx(idx int)

SetFocusChildIdx sets the focused child index for the current focus scope. Call this when you know which child index is focused (e.g., selected row in table).

func (*Context) SetFocusPath

func (ctx *Context) SetFocusPath(nodes ...FocusNode)

SetFocusPath sets a node in the focus path. This is typically called when focus changes (e.g., user clicks, keyboard nav).

func (*Context) SetFocused

func (ctx *Context) SetFocused(id ID)

SetFocused sets the focused widget.

func (*Context) SetFont

func (ctx *Context) SetFont(name string) error

SetFont sets the active font by name. Returns an error if the font is not found. Does nothing if no font provider is set.

func (*Context) SetFontProvider

func (ctx *Context) SetFontProvider(fp FontProvider)

SetFontProvider sets the font provider for advanced font support. The provider must implement the FontProvider interface. Pass nil to disable font provider and use built-in monospace font.

func (*Context) SetPanelRegistry

func (ctx *Context) SetPanelRegistry(registry *PanelRegistry)

SetPanelRegistry associates a panel registry with this context. This enables panel focus tracking for Ctrl+Tab cycling.

func (*Context) SetRegistryFocus

func (ctx *Context) SetRegistryFocus(id ID)

SetRegistryFocus sets focus to the widget with the given ID. This updates the focus registry, which is separate from the simple focusedID.

func (*Context) SetScrollFocus

func (ctx *Context) SetScrollFocus(y float32, padding float32)

SetScrollFocus registers a Y position that should be kept visible by parent Scrollable. Call this from widgets (like Table) when they have a selected/focused row. The parent Scrollable will automatically scroll to keep this Y visible. The Y is relative to the Scrollable's content area (not screen coordinates).

func (*Context) SetStyle

func (ctx *Context) SetStyle(style Style)

SetStyle sets the base style.

func (*Context) SliderFloat

func (ctx *Context) SliderFloat(label string, value *float32, minVal, maxVal float32, opts ...Option) bool

SliderFloat draws a horizontal slider for float32 values. Returns true if the value was changed.

Usage:

if ctx.SliderFloat("Volume", &volume, 0, 1) {
    updateVolume(volume)
}

func (*Context) SliderInt

func (ctx *Context) SliderInt(label string, value *int, minVal, maxVal int, opts ...Option) bool

SliderInt draws a horizontal slider for int values. Returns true if the value was changed.

Usage:

if ctx.SliderInt("Count", &count, 0, 100) {
    updateCount(count)
}

func (*Context) SmallButton

func (ctx *Context) SmallButton(label string, opts ...Option) bool

SmallButton draws a smaller button without extra padding.

func (*Context) Spacing

func (ctx *Context) Spacing(pixels float32)

Spacing adds vertical space.

func (*Context) Style

func (ctx *Context) Style() Style

Style returns the current style.

func (*Context) Text

func (ctx *Context) Text(text string)

Text draws text at the current cursor position.

func (*Context) TextColored

func (ctx *Context) TextColored(text string, color uint32)

TextColored draws text with a specific color.

func (*Context) TextDisabled

func (ctx *Context) TextDisabled(text string)

TextDisabled draws text with the disabled color.

func (*Context) TextWrapped

func (ctx *Context) TextWrapped(text string, maxWidth float32)

TextWrapped draws text with automatic word wrapping. maxWidth specifies the maximum line width (0 = use current layout width). This fixes ImGui's missing text wrapping feature.

func (*Context) Tooltip

func (ctx *Context) Tooltip(text string)

Tooltip shows a tooltip at the mouse position. Should be called right after the widget you want to add a tooltip to.

func (*Context) TreeNode

func (ctx *Context) TreeNode(label string, opts ...Option) bool

TreeNode draws a tree node that can be expanded/collapsed. Returns true if the node is expanded (call TreePop when done).

func (*Context) TreePop

func (ctx *Context) TreePop()

TreePop ends a tree node started with TreeNode.

func (*Context) Unindent

func (ctx *Context) Unindent(pixels float32)

Unindent decreases the cursor X position.

func (*Context) VStack

func (ctx *Context) VStack(opts ...LayoutOption) func(func())

VStack creates a vertical layout container.

Usage:

ctx.VStack(Gap(8))(func() {
    ctx.Text("Line 1")
    ctx.Text("Line 2")
})

type CursorChangeCallback

type CursorChangeCallback func(captured bool)

CursorChangeCallback is called when cursor capture state should change. captured=true means cursor should be captured (hidden, for FPS camera). captured=false means cursor should be released (visible, for UI interaction).

type DragState

type DragState struct {
	Active    bool    // Currently being dragged
	StartX    float32 // Mouse X when drag started
	StartY    float32 // Mouse Y when drag started
	OffsetX   float32 // Panel X offset from mouse when drag started
	OffsetY   float32 // Panel Y offset from mouse when drag started
	PanelName string  // Name of the panel being dragged (for identification)
}

DragState tracks the state of a drag operation. Used by draggable panels to enable window movement.

func (*DragState) Reset

func (d *DragState) Reset()

Reset clears the drag state.

type DraggablePanel

type DraggablePanel struct {
	// Position is the panel's current position.
	Position Vec2

	// Size is the panel's current size (set after drawing).
	Size Vec2

	// Draggable enables/disables drag functionality.
	Draggable bool

	// TitleBarHeight is the height of the draggable title bar region.
	// If 0, uses the default (line height + padding).
	TitleBarHeight float32

	// SnapConfig controls snapping behavior.
	SnapConfig SnapConfig

	// Resizable enables/disables resize functionality.
	Resizable bool

	// MinSize is the minimum allowed size when resizing.
	MinSize Vec2

	// MaxSize is the maximum allowed size when resizing.
	// Zero means no maximum.
	MaxSize Vec2

	// ResizeHandleSize is the width of the resize handle area in pixels.
	// Default is 6 pixels.
	ResizeHandleSize float32
	// contains filtered or unexported fields
}

DraggablePanel wraps panel positioning and drag behavior. Panels can embed this to gain drag functionality.

func NewDraggablePanel

func NewDraggablePanel(x, y float32) *DraggablePanel

NewDraggablePanel creates a new draggable panel with default settings.

func NewResizablePanel

func NewResizablePanel(x, y, w, h float32) *DraggablePanel

NewResizablePanel creates a new draggable and resizable panel.

func (*DraggablePanel) Constrain

func (dp *DraggablePanel) Constrain(displaySize Vec2)

Constrain ensures the panel stays within screen bounds.

func (*DraggablePanel) DrawResizeHandles

func (dp *DraggablePanel) DrawResizeHandles(ctx *Context)

DrawResizeHandles draws visual indicators for resize handles. Call this after drawing the panel content. Uses dp.Position and dp.Size for bounds - ensure Size is updated before calling.

func (*DraggablePanel) DrawResizeHandlesAt

func (dp *DraggablePanel) DrawResizeHandlesAt(ctx *Context, x, y, w, h float32)

DrawResizeHandlesAt draws resize handles at specific bounds. Use this when the panel's actual rendered bounds differ from dp.Size.

func (*DraggablePanel) DrawSnapGuides

func (dp *DraggablePanel) DrawSnapGuides(ctx *Context)

DrawSnapGuides draws the snap guide lines during a drag operation. Call this after drawing all panels to show snap feedback on top.

func (*DraggablePanel) GetPosition

func (dp *DraggablePanel) GetPosition() Vec2

GetPosition returns the current panel position.

func (*DraggablePanel) GetResizeEdge

func (dp *DraggablePanel) GetResizeEdge(ctx *Context) ResizableEdge

GetResizeEdge returns which edge(s) the mouse is near for resize. Returns ResizeEdgeNone if mouse is not near any edge or if not resizable.

func (*DraggablePanel) GetSize

func (dp *DraggablePanel) GetSize() Vec2

GetSize returns the current panel size.

func (*DraggablePanel) HandleDrag

func (dp *DraggablePanel) HandleDrag(ctx *Context) bool

HandleDrag processes drag input for the panel. Call this before drawing the panel each frame. Returns true if the panel is currently being dragged.

func (*DraggablePanel) HandleResize

func (dp *DraggablePanel) HandleResize(ctx *Context) bool

HandleResize processes resize input for the panel. Call this before drawing the panel each frame. Returns true if the panel is currently being resized.

func (*DraggablePanel) HasActiveSnapGuides

func (dp *DraggablePanel) HasActiveSnapGuides() bool

HasActiveSnapGuides returns true if there are snap guides to display.

func (*DraggablePanel) IsDragging

func (dp *DraggablePanel) IsDragging() bool

IsDragging returns true if the panel is currently being dragged.

func (*DraggablePanel) IsResizing

func (dp *DraggablePanel) IsResizing() bool

IsResizing returns true if the panel is currently being resized.

func (*DraggablePanel) SetPosition

func (dp *DraggablePanel) SetPosition(x, y float32)

SetPosition sets the panel position.

func (*DraggablePanel) SetSize

func (dp *DraggablePanel) SetSize(w, h float32)

SetSize sets the panel size (typically called after measuring content).

func (*DraggablePanel) SetSnapManager

func (dp *DraggablePanel) SetSnapManager(sm *SnapManager, panelName string)

SetSnapManager sets the snap manager for live snap visualization. Pass nil to disable snap visualization.

func (*DraggablePanel) TitleBarRect

func (dp *DraggablePanel) TitleBarRect(ctx *Context) Rect

TitleBarRect returns the rectangle for the draggable title bar area. The title bar is at the top of the panel.

type DrawCmd

type DrawCmd struct {
	ElemCount    uint32     // Number of indices to draw
	ClipRect     [4]float32 // Clip rectangle (x1, y1, x2, y2)
	TextureID    uint32     // OpenGL texture ID (0 = no texture)
	VertexOffset uint32     // Offset into vertex buffer
	IndexOffset  uint32     // Offset into index buffer
}

DrawCmd represents a single draw command. Commands are batched by texture to minimize state changes.

type DrawList

type DrawList struct {
	CmdBuffer []DrawCmd // Draw commands
	VtxBuffer []Vertex  // Vertex data
	IdxBuffer []uint16  // Index data
	// contains filtered or unexported fields
}

DrawList accumulates draw commands for a frame. It batches primitives by texture to minimize GPU state changes.

func AcquireDrawList

func AcquireDrawList() *DrawList

AcquireDrawList gets a DrawList from the pool. Call ReleaseDrawList when done to return it.

func (*DrawList) AddGlyphQuads

func (dl *DrawList) AddGlyphQuads(quads []GlyphQuad, color uint32)

AddGlyphQuads draws a slice of glyph quads with the specified color. This is used for rendering text from proportional fonts.

func (*DrawList) AddLine

func (dl *DrawList) AddLine(x1, y1, x2, y2 float32, color uint32, thickness float32)

AddLine draws a line between two points. Uses a quad to create thickness.

func (*DrawList) AddRect

func (dl *DrawList) AddRect(x, y, w, h float32, color uint32)

AddRect draws a filled rectangle.

func (*DrawList) AddRectOutline

func (dl *DrawList) AddRectOutline(x, y, w, h float32, color uint32, thickness float32)

AddRectOutline draws a rectangle outline.

func (*DrawList) AddText

func (dl *DrawList) AddText(x, y float32, text string, color uint32, fontScale float32, charWidth, charHeight float32)

AddText draws text at the specified position. fontScale is typically 1.0 for normal size. charWidth and charHeight define the size of each character cell.

func (*DrawList) AddTriangle

func (dl *DrawList) AddTriangle(x1, y1, x2, y2, x3, y3 float32, color uint32)

AddTriangle draws a filled triangle.

func (*DrawList) Clear

func (dl *DrawList) Clear()

Clear resets the DrawList for a new frame. Retains allocated capacity to avoid reallocations.

func (*DrawList) Finalize

func (dl *DrawList) Finalize()

Finalize prepares the DrawList for rendering. Must be called after all primitives are added.

func (*DrawList) InsertRect

func (dl *DrawList) InsertRect(x, y, w, h float32, color uint32)

InsertRect inserts a rectangle at the beginning of the draw list. Useful for drawing backgrounds after content (to get correct size).

func (*DrawList) PopClipRect

func (dl *DrawList) PopClipRect()

PopClipRect pops the clip rectangle stack.

func (*DrawList) PushClipRect

func (dl *DrawList) PushClipRect(x1, y1, x2, y2 float32)

PushClipRect pushes a new clip rectangle onto the stack. All subsequent primitives will be clipped to this rectangle.

func (*DrawList) SetTexture

func (dl *DrawList) SetTexture(textureID uint32)

SetTexture sets the current texture for subsequent primitives.

type FocusInfo

type FocusInfo struct {
	// HasFocusedChild is true if any child within the scope had focus
	HasFocusedChild bool

	// FocusedChildIdx is the index of the focused child within this scope
	// -1 if no child is focused or if the scope itself is focused
	FocusedChildIdx int

	// FocusedChildY is the Y position of the focused child (for auto-scroll)
	// Relative to the scope's content area
	FocusedChildY float32

	// FocusedChildHeight is the height of the focused child
	FocusedChildHeight float32
}

FocusInfo is returned by EndFocusScope to inform the parent about focus within the scope that just ended.

type FocusManager

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

FocusManager tracks which panel currently has keyboard focus and handles panel cycling with Ctrl+Tab. This enables ImGui-like window navigation without requiring a full docking system.

Key features: - Tracks a single focused panel from the registry - Ctrl+Tab / Ctrl+Shift+Tab to cycle focus between open panels - Visual focus indicator ring on the focused panel - Arrow key navigation between adjacent panels (future)

func NewFocusManager

func NewFocusManager(registry *PanelRegistry) *FocusManager

NewFocusManager creates a new focus manager attached to a panel registry.

func (*FocusManager) ClearFocus

func (fm *FocusManager) ClearFocus()

ClearFocus removes focus from all panels.

func (*FocusManager) FocusNext

func (fm *FocusManager) FocusNext()

FocusNext cycles focus to the next open panel (Ctrl+Tab).

func (*FocusManager) FocusPanel

func (fm *FocusManager) FocusPanel(panel Panel)

FocusPanel focuses a specific panel by reference.

func (*FocusManager) FocusPanelByName

func (fm *FocusManager) FocusPanelByName(name string)

FocusPanelByName focuses a specific panel by name.

func (*FocusManager) FocusPrev

func (fm *FocusManager) FocusPrev()

FocusPrev cycles focus to the previous open panel (Ctrl+Shift+Tab).

func (*FocusManager) FocusedPanel

func (fm *FocusManager) FocusedPanel() Panel

FocusedPanel returns the currently focused panel, or nil if none.

func (*FocusManager) FocusedPanelName

func (fm *FocusManager) FocusedPanelName() string

FocusedPanelName returns the name of the currently focused panel, or empty string.

func (*FocusManager) HandleInput

func (fm *FocusManager) HandleInput(input *InputState) bool

HandleInput processes focus-related keyboard input. Returns true if input was consumed.

func (*FocusManager) IsFocusVisible

func (fm *FocusManager) IsFocusVisible() bool

IsFocusVisible returns true if the focus indicator should be drawn.

func (*FocusManager) IsFocused

func (fm *FocusManager) IsFocused(panel Panel) bool

IsFocused returns true if the given panel is currently focused.

func (*FocusManager) SetFocusVisible

func (fm *FocusManager) SetFocusVisible(visible bool)

SetFocusVisible enables or disables the focus indicator ring.

func (*FocusManager) Update

func (fm *FocusManager) Update()

Update synchronizes the focused index with the registry's open panels. Call this each frame before handling input to ensure the focused panel is still valid (e.g., if a panel was closed externally).

type FocusNode

type FocusNode struct {
	ID       ID        // Widget ID for state lookup
	Name     string    // Debug-friendly identifier
	Type     FocusType // Widget category
	ChildIdx int       // Which child is focused (-1 = self/none)
	Rect     Rect      // Bounds for hit testing
	// contains filtered or unexported fields
}

FocusNode represents one level in the focus hierarchy. Each node knows its ID, type, and which child (if any) has focus.

type FocusPath

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

FocusPath tracks the active path from root to the focused leaf widget. This enables hierarchical focus tracking where parents know which child has focus and where focus is within that child.

Example path for a focused table row inside a scrollable inside a panel:

[0] Panel      (ChildIdx=0, points to Scrollable)
[1] Scrollable (ChildIdx=2, points to Table row)
[2] Table      (ChildIdx=5, row index)

func NewFocusPath

func NewFocusPath() *FocusPath

NewFocusPath creates an empty focus path.

func (*FocusPath) At

func (fp *FocusPath) At(depth int) FocusNode

At returns the node at the given depth, or empty node if out of range.

func (*FocusPath) Clear

func (fp *FocusPath) Clear()

Clear removes all nodes from the path.

func (*FocusPath) Contains

func (fp *FocusPath) Contains(id ID) bool

Contains returns true if the given ID is anywhere in the focus path.

func (*FocusPath) Depth

func (fp *FocusPath) Depth() int

Depth returns the current depth of the focus path.

func (*FocusPath) IndexOf

func (fp *FocusPath) IndexOf(id ID) int

IndexOf returns the depth of the given ID in the path, or -1 if not found.

func (*FocusPath) Leaf

func (fp *FocusPath) Leaf() FocusNode

Leaf returns the deepest (most specific) focused node, or empty if no focus.

func (*FocusPath) Nodes

func (fp *FocusPath) Nodes() []FocusNode

Nodes returns a copy of all nodes in the path.

func (*FocusPath) Pop

func (fp *FocusPath) Pop() FocusNode

Pop removes and returns the last node, or empty node if path is empty.

func (*FocusPath) Push

func (fp *FocusPath) Push(node FocusNode)

Push adds a node to the path.

func (*FocusPath) Root

func (fp *FocusPath) Root() FocusNode

Root returns the topmost focused node, or empty if no focus.

func (*FocusPath) SetChildIdx

func (fp *FocusPath) SetChildIdx(depth int, childIdx int) bool

SetChildIdx updates the ChildIdx of the node at the given depth. Returns false if depth is out of range.

func (*FocusPath) Version

func (fp *FocusPath) Version() uint64

Version returns the current version number. Incremented each time the path changes, useful for dirty checking.

type FocusRegistry

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

FocusRegistry manages focusable widgets within a single frame. This bridges the immediate-mode GUI paradigm with the Focusable interface.

In immediate-mode GUI, widgets don't persist between frames - they're drawn fresh each frame. The FocusRegistry solves this by:

  1. Widgets register themselves as focusable during drawing
  2. The registry tracks which widget has focus via ID matching
  3. Navigation methods move focus between registered widgets
  4. Debug highlighting is drawn automatically for focused widgets

IMPORTANT: Due to frame ordering (HandleInput before Draw), the registry uses double-buffering. Navigation uses the previous frame's registrations while new registrations build up in the current frame's buffer.

Usage:

// In Context initialization
ctx.focusRegistry = NewFocusRegistry()

// In widget drawing
focusable := ctx.RegisterFocusable(id, "button", rect, FocusTypeLeaf)
if focusable.IsFocused() {
    ctx.DrawDebugFocusRect(rect.X, rect.Y, rect.W, rect.H)
}

// In panel HandleInput
if input.KeyPressed(KeyUp) {
    ctx.NavigateFocus(NavUp)
}

func NewFocusRegistry

func NewFocusRegistry() *FocusRegistry

NewFocusRegistry creates a new focus registry.

func (*FocusRegistry) BeginScope

func (r *FocusRegistry) BeginScope(id ID, name string, typ FocusType, rect Rect)

BeginScope starts a new focus scope (container). Child widgets registered after this are considered part of the scope.

func (*FocusRegistry) ClearFocus

func (r *FocusRegistry) ClearFocus()

ClearFocus removes focus from all widgets.

func (*FocusRegistry) CurrentFocusID

func (r *FocusRegistry) CurrentFocusID() ID

CurrentFocusID returns the ID of the currently focused widget.

func (*FocusRegistry) CurrentFocusIdx

func (r *FocusRegistry) CurrentFocusIdx() int

CurrentFocusIdx returns the index of the currently focused widget in prevItems. Returns -1 if no widget is focused.

func (*FocusRegistry) CurrentFocusItem

func (r *FocusRegistry) CurrentFocusItem() *FocusableItem

CurrentFocusItem returns the currently focused item, or nil if none. Uses prevItems for consistency with navigation (double-buffered).

func (*FocusRegistry) CurrentItemCount

func (r *FocusRegistry) CurrentItemCount() int

CurrentItemCount returns the number of items registered in the current frame so far. This is for debugging - shows items being built during Draw.

func (*FocusRegistry) EndScope

func (r *FocusRegistry) EndScope() FocusScopeEntry

EndScope ends the current focus scope. Returns info about which child had focus.

func (*FocusRegistry) FocusByIndex

func (r *FocusRegistry) FocusByIndex(idx int) bool

FocusByIndex sets focus to the item at the given registration index. Uses prevItems for navigation (double-buffered).

func (*FocusRegistry) FocusFirst

func (r *FocusRegistry) FocusFirst() bool

FocusFirst sets focus to the first focusable widget. Uses prevItems for navigation (double-buffered).

func (*FocusRegistry) FocusLast

func (r *FocusRegistry) FocusLast() bool

FocusLast sets focus to the last focusable widget. Uses prevItems for navigation (double-buffered).

func (*FocusRegistry) ItemCount

func (r *FocusRegistry) ItemCount() int

ItemCount returns the number of registered focusable items from the previous frame. This is the count used for navigation (double-buffered).

func (*FocusRegistry) Items

func (r *FocusRegistry) Items() []FocusableItem

Items returns all registered items from the previous frame (for debugging/inspection). This is what's used for navigation (double-buffered).

func (*FocusRegistry) MarkKeyboardNavigated

func (r *FocusRegistry) MarkKeyboardNavigated()

MarkKeyboardNavigated manually sets the keyboard navigation flag. Call this from panels that use custom navigation (not NavigateFocus) to enable auto-scroll when navigating via keyboard.

func (*FocusRegistry) Navigate

func (r *FocusRegistry) Navigate(dir NavDirection) bool

Navigate moves focus in the given direction. Returns true if focus moved, false if at boundary or no focusable widgets. Uses the previous frame's items for navigation (double-buffered). Sets keyboardNavigated flag on success, enabling auto-scroll in Scrollable.

func (*FocusRegistry) Register

func (r *FocusRegistry) Register(id ID, name string, rect Rect, typ FocusType) *FocusableHandle

Register adds a focusable widget to the registry. Returns a FocusableHandle that can be used to check focus state.

func (*FocusRegistry) RegisterDisabled

func (r *FocusRegistry) RegisterDisabled(id ID, name string, rect Rect, typ FocusType) *FocusableHandle

RegisterDisabled adds a widget that cannot receive focus but is tracked for navigation.

func (*FocusRegistry) Reset

func (r *FocusRegistry) Reset()

Reset is a convenience method that calls ResetForFrame(0). Deprecated: Use ResetForFrame with a frame number for proper double-reset protection.

func (*FocusRegistry) ResetForFrame

func (r *FocusRegistry) ResetForFrame(frameNumber uint64)

Reset prepares the registry for a new frame. Called at the start of each frame by GUI.PrepareInputHandling(). Uses double-buffering: previous frame's items are kept for navigation while current frame builds new registrations.

The frameNumber parameter prevents double-reset when called multiple times in the same frame (e.g., from PrepareInputHandling and Context.Reset).

func (*FocusRegistry) SetFocus

func (r *FocusRegistry) SetFocus(id ID)

SetFocus sets focus to the widget with the given ID. Searches prevItems for navigation (double-buffered).

func (*FocusRegistry) SetFocusDeferred

func (r *FocusRegistry) SetFocusDeferred(id ID)

SetFocusDeferred sets focus to take effect next frame. Use this when setting focus from outside the render loop.

func (*FocusRegistry) SetNavHandler

func (r *FocusRegistry) SetNavHandler(handler func(dir NavDirection) bool)

SetNavHandler sets a custom navigation handler. Return true to indicate navigation was handled, false for default behavior.

func (*FocusRegistry) WasKeyboardNavigated

func (r *FocusRegistry) WasKeyboardNavigated() bool

WasKeyboardNavigated returns true if auto-scroll should be enabled. Defaults to true at frame start. Set to false to disable auto-scroll for specific interactions that shouldn't trigger scrolling.

type FocusScopeEntry

type FocusScopeEntry struct {
	ID           ID
	Name         string
	Type         FocusType
	Rect         Rect
	StartIdx     int // Index of first child in items
	FocusedChild int // Which child has focus (-1 = none)
}

FocusScopeEntry represents a nested focus scope (container).

type FocusType

type FocusType uint8

FocusType identifies the kind of focusable widget in the hierarchy.

const (
	// FocusTypeContainer can contain focusable children (panels, groups)
	FocusTypeContainer FocusType = iota

	// FocusTypeLeaf is a terminal focusable element (button, input)
	FocusTypeLeaf

	// FocusTypeSection is a collapsible container
	FocusTypeSection

	// FocusTypeList has indexed children (tables, lists)
	FocusTypeList
)

func (FocusType) String

func (t FocusType) String() string

String returns a human-readable name for the focus type.

type FocusValue

type FocusValue struct {
	Y       float32
	Padding float32
	Set     bool
}

FocusValue holds focus Y position and padding for auto-scroll.

type Focusable

type Focusable interface {
	// IsFocused returns true if this widget currently has focus.
	IsFocused() bool

	// CanFocus returns true if this widget can receive focus.
	// Some widgets may be disabled or hidden and should return false.
	CanFocus() bool

	// HandleNav processes a navigation input and returns true if handled.
	// If the widget handles the navigation internally (e.g., moving between
	// items in a list), it returns true. If the navigation should propagate
	// to the parent (e.g., trying to move up from the first item), return false.
	HandleNav(dir NavDirection) bool
}

Focusable is implemented by widgets that can receive keyboard focus. This interface enables the focus hierarchy to navigate between widgets.

Widgets that contain focusable children should implement the container methods (FocusedChildIndex, FocusChild, ChildCount) in addition to the basic focus methods.

type FocusableContainer

type FocusableContainer interface {
	Focusable

	// FocusedChildIndex returns the index of the currently focused child.
	// Returns -1 if no child is focused (the container itself may have focus).
	FocusedChildIndex() int

	// FocusChild sets focus to the child at the given index.
	// Pass -1 to focus the container itself.
	FocusChild(index int)

	// ChildCount returns the number of focusable children.
	ChildCount() int
}

FocusableContainer extends Focusable for widgets that contain focusable children. Examples: Panels, Sections, Lists, Tables.

type FocusableHandle

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

FocusableHandle is returned by RegisterFocusable and implements the Focusable interface. It provides methods to check focus state and handle navigation.

func (*FocusableHandle) CanFocus

func (h *FocusableHandle) CanFocus() bool

CanFocus returns true if this widget can receive focus.

func (*FocusableHandle) Focus

func (h *FocusableHandle) Focus()

Focus requests focus for this widget.

func (*FocusableHandle) FocusBounds

func (h *FocusableHandle) FocusBounds() Rect

FocusBounds returns the rectangle for auto-scroll purposes.

func (*FocusableHandle) HandleNav

func (h *FocusableHandle) HandleNav(dir NavDirection) bool

HandleNav processes a navigation input. For leaf widgets, this always returns false (propagate to parent). Container widgets should override by setting custom nav targets.

func (*FocusableHandle) Index

func (h *FocusableHandle) Index() int

Index returns the registration index of this item.

func (*FocusableHandle) IsFocused

func (h *FocusableHandle) IsFocused() bool

IsFocused returns true if this widget currently has focus.

func (*FocusableHandle) SetNavTarget

func (h *FocusableHandle) SetNavTarget(dir NavDirection, targetID ID)

SetNavTarget sets a custom navigation target for a direction.

type FocusableItem

type FocusableItem struct {
	ID       ID        // Unique widget identifier
	Name     string    // Debug-friendly name
	Rect     Rect      // Bounds for hit testing and navigation
	Type     FocusType // Widget category
	ScopeIdx int       // Index of parent scope (-1 if root level)
	CanFocus bool      // Whether this widget can receive focus
	NavUp    ID        // Custom navigation target for up direction (0 = auto)
	NavDown  ID        // Custom navigation target for down direction (0 = auto)
	NavLeft  ID        // Custom navigation target for left direction (0 = auto)
	NavRight ID        // Custom navigation target for right direction (0 = auto)
}

FocusableItem represents a widget that can receive focus. This is the immediate-mode equivalent of implementing the Focusable interface.

type FocusableWithBounds

type FocusableWithBounds interface {
	Focusable

	// FocusBounds returns the rectangle that should be visible when focused.
	// Parent scrollables use this to auto-scroll to keep focused items visible.
	FocusBounds() Rect
}

FocusableWithBounds extends Focusable with bounds information for auto-scroll.

type Font

type Font interface {
	// TextureID returns the OpenGL texture ID for the font atlas.
	// This texture should be bound before rendering glyph quads.
	TextureID() uint32

	// HasGlyph returns true if the font has a glyph for the given rune.
	// This is useful for checking character support before rendering,
	// or for implementing fallback font logic.
	HasGlyph(r rune) bool

	// MeasureText returns the pixel dimensions of the given text at the specified scale.
	// This is used for layout calculations before rendering.
	MeasureText(text string, scale float32) FontVec2

	// GetGlyphQuads generates quads for rendering the given text.
	// Each quad contains screen coordinates and texture coordinates.
	// The returned slice should be used immediately and not stored.
	GetGlyphQuads(text string, x, y, scale float32) []FontGlyphQuad

	// LineHeight returns the line height at the specified scale.
	LineHeight(scale float32) float32
}

Font is the interface for a single font that can render text. It provides methods for measuring text and generating rendering quads.

Implementations should be GPU-optimized, using pre-generated texture atlases rather than CPU rasterization at render time.

type FontGlyphQuad

type FontGlyphQuad struct {
	// Screen coordinates (top-left and bottom-right)
	X0, Y0 float32
	X1, Y1 float32

	// Texture coordinates (top-left and bottom-right)
	U0, V0 float32
	U1, V1 float32
}

FontGlyphQuad represents a single character's rendering quad from a font. This mirrors the font package's GlyphQuad to avoid import dependencies.

type FontProvider

type FontProvider interface {
	// ActiveFont returns the currently active font for rendering.
	// Returns nil if no font is loaded or active.
	ActiveFont() Font

	// SetActiveFont sets the active font by name.
	// Returns an error if the font is not found.
	SetActiveFont(name string) error
}

FontProvider is the interface for font management in the GUI system. It abstracts font loading, caching, and selection, allowing different implementations to be injected (e.g., GTA fonts, system fonts, mock fonts for testing).

The GUI package does not depend on any concrete font implementation. Instead, applications inject a FontProvider that satisfies this interface.

Example usage:

// Application code creates a concrete font manager
fontMgr := font.NewManager()
fontMgr.LoadGTAFonts(gameDir)

// Inject into GUI context
ctx := gui.NewContext()
ctx.SetFontProvider(fontMgr)

type FontVec2

type FontVec2 struct {
	X, Y float32
}

FontVec2 represents a 2D vector returned by font measurement. This mirrors the font package's Vec2 to avoid import dependencies.

type FrameStore

type FrameStore[T any] struct {
	// contains filtered or unexported fields
}

FrameStore is a type-safe store for widget state that automatically cleans up unused entries each frame.

Unlike the old StateStore which used any (interface{}) and required type assertions, FrameStore is fully generic - no runtime type checks, no allocations for boxing primitive types.

Usage:

// At package level - create one store per state type
var sectionStore = gui.NewFrameStore[SectionState]()

// In widget code - get state with compile-time type safety
func (ctx *Context) Section(label string) {
    id := ctx.GetID(label)
    state := sectionStore.Get(id, SectionState{Open: false})
    // state is *SectionState - no type assertion needed
    state.Open = !state.Open  // Direct modification
}

For user-defined widgets, create your own FrameStore without modifying gui:

var myStore = gui.NewFrameStore[MyWidgetState]()

func NewFrameStore

func NewFrameStore[T any]() *FrameStore[T]

NewFrameStore creates a new type-safe state store and registers it for automatic cleanup. The store will automatically remove entries that weren't accessed in the previous frame.

Call this at package initialization time (package-level var):

var sliderStore = gui.NewFrameStore[SliderState]()

func (*FrameStore[T]) Cleanup

func (s *FrameStore[T]) Cleanup(frame uint64)

Cleanup removes all entries that weren't accessed in the previous frame. This is called automatically by NextFrame() - don't call it manually.

func (*FrameStore[T]) Clear

func (s *FrameStore[T]) Clear()

Clear removes all entries immediately. Useful for resetting state (e.g., when switching scenes).

func (*FrameStore[T]) Delete

func (s *FrameStore[T]) Delete(id ID)

Delete explicitly removes state for an ID. Use this when you know state is no longer needed (e.g., widget destroyed).

func (*FrameStore[T]) Get

func (s *FrameStore[T]) Get(id ID, defaultVal T) *T

Get retrieves state for the given ID, or creates it with defaultVal if not found. Returns a pointer to the state, allowing direct modification. The state is automatically marked as "used this frame" to prevent cleanup.

This method is safe for concurrent use.

func (*FrameStore[T]) GetIfExists

func (s *FrameStore[T]) GetIfExists(id ID) *T

GetIfExists retrieves state only if it already exists. Returns nil if no state exists for this ID. Does NOT create default state or mark as used.

func (*FrameStore[T]) Len

func (s *FrameStore[T]) Len() int

Len returns the number of stored entries. Useful for debugging and monitoring.

func (*FrameStore[T]) Set

func (s *FrameStore[T]) Set(id ID, value T)

Set explicitly sets state for an ID. Creates or updates the entry and marks it as used this frame.

type GUI

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

GUI manages the immediate mode UI system.

func New

func New(renderer Renderer, opts ...GUIOption) *GUI

New creates a new GUI instance.

func (*GUI) Begin

func (g *GUI) Begin(input *InputState, displaySize Vec2, deltaTime float32) *Context

Begin starts a new frame and returns the GUI context. Call this at the start of each frame before drawing any UI.

func (*GUI) Context

func (g *GUI) Context() *Context

Context returns the current GUI context. Only valid between Begin() and End() calls.

func (*GUI) End

func (g *GUI) End() error

End finishes the frame and renders the UI. Call this after all UI drawing is complete.

func (*GUI) FontProvider

func (g *GUI) FontProvider() FontProvider

FontProvider returns the current font provider, or nil if not set.

func (*GUI) PrepareInputHandling

func (g *GUI) PrepareInputHandling()

PrepareInputHandling prepares the GUI for input handling by swapping the focus registry buffers. CRITICAL: Call this at the START of BeginFrame(), BEFORE any panel HandleInput() is called.

This is necessary because:

  • HandleInput() runs in BeginFrame() and needs the previous frame's widget registrations
  • Widgets register themselves during Draw() which happens in EndFrame()
  • The focus registry uses double-buffering: prevItems (for navigation) and items (being built)
  • This method swaps the buffers so prevItems contains the last frame's widgets

func (*GUI) Resize

func (g *GUI) Resize(width, height int)

Resize notifies the GUI of a display size change.

func (*GUI) SetFontProvider

func (g *GUI) SetFontProvider(fp FontProvider)

SetFontProvider sets the font provider for advanced font support. The provider will be passed to each frame's Context.

func (*GUI) SetStyle

func (g *GUI) SetStyle(style Style)

SetStyle sets the GUI style.

func (*GUI) Style

func (g *GUI) Style() Style

Style returns the current GUI style.

type GUIOption

type GUIOption func(*GUI)

GUIOption configures a GUI instance.

func WithStateStore

func WithStateStore(store StateStore) GUIOption

WithStateStore sets a custom state store.

func WithStyle

func WithStyle(style Style) GUIOption

WithStyle sets the GUI style.

type GlyphQuad

type GlyphQuad struct {
	X0, Y0 float32 // Screen coordinates (top-left)
	X1, Y1 float32 // Screen coordinates (bottom-right)
	U0, V0 float32 // Texture coordinates (top-left)
	U1, V1 float32 // Texture coordinates (bottom-right)
}

GlyphQuad represents a single character's rendering quad. Used for passing glyph data to AddGlyphQuads.

type GraphData

type GraphData struct {
	Label  string
	Values []float32
	Color  uint32
}

GraphData represents a single data series in a graph.

type GraphState

type GraphState struct {
	HoveredIndex int     // Index of hovered data point (-1 = none)
	ZoomLevel    float32 // Zoom factor (1.0 = no zoom)
	PanOffset    float32 // Horizontal pan offset in pixels
}

GraphState holds the interactive state of a graph widget.

type HintAction

type HintAction struct {
	Key    HintKey
	Action string
}

HintAction pairs a key with its action description.

func Hint

func Hint(key HintKey, action string) HintAction

Hint creates a HintAction for use with HintFooter.

Usage:

ctx.HintFooter(
    gui.Hint(gui.HintKeyUpDown, "Navigate"),
    gui.Hint(gui.HintKeyEnter, "Select"),
    gui.Hint(gui.HintKeyEscape, "Close"),
)

type HintKey

type HintKey string

HintKey represents a keyboard key for hint display. Use the predefined constants for consistency.

const (
	HintKeyUp        HintKey = "↑"
	HintKeyDown      HintKey = "↓"
	HintKeyLeft      HintKey = "←"
	HintKeyRight     HintKey = "→"
	HintKeyUpDown    HintKey = "↑↓"
	HintKeyLeftRight HintKey = "←→"
	HintKeyArrows    HintKey = "←→↑↓"
	HintKeyEnter     HintKey = "Enter"
	HintKeyEscape    HintKey = "Esc"
	HintKeySpace     HintKey = "Space"
	HintKeyTab       HintKey = "Tab"
	HintKeyBackspace HintKey = "Bksp"
	HintKeyDelete    HintKey = "Del"
	HintKeyHome      HintKey = "Home"
	HintKeyEnd       HintKey = "End"
	HintKeyPageUp    HintKey = "PgUp"
	HintKeyPageDown  HintKey = "PgDn"
	HintKeyType      HintKey = "Type"
	HintKeyScroll    HintKey = "Scroll"
	HintKeyClick     HintKey = "Click"
	HintKeyDrag      HintKey = "Drag"
	HintKeyF1        HintKey = "F1"
	HintKeyF2        HintKey = "F2"
	HintKeyF3        HintKey = "F3"
	HintKeyF4        HintKey = "F4"
	HintKeyF5        HintKey = "F5"
)

Standard hint keys with consistent formatting. Uses Unicode arrows which are supported by the built-in font.

type HistogramBar

type HistogramBar struct {
	Label string
	Value float32
	Color uint32 // 0 = use default color
}

HistogramBar represents a single bar in a histogram.

type HistogramState

type HistogramState struct {
	HoveredBar int // Index of hovered bar (-1 = none)
}

HistogramState holds the interactive state of a histogram widget.

type HotkeyCheck

type HotkeyCheck func() bool

HotkeyCheck is a function that returns true if the panel's hotkey is pressed. This allows integration with settings-based rebindable keys.

type ID

type ID uint64

ID uniquely identifies a widget for state persistence. IDs are stable across frames for the same widget.

type InputState

type InputState struct {
	// Mouse position
	MouseX, MouseY float32

	// Mouse wheel
	MouseWheelX float32
	MouseWheelY float32

	// Text input (Unicode characters typed this frame)
	InputChars []rune

	// Modifiers
	ModCtrl  bool
	ModShift bool
	ModAlt   bool
	ModSuper bool
	// contains filtered or unexported fields
}

InputState holds input state for the current frame. This is typically populated by the application from GLFW or similar.

func NewInputState

func NewInputState() *InputState

NewInputState creates a new InputState.

func (*InputState) AddInputChar

func (s *InputState) AddInputChar(ch rune)

AddInputChar adds a typed character.

func (*InputState) ConsumeInputChars

func (s *InputState) ConsumeInputChars()

ConsumeInputChars clears all typed characters for this frame. Call this after processing a keyboard shortcut to prevent the shortcut key from also being typed into text fields (e.g., 'V' opens menu but shouldn't type 'v').

func (*InputState) HasInputChars

func (s *InputState) HasInputChars() bool

HasInputChars returns true if there are typed characters this frame.

func (*InputState) KeyDown

func (s *InputState) KeyDown(key Key) bool

KeyDown returns true if a key is currently held.

func (*InputState) KeyPressed

func (s *InputState) KeyPressed(key Key) bool

KeyPressed returns true if a key was just pressed (pressed this frame).

func (*InputState) KeyReleased

func (s *InputState) KeyReleased(key Key) bool

KeyReleased returns true if a key was just released.

func (*InputState) KeyRepeated

func (s *InputState) KeyRepeated(key Key) bool

KeyRepeated returns true if a key should trigger this frame. Returns true on initial press, then after KeyRepeatDelay, then every KeyRepeatInterval. Use this for actions that should repeat when holding a key (like backspace in text input).

func (*InputState) MouseClicked

func (s *InputState) MouseClicked(button MouseButton) bool

MouseClicked returns true if a mouse button was just clicked (pressed this frame).

func (*InputState) MouseDown

func (s *InputState) MouseDown(button MouseButton) bool

MouseDown returns true if a mouse button is currently held.

func (*InputState) MouseReleased

func (s *InputState) MouseReleased(button MouseButton) bool

MouseReleased returns true if a mouse button was just released.

func (*InputState) Reset

func (s *InputState) Reset()

Reset clears per-frame input state. Call this at the start of each frame before collecting input.

func (*InputState) SetKey

func (s *InputState) SetKey(key Key, down bool)

SetKey sets key state.

func (*InputState) SetMouseButton

func (s *InputState) SetMouseButton(button MouseButton, down bool)

SetMouseButton sets mouse button state.

func (*InputState) SetMousePos

func (s *InputState) SetMousePos(x, y float32)

SetMousePos sets the mouse position.

func (*InputState) SetMouseWheel

func (s *InputState) SetMouseWheel(x, y float32)

SetMouseWheel sets the mouse wheel delta.

func (*InputState) UpdateKeyRepeat

func (s *InputState) UpdateKeyRepeat(dt float32)

UpdateKeyRepeat updates key hold times for repeat detection. Call this once per frame with the frame's delta time.

type InputTextState

type InputTextState struct {
	// Editing indicates whether the widget is in active text editing mode.
	// When true, the widget captures keyboard input for text entry.
	// This is separate from registry focus - a widget can be registry-focused
	// (highlighted for navigation) without being in edit mode.
	Editing bool

	// Cursor position (in runes, not bytes)
	CursorPos int

	// Selection range (in runes). SelectionStart is the anchor point,
	// SelectionEnd follows the cursor. -1 means no selection.
	SelectionStart int
	SelectionEnd   int

	// Horizontal scroll offset for long text that exceeds input width
	ScrollOffset float32

	// Undo/redo stack
	UndoStack []string // Previous text states
	UndoIndex int      // Current position in undo stack

	// Cursor blink state (managed internally)
	CursorBlinkTime float32
}

InputTextState tracks state for text input widgets. Supports cursor positioning, text selection, and undo/redo.

func (*InputTextState) CanRedo

func (s *InputTextState) CanRedo() bool

CanRedo returns true if redo is available.

func (*InputTextState) CanUndo

func (s *InputTextState) CanUndo() bool

CanUndo returns true if undo is available.

func (*InputTextState) ClearSelection

func (s *InputTextState) ClearSelection()

ClearSelection removes the selection.

func (*InputTextState) GetSelectedRange

func (s *InputTextState) GetSelectedRange() (start, end int)

GetSelectedRange returns the selection range as (start, end) where start <= end. Returns (-1, -1) if no selection.

func (*InputTextState) HasSelection

func (s *InputTextState) HasSelection() bool

HasSelection returns true if there's an active text selection.

func (*InputTextState) PushUndo

func (s *InputTextState) PushUndo(text string)

PushUndo saves the current text to the undo stack. Call this before making changes to the text.

func (*InputTextState) Redo

func (s *InputTextState) Redo() (string, bool)

Redo returns the next text state, or empty string if nothing to redo.

func (*InputTextState) SelectAll

func (s *InputTextState) SelectAll(textLen int)

SelectAll selects all text.

func (*InputTextState) Undo

func (s *InputTextState) Undo(currentText string) (string, bool)

Undo returns the previous text state, or empty string if nothing to undo. Also updates the undo index.

type InteractiveComponent

type InteractiveComponent interface {
	Component
	// HandleInput processes input and returns true if the component value changed.
	HandleInput(ctx *Context, input *InputState) bool
}

InteractiveComponent is a component that can receive input.

type Justification

type Justification uint8

Justification values (like Tailwind justify-*)

const (
	JustifyStart   Justification = iota // justify-start (default)
	JustifyCenter                       // justify-center
	JustifyEnd                          // justify-end
	JustifyBetween                      // justify-between
)

type Key

type Key int

Key represents a keyboard key.

const (
	KeyNone Key = iota
	KeyTab
	KeyLeft
	KeyRight
	KeyUp
	KeyDown
	KeyPageUp
	KeyPageDown
	KeyHome
	KeyEnd
	KeyInsert
	KeyDelete
	KeyBackspace
	KeySpace
	KeyEnter
	KeyEscape
	KeyA
	KeyC
	KeyS
	KeyT
	KeyV
	KeyX
	KeyY
	KeyZ
	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyCount
)

type Layout

type Layout struct {
	Type LayoutType

	// Position tracking
	StartX, StartY   float32
	CursorX, CursorY float32

	// Sizing
	Width, Height       float32 // Available size
	MaxWidth, MaxHeight float32 // Accumulated content size

	// Spacing (Tailwind-style)
	Gap      float32 // Space between children (gap-*)
	GapX     float32 // Horizontal gap override
	GapY     float32 // Vertical gap override
	Padding  float32 // Inner padding (p-*)
	PaddingX float32 // Horizontal padding override
	PaddingY float32 // Vertical padding override

	// Alignment
	Align   Alignment     // Cross-axis (items-*)
	Justify Justification // Main-axis (justify-*)

	// State
	ItemCount int // For gap calculation

	// Panel-specific options
	Hotkey           string  // Keyboard shortcut to display (e.g., "T" -> "Title [T]")
	HeightConstraint float32 // Maximum height constraint (0 = no limit, > 0 = limit)
}

Layout tracks the current layout state.

type LayoutOption

type LayoutOption func(*Layout)

LayoutOption configures a layout container.

func Align

func Align(a Alignment) LayoutOption

Align sets cross-axis alignment (like Tailwind items-*).

func Gap

func Gap(pixels float32) LayoutOption

Gap sets spacing between children (like Tailwind gap-*).

func GapX

func GapX(pixels float32) LayoutOption

GapX sets horizontal spacing (like Tailwind gap-x-*).

func GapY

func GapY(pixels float32) LayoutOption

GapY sets vertical spacing (like Tailwind gap-y-*).

func Height

func Height(h float32) LayoutOption

Height sets a fixed height for the layout.

func Justify

func Justify(j Justification) LayoutOption

Justify sets main-axis alignment (like Tailwind justify-*).

func MaxHeight

func MaxHeight(h float32) LayoutOption

MaxHeight sets a maximum height constraint for the panel. If content exceeds this, it will be clipped (use with Scrollable). Pass 0 to disable the constraint.

func Padding

func Padding(pixels float32) LayoutOption

Padding sets inner padding (like Tailwind p-*).

func PaddingXY

func PaddingXY(x, y float32) LayoutOption

PaddingXY sets horizontal and vertical padding separately.

func Width

func Width(w float32) LayoutOption

Width sets a fixed width for the layout.

func WithHotkey

func WithHotkey(key string) LayoutOption

WithHotkey sets the keyboard shortcut to display in panel headers. The hotkey is shown as "Key" after the title.

type LayoutType

type LayoutType uint8

LayoutType defines the direction of a layout.

const (
	LayoutVertical   LayoutType = iota // Items stack vertically (default)
	LayoutHorizontal                   // Items stack horizontally
)

type LegacyRenderer

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

LegacyRenderer implements the low-level OpenGL rendering for LegacyUI. It provides immediate drawing calls that bypass the DrawList batching for compatibility with the old UI's draw-immediate style.

type LegacyUI

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

LegacyUI provides a compatibility layer for the old UI interface. It wraps the new GUI system but exposes the old-style methods (DrawText, DrawRect, DrawLines, Begin, End) that existing code expects.

This allows gradual migration from the old retained-mode UI to the new immediate-mode GUI without breaking existing code.

func NewLegacyUI

func NewLegacyUI(width, height int) (*LegacyUI, error)

NewLegacyUI creates a new LegacyUI that wraps both the new GUI and provides old-style immediate rendering for compatibility.

func (*LegacyUI) Begin

func (u *LegacyUI) Begin()

Begin starts UI rendering (old API compatibility).

func (*LegacyUI) Delete

func (u *LegacyUI) Delete()

Delete releases all resources.

func (*LegacyUI) DrawLine

func (u *LegacyUI) DrawLine(x1, y1, x2, y2 float32, r, g, b, a float32)

DrawLine draws a line between two points (old API compatibility).

func (*LegacyUI) DrawLines

func (u *LegacyUI) DrawLines(points [][2]float32, r, g, b, a float32)

DrawLines draws multiple line segments (old API compatibility). Each pair of points forms a line segment.

func (*LegacyUI) DrawRect

func (u *LegacyUI) DrawRect(x, y, w, h float32, r, g, b, a float32)

DrawRect renders a filled rectangle (old API compatibility).

func (*LegacyUI) DrawText

func (u *LegacyUI) DrawText(x, y float32, text string, r, g, b, a float32, scale float32)

DrawText renders text at the specified position (old API compatibility).

func (*LegacyUI) End

func (u *LegacyUI) End()

End finishes UI rendering (old API compatibility).

func (*LegacyUI) Resize

func (u *LegacyUI) Resize(width, height int)

Resize updates the UI dimensions.

type LegacyVertex

type LegacyVertex struct {
	Pos      [2]float32
	TexCoord [2]float32
	Color    [4]float32
}

LegacyVertex matches the old UIVertex layout for compatibility.

type ListBuilder

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

ListBuilder provides a fluent API for building list components.

func (*ListBuilder) End

func (lb *ListBuilder) End() int

End finishes the list and handles cleanup.

func (*ListBuilder) OnSelect

func (lb *ListBuilder) OnSelect(callback func(int)) *ListBuilder

OnSelect sets a callback for when an item is selected.

func (*ListBuilder) Section

func (lb *ListBuilder) Section(name string, opts ...Option) *SectionBuilder

Section starts a new collapsible section.

func (*ListBuilder) Selected

func (lb *ListBuilder) Selected() int

Selected returns the index of the item that was clicked this frame, or -1.

type ListClipper

type ListClipper struct {
	StartIdx   int     // First visible item index (inclusive)
	EndIdx     int     // Last visible item index (exclusive)
	ItemHeight float32 // Height of each item
	TotalItems int     // Total number of items in the list
}

ListClipper helps virtualize large lists by calculating the visible item range. This is critical for performance with large datasets (1000+ items) where rendering all items every frame would cause significant slowdown.

Usage:

clipper := NewListClipper(totalItems, itemHeight, visibleHeight, scrollY)
for i := clipper.StartIdx; i < clipper.EndIdx; i++ {
    y := clipper.ItemY(i, baseY, scrollY)
    // Draw item at y position
}

func NewListClipper

func NewListClipper(totalItems int, itemHeight, visibleHeight, scrollY float32) *ListClipper

NewListClipper calculates the visible item range for a scrollable list.

Parameters:

  • totalItems: Total number of items in the list
  • itemHeight: Height of each item in pixels
  • visibleHeight: Height of the visible area in pixels
  • scrollY: Current vertical scroll offset in pixels

Returns a ListClipper with StartIdx and EndIdx set to the visible range.

func (*ListClipper) ContentHeight

func (c *ListClipper) ContentHeight() float32

ContentHeight returns the total content height (for scrollbar calculations).

func (*ListClipper) ItemY

func (c *ListClipper) ItemY(idx int, baseY, scrollY float32) float32

ItemY calculates the Y position for an item relative to the visible area.

Parameters:

  • idx: The item index
  • baseY: The Y position of the list's top edge
  • scrollY: Current scroll offset

Returns the Y position where the item should be drawn.

func (*ListClipper) MaxScroll

func (c *ListClipper) MaxScroll(visibleHeight float32) float32

MaxScroll returns the maximum valid scroll offset.

func (*ListClipper) ScrollToItem

func (c *ListClipper) ScrollToItem(idx int, currentScroll, visibleHeight float32) float32

ScrollToItem returns the scroll offset needed to make an item visible. If the item is already visible, returns the current scroll unchanged.

func (*ListClipper) ShouldRender

func (c *ListClipper) ShouldRender(idx int) bool

ShouldRender returns true if the item at the given index should be rendered. Use this when iterating through all items to skip invisible ones.

func (*ListClipper) VisibleCount

func (c *ListClipper) VisibleCount() int

VisibleCount returns the number of items that should be rendered.

type ListState

type ListState struct {
	ScrollY           float32         // Scroll position
	SearchText        string          // Current search/filter text
	FilterEditing     bool            // True when filter input is in edit mode
	CollapsedSections map[string]bool // Section collapsed states (true = collapsed)
	SelectedIndex     int             // Currently selected item index
}

ListState tracks state for list components.

type MapStateStore

type MapStateStore map[ID]any

MapStateStore is a simple in-memory StateStore implementation.

func (MapStateStore) Delete

func (m MapStateStore) Delete(id ID)

Delete removes a value from the store.

func (MapStateStore) Get

func (m MapStateStore) Get(id ID) (any, bool)

Get retrieves a value from the store.

func (MapStateStore) Set

func (m MapStateStore) Set(id ID, value any)

Set stores a value in the store.

type MenuDataSource interface {
	// Count returns the total number of items (after filtering).
	Count() int

	// Label returns the display text for an item at the given index.
	Label(index int) string

	// IsMarked returns true if the item should be marked (e.g., current selection).
	IsMarked(index int) bool

	// Filter applies a search query to the data source.
	// Empty string means show all items.
	Filter(query string)
}

MenuDataSource provides items for a modal menu to display. The menu doesn't know what the items represent - just how to display them.

type MenuDelegate interface {
	// OnSelect is called when the selection changes (for preview).
	OnSelect(index int)

	// OnConfirm is called when the user confirms selection (Enter).
	OnConfirm(index int)

	// OnCancel is called when the user cancels (Escape).
	OnCancel()
}

MenuDelegate receives callbacks from menu interactions.

type ModalMenu

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

ModalMenu is a generic searchable list menu. It handles display, scrolling, selection, and search without knowing anything about the actual data being displayed.

func NewModalMenu

func NewModalMenu(title string, width float32, maxVisible int) *ModalMenu

NewModalMenu creates a new modal menu.

func (*ModalMenu) Close

func (m *ModalMenu) Close()

Close closes the menu.

func (*ModalMenu) Draggable

func (m *ModalMenu) Draggable() *DraggablePanel

Draggable returns the draggable panel for configuration.

func (*ModalMenu) Draw

func (m *ModalMenu) Draw(ctx *Context)

Draw renders the menu using the provided GUI context.

func (*ModalMenu) HandleInput

func (m *ModalMenu) HandleInput(input *InputState) bool

HandleInput processes input for the menu. Returns true if input was consumed.

func (*ModalMenu) IsOpen

func (m *ModalMenu) IsOpen() bool

IsOpen returns true if the menu is open.

func (*ModalMenu) Open

func (m *ModalMenu) Open()

Open opens the menu and resets state.

func (*ModalMenu) SearchText

func (m *ModalMenu) SearchText() string

SearchText returns the current search text.

func (*ModalMenu) SelectedIndex

func (m *ModalMenu) SelectedIndex() int

SelectedIndex returns the currently selected index.

func (*ModalMenu) SetDataSource

func (m *ModalMenu) SetDataSource(ds MenuDataSource)

SetDataSource sets the data source for the menu.

func (*ModalMenu) SetDelegate

func (m *ModalMenu) SetDelegate(del MenuDelegate)

SetDelegate sets the delegate for menu callbacks.

func (*ModalMenu) SetHotkey

func (m *ModalMenu) SetHotkey(key string)

SetHotkey sets the keyboard shortcut to display in the header.

func (*ModalMenu) SetPosition

func (m *ModalMenu) SetPosition(x, y float32)

SetPosition sets the top-left position of the menu.

func (*ModalMenu) Toggle

func (m *ModalMenu) Toggle()

Toggle toggles the menu open/closed state.

type MouseButton

type MouseButton int

MouseButton represents a mouse button.

const (
	MouseButtonLeft MouseButton = iota
	MouseButtonRight
	MouseButtonMiddle
	MouseButtonCount
)
type NavDirection uint8

NavDirection represents a navigation direction for keyboard focus movement.

const (
	NavUp NavDirection = iota
	NavDown
	NavLeft
	NavRight
)
func (d NavDirection) IsHorizontal() bool

IsHorizontal returns true for Left/Right directions.

func (d NavDirection) IsVertical() bool

IsVertical returns true for Up/Down directions.

func (d NavDirection) Opposite() NavDirection

Opposite returns the opposite direction (Up<->Down, Left<->Right).

func (d NavDirection) String() string

String returns a human-readable name for the navigation direction.

type NumberInputState

type NumberInputState struct {
	Editing        bool    // True when in text edit mode
	EditText       string  // Text being edited
	Dragging       bool    // True when value is being dragged
	DragStartX     float32 // Mouse X when drag started
	DragStartValue float32 // Value when drag started
}

NumberInputState tracks state for number input widgets.

type OpenValue

type OpenValue struct {
	Ptr *bool // If non-nil, section reads/writes through this pointer
}

OpenValue wraps a boolean pointer for controlled section state. When Ptr is non-nil, the section is in controlled mode and writes back to it.

type OptKey

type OptKey[T any] struct {
	// contains filtered or unexported fields
}

OptKey is a typed key for widget options. All options (built-in and custom) use this system for consistency.

Example:

// Define option keys (built-in ones are already defined below)
var OptCustomThing = gui.NewOptKey("customThing", defaultValue)

// Set options
ctx.MyWidget("id", gui.WithOpt(OptCustomThing, value))

// Read in widget implementation
value := gui.GetOpt(opts, OptCustomThing)

func NewOptKey

func NewOptKey[T any](name string, defaultValue T) OptKey[T]

NewOptKey creates a typed option key with a default value. The default is returned when the option is not set.

func (OptKey[T]) Default

func (k OptKey[T]) Default() T

Default returns the default value for this key.

func (OptKey[T]) Name

func (k OptKey[T]) Name() string

Name returns the key name (useful for debugging).

type Option

type Option func(*options)

Option configures a UI widget.

func ClampToContent

func ClampToContent() Option

ClampToContent prevents scrolling past content bounds.

func DefaultOpen

func DefaultOpen() Option

DefaultOpen makes sections start in the expanded state.

func EnableHorizontal

func EnableHorizontal() Option

EnableHorizontal enables horizontal scrolling.

func FocusY

func FocusY(y float32, padding ...float32) Option

FocusY tracks focus position and auto-scrolls when it changes.

func Focused

func Focused() Option

Focused marks the widget as keyboard-focused (visual highlight).

func ForceFocus

func ForceFocus() Option

ForceFocus programmatically grabs keyboard focus for the widget. Use this when you want a widget to become active on render (e.g., after pressing Enter).

func IndentSize

func IndentSize(px float32) Option

IndentSize sets a custom indentation in pixels for Section content.

func NoIndent

func NoIndent() Option

NoIndent disables automatic indentation in Section widgets.

func Open

func Open(ptr *bool) Option

Open binds the section's open/closed state to an external boolean variable. The section reads from and writes to this variable, making it fully controlled. When the user clicks to toggle, the variable is updated automatically.

Usage:

ctx.Section("Windows", gui.Open(&p.windowsExpanded))(func() {
    // content
})

func ScrollbarPosition

func ScrollbarPosition(side ScrollbarSide) Option

ScrollbarPosition sets which side the scrollbar appears on.

func ShowScrollbar

func ShowScrollbar(always bool) Option

ShowScrollbar controls scrollbar visibility.

func WithColumns

func WithColumns(n int) Option

WithColumns sets the number of columns for multi-column layouts.

func WithDisabled

func WithDisabled(disabled bool) Option

WithDisabled disables the widget (grayed out, no interaction).

func WithDragSpeed

func WithDragSpeed(speed float32) Option

WithDragSpeed sets the drag sensitivity (pixels per unit change).

func WithFilter

func WithFilter(placeholder string) Option

WithFilter enables a search filter input.

func WithFormat

func WithFormat(format string) Option

WithFormat sets the display format for numeric values.

func WithGraphGridLines

func WithGraphGridLines(n int) Option

WithGraphGridLines sets the number of horizontal grid lines.

func WithGraphLegend

func WithGraphLegend() Option

WithGraphLegend enables the legend for graphs.

func WithGraphYRange

func WithGraphYRange(minVal, maxVal float32) Option

WithGraphYRange sets the Y-axis range for graphs.

func WithHeight

func WithHeight(height float32) Option

WithHeight sets a specific height for the widget.

func WithHistogramHorizontal

func WithHistogramHorizontal() Option

WithHistogramHorizontal draws horizontal bars instead of vertical.

func WithHistogramShowValues

func WithHistogramShowValues() Option

WithHistogramShowValues shows value text above histogram bars.

func WithHistogramYRange

func WithHistogramYRange(minVal, maxVal float32) Option

WithHistogramYRange sets the Y-axis range for histograms.

func WithID

func WithID(id string) Option

WithID sets an explicit ID for the widget.

func WithMaxDropdownHeight

func WithMaxDropdownHeight(height float32) Option

WithMaxDropdownHeight limits the maximum height of dropdown menus.

func WithMultiSelect

func WithMultiSelect() Option

WithMultiSelect enables selecting multiple items in a list.

func WithOpt

func WithOpt[T any](key OptKey[T], value T) Option

WithOpt sets an option value using a typed key.

func WithPrefix

func WithPrefix(prefix string) Option

WithPrefix sets a prefix text displayed before the value.

func WithRange

func WithRange(minVal, maxVal float32) Option

WithRange sets the minimum and maximum values.

func WithSearchable

func WithSearchable() Option

WithSearchable enables typing to filter items in a ComboBox.

func WithSequencerControls

func WithSequencerControls() Option

WithSequencerControls shows play/pause controls in the sequencer.

func WithStep

func WithStep(step float32) Option

WithStep sets the increment step for value adjustments.

func WithSuffix

func WithSuffix(suffix string) Option

WithSuffix sets a suffix text displayed after the value.

func WithWidth

func WithWidth(width float32) Option

WithWidth sets a specific width for the widget.

type Panel

type Panel interface {
	// Open opens the panel.
	Open()

	// Close closes the panel.
	Close()

	// Toggle toggles the panel open/closed state.
	// Returns true if the panel is now open.
	Toggle() bool

	// IsOpen returns true if the panel is currently open.
	IsOpen() bool

	// CanOpen returns true if the panel can be opened.
	// Use this for preconditions (e.g., needs a model loaded).
	// Default should return true.
	CanOpen() bool

	// Draw renders the panel using the provided GUI context.
	// This is called every frame regardless of open state - panels
	// should return early if not open.
	Draw(ctx *Context)

	// HandleInput processes input for the panel.
	// Returns true if input was consumed.
	// Called only when the panel is open.
	HandleInput(input *InputState) bool
}

Panel is the interface for any openable UI panel or menu. Panels can register with a PanelRegistry to get automatic hotkey handling, input routing, and mutual exclusion.

type PanelBounds

type PanelBounds struct {
	X, Y, W, H float32
	Name       string
}

PanelBounds represents the bounds of a panel for snapping calculations.

type PanelEntry

type PanelEntry struct {
	Name        string      // Display name (e.g., "Model Menu")
	Panel       Panel       // The panel itself
	Hotkey      Key         // Key to toggle the panel (simple mode)
	HotkeyName  string      // Display name for hotkey (used when CheckHotkey is set)
	CheckHotkey HotkeyCheck // Custom hotkey check (overrides Hotkey if set)
	CloseKey    Key         // Key to close the panel (default: KeyEscape)
	CheckClose  HotkeyCheck // Custom close key check (overrides CloseKey if set)
	Priority    int         // Higher priority panels handle input first
	NeedsCursor bool        // If true, opening this panel releases cursor
	BlockedBy   []string    // Panel names that block this panel's hotkey
	Global      bool        // If true, hotkey works in all modes (not just model view)
}

PanelEntry holds a registered panel with its configuration.

func (*PanelEntry) IsCloseKeyPressed

func (e *PanelEntry) IsCloseKeyPressed(input *InputState, defaultCheck HotkeyCheck) bool

IsCloseKeyPressed returns true if the panel's close key is pressed. Uses CheckClose if set, otherwise checks CloseKey. If neither is set, use defaultCheck (typically the registry's default close check).

type PanelGroup

type PanelGroup struct {
	// ID is a unique identifier for this group.
	ID string

	// ActiveTab is the index of the currently visible tab.
	ActiveTab int

	// Position and size for the group container.
	DraggablePanel
	// contains filtered or unexported fields
}

PanelGroup manages multiple panels in a single tabbed container. This allows users to group related panels together, saving screen space and enabling organization similar to ImGui's docking system.

Usage:

group := gui.NewPanelGroup("My Group")
group.AddPanel("Tab1", panel1)
group.AddPanel("Tab2", panel2)

// In draw loop:
group.Draw(ctx)

Tab switching: - Click on tab to switch - Ctrl+1-9 to switch to specific tab (when focused) - Ctrl+PgUp/PgDown to cycle tabs

func NewPanelGroup

func NewPanelGroup(id string) *PanelGroup

NewPanelGroup creates a new panel group with the given ID.

func (*PanelGroup) ActivePanel

func (pg *PanelGroup) ActivePanel() Panel

ActivePanel returns the currently active panel, or nil if empty.

func (*PanelGroup) AddPanel

func (pg *PanelGroup) AddPanel(name string, panel Panel)

AddPanel adds a panel to the group with the given tab name.

func (*PanelGroup) CanOpen

func (pg *PanelGroup) CanOpen() bool

CanOpen returns true (groups can always open).

func (*PanelGroup) Close

func (pg *PanelGroup) Close()

Close closes the panel group.

func (*PanelGroup) Draw

func (pg *PanelGroup) Draw(ctx *Context)

Draw renders the panel group with tab bar.

func (*PanelGroup) GetPanel

func (pg *PanelGroup) GetPanel(name string) Panel

GetPanel returns a panel by tab name, or nil if not found.

func (*PanelGroup) HandleInput

func (pg *PanelGroup) HandleInput(input *InputState) bool

HandleInput processes input for the panel group.

func (*PanelGroup) IsOpen

func (pg *PanelGroup) IsOpen() bool

IsOpen returns true if the group is open.

func (*PanelGroup) NextTab

func (pg *PanelGroup) NextTab()

NextTab cycles to the next tab (wraps around).

func (*PanelGroup) Open

func (pg *PanelGroup) Open()

Open opens the panel group.

func (*PanelGroup) PanelCount

func (pg *PanelGroup) PanelCount() int

PanelCount returns the number of panels in the group.

func (*PanelGroup) PrevTab

func (pg *PanelGroup) PrevTab()

PrevTab cycles to the previous tab (wraps around).

func (*PanelGroup) RemovePanel

func (pg *PanelGroup) RemovePanel(name string) bool

RemovePanel removes a panel from the group by name. Returns true if the panel was found and removed.

func (*PanelGroup) SetActiveTab

func (pg *PanelGroup) SetActiveTab(index int)

SetActiveTab sets the active tab by index.

func (*PanelGroup) SetActiveTabByName

func (pg *PanelGroup) SetActiveTabByName(name string) bool

SetActiveTabByName sets the active tab by name. Returns true if the tab was found and activated.

func (*PanelGroup) SetOnClose

func (pg *PanelGroup) SetOnClose(fn func())

SetOnClose sets the callback for when the group closes.

func (*PanelGroup) Toggle

func (pg *PanelGroup) Toggle() bool

Toggle toggles the group open/closed state.

type PanelRegistry

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

PanelRegistry manages a collection of panels with automatic hotkey handling. It handles: - Opening/closing panels via hotkeys - Mutual exclusion (optional - close others when one opens) - Routing input to the currently active panel - Drawing all panels - Cursor capture state management - Focus management with Ctrl+Tab cycling

func NewPanelRegistry

func NewPanelRegistry() *PanelRegistry

NewPanelRegistry creates a new panel registry.

func (*PanelRegistry) CloseAll

func (r *PanelRegistry) CloseAll()

CloseAll closes all panels and restores cursor capture.

func (*PanelRegistry) Draw

func (r *PanelRegistry) Draw(ctx *Context)

Draw renders all open panels.

func (*PanelRegistry) Entries

func (r *PanelRegistry) Entries() []PanelEntry

Entries returns all registered panel entries (for inspection/debugging).

func (*PanelRegistry) FocusManager

func (r *PanelRegistry) FocusManager() *FocusManager

FocusManager returns the focus manager for this registry. Use this for advanced focus control (cycling, checking focus state, etc.).

func (*PanelRegistry) FocusedPanel

func (r *PanelRegistry) FocusedPanel() Panel

FocusedPanel returns the currently focused panel, or nil if none.

func (*PanelRegistry) GetPanel

func (r *PanelRegistry) GetPanel(name string) Panel

GetPanel returns a panel by name, or nil if not found.

func (*PanelRegistry) HandleHotkeys

func (r *PanelRegistry) HandleHotkeys(input *InputState, modelViewMode bool) bool

HandleHotkeys checks for hotkey presses and opens/closes panels. Call this each frame to handle panel hotkeys automatically. Returns true if a hotkey was handled. HandleHotkeys checks panel hotkeys and toggles them. modelViewMode indicates if we're in model view mode (vs world mode). Global panels work in all modes, non-global panels only work in model view mode.

func (*PanelRegistry) HandleInput

func (r *PanelRegistry) HandleInput(input *InputState) bool

HandleInput routes input to open panels. Returns true if input was consumed by any panel.

func (*PanelRegistry) IsAnyOpen

func (r *PanelRegistry) IsAnyOpen() bool

IsAnyOpen returns true if any panel is currently open.

func (*PanelRegistry) IsPanelFocused

func (r *PanelRegistry) IsPanelFocused(panel Panel) bool

IsPanelFocused returns true if the given panel is currently focused.

func (*PanelRegistry) OpenPanel

func (r *PanelRegistry) OpenPanel(name string)

OpenPanel opens a specific panel by name. If exclusive mode is enabled, closes other panels first.

func (*PanelRegistry) Register

func (r *PanelRegistry) Register(name string, panel Panel, hotkey Key, priority int)

Register adds a panel to the registry with its hotkey. Priority determines input handling order (higher = first). Use RegisterWithCursor for panels that need cursor interaction.

func (*PanelRegistry) RegisterWithBinding

func (r *PanelRegistry) RegisterWithBinding(name string, panel Panel, checkHotkey HotkeyCheck, priority int, needsCursor bool, global bool, blockedBy ...string)

RegisterWithBinding adds a panel with a custom hotkey check function. This allows integration with settings-based rebindable keys. If global is true, the hotkey works in all modes (not just model view mode). blockedBy lists panel names that prevent this panel's hotkey from working (e.g., typing in search).

func (*PanelRegistry) RegisterWithCursor

func (r *PanelRegistry) RegisterWithCursor(name string, panel Panel, hotkey Key, priority int, needsCursor bool)

RegisterWithCursor adds a panel with cursor capture control. If needsCursor is true, opening this panel will release cursor capture.

func (*PanelRegistry) SetCloseBinding

func (r *PanelRegistry) SetCloseBinding(name string, checkClose HotkeyCheck)

SetCloseBinding sets a custom close key check function for a panel. This allows integration with settings-based rebindable close keys.

func (*PanelRegistry) SetCloseKey

func (r *PanelRegistry) SetCloseKey(name string, closeKey Key)

SetCloseKey sets the close key for a panel by name. Pass KeyNone to use the default (Escape).

func (*PanelRegistry) SetCursorChangeCallback

func (r *PanelRegistry) SetCursorChangeCallback(fn CursorChangeCallback)

SetCursorChangeCallback sets the callback for cursor state changes. This is called when panels open/close that require cursor interaction.

func (*PanelRegistry) SetDefaultCloseCheck

func (r *PanelRegistry) SetDefaultCloseCheck(check HotkeyCheck)

SetDefaultCloseCheck sets the default close key check for all panels. This is typically set to check the settings' Cancel binding. Panels can override this with their own CloseKey or CheckClose.

func (*PanelRegistry) SetExclusive

func (r *PanelRegistry) SetExclusive(exclusive bool)

SetExclusive sets whether opening one panel closes others.

func (*PanelRegistry) SetHotkeyName

func (r *PanelRegistry) SetHotkeyName(name string, hotkeyName string)

SetHotkeyName sets the display name for a panel's hotkey. Use this for panels with custom hotkey checks to show the actual key in the F1 help.

func (*PanelRegistry) TogglePanel

func (r *PanelRegistry) TogglePanel(name string) bool

TogglePanel toggles a panel by name. Returns true if the panel is now open. If input is provided, consumes input chars to prevent hotkey from typing.

func (*PanelRegistry) TogglePanelWithInput

func (r *PanelRegistry) TogglePanelWithInput(name string, input *InputState) bool

TogglePanelWithInput toggles a panel and optionally consumes input chars.

func (*PanelRegistry) Unregister

func (r *PanelRegistry) Unregister(name string)

Unregister removes a panel from the registry.

type RangeValue

type RangeValue struct {
	Min, Max float32
	HasRange bool
}

RangeValue holds min/max range for sliders and number inputs.

type Rect

type Rect struct {
	X, Y float32 // Top-left position
	W, H float32 // Width and height
}

Rect represents a rectangle with position and size.

func (Rect) Contains

func (r Rect) Contains(p Vec2) bool

Contains returns true if the point is inside the rectangle.

func (Rect) Intersects

func (r Rect) Intersects(other Rect) bool

Intersects returns true if two rectangles overlap.

type Renderer

type Renderer interface {
	Render(dl *DrawList) error
	FontTextureID() uint32
	Resize(width, height int)
}

Renderer is the interface for rendering GUI draw data.

type ResizableEdge

type ResizableEdge uint8

ResizableEdge represents which edge(s) of a panel are being resized.

const (
	ResizeEdgeNone   ResizableEdge = 0
	ResizeEdgeLeft   ResizableEdge = 1 << 0
	ResizeEdgeRight  ResizableEdge = 1 << 1
	ResizeEdgeTop    ResizableEdge = 1 << 2
	ResizeEdgeBottom ResizableEdge = 1 << 3
)

type ResizeState

type ResizeState struct {
	Active      bool          // Currently being resized
	Edge        ResizableEdge // Which edge(s) are being resized
	StartMouseX float32       // Mouse X when resize started
	StartMouseY float32       // Mouse Y when resize started
	StartX      float32       // Panel X when resize started
	StartY      float32       // Panel Y when resize started
	StartW      float32       // Panel width when resize started
	StartH      float32       // Panel height when resize started
}

ResizeState tracks the state of a panel resize operation.

type ScrollHints

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

ScrollHints tracks scroll position and draws indicators.

func (*ScrollHints) After

func (sh *ScrollHints) After(ctx *Context)

After draws the "more below" indicator if there are items below the viewport.

func (*ScrollHints) Before

func (sh *ScrollHints) Before(ctx *Context)

Before draws the "more above" indicator if there are items above the viewport.

func (*ScrollHints) HasMoreAbove

func (sh *ScrollHints) HasMoreAbove() bool

HasMoreAbove returns true if there are items above the viewport.

func (*ScrollHints) HasMoreBelow

func (sh *ScrollHints) HasMoreBelow() bool

HasMoreBelow returns true if there are items below the viewport.

func (*ScrollHints) WithCount

func (sh *ScrollHints) WithCount() *ScrollHints

WithCount enables showing the count of hidden items.

Usage:

scroll := ctx.HintScroll(offset, visible, total).WithCount()

type ScrollState

type ScrollState struct {
	ScrollY       float32 // Current scroll position
	TargetScrollY float32 // Target for smooth scrolling
	ContentHeight float32 // Total content height
}

ScrollState tracks scroll position for scrollable areas.

func (*ScrollState) UpdateSmooth

func (s *ScrollState) UpdateSmooth(deltaTime float32) bool

UpdateSmooth smoothly interpolates scroll position toward target. Call this each frame with the frame's delta time. Returns true if still animating.

type ScrollableState

type ScrollableState struct {
	ScrollY       float32 // Vertical scroll position
	ScrollX       float32 // Horizontal scroll position (when enabled)
	TargetScrollY float32 // Target vertical position (for smooth scrolling)
	TargetScrollX float32 // Target horizontal position (for smooth scrolling)
	ContentHeight float32 // Measured content height
	ContentWidth  float32 // Measured content width
	Dragging      bool    // True when scrollbar thumb is being dragged
	DragStartY    float32 // Mouse Y when scrollbar drag started
	DragStartScr  float32 // ScrollY when scrollbar drag started
	LastFocusY    float32 // Previous frame's focus Y (for change detection)
	FocusYSet     bool    // True if focus Y was set (to distinguish 0 from "not set")

	// User scroll tracking - suppresses auto-scroll during manual interaction
	UserScrolledThisFrame bool    // True if user scrolled via mouse/keyboard this frame
	UserScrollTime        float32 // Time since last user scroll (for cooldown)
}

ScrollableState tracks state for scrollable areas.

func GetScrollableState

func GetScrollableState(ctx *Context, id string) *ScrollableState

GetScrollableState returns a pointer to the scrollable's state for advanced manipulation. Returns nil if the scrollable hasn't been rendered yet. Note: This returns state from the FrameStore which persists across frames until cleanup.

func (*ScrollableState) UpdateSmoothScroll

func (s *ScrollableState) UpdateSmoothScroll(deltaTime float32) bool

UpdateSmoothScroll smoothly interpolates scroll positions toward targets. Call this each frame. Returns true if still animating.

type ScrollbarSide

type ScrollbarSide int

ScrollbarSide controls which side the scrollbar appears on.

const (
	ScrollbarRight ScrollbarSide = iota // Scrollbar on right side (default)
	ScrollbarLeft                       // Scrollbar on left side
)

type ScrollbarVisibility

type ScrollbarVisibility int

ScrollbarVisibility controls when scrollbars are shown.

const (
	ScrollbarAuto   ScrollbarVisibility = iota // Show only when content exceeds viewport
	ScrollbarAlways                            // Always show scrollbar
	ScrollbarNever                             // Never show scrollbar
)

type SectionBuilder

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

SectionBuilder provides a fluent API for building list sections.

func (*SectionBuilder) End

func (sb *SectionBuilder) End() *ListBuilder

End finishes the section.

func (*SectionBuilder) Item

func (sb *SectionBuilder) Item(label string, selected bool) *SectionBuilder

Item adds a simple selectable item to the section. Returns the SectionBuilder for chaining.

func (*SectionBuilder) ItemFunc

func (sb *SectionBuilder) ItemFunc(label string, selected bool, content func()) *SectionBuilder

ItemFunc adds an item with custom widget content. Returns the SectionBuilder for chaining.

type SectionState

type SectionState struct {
	Open bool // Whether the section is expanded
	// contains filtered or unexported fields
}

SectionState holds the state needed for section expansion. This extends CollapsingHeaderState with section-specific tracking.

func GetSectionState

func GetSectionState(id ID) *SectionState

GetSectionState returns a pointer to the section's state for advanced manipulation. Returns nil if the section hasn't been rendered yet this frame.

type SequencerConfig

type SequencerConfig struct {
	Duration    float32          // Total duration in seconds
	CurrentTime float32          // Current playhead position
	Tracks      []SequencerTrack // Animation tracks
	Playing     bool             // True if playing

	// Callbacks (optional)
	OnSeek  func(time float32) // Called when user seeks
	OnPlay  func()             // Called when play is pressed
	OnPause func()             // Called when pause is pressed
}

SequencerConfig holds the configuration for a sequencer widget.

type SequencerState

type SequencerState struct {
	ZoomLevel       float32         // Zoom factor (1.0 = fit duration to width)
	PanOffsetX      float32         // Horizontal pan offset in pixels
	CollapsedTracks map[string]bool // Track collapse state (true = collapsed)
	SelectedTrack   string          // Name of selected track
	SelectedKeyIdx  int             // Index of selected keyframe (-1 = none)
	Scrubbing       bool            // True when dragging playhead
	HoveredTrack    string          // Name of hovered track
	HoveredKeyIdx   int             // Index of hovered keyframe (-1 = none)
}

SequencerState holds the interactive state of a sequencer widget.

type SequencerTrack

type SequencerTrack struct {
	Name      string
	Keyframes []float32 // Times in seconds where keyframes exist
	Color     uint32    // Track color (0 = default)
}

SequencerTrack represents a single track (e.g., bone animation) in the sequencer.

type SliderState

type SliderState struct {
	Dragging       bool    // True when the grab handle is being dragged
	DragStartX     float32 // Mouse X position when drag started
	DragStartValue float32 // Value when drag started
}

SliderState tracks state for slider widgets.

func GetSliderState

func GetSliderState(ctx *Context, label string) *SliderState

GetSliderState returns a pointer to the slider's state for advanced manipulation. Returns nil if the slider hasn't been rendered yet this frame.

type SnapConfig

type SnapConfig struct {
	Enabled     bool    // Enable snapping
	GridSize    float32 // Grid size for grid snapping (0 = disabled)
	EdgeMargin  float32 // Snap to screen edges within this margin
	PanelMargin float32 // Snap to other panels within this margin
}

SnapConfig configures panel snapping behavior.

func DefaultSnapConfig

func DefaultSnapConfig() SnapConfig

DefaultSnapConfig returns a sensible default snap configuration.

type SnapGuide

type SnapGuide struct {
	X1, Y1, X2, Y2 float32
	Horizontal     bool
}

SnapGuide represents a visual snap guide line.

type SnapManager

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

SnapManager handles panel snapping to screen edges and other panels.

func NewSnapManager

func NewSnapManager(screenSize Vec2, config SnapConfig) *SnapManager

NewSnapManager creates a new snap manager.

func (*SnapManager) ActiveGuides

func (sm *SnapManager) ActiveGuides() []SnapGuide

ActiveGuides returns the currently active snap guides.

func (*SnapManager) CalculateSnap

func (sm *SnapManager) CalculateSnap(bounds PanelBounds, excluding string) (Vec2, []SnapGuide)

CalculateSnap calculates the snapped position for a panel being dragged. Returns the adjusted position and which edges snapped. excluding is the name of the panel being dragged (to avoid self-snapping).

func (*SnapManager) Clear

func (sm *SnapManager) Clear()

Clear removes all registered panels.

func (*SnapManager) ClearGuides

func (sm *SnapManager) ClearGuides()

ClearGuides clears the active snap guides.

func (*SnapManager) DrawGuides

func (sm *SnapManager) DrawGuides(dl *DrawList, style Style)

DrawGuides draws the active snap guide lines. Call this during a drag operation to show visual feedback.

func (*SnapManager) RegisterPanel

func (sm *SnapManager) RegisterPanel(name string, bounds PanelBounds)

RegisterPanel adds a panel to the snap manager.

func (*SnapManager) RemovePanel

func (sm *SnapManager) RemovePanel(name string)

RemovePanel removes a panel from the snap manager.

func (*SnapManager) SetConfig

func (sm *SnapManager) SetConfig(config SnapConfig)

SetConfig updates the snap configuration.

func (*SnapManager) SetScreenSize

func (sm *SnapManager) SetScreenSize(size Vec2)

SetScreenSize updates the screen size for edge snapping.

func (*SnapManager) UpdatePanel

func (sm *SnapManager) UpdatePanel(name string, bounds PanelBounds)

UpdatePanel updates the bounds of an existing panel.

type StateStore

type StateStore interface {
	Get(id ID) (any, bool)
	Set(id ID, value any)
	Delete(id ID)
}

StateStore persists widget state between frames. Unlike ImGui's hidden state, this is explicit and inspectable.

type Style

type Style struct {
	// Colors
	TextColor          uint32
	TextDisabledColor  uint32
	TextHighlightColor uint32

	// Panel colors
	PanelColor           uint32
	PanelBorderColor     uint32
	PanelHeaderBgColor   uint32 // Header background (0 = use ButtonColor)
	PanelHeaderTextColor uint32 // Header text (0 = use TextColor)

	// Button colors
	ButtonColor         uint32
	ButtonHoveredColor  uint32
	ButtonActiveColor   uint32
	ButtonDisabledColor uint32

	// Selection colors
	SelectedBgColor   uint32
	SelectedTextColor uint32
	HoveredBgColor    uint32

	// Input colors
	InputBgColor        uint32
	InputFocusedBgColor uint32
	InputBorderColor    uint32

	// Separator
	SeparatorColor uint32

	// Table colors
	BorderColor     uint32 // General border color (tables, frames)
	HeaderBgColor   uint32 // Table header background
	HeaderTextColor uint32 // Table header text (0 = use TextColor)
	RowBgAltColor   uint32 // Alternate row background

	// Scrollbar
	ScrollbarBgColor     uint32
	ScrollbarGrabColor   uint32
	ScrollbarGrabHovered uint32

	// Slider colors
	SliderTrackColor  uint32 // Background track
	SliderFillColor   uint32 // Filled portion
	SliderGrabColor   uint32 // Handle/grab
	SliderGrabHovered uint32 // Handle when hovered
	SliderGrabActive  uint32 // Handle when dragging

	// Dropdown/ComboBox colors
	DropdownBgColor uint32 // Dropdown menu background
	ComboArrowColor uint32 // Arrow indicator color

	// Focus indicator
	FocusColor uint32

	// Toast notification colors
	ToastInfoColor    uint32
	ToastSuccessColor uint32
	ToastWarningColor uint32
	ToastErrorColor   uint32

	// Font
	FontName string // Font name for use with FontManager (e.g., "font1", "plate")

	// Sizing
	FontScale     float32
	CharWidth     float32
	CharHeight    float32
	ItemSpacing   float32 // Default gap between items
	PanelPadding  float32
	ButtonPadding float32
	InputPadding  float32

	// Border
	BorderSize float32
	Rounding   float32 // Corner rounding (0 = sharp corners)

	// Scrollbar
	ScrollbarSize float32
}

Style defines the visual appearance of UI elements.

func DarkStyle

func DarkStyle() Style

DarkStyle returns a modern dark theme.

func DefaultStyle

func DefaultStyle() Style

DefaultStyle returns the default style with sensible defaults.

func GTAStyle

func GTAStyle() Style

GTAStyle returns a GTA San Andreas-inspired style. Dark theme with cyan/yellow accents reminiscent of the game's menus.

func LightStyle

func LightStyle() Style

LightStyle returns a light theme.

type StyleColorField

type StyleColorField int

StyleColorField identifies a color field in Style for PushStyleColor.

const (
	StyleColorText StyleColorField = iota
	StyleColorButton
	StyleColorButtonHovered
	StyleColorButtonActive
	StyleColorPanel
	StyleColorSelected
)

type TabStyle

type TabStyle struct {
	Selected bool
	Closable bool
}

TabStyle configures the appearance of a tab button.

type Table

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

Table manages table drawing state for the current frame.

func (*Table) Columns

func (t *Table) Columns() []TableColumn

Columns returns the computed column definitions.

func (*Table) EndTable

func (t *Table) EndTable()

EndTable finishes the table and advances the cursor.

func (*Table) FirstVisibleRow

func (t *Table) FirstVisibleRow() int

FirstVisibleRow returns the first row index that should be rendered. Use this with virtualized tables to iterate only over visible rows.

func (*Table) HandleScrollInput

func (t *Table) HandleScrollInput()

HandleScrollInput processes mouse wheel input for table scrolling. Call this after EndTable if you want custom scroll handling.

func (*Table) IsRowVisibleVirtualized

func (t *Table) IsRowVisibleVirtualized(rowIdx int) bool

IsRowVisibleVirtualized returns true if the row at the given index is currently visible.

func (*Table) LastVisibleRow

func (t *Table) LastVisibleRow() int

LastVisibleRow returns one past the last row index that should be rendered. Use this with virtualized tables to iterate only over visible rows.

func (*Table) MaxVisibleRows

func (t *Table) MaxVisibleRows() int

MaxVisibleRows returns the configured max visible rows (0 = unlimited).

func (*Table) ScrollToRow

func (t *Table) ScrollToRow(rowIdx int)

ScrollToRow scrolls the table to make the specified row visible.

func (*Table) State

func (t *Table) State() *TableState

State returns the table's current state for external manipulation.

func (*Table) TableGetColumnPos

func (t *Table) TableGetColumnPos() Vec2

TableGetColumnPos returns the current column's draw position.

func (*Table) TableGetColumnPosVirtualized

func (t *Table) TableGetColumnPosVirtualized() Vec2

TableGetColumnPosVirtualized returns the draw position accounting for scroll offset. Use this with virtualized tables instead of TableGetColumnPos.

func (*Table) TableGetColumnWidth

func (t *Table) TableGetColumnWidth() float32

TableGetColumnWidth returns the width of the current column.

func (*Table) TableHeadersRow

func (t *Table) TableHeadersRow()

TableHeadersRow renders the header row with column labels.

func (*Table) TableIsRowClicked

func (t *Table) TableIsRowClicked() bool

TableIsRowClicked returns true if the current row was clicked.

func (*Table) TableIsRowHovered

func (t *Table) TableIsRowHovered() bool

TableIsRowHovered returns true if the current row is hovered.

func (*Table) TableNextColumn

func (t *Table) TableNextColumn() Vec2

TableNextColumn moves to the next column and returns the draw position. Returns the position where content should be drawn.

func (*Table) TableNextRow

func (t *Table) TableNextRow()

TableNextRow starts a new row.

func (*Table) TableNextRowVirtualized

func (t *Table) TableNextRowVirtualized(rowIdx int) bool

TableNextRowVirtualized starts a new row at the specified index for virtualized tables. Unlike TableNextRow which auto-increments, this allows sparse row rendering. Returns true if the row is visible and should be drawn, false to skip.

func (*Table) TableSetColumnIndex

func (t *Table) TableSetColumnIndex(column int)

TableSetColumnIndex sets the current column explicitly.

func (*Table) TableText

func (t *Table) TableText(text string)

TableText draws text in the current column.

func (*Table) TableTextColored

func (t *Table) TableTextColored(text string, color uint32)

TableTextColored draws colored text in the current column.

func (*Table) TableTextColoredVirtualized

func (t *Table) TableTextColoredVirtualized(text string, color uint32)

TableTextColoredVirtualized draws colored text in the current column for virtualized tables.

func (*Table) TableTextVirtualized

func (t *Table) TableTextVirtualized(text string)

TableTextVirtualized draws text in the current column for virtualized tables.

func (*Table) TotalRows

func (t *Table) TotalRows() int

TotalRows returns the total row count for virtualized tables.

type TableColumn

type TableColumn struct {
	Label     string
	Flags     TableColumnFlags
	InitWidth float32 // Initial/fixed width (0 = auto)
	MinWidth  float32 // Minimum width when resizing
	MaxWidth  float32 // Maximum width when resizing (0 = unlimited)
	// contains filtered or unexported fields
}

TableColumn defines a table column.

type TableColumnFlags

type TableColumnFlags uint32

TableColumnFlags control individual column behavior.

const (
	TableColumnFlagsNone TableColumnFlags = 0

	// Sizing
	TableColumnFlagsWidthFixed   TableColumnFlags = 1 << 0 // Fixed width column
	TableColumnFlagsWidthStretch TableColumnFlags = 1 << 1 // Stretch to fill available space
	TableColumnFlagsWidthAuto    TableColumnFlags = 1 << 2 // Auto-size to content (default)

	// Behavior
	TableColumnFlagsNoResize TableColumnFlags = 1 << 8 // Disable manual resizing
	TableColumnFlagsNoSort   TableColumnFlags = 1 << 9 // Disable sorting for this column
)

type TableFlags

type TableFlags uint32

TableFlags control table behavior and appearance.

const (
	TableFlagsNone TableFlags = 0

	// Features
	TableFlagsResizable       TableFlags = 1 << 0 // Enable column resizing
	TableFlagsSortable        TableFlags = 1 << 1 // Enable sorting (shows sort indicators)
	TableFlagsRowSelect       TableFlags = 1 << 2 // Enable row selection
	TableFlagsScrollY         TableFlags = 1 << 3 // Enable vertical scrolling (requires height)
	TableFlagsStickyHeader    TableFlags = 1 << 4 // Keep header visible when scrolling
	TableFlagsAutoSizeColumns TableFlags = 1 << 5 // Auto-size columns to fit content

	// Borders
	TableFlagsBordersInnerH TableFlags = 1 << 8  // Horizontal borders between rows
	TableFlagsBordersInnerV TableFlags = 1 << 9  // Vertical borders between columns
	TableFlagsBordersOuterH TableFlags = 1 << 10 // Horizontal border on top/bottom
	TableFlagsBordersOuterV TableFlags = 1 << 11 // Vertical border on left/right

	// Convenience
	TableFlagsBordersInner TableFlags = TableFlagsBordersInnerH | TableFlagsBordersInnerV
	TableFlagsBordersOuter TableFlags = TableFlagsBordersOuterH | TableFlagsBordersOuterV
	TableFlagsBorders      TableFlags = TableFlagsBordersInner | TableFlagsBordersOuter

	// Row appearance
	TableFlagsRowBg          TableFlags = 1 << 16 // Alternate row background colors
	TableFlagsHighlightHover TableFlags = 1 << 17 // Highlight hovered row
)

type TableOptions

type TableOptions struct {
	MaxVisibleRows int // Maximum visible rows before scrolling (0 = unlimited)
}

TableOptions configures table behavior.

func TableMaxVisibleRows

func TableMaxVisibleRows(n int) TableOptions

TableMaxVisibleRows sets the maximum number of visible rows before scrolling.

type TableState

type TableState struct {
	ColumnWidths     []float32 // User-adjusted column widths
	MaxContentWidths []float32 // Max content width per column (for auto-sizing)
	SortColumn       int       // Currently sorted column (-1 = none)
	SortAscending    bool      // Sort direction
	SelectedRow      int       // Selected row index (-1 = none)
	ScrollOffset     float32   // Vertical scroll position
}

TableState persists table state between frames.

type TextWrapMode

type TextWrapMode int

TextWrapMode specifies how text should be wrapped.

const (
	// WrapModeWord wraps at word boundaries (default for Latin text).
	WrapModeWord TextWrapMode = iota
	// WrapModeChar wraps at character boundaries (for CJK or dense text).
	WrapModeChar
	// WrapModeAuto detects text type and chooses appropriate mode.
	WrapModeAuto
)

type ToastNotification

type ToastNotification struct {
	Message  string
	Type     ToastType
	Duration float32 // Total duration in seconds
	Elapsed  float32 // Time elapsed since shown
}

ToastNotification represents a single toast message.

type ToastState

type ToastState struct {
	Toasts []ToastNotification
}

ToastState holds the state for toast notifications. Store this in your application and pass it to DrawToasts.

func (*ToastState) Toast

func (ts *ToastState) Toast(message string, toastType ToastType, duration ...float32)

Toast adds a toast notification with the specified type and optional duration. If duration is not provided, DefaultToastDuration is used.

func (*ToastState) ToastError

func (ts *ToastState) ToastError(message string)

ToastError adds an error toast.

func (*ToastState) ToastInfo

func (ts *ToastState) ToastInfo(message string)

ToastInfo adds an info toast.

func (*ToastState) ToastSuccess

func (ts *ToastState) ToastSuccess(message string)

ToastSuccess adds a success toast.

func (*ToastState) ToastWarning

func (ts *ToastState) ToastWarning(message string)

ToastWarning adds a warning toast.

func (*ToastState) Update

func (ts *ToastState) Update(deltaTime float32)

Update advances toast timers and removes expired toasts. Call this once per frame with deltaTime.

type ToastType

type ToastType uint8

ToastType defines the type of toast notification.

const (
	ToastTypeInfo ToastType = iota
	ToastTypeSuccess
	ToastTypeWarning
	ToastTypeError
)

type TreeNodeState

type TreeNodeState struct {
	Open bool
}

TreeNodeState tracks expanded/collapsed state for tree nodes.

type Vec2

type Vec2 struct {
	X, Y float32
}

Vec2 represents a 2D vector for positions and sizes.

func MeasureWrappedText

func MeasureWrappedText(ctx *Context, text string, maxWidth float32, mode TextWrapMode) Vec2

MeasureWrappedText returns the size of text when wrapped to maxWidth.

func (Vec2) Add

func (v Vec2) Add(other Vec2) Vec2

Add returns the sum of two vectors.

func (Vec2) Mul

func (v Vec2) Mul(s float32) Vec2

Mul returns the vector scaled by a scalar.

func (Vec2) Sub

func (v Vec2) Sub(other Vec2) Vec2

Sub returns the difference of two vectors.

type Vertex

type Vertex struct {
	Pos      [2]float32 // Position (x, y)
	TexCoord [2]float32 // Texture coordinates (u, v)
	Color    uint32     // RGBA packed color
}

Vertex represents a vertex for UI rendering. Memory layout matches OpenGL vertex attribute expectations.

Directories

Path Synopsis
backend
opengl
Package opengl provides an OpenGL 4.1 backend for the GUI package.
Package opengl provides an OpenGL 4.1 backend for the GUI package.
doc
gen command
Command gen renders every widget with sample data, captures framebuffer pixels, and saves JPEG screenshots to doc/imgs/.
Command gen renders every widget with sample data, captures framebuffer pixels, and saves JPEG screenshots to doc/imgs/.
Example demonstrates a minimal GUI window with a panel and a few widgets.
Example demonstrates a minimal GUI window with a panel and a few widgets.

Jump to

Keyboard shortcuts

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