dfx

package module
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

README

dfx

dfx is a simplified second-generation immediate-mode GUI framework built on top of Dear ImGui. It provides a clean, Go-idiomatic API for building desktop applications with a focus on simplicity and ease of use.

Overview

dfx is a complete rewrite of the original imapp framework (a personal project, never released), designed to provide the same core functionality with a much simpler and more intuitive API. Key improvements include:

  • 50% less code - Eliminated redundant abstractions
  • Simpler mental model - Everything is a Component
  • Better composition - Components can have children
  • Type safety - Structured events instead of raw IO polling
  • Conflict detection - Actions prevent key binding conflicts
  • Built-in theming - Comprehensive font and theme system

The dfx Roadmap is always up-to-date with the current and planned work on the project.

Core Concepts

Component Interface

The fundamental abstraction in dfx is the Component:

type Component interface {
    Draw(state *State)
    Actions() *ActionRegistry
}

Components receive a State containing all drawing context and can define keyboard actions.

State

The State struct consolidates all drawing parameters:

type State struct {
    Size     imgui.Vec2  // Available drawing area
    Position imgui.Vec2  // Position within parent
    IO       *imgui.IO  // ImGui input/output
    App      *App       // Application reference
    Parent   Component  // Parent component (nil for root)
}
Component Types
Func - Simple Function Components

The simplest way to create a component:

root := dfx.NewFunc(func(state *dfx.State) {
    imgui.Text("Hello World!")
    if imgui.Button("Click Me") {
        fmt.Println("Button clicked!")
    }
})
Container - Composable Components

For more complex components with state and children:

type MyComponent struct {
    dfx.Container
    counter int
}

func NewMyComponent() *MyComponent {
    c := &MyComponent{}
    c.Visible = true
    c.OnDraw = func(state *dfx.State) {
        imgui.Text(fmt.Sprintf("Counter: %d", c.counter))
        if imgui.Button("Increment") {
            c.counter++
        }
    }
    return c
}

Quick Start

Basic Application
package main

import "github.com/michaelquigley/dfx"

func main() {
    root := dfx.NewFunc(func(state *dfx.State) {
        imgui.Text("Hello from dfx!")
        if imgui.Button("Click Me") {
            // handle button click
        }
    })

    app := dfx.New(root, dfx.Config{
        Title:  "My App",
        Width:  800,
        Height: 600,
    })

    app.Run()
}
With Menu Bar
menuBar := dfx.NewFunc(func(state *dfx.State) {
    if imgui.BeginMenu("File") {
        if imgui.MenuItemBoolV("New", "Ctrl+N", false, true) {
            // handle new
        }
        if imgui.MenuItemBoolV("Open", "Ctrl+O", false, true) {
            // handle open
        }
        imgui.EndMenu()
    }
})

app := dfx.New(root, dfx.Config{
    Title:   "My App",
    MenuBar: menuBar,
})
Application Lifecycle

Config Callbacks:

  • OnSetup(app *App) - Called once after ImGui context is created
  • OnShutdown(app *App) - Called before shutdown
  • OnTick(app *App) - Called each frame before drawing
  • OnClose(app *App) - Called when window is about to close (can cancel via SetShouldClose(false))
  • OnSizeChange(width, height int) - Called when window is resized

Config Fields:

  • Icons []image.Image - Optional window icons for taskbar/title bar

App Methods:

  • Run() error - Run the application (blocks until closed)
  • Wait() error - Block until Run() completes (useful when Run() is called from a goroutine)
  • Stop() - Request application to stop
  • SetRoot(root Component) - Change the root component at runtime
  • Actions() *ActionRegistry - Get global action registry
  • SetWindowTitle(title string) - Update window title dynamically
  • SetShouldClose(shouldClose bool) - Control window close behavior
  • GetWindowSize() (int, int) - Get current window dimensions
  • GetWindowPos() (int, int) - Get current window position

Theming System

dfx includes a comprehensive theming system with both predefined and customizable themes.

Predefined Themes
app := dfx.New(root, dfx.Config{
    Title: "Themed App",
    Theme: dfx.BlueTheme,    // or GreenTheme, RedTheme, PurpleTheme, ModernDark
})
Custom HSV Themes
customTheme := dfx.NewHueColorScheme("Custom", 180, 60, 200)
app := dfx.New(root, dfx.Config{
    Title: "Custom Themed App",
    Theme: customTheme,
})
Runtime Theme Switching
// Change theme during runtime
dfx.SetTheme(dfx.ModernDark)

Font System

dfx provides three font constants with Material Icons merged where applicable:

  • MainFont (20px) - Gidole Regular with Material Icons
  • MonospaceFont (16px) - JetBrains Mono for code
  • SmallFont (16px) - Gidole Regular small with Material Icons, for labels/indicators
Using Different Fonts
// Default font (with icons)
imgui.Text("Regular text " + string(fonts.ICON_FAVORITE))

// Monospace font
dfx.PushFont(dfx.MonospaceFont)
imgui.Text("Monospace code text")
dfx.PopFont()

// Small font for labels and indicators
dfx.PushFont(dfx.SmallFont)
imgui.Text("CH1")
dfx.PopFont()
Disabling Font/Theme System
app := dfx.New(root, dfx.Config{
    Title:          "Minimal App",
    DisableFonts:   true,  // Use default ImGui fonts
    DisableTheming: true,  // Use default ImGui theme
})

Controls

For trivial ImGui operations (Button, Text, Separator, SameLine, Spacing, TreeNode, TreePop, BeginChild, EndChild, BeginMenu, EndMenu, BeginMenuBar, EndMenuBar, MenuItem), call imgui.* directly. dfx provides value-add wrappers for controls that benefit from a cleaner Go-idiomatic API, returning (newValue, changed) tuples instead of requiring pointers:

// Text input
text, changed := dfx.Input("Label", currentText)
if changed {
    // handle text change
}

// Slider
value, changed := dfx.Slider("Volume", currentValue, 0.0, 1.0)

// Checkbox
checked, changed := dfx.Checkbox("Enable feature", isEnabled)

// Button (use imgui directly)
if imgui.Button("Submit") {
    // handle button click
}

// Combo/Dropdown
items := []string{"Option 1", "Option 2", "Option 3"}
selected, changed := dfx.Combo("Choose", currentIndex, items)

Value-add wrappers (in controls.go): Input, InputMultiline, Checkbox, Slider, SliderInt, Combo, ColorEdit3, ColorEdit4, Toggle, WheelSlider.

Text Utilities (in text.go):

  • CenterText(text string) - Draws text centered horizontally and vertically in the available content region
  • CenterTextDisabled(text string) - Draws disabled (dimmed) text centered horizontally and vertically
Enhanced Controls

dfx provides several enhanced controls with additional features beyond standard ImGui widgets:

Toolbar - Full-width header bar for section labels:

// simple toolbar with label
dfx.Toolbar("Settings")

// toolbar with extra controls on the right
dfx.ToolbarEx("Actions", func() {
    if imgui.Button("Add") {
        // handle add
    }
    imgui.SameLine()
    if imgui.Button("Remove") {
        // handle remove
    }
})

Features:

  • Draws full-width background rectangle using ColHeader color
  • Automatically handles padding and cursor positioning
  • ToolbarEx allows additional controls to the right of the label via callback

Toggle - Boolean toggle button with visual feedback:

// inactive (false): dimmed appearance
// active (true): checkmark color
enabled, changed := dfx.Toggle("Play", playEnabled)

WheelSlider - Horizontal slider with mouse wheel support:

// hover and scroll to adjust, Ctrl = 10x faster, Alt = 10x slower
value, changed := dfx.WheelSlider("Volume", volume, 0.0, 1.0, 100, "%.2f", imgui.SliderFlagsNone)

Fader - Advanced vertical fader designed for audio mixing applications with support for logarithmic tapers, range limits, and multiple value representations:

FaderN - Normalized fader (0.0 to 1.0):

params := dfx.DefaultFaderParams()
params.Taper = dfx.AudioTaper()
params.Format = func(norm float32) string {
    return fmt.Sprintf("%.2f", norm)
}
value, changed := dfx.FaderN("##fader", normalizedValue, params)

FaderF - Float fader (arbitrary min/max range):

// Example: -60.0 dB to +12.0 dB with audio taper
params := dfx.DefaultFaderParams()
params.Taper = dfx.AudioTaper()
params.Format = func(norm float32) string {
    db := norm*72.0 - 60.0
    if db <= -59.9 {
        return "-∞ dB"
    }
    return fmt.Sprintf("%.1f dB", db)
}
dbValue, changed := dfx.FaderF("##db", gainDB, -60.0, 12.0, params)

FaderI - Integer fader (arbitrary min/max range):

// Example: 0 to 32767 for hardware control
params := dfx.DefaultFaderParams()
params.MinStop = 0.1  // limit to 10%-90% of range
params.MaxStop = 0.9
hwValue, changed := dfx.FaderI("##hw", hardwareValue, 0, 32767, params)

FaderParams provides extensive configuration:

  • Taper - Response curve (Linear, Log, Audio, or Custom)
  • MinStop / MaxStop - Range limits in normalized 0-1 space
  • ResetValue - Right-click reset target (normalized 0-1 space)
  • Width / Height - Fader dimensions
  • Format - Custom tooltip formatting function
  • ShowTooltip - Enable/disable value tooltip (default: true)
  • WheelSteps - Mouse wheel sensitivity (default: 100.0)

Built-in Tapers:

  • LinearTaper() - No taper, 1:1 mapping (default)
  • LogTaper(steepness) - Logarithmic curve (steepness: 1.0 = gentle, 3.0 = moderate, 10.0 = steep)
  • AudioTaper() - Standard audio fader curve (gentle bottom, steep top, optimized for dB scales)
  • DecibelTaper(dbRange) - UI position linear with dB; for hardware values proportional to amplitude
  • CustomTaper(apply, invert) - User-defined taper functions

Multi-Representation Pattern: Advanced faders support maintaining multiple value representations (normalized, hardware, display) synchronized via conversion functions:

type FaderState struct {
    normalized float32  // 0.0 - 1.0 (master value)
    hardware   int      // 0 - 32767
    decibels   float32  // -60.0 to +12.0
}

func updateFromNormalized(state *FaderState, norm float32) {
    state.normalized = norm
    state.hardware = int(norm * 32767)
    state.decibels = norm*72.0 - 60.0
}

// User chooses which API to use based on their needs
// FaderN for normalized, FaderI for hardware, FaderF for display values

Faders with Scales: The FaderWithScaleN/F/I functions add tick marks and labels next to faders, perfect for audio applications that need visual reference marks:

// Example: dB fader with scale
params := dfx.DefaultFaderParams()
params.Taper = dfx.AudioTaper()

scale := dfx.DefaultScaleConfig()
scale.Marks = []float32{0.0, 0.417, 0.667, 0.833, 1.0}
scale.Labels = map[float32]string{
    0.0:   "-60",
    0.417: "-30",
    0.667: "-12",
    0.833: "0",
    1.0:   "+12",
}

dbValue, changed := dfx.FaderWithScaleF("##gain", gainDB, -60.0, 12.0, params, scale)

ScaleConfig provides:

  • Marks - Array of normalized positions (0-1) for tick marks
  • Labels - Map of position → label text for specific marks
  • TickLength - Tick mark length in pixels (default: 5.0)
  • LabelOffset - Distance from ticks to labels (default: 3.0)
  • Position - "left" or "right" side placement (default: "left")

Key features:

  • Taper-aware: Tick marks automatically respect the fader's taper curve for visual accuracy
  • Theme integration: Uses colors from the current theme
  • Flexible: Add scales to any normalized, float, or integer range fader

See examples/dfx_example_mixer for a complete demonstration with horizontally scrollable mixer interface showcasing all fader types and scales.

VUMeter - Vertical level meter with multi-channel support and three display modes:

// create a stereo meter
meter := dfx.NewVUMeter(2)
meter.SetLabels([]string{"L", "R"})

// set display mode (optional - VUMeterSolid is default)
meter.Mode = dfx.VUMeterSolid     // continuous fill
meter.Mode = dfx.VUMeterHighres   // 1px segments with 1px gaps
meter.Mode = dfx.VUMeterSegmented // configurable segments

// update levels each frame (0.0 to 1.0)
meter.SetLevels([]float32{leftLevel, rightLevel})

// draw the meter
meter.Draw(state)

Configuration:

  • Mode - Display mode: VUMeterSolid (default), VUMeterHighres, VUMeterSegmented
  • Height - Total height in pixels (default: 200)
  • ChannelWidth - Width of each channel meter (default: 12)
  • SegmentCount - Number of vertical segments, applies to VUMeterSegmented mode (default: 20)
  • SegmentGap / ChannelGap - Spacing between segments and channels
  • PeakHoldMs - Peak hold duration in ms, 0 = disabled (default: 1000)
  • PeakDecayRate - Peak decay rate per second (default: 0.5)
  • ClipHoldMs - Clip indicator hold time in ms (default: 2000)
  • Labels - Custom labels per channel (e.g., "L", "R", "Kick")
  • ColorLow/Mid/High/Off/Peak/Clip - Customizable segment colors

Display Modes:

  • VUMeterSolid: Continuous fill with stacked color zones - clean, modern look
  • VUMeterHighres: Fixed 1px segments with 1px gaps - high resolution digital look
  • VUMeterSegmented: Configurable segments via SegmentCount and SegmentGap

Features:

  • Multi-channel: Supports any number of channels displayed side-by-side
  • Color zones: Green (0-60%), yellow (60-80%), red (80-100%)
  • Peak hold: Displays peak level with configurable hold and decay
  • Clip indicator: Top indicator lights red when signal clips, auto-resets
  • Custom labels: Per-channel labels displayed below meters

See examples/dfx_example_vumeter for a complete demonstration.

VUWaterfall - Scrolling history display of VU levels over time:

// create a stereo waterfall
waterfall := dfx.NewVUWaterfall(2)
waterfall.Height = 150
waterfall.HistorySize = 100 // samples to retain

// each frame, add current levels to history
waterfall.SetLevels([]float32{leftLevel, rightLevel})

// draw the waterfall
waterfall.Draw(state)

Configuration:

  • Height - Total height in pixels (default: 200)
  • ChannelWidth - Width per channel (default: 40)
  • ChannelGap - Gap between channels (default: 4)
  • RowHeight - Height of each history row (default: 2)
  • RowGap - Gap between rows (default: 0)
  • HistorySize - Number of samples to retain (default: 100)
  • SampleInterval - Minimum time between samples for throttling (default: 16ms / ~60fps)
  • Highres - When true, alternates row opacity for scanline effect
  • ColorLow/Mid/High/Off - Zone colors (same defaults as VUMeter)

Additional Methods:

  • SetHistorySize(size int) - Change history depth (clears buffer)
  • ChannelCount() int - Get current channel count

Features:

  • Vertical scrolling: New data appears at bottom, scrolls upward
  • Multi-channel: Channels displayed side-by-side
  • Color zones: Green (0-60%), yellow (60-80%), red (80-100%)
  • Centered bars: Level represented by bar width, centered in channel
  • Sample throttling: Consistent scroll speed via SampleInterval
  • Highres mode: Scanline effect with alternating row opacity

See examples/dfx_example_vumeter for a complete demonstration.

LogViewer - Buffered log display with configurable empty-state behavior:

buffer := dfx.NewLogBuffer(1000)
viewer := dfx.NewLogViewer(buffer)

viewer.Visible = true
viewer.ShowDisabledMessage = true
viewer.DisabledMessage = "logging capture disabled"

Visibility behavior:

  • Visible == false renders nothing
  • Visible == true and Buffer != nil renders the log stream
  • Visible == true and Buffer == nil renders DisabledMessage only when ShowDisabledMessage == true

Use NewSlogHandler(...) with a shared LogBuffer to route slog output into the viewer.

FileNode Search/Filter

FileNode provides a Find method for searching trees, along with predicate constructors for common patterns:

// find all .go files
goFiles := root.Find(dfx.MatchExt(".go"))

// find by name regex
pred, err := dfx.MatchName(`^main\.`)
if err != nil {
    // handle invalid regex
}
mains := root.Find(pred)

// find by full path regex
pred, err = dfx.MatchPath(`src/.*\.go$`)
if err != nil {
    // handle invalid regex
}
srcGoFiles := root.Find(pred)

// find all directories with an inline predicate
dirs := root.Find(func(n *dfx.FileNode) bool { return n.Dir })

Methods:

  • Find(predicate func(*FileNode) bool) []*FileNode - Returns all matching nodes in depth-first pre-order. Returns nil on a nil receiver.

Predicate Constructors:

  • MatchExt(ext string) func(*FileNode) bool - Matches non-directory nodes by file extension (case-insensitive). The ext parameter should include the dot (e.g. ".go").
  • MatchName(pattern string) (func(*FileNode) bool, error) - Matches nodes whose Name matches the given regex.
  • MatchPath(pattern string) (func(*FileNode) bool, error) - Matches nodes whose full Path() matches the given regex.

Predicates are composable with FileTree.Filter:

fileTree.Filter = dfx.MatchExt(".go")

Actions and Keyboard Shortcuts

dfx provides a hierarchical action system with conflict detection:

Global Actions

Register application-wide keyboard shortcuts:

app := dfx.New(root, dfx.Config{
    Title: "App with Shortcuts",
    OnSetup: func(app *dfx.App) {
        // Register global shortcuts
        app.Actions().Register("save", "Ctrl+S", func() {
            // handle save
        })

        app.Actions().Register("quit", "Ctrl+Q", func() {
            app.Stop()
        })
    },
})
Component-Local Actions

Components can define their own keyboard shortcuts that automatically override global actions:

myComponent := &dfx.Container{
    Visible: true,
    OnDraw: func(state *dfx.State) {
        imgui.Text("Component with local actions")
    },
}

// Add component-specific actions
myComponent.Actions().Register("increment", "Up", func() {
    // handle up arrow - only when this component has focus
})

myComponent.Actions().Register("decrement", "Down", func() {
    // handle down arrow
})

The action system provides:

  • Automatic conflict detection within components
  • Hierarchical override behavior - component actions override global actions
  • Simple key binding syntax - "Ctrl+S", "Alt+F4", "Up", etc.
  • No boilerplate - just define actions and they work
Action Traversal

For custom composite components, implement:

  • ChildActions() []Component to expose children for traversal
  • LocalActions() *ActionRegistry to expose local actions

Action precedence is:

  • child component actions first
  • parent-local actions next
  • app-global actions last
Menu-Compatible Actions

For applications with menu bars, dfx provides menu-compatible actions that work both as keyboard shortcuts and menu items:

// create menu actions
fileNew := dfx.NewMenuAction("New", "Ctrl+N", func() {
    // handle new file
})

fileSave := dfx.NewMenuAction("Save", "Ctrl+S", func() {
    // handle save
})

fileQuit := dfx.NewMenuAction("Quit", "Ctrl+Q", func() {
    app.Stop()
})

// create menu bar component
// NOTE: dfx.Config.MenuBar already wraps this in BeginMainMenuBar/EndMainMenuBar
menuBar := dfx.NewFunc(func(state *dfx.State) {
    if imgui.BeginMenu("File") {
        fileNew.DrawMenuItem()    // renders as menu item with shortcut label
        imgui.Separator()
        fileSave.DrawMenuItem()
        imgui.Separator()
        fileQuit.DrawMenuItem()
        imgui.EndMenu()
    }
})

// register for keyboard shortcuts
app.Actions().MustRegisterAction(fileNew)
app.Actions().MustRegisterAction(fileSave)
app.Actions().MustRegisterAction(fileQuit)

// use menu bar in config
app := dfx.New(root, dfx.Config{
    MenuBar: menuBar,
})

Menu actions provide:

  • Dual functionality - work as both menu items and keyboard shortcuts
  • Automatic shortcut labels - keyboard shortcuts display in menus
  • Single definition - define once, use in both menu and keyboard
  • Consistent behavior - clicking menu or pressing keys calls the same handler

See examples/dfx_example_menu for a complete demonstration.

Layout and Composition

For a comprehensive guide to Dear ImGui's layout system including child windows, sizing semantics, and practical patterns, see docs/current/layout-guide.md. The interactive demo in examples/dfx_example_layout demonstrates all concepts with real-time values.

Components can contain children for complex layouts:

container := &dfx.Container{
    Visible: true,
    Children: []dfx.Component{
        header,
        content,
        footer,
    },
    OnDraw: func(state *dfx.State) {
        // Custom layout logic for this container.
        // Children are drawn automatically by Container.Draw().
    },
}
HCollapse - Horizontal Collapsible Panel

The HCollapse component provides a horizontal collapsible panel that contains content to its right. When collapsed, only the toggle button is visible. When expanded, it shows a header bar with title and the content below.

// create a collapsible sidebar
sidebar := dfx.NewHCollapse(
    sidebarContent,
    dfx.HCollapseConfig{
        Title:         "Sidebar",
        ExpandedWidth: 250,
        TransitionMs:  100,
        Resizable:     true,
        Expanded:      true,
    },
)

// optional: add keyboard shortcut for toggle
sidebar.Actions().Register("toggle-sidebar", "[", func() {
    sidebar.Toggle()
})

// in Draw, use SameLine() to place content to the right
func (m *MyApp) Draw(state *dfx.State) {
    sidebar.Draw(state)
    imgui.SameLine()

    // main content fills remaining width
    remaining := state.Size.X - sidebar.CurrentWidth
    imgui.BeginChildStrV("main", imgui.Vec2{X: remaining, Y: state.Size.Y}, 0, 0)
    mainContent.Draw(state)
    imgui.EndChild()
}

Configuration:

  • Title - displayed in header when expanded (also used for unique imgui ID)
  • ExpandedWidth - width when fully expanded
  • MinWidth - collapsed width (defaults to 36px, toggle button only)
  • MaxWidth - maximum width when resizing (0 = no limit)
  • TransitionMs - animation duration (default: 80ms)
  • Resizable - allow drag-to-resize when expanded
  • Expanded - initial state

Features:

  • Animated transitions - smooth expand/collapse animation
  • Header bar - toggle button on left, title when expanded, resize handle on right
  • Drag-to-resize - adjust width by dragging the right edge
  • Collapsed tooltip - hovering over collapsed toggle shows title
  • Toggle callback - OnToggle func(expanded bool) for state change notifications
  • CurrentWidth - read current width for layout calculations

Note: When using custom-drawn components (like VUMeter, Fader) inside tables within an HCollapse, use imgui.TableFlagsNoClip and imgui.TableColumnFlagsNoClip to prevent cell clipping.

Workspace - View Switching

The Workspace component provides high-level management of multiple named views with easy switching. It separates stable identifiers from display names, allowing display names to include icons and formatting without affecting code that switches workspaces.

// create workspaces
editor := dfx.NewFunc(func(state *dfx.State) {
    imgui.Text("Editor View")
    // editor UI...
})

viewer := dfx.NewFunc(func(state *dfx.State) {
    imgui.Text("Viewer")
    // viewer UI...
})

// create workspace manager with IDs and display names
ws := dfx.NewWorkspace()
ws.Add("editor", "📝 Editor", editor)  // ID, display name, component
ws.Add("viewer", "👁️ Viewer", viewer)
ws.ShowSelector = true      // shows combo selector
ws.SelectorLabel = "View"

// callback receives stable IDs
ws.OnSwitch = func(oldID, newID string) {
    fmt.Printf("switched from '%s' to '%s'\n", oldID, newID)
}

// add keyboard shortcuts using stable IDs
ws.Actions().MustRegister("Switch to Editor", "Ctrl+1", func() {
    ws.Switch("editor")  // won't break if display name changes
})
ws.Actions().MustRegister("Switch to Viewer", "Ctrl+2", func() {
    ws.Switch("viewer")
})

// change display name without affecting code
ws.SetName("editor", "✏️ Code Editor")

app := dfx.New(ws, dfx.Config{...})

API Methods:

  • NewWorkspace() - create workspace manager
  • Add(id, name, component) - add/replace workspace with ID and display name
  • Remove(id) - remove workspace by ID
  • Switch(id) - switch to workspace by ID
  • SwitchByIndex(index) - switch by index
  • Current() - get current workspace ID
  • CurrentName() - get current display name
  • CurrentComponent() - get current component
  • SetName(id, name) - change display name (ID unchanged)
  • GetName(id) - get display name for ID
  • WorkspaceIds() - get list of workspace IDs
  • WorkspaceNames() - get list of display names

Configuration:

  • ShowSelector - show/hide combo selector (default: true)
  • SelectorLabel - label for combo (default: "Workspace")
  • SelectorWidth - width of selector (default: 200, -1 for auto)
  • OnSwitch - callback when workspace changes (receives IDs)

Benefits of ID/Name Separation:

  • Stable IDs for code, config files, keyboard shortcuts
  • Display names can include icons, emoji, formatting
  • Change display names without breaking code
  • Easy localization (same ID, different display names)

See examples/dfx_example_workspace for a complete demonstration.

Undo/Redo System

dfx includes a command-pattern undo/redo system for tracking reversible operations:

// define a command
type SetValueCommand struct {
    dfx.BaseCommand
    target   *int
    oldValue int
    newValue int
}

func (c *SetValueCommand) Description() string { return fmt.Sprintf("set value to %d", c.newValue) }
func (c *SetValueCommand) Run()                { *c.target = c.newValue }
func (c *SetValueCommand) Undo()               { *c.target = c.oldValue }

// create and use the undo system
undoSystem := dfx.NewUndoSystem()
undoSystem.Run(&SetValueCommand{target: &myValue, oldValue: myValue, newValue: 42})
undoSystem.Undo()  // reverts to old value
undoSystem.Redo()  // re-applies new value

API:

  • NewUndoSystem() *UndoSystem - Create undo system
  • Run(cmd Command) - Execute and track command (supports automatic merging via MergeableCommand)
  • Undo() / Redo() - Navigate command history
  • Clear() - Remove all commands from both stacks
  • CanUndo() bool / CanRedo() bool - Check availability
  • HistoryComponent() - Returns a component displaying undo/redo history
  • RunF func(Command) - Optional callback invoked whenever a command is executed

Command Interfaces:

  • Command - Core: Description(), Run(), Undo()
  • MergeableCommand - Adds Merge(other Command) bool for combining adjacent commands
  • StampedCommand - Adds Stamp() time.Time for timestamp tracking
  • FullCommand - Combines MergeableCommand and StampedCommand

BaseCommand - Embeddable helper struct providing automatic timestamp via Stamp() and manual override via SetStamp(time.Time).

See examples/dfx_example_undo for a complete demonstration.

Debug Utilities

SizeDebugger - Visual component that displays the available drawing area size and draws a border with crossing lines. Useful for debugging layout issues.

debugger := dfx.NewSizeDebugger()
debugger.Margin = 8  // inset from edges (default: 4)
// use as any Component - shows size label and border lines
// press Shift+Alt+D to toggle the size label

Configuration Persistence

dfx provides optional utilities for configuration management in config.go. These helpers simplify common patterns like saving/loading JSON configuration, persisting window state, and managing dashboard layouts.

Basic Configuration Pattern
type Config struct {
    Window dfx.WindowConfig              `json:"window"`
    Dashes map[string]dfx.DashConfig     `json:"dashes"`
    // ... your app-specific settings
}

func main() {
    // determine config file path
    cfgPath, _ := dfx.ConfigPath("myapp", "config.json")

    // load with defaults
    cfg := defaultConfig()
    dfx.LoadJSON(cfgPath, cfg)

    // create app with saved window size and position
    app := dfx.New(root, dfx.Config{
        Title:  "My App",
        Width:  cfg.Window.Width,
        Height: cfg.Window.Height,
        X:      cfg.Window.X,
        Y:      cfg.Window.Y,

        OnClose: func(app *dfx.App) {
            cfg.Window = dfx.CaptureWindowState(app)
            dfx.SaveJSON(cfgPath, cfg)
        },

        OnSizeChange: func(width, height int) {
            cfg.Window.Width = width
            cfg.Window.Height = height
        },
    })

    app.Run()
}
Dashboard State Persistence
// capture dashboard state
cfg.Dashes = dfx.CaptureDashState(dashMgr)

// save to file
dfx.SaveJSON(cfgPath, cfg)

// later, restore dashboard state
dfx.RestoreDashState(dashMgr, cfg.Dashes)
Configuration Helper Functions
  • ConfigPath(appName, filename string) (string, error) - Returns standard config file path in user home directory (e.g., ~/.myapp/config.json)
  • SaveJSON(path string, config interface{}) error - Saves struct to JSON file with formatting
  • LoadJSON(path string, config interface{}) error - Loads JSON file into struct (silent if file doesn't exist)
  • CaptureDashState(dm *DashManager) map[string]DashConfig - Extracts dashboard visibility and sizes
  • RestoreDashState(dm *DashManager, config map[string]DashConfig) - Applies configuration to dashboards
  • CaptureWindowState(app *App) WindowConfig - Gets current window position, size, and state

Note: WindowConfig includes a Maximized field for future compatibility, but maximized state capture/restore is not yet implemented (requires backend enhancements).

Example

See examples/dfx_example_config for a complete demonstration of configuration persistence including window state, dashboard layouts, and application settings.

Container-Based Architecture with df/da

For larger applications, dfx integrates with the df/da dependency injection container and df/dd data-driven serialization packages. This pattern provides a more scalable architecture with factory-based component creation and automatic lifecycle management.

Pattern Overview

The container-based pattern uses three packages:

  • da.Application[C] - Application lifecycle with typed configuration
  • dfx - GUI framework
  • dd - Struct-to-YAML/JSON bidirectional binding

The lifecycle flow is: Configure → Build (factories) → Link → Start → (user interaction) → Stop → Save

Basic Structure
// config.go - typed configuration
type config struct {
    WindowX      int
    WindowY      int
    WindowWidth  int
    WindowHeight int
    Counter      int
}

func defaultConfig() config {
    return config{
        WindowX:      100,
        WindowY:      100,
        WindowWidth:  800,
        WindowHeight: 600,
    }
}
// shellFactory.go - factory creates the main window
type shellFactory struct{}

func (f *shellFactory) Build(a *da.Application[config]) error {
    shl := &shell{
        cfg:       &a.Cfg,  // reference to mutable config
        workspace: dfx.NewWorkspace(),
    }

    shl.app = dfx.New(shl.root, dfx.Config{
        Title:  "my app",
        Width:  shl.cfg.WindowWidth,
        Height: shl.cfg.WindowHeight,
        X:      shl.cfg.WindowX,
        Y:      shl.cfg.WindowY,
        OnSizeChange: func(w, h int) {
            shl.cfg.WindowWidth = w
            shl.cfg.WindowHeight = h
        },
        OnClose: func(app *dfx.App) {
            shl.cfg.WindowX, shl.cfg.WindowY = app.GetWindowPos()
        },
    })

    da.Set(a.C, shl)  // register in container
    return nil
}

// Link wires up tagged workspace components
func (s *shell) Link(c *da.Container) error {
    for i, ws := range da.TaggedAsType[dfx.Component](c, "workspaces") {
        s.workspace.Add(fmt.Sprintf("ws-%d", i), fmt.Sprintf("workspace %d", i+1), ws)
    }
    return nil
}

func (s *shell) Start() error {
    go s.app.Run()
    return nil
}
// panelFactory.go - factory registers tagged workspace component
type panelFactory struct{}

func (f *panelFactory) Build(a *da.Application[config]) error {
    panel := &myPanel{cfg: &a.Cfg}
    da.AddTagged(a.C, "workspaces", panel)  // tagged registration
    return nil
}
// main.go - application lifecycle
func main() {
    cfgPath, _ := configPath()

    app := da.NewApplication[config](defaultConfig())
    app.Factories = append(app.Factories, &panelFactory{})
    app.Factories = append(app.Factories, &shellFactory{})

    app.InitializeWithPaths(da.OptionalPath(cfgPath))
    app.Start()

    // wait for GUI to close
    if shl, ok := da.Get[*shell](app.C); ok {
        shl.app.Wait()
    }

    // save config
    dd.UnbindYAMLFile(app.Cfg, cfgPath)
    app.Stop()
}
Key Benefits
  • Factory pattern - Components created via Build() methods with access to typed config
  • Tagged components - da.AddTagged() for modular registration without naming conflicts
  • Link phase - Wire up dependencies after all factories complete
  • Config mutation - Components hold *config reference for real-time state updates
  • Automatic persistence - dd.UnbindYAMLFile() saves config struct to YAML on shutdown
Example

See examples/dfx_example_container for a complete demonstration of container-based architecture with tagged workspace components.

Examples

See the examples/ directory for complete working examples:

  • dfx_example_simple - Basic usage
  • dfx_example_actions - Keyboard shortcuts
  • dfx_example_custom_component - Custom component creation
  • dfx_example_composition - Complex UI with menu bars
  • dfx_example_themes - Theming and font demonstration
  • dfx_example_filetree - Filesystem tree viewer
  • dfx_example_logviewer - Log viewer with df/dl integration
  • dfx_example_controls - Control wrappers (Combo, Toggle, WheelSlider)
  • dfx_example_mixer - Advanced fader demonstration with tapers, range limits, and horizontal scrolling mixer
  • dfx_example_vumeter - VU meter and waterfall with display modes and scrolling history
  • dfx_example_hcollapse - Horizontal collapsible panels with faders and meters
  • dfx_example_simple_hcollapse - Minimal HCollapse example
  • dfx_example_workspace - Workspace switching with multiple views
  • dfx_example_lifecycle - Window lifecycle callbacks
  • dfx_example_config - Configuration persistence with window and dashboard state
  • dfx_example_container - Container-based lifecycle with df/da dependency injection
  • dfx_example_layout - Comprehensive ImGui layout and sizing tutorial (see docs/current/layout-guide.md)
  • dfx_example_multigrid - MultiGrid layout system
  • dfx_example_dash - DashManager panel system
  • dfx_example_undo - Undo/redo system demo
  • dfx_example_menu - Menu-compatible actions
  • dfx_example_demo - ImGui demo window

Building Examples

# Build all examples
go build ./examples/dfx_example_simple
go build ./examples/dfx_example_actions
go build ./examples/dfx_example_themes

# Run an example
./dfx_example_themes

Migration from imapp v1

dfx is designed as a replacement for imapp v1:

  1. Replace imapp.Surface usage with dfx.Component
  2. Convert Surface.DrawF functions to dfx.Func components
  3. Replace action registration with new conflict-detecting system
  4. Update control usage to new return-value API

The migration should be straightforward due to conceptual similarity, but the new API is much cleaner and more Go-idiomatic.

Architecture Notes

Full-Window Rendering

Components render within an invisible, borderless ImGui window that fills the entire backend window. This matches imapp v1's behavior exactly and provides a transparent "canvas" for drawing.

No Layout System

dfx deliberately does not include a layout system, allowing components to handle their own positioning. This keeps the framework simple while enabling maximum flexibility.

Single Backend

Currently supports only the GLFW backend, matching imapp v1's approach.

License

Part of the baab project.

Documentation

Index

Constants

View Source
const (
	DefaultDashSize      = 400
	DefaultDashMinSize   = 40
	DefaultDashMaxSize   = 1000
	DefaultTransitionMs  = 100
	DashBackgroundAlpha  = 0.85
	DashWindowRounding   = 5
	DashScrollbarSize    = 5
	DragHandleSize       = 20
	DashTitleBarHeight   = 27
	DashTitleBarOffset   = 22
	DashDragHandleOffset = 22
	DashSurfacePadding   = 20
	FramerateToMs        = 1000
)
View Source
const (
	VerticalPrecedence = DashPrecedence(iota)
	HorizontalPrecedence
)
View Source
const (
	MainFont      = 0 // default font (Gidole Regular, 20px) with Material Icons merged
	MonospaceFont = 1 // monospace font (JetBrains Mono, 16px)
	SmallFont     = 2 // small font (Gidole Regular, 16px) with Material Icons merged
)

font indices for easy access note: icon fonts are merged into their base fonts, not separate entries

View Source
const (
	HCollapseHeaderHeight      = 36
	HCollapseDefaultMinWidth   = 36
	HCollapseDefaultTransition = 80
	HCollapseResizeHandleSize  = 20
)

HCollapse constants

View Source
const (
	// default padding and spacing
	DefaultWindowPadding = 4
	DefaultFramePadding  = 4
	DefaultItemSpacing   = 4

	// scrollbar and border sizes
	DefaultScrollbarSize = 12
	DefaultWindowBorder  = 0
	DefaultChildBorder   = 0
	DefaultPopupBorder   = 1
	DefaultFrameBorder   = 0

	// rounding values
	DefaultWindowRounding    = 3
	DefaultChildRounding     = 0
	DefaultFrameRounding     = 3
	DefaultPopupRounding     = 3
	DefaultScrollbarRounding = 2
	DefaultGrabRounding      = 2
)
View Source
const (
	VUZoneGreen  = 0.6 // green zone boundary (0 to 60%)
	VUZoneYellow = 0.8 // yellow zone boundary (60% to 80%)
)

VU zone thresholds for color transitions.

View Source
const (
	LogTimeFormat = "[%8.3f]" // time formatting for log entries
)

Variables

View Source
var (
	LogTimeColor     = imgui.Vec4{X: 0.5, Y: 0.5, Z: 0.5, W: 1.0}
	LogDebugColor    = imgui.Vec4{X: 0.0, Y: 0.0, Z: 1.0, W: 1.0}
	LogWarningColor  = imgui.Vec4{X: 1.0, Y: 1.0, Z: 0.0, W: 1.0}
	LogErrorColor    = imgui.Vec4{X: 1.0, Y: 0.0, Z: 0.0, W: 1.0}
	LogFunctionColor = imgui.Vec4{X: 0.023, Y: 0.596, Z: 0.603, W: 1.0}
	LogFieldsColor   = imgui.Vec4{X: 0.203, Y: 0.886, Z: 0.886, W: 1.0}
)
View Source
var (
	BlueTheme   = NewHueColorScheme("Blue", 240, 50, 180)
	GreenTheme  = NewHueColorScheme("Green", 120, 40, 170)
	RedTheme    = NewHueColorScheme("Red", 0, 45, 175)
	PurpleTheme = NewHueColorScheme("Purple", 270, 35, 165)
	ModernDark  = &ModernTheme{}
)

predefined themes for convenience

View Source
var Fonts []*imgui.Font

Functions

func CaptureDashState

func CaptureDashState(dm *DashManager) map[string]DashConfig

CaptureDashState extracts configuration from a DashManager. returns a map with keys: "top", "left", "right", "bottom"

func CenterText added in v0.0.9

func CenterText(text string)

CenterText draws text centered horizontally and vertically in the available content region.

func CenterTextDisabled added in v0.0.9

func CenterTextDisabled(text string)

CenterTextDisabled draws disabled text centered horizontally and vertically in the available content region.

func Checkbox

func Checkbox(label string, checked bool) (bool, bool)

Checkbox returns new state and whether it changed

func ColorEdit3

func ColorEdit3(label string, r, g, b float32) (float32, float32, float32, bool)

ColorEdit3 edits RGB color. Returns new color and whether it changed.

func ColorEdit4

func ColorEdit4(label string, r, g, b, a float32) (float32, float32, float32, float32, bool)

ColorEdit4 edits RGBA color. Returns new color and whether it changed.

func Combo

func Combo(label string, current int, items []string) (int, bool)

Combo creates a dropdown. Returns selected index and whether it changed.

func ConfigPath

func ConfigPath(appName, filename string) (string, error)

ConfigPath returns a standard configuration file path in the user's home directory Example: ConfigPath("myapp", "config.json") -> "~/.myapp/config.json"

func DefaultStyle

func DefaultStyle()

DefaultStyle sets up the default ImGui style parameters this should be called after font setup but before theme application

func FaderF

func FaderF(label string, value, min, max float32, params FaderParams) (float32, bool)

FaderF draws a vertical fader working in an arbitrary float range. Internally converts to/from normalized 0-1 space. Example: -60.0 to +12.0 dB, 20.0 to 20000.0 Hz

func FaderI

func FaderI(label string, value int, min, max int, params FaderParams) (int, bool)

FaderI draws a vertical fader working in an integer range. Internally converts to/from normalized 0-1 space. Example: 0 to 32767 for hardware, 0 to 127 for MIDI

func FaderN

func FaderN(label string, value float32, params FaderParams) (float32, bool)

FaderN draws a vertical fader working in normalized 0.0-1.0 space. This is the foundation for FaderF and FaderI.

func FaderWithScaleF

func FaderWithScaleF(label string, value, min, max float32, params FaderParams, scale ScaleConfig) (float32, bool)

FaderWithScaleF draws a float-range fader with tick marks and labels.

func FaderWithScaleI

func FaderWithScaleI(label string, value int, min, max int, params FaderParams, scale ScaleConfig) (int, bool)

FaderWithScaleI draws an integer-range fader with tick marks and labels.

func FaderWithScaleN

func FaderWithScaleN(label string, value float32, params FaderParams, scale ScaleConfig) (float32, bool)

FaderWithScaleN draws a normalized fader (0.0-1.0) with tick marks and labels.

func Input

func Input(label string, value string) (string, bool)

Input is a simplified text input that returns the new value and whether it changed

func InputMultiline

func InputMultiline(label string, value string, width, height float32) (string, bool)

InputMultiline is a multiline text input

func LoadJSON

func LoadJSON(path string, config interface{}) error

LoadJSON loads a JSON file into a struct If the file doesn't exist, the config parameter is left unchanged (use defaults) Returns error only if the file exists but can't be read or parsed

func MatchExt added in v0.0.9

func MatchExt(ext string) func(*FileNode) bool

MatchExt returns a predicate that matches non-directory nodes whose file extension equals ext. the ext parameter should include the dot (e.g. ".go"). the comparison is case-insensitive.

func MatchName added in v0.0.9

func MatchName(pattern string) (func(*FileNode) bool, error)

MatchName returns a predicate that matches nodes whose Name matches the given regular expression pattern.

func MatchPath added in v0.0.9

func MatchPath(pattern string) (func(*FileNode) bool, error)

MatchPath returns a predicate that matches nodes whose full Path() matches the given regular expression pattern.

func PopFont

func PopFont()

PopFont convenience function - matches PushFont

func PushFont

func PushFont(fontIndex int)

PushFont convenience function for temporarily switching fonts. passes the font's configured size to ensure correct rendering.

func RestoreDashState

func RestoreDashState(dm *DashManager, config map[string]DashConfig)

RestoreDashState applies configuration to a DashManager. accepts a map with keys: "top", "left", "right", "bottom"

func SaveJSON

func SaveJSON(path string, config interface{}) error

SaveJSON saves any struct to a JSON file with proper formatting and error handling Creates parent directories if they don't exist

func SetTheme

func SetTheme(theme Theme)

SetTheme applies a theme to the current ImGui style

func SetupFonts

func SetupFonts()

SetupFonts initializes and loads all fonts this should be called during app initialization

func Slider

func Slider(label string, value float32, min, max float32) (float32, bool)

Slider returns new value and whether it changed

func SliderInt

func SliderInt(label string, value int, min, max int) (int, bool)

SliderInt returns new value and whether it changed

func Toggle

func Toggle(label string, value bool) (bool, bool)

Toggle creates a button that acts as a boolean toggle. when inactive (false), the button is dimmed. when active (true), it uses the checkmark color. returns (newValue, changed) following dfx conventions.

func Toolbar added in v0.0.9

func Toolbar(label string)

Toolbar draws a full-width header bar with the given label.

func ToolbarEx added in v0.0.9

func ToolbarEx(label string, extra func())

ToolbarEx draws a full-width header bar with the given label, and optionally calls extra to draw additional controls on the same line.

func ToolbarExLayout added in v0.1.1

func ToolbarExLayout(label string, extra func(*ToolbarLayout))

ToolbarExLayout draws a full-width header bar with the given label, and calls extra with a ToolbarLayout for precise vertical centering of mixed item types (combos, text, buttons).

func WheelSlider

func WheelSlider(label string, value, min, max, wheelSteps float32, format string, flags imgui.SliderFlags) (float32, bool)

WheelSlider creates a slider that responds to mouse wheel when hovered. wheelSteps controls sensitivity (larger value = smaller adjustments per wheel tick). modifiers: Ctrl = 10x faster, Alt = 10x slower. returns (newValue, changed) following dfx conventions.

Types

type Action

type Action struct {
	Id      string
	Label   string // display name for menu items (if empty, uses Id)
	Keys    string // e.g. "Ctrl+A", "Alt+Shift+F1"
	Handler func()
	// contains filtered or unexported fields
}

Action represents a keybinding and its associated function

func NewMenuAction

func NewMenuAction(label, keys string, handler func()) *Action

NewMenuAction creates an action suitable for both menus and keyboard shortcuts label: display name for menu items (e.g., "Save As...") keys: keyboard shortcut (e.g., "Ctrl+Shift+S") handler: function to execute

func (*Action) DrawMenuItem

func (a *Action) DrawMenuItem() bool

DrawMenuItem renders the action as a menu item returns true if the menu item was clicked

type ActionEvent added in v0.1.4

type ActionEvent struct {
	Action *Action      // the action that was invoked (Id, Label, Keys)
	Source ActionSource // how it was triggered
	Time   time.Time    // when it fired
}

ActionEvent describes a single action invocation, delivered to Config.OnAction. It is intended for usage telemetry (e.g. building a heatmap of which actions and shortcuts are exercised). The Action pointer is the live registered action and should be treated as read-only.

type ActionRegistry

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

ActionRegistry manages actions (unified for both App and Components)

func NewActionRegistry

func NewActionRegistry() *ActionRegistry

func (*ActionRegistry) MustRegister

func (r *ActionRegistry) MustRegister(id, key string, handler func())

func (*ActionRegistry) MustRegisterAction

func (r *ActionRegistry) MustRegisterAction(action *Action)

MustRegisterAction adds a pre-created action and panics on error

func (*ActionRegistry) Register

func (r *ActionRegistry) Register(id, keys string, handler func()) error

Register adds an action to the registry

func (*ActionRegistry) RegisterAction

func (r *ActionRegistry) RegisterAction(action *Action) error

RegisterAction adds a pre-created action (e.g., menu action) to the registry

type ActionSource added in v0.1.4

type ActionSource uint8

ActionSource identifies how an action was invoked.

const (
	ActionSourceKeyboard ActionSource = iota // triggered by a matching keyboard shortcut
	ActionSourceMenu                         // triggered by a menu click (reserved; not yet emitted)
)

type App

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

func New

func New(root Component, config Config) *App

func (*App) Actions

func (app *App) Actions() *ActionRegistry

Actions returns the action registry

func (*App) GetWindowPos

func (app *App) GetWindowPos() (int, int)

GetWindowPos returns the current window position

func (*App) GetWindowSize

func (app *App) GetWindowSize() (int, int)

GetWindowSize returns the current window size

func (*App) Run

func (app *App) Run() error

func (*App) SetRoot

func (app *App) SetRoot(root Component)

SetRoot changes the root component

func (*App) SetShouldClose

func (app *App) SetShouldClose(shouldClose bool)

SetShouldClose sets whether the window should close this can be used in OnClose callback to cancel closing

func (*App) SetWindowPos added in v0.1.5

func (app *App) SetWindowPos(x, y int)

SetWindowPos moves the window to the given position. the move is applied at the next frame boundary rather than immediately, since a geometry change made during a frame can re-enter the render loop; a later call before that boundary supersedes an earlier one. must be called on the UI goroutine (e.g. from an action handler or a Config callback), since the underlying GLFW window operation is main-thread only.

func (*App) SetWindowSize added in v0.1.5

func (app *App) SetWindowSize(w, h int)

SetWindowSize resizes the window to the given dimensions. applied at the next frame boundary; see SetWindowPos. must be called on the UI goroutine (e.g. from an action handler or a Config callback), since the underlying GLFW window operation is main-thread only.

func (*App) SetWindowTitle

func (app *App) SetWindowTitle(title string)

SetWindowTitle updates the window title

func (*App) Stop

func (app *App) Stop()

Stop signals the app to stop running

func (*App) Wait added in v0.0.3

func (app *App) Wait() error

Wait blocks until Run() completes and returns any error from Run()

type BaseCommand

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

BaseCommand provides default implementations for common command functionality. embed this struct to get sensible defaults for timestamp tracking.

func (*BaseCommand) SetStamp

func (bc *BaseCommand) SetStamp(t time.Time)

SetStamp allows manual setting of the timestamp.

func (*BaseCommand) Stamp

func (bc *BaseCommand) Stamp() time.Time

Stamp implements StampedCommand with automatic timestamp on first call.

type Bounds added in v0.1.0

type Bounds struct {
	X, Y float32 // top-left position
	W, H float32 // width and height
}

Bounds represents a rectangular region with explicit position and dimensions.

type ChildActionProvider added in v0.0.10

type ChildActionProvider interface {
	ChildActions() []Component
}

ChildActionProvider exposes child components for action traversal. components that compose other components can implement this to participate in hierarchical action lookup.

type Command

type Command interface {
	Description() string
	Run()
	Undo()
}

Command is the core interface for undoable operations. simple commands only need to implement these three methods.

type Component

type Component interface {
	// Draw renders the component. Unlike Surface.DrawF, we pass a State
	// that contains more than just size - it has everything needed to draw.
	Draw(state *State)

	// Actions returns the component's action registry.
	// this provides a consistent API for registering keyboard shortcuts.
	Actions() *ActionRegistry
}

Component is the core abstraction - a drawable, interactive UI element.

type Config

type Config struct {
	Title          string
	Width          int
	Height         int
	X              int               // window X position (0 = don't set)
	Y              int               // window Y position (0 = don't set)
	OnSetup        func(*App)        // called once after imgui context created
	OnShutdown     func(*App)        // called before shutdown
	OnTick         func(*App)        // called each frame before drawing
	OnClose        func(*App)        // called when window is about to close (can call SetShouldClose to cancel)
	OnSizeChange   func(int, int)    // called when window is resized
	OnAction       func(ActionEvent) // called whenever an action is invoked (usage telemetry)
	MenuBar        Component         // optional menu bar component
	Theme          Theme             // optional theme (defaults to DefaultTheme)
	DisableFonts   bool              // if true, skip font setup (use default ImGui fonts)
	DisableTheming bool              // if true, skip theme setup (use default ImGui theme)
	Icons          []image.Image     // optional window icons
}

type Container

type Container struct {
	Visible  bool
	Children []Component
	OnDraw   func(*State)
	// contains filtered or unexported fields
}

Container is a basic component implementation that others can embed. provides default implementations and common fields.

func (*Container) Actions

func (c *Container) Actions() *ActionRegistry

Actions implements Component

func (*Container) ChildActions added in v0.0.10

func (c *Container) ChildActions() []Component

ChildActions returns action-traversable children.

func (*Container) Draw

func (c *Container) Draw(state *State)

Draw implements Component with a simple delegation pattern

func (*Container) LocalActions added in v0.0.10

func (c *Container) LocalActions() *ActionRegistry

LocalActions returns this container's local action registry.

type Dash

type Dash struct {
	Container
	Name         string
	Component    Component
	TargetSize   int
	CurrentSize  int
	MinSize      int
	MaxSize      int
	Resizable    bool
	TransitionMs int
	Focused      bool
}

func NewDash

func NewDash(name string, component Component) *Dash

func (*Dash) Actions

func (d *Dash) Actions() *ActionRegistry

Actions implements Component by delegating to the child component

func (*Dash) ChildActions added in v0.0.10

func (d *Dash) ChildActions() []Component

ChildActions returns dash content for action traversal.

func (*Dash) Draw

func (d *Dash) Draw(state *State)

Draw implements Component interface - this is for when Dash is used as a standalone component

func (*Dash) DrawDash

func (d *Dash) DrawDash(state *State, bounds Bounds, attachment DashAttachment)

func (*Dash) LocalActions added in v0.0.10

func (d *Dash) LocalActions() *ActionRegistry

LocalActions returns dash-local actions without delegation.

type DashAttachment

type DashAttachment int
const (
	LeftDash DashAttachment = iota
	RightDash
	TopDash
	BottomDash
)

type DashConfig

type DashConfig struct {
	Visible bool
	Size    int
}

DashConfig holds configuration for a single dashboard panel

type DashManager

type DashManager struct {
	Container
	Precedence DashPrecedence
	TopMargin  float32
	Margin     float32
	Left       *Dash
	Top        *Dash
	Right      *Dash
	Bottom     *Dash
	Focused    *Dash
	Inner      Component
}

func NewDashManager

func NewDashManager() *DashManager

func (*DashManager) Actions

func (d *DashManager) Actions() *ActionRegistry

Actions implements Component by prioritizing focused dash actions

func (*DashManager) ChildActions added in v0.0.10

func (d *DashManager) ChildActions() []Component

ChildActions returns the active child component for action traversal.

func (*DashManager) Draw

func (d *DashManager) Draw(state *State)

func (*DashManager) LocalActions added in v0.0.10

func (d *DashManager) LocalActions() *ActionRegistry

LocalActions returns dash manager-local actions without delegation.

type DashPrecedence

type DashPrecedence int

type DragType

type DragType int
const (
	DragNone DragType = iota
	DragRow
	DragColumn
)

type FaderParams

type FaderParams struct {
	// Taper curve (affects UI feel, not values)
	// nil = linear taper
	Taper Taper

	// Range stops (in normalized 0-1 space, applied after taper)
	MinStop float32 // minimum value (default 0.0)
	MaxStop float32 // maximum value (default 1.0)

	// Reset value (in normalized 0-1 space)
	ResetValue float32 // default 0.0

	// Dimensions
	Width  float32 // default 30.0
	Height float32 // default 300.0

	// Display options
	Format      func(normalized float32) string // optional: custom tooltip format
	ShowTooltip bool                            // show value on hover (default true)

	// Mouse wheel sensitivity
	WheelSteps float32 // default 100.0 (finer = more steps)

	// Custom track/background color (nil = use theme default)
	TrackColor *imgui.Vec4
}

FaderParams configures extended fader behavior.

func DefaultFaderParams

func DefaultFaderParams() FaderParams

DefaultFaderParams returns sensible default parameters.

type FileNode

type FileNode struct {
	Name     string
	Dir      bool
	Parent   *FileNode
	Children []*FileNode
}

FileNode represents a node in the filesystem tree. nodes maintain parent-child relationships and can represent either directories or files.

func BuildTree

func BuildTree(path string, parent *FileNode) (*FileNode, error)

BuildTree recursively scans a filesystem path and builds a tree structure. the parent parameter should be nil for the root node.

func (*FileNode) Find added in v0.0.9

func (n *FileNode) Find(predicate func(*FileNode) bool) []*FileNode

Find returns all nodes in the tree rooted at this node for which the predicate returns true. traversal is depth-first pre-order.

func (*FileNode) Path

func (n *FileNode) Path() string

Path returns the path from the root to this node, relative to the root. for the root node itself, this returns an empty string.

type FileTree

type FileTree struct {
	Container
	Root          *FileNode
	Selected      *FileNode
	OnSelect      func(*FileNode)
	OnDoubleClick func(*FileNode)
	Filter        func(*FileNode) bool
}

FileTree is a component that displays a filesystem tree with selection and interaction support.

func NewFileTree

func NewFileTree(root *FileNode) *FileTree

NewFileTree creates a new filesystem tree component.

func (*FileTree) Draw

func (ft *FileTree) Draw(state *State)

Draw renders the filesystem tree.

func (*FileTree) SelectNode

func (ft *FileTree) SelectNode(node *FileNode)

SelectNode programmatically selects a node.

func (*FileTree) SetRoot

func (ft *FileTree) SetRoot(root *FileNode)

SetRoot updates the tree root and clears selection.

type FlexLayout

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

FlexLayout provides a resizable grid layout similar to the original MultiSurface

func NewFlexLayout

func NewFlexLayout(arrangement [][]string) *FlexLayout

NewFlexLayout creates a flexible layout with the given arrangement

func (*FlexLayout) Arrange

func (fl *FlexLayout) Arrange(components map[string]Component, state *State)

Arrange renders components in a flexible grid with resizable splitters

func (*FlexLayout) ColWidths added in v0.0.9

func (fl *FlexLayout) ColWidths() [][]int

ColWidths returns a copy of the current column widths for all rows.

func (*FlexLayout) HandleInput

func (fl *FlexLayout) HandleInput(state *State)

HandleInput processes mouse input for resize operations

func (*FlexLayout) RowHeights added in v0.0.9

func (fl *FlexLayout) RowHeights() []int

RowHeights returns a copy of the current row heights.

func (*FlexLayout) SetColWidths added in v0.0.9

func (fl *FlexLayout) SetColWidths(widths [][]int)

SetColWidths sets the column widths for all rows. the structure must match the arrangement.

func (*FlexLayout) SetRowHeights added in v0.0.9

func (fl *FlexLayout) SetRowHeights(heights []int)

SetRowHeights sets the row heights. the slice length must match the number of rows.

type FullCommand

type FullCommand interface {
	MergeableCommand
	StampedCommand
}

FullCommand combines both mergeable and stamped capabilities.

type Func

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

Func is a function component that can have keyboard actions. use this when you need a simple component with keyboard shortcuts.

func NewFunc

func NewFunc(draw func(*State)) *Func

func (*Func) Actions

func (f *Func) Actions() *ActionRegistry

func (*Func) Draw

func (f *Func) Draw(state *State)

func (*Func) LocalActions added in v0.0.10

func (f *Func) LocalActions() *ActionRegistry

LocalActions returns this component's local action registry.

type GridCell

type GridCell struct {
	Row, Col         int // grid position (0-based)
	RowSpan, ColSpan int // span (1,1 = single cell)
}

GridCell defines a component's position in the grid

type GridLayout

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

GridLayout provides fixed-position grid layout with no interactive resizing

func NewGridLayout

func NewGridLayout(gridWidth, gridHeight int) *GridLayout

NewGridLayout creates a fixed grid layout

func (*GridLayout) Arrange

func (gl *GridLayout) Arrange(components map[string]Component, state *State)

Arrange renders components at fixed grid positions

func (*GridLayout) HandleInput

func (gl *GridLayout) HandleInput(state *State)

HandleInput processes input (no interactive resizing for grid layout)

func (*GridLayout) SetCell

func (gl *GridLayout) SetCell(componentID string, row, col int, rowSpan, colSpan int)

SetCell positions a component in the grid

type HCollapse added in v0.0.5

type HCollapse struct {
	Container
	Title         string              // displayed in header when expanded (also used for imgui ID)
	Expanded      bool                // current state
	ExpandedWidth float32             // width when fully expanded
	CurrentWidth  float32             // animated width (internal)
	MinWidth      float32             // collapsed width (toggle button only)
	MaxWidth      float32             // maximum width when resizing (0 = no limit)
	Height        float32             // vertical height (0 = use available height from state.Size.Y)
	TransitionMs  int                 // animation duration
	Resizable     bool                // allow drag-to-resize when expanded
	Content       Component           // the component to show/hide
	OnToggle      func(expanded bool) // optional callback on state change
}

HCollapse is a horizontal collapsible component that contains content to its right. when collapsed, only the toggle button is visible. when expanded, shows a header bar with title and the content below.

func NewHCollapse added in v0.0.5

func NewHCollapse(content Component, cfg HCollapseConfig) *HCollapse

NewHCollapse creates a new horizontal collapsible component.

func (*HCollapse) Actions added in v0.0.5

func (h *HCollapse) Actions() *ActionRegistry

Actions implements Component by delegating to the content component.

func (*HCollapse) ChildActions added in v0.0.10

func (h *HCollapse) ChildActions() []Component

ChildActions returns the content component for action traversal.

func (*HCollapse) Draw added in v0.0.5

func (h *HCollapse) Draw(state *State)

Draw implements Component.

func (*HCollapse) LocalActions added in v0.0.10

func (h *HCollapse) LocalActions() *ActionRegistry

LocalActions returns panel-local actions without delegation.

func (*HCollapse) Toggle added in v0.0.5

func (h *HCollapse) Toggle()

Toggle toggles the expanded state.

type HCollapseConfig added in v0.0.5

type HCollapseConfig struct {
	Title         string
	ExpandedWidth float32
	MinWidth      float32 // defaults to HCollapseDefaultMinWidth
	MaxWidth      float32 // 0 = no limit
	Height        float32 // 0 = fill available height from parent
	TransitionMs  int     // defaults to HCollapseDefaultTransition
	Resizable     bool
	Expanded      bool // initial state
}

HCollapseConfig provides configuration options for NewHCollapse.

type HueColorScheme

type HueColorScheme struct {
	Hue            int
	TextSaturation float32
	TextValue      float32
	MainSaturation float32
	MainValue      float32
	AreaSaturation float32
	AreaValue      float32
	BgSaturation   float32
	BgValue        float32
	// contains filtered or unexported fields
}

HueColorScheme creates themes based on HSV color space this allows dynamic theme generation with consistent relationships

func NewHueColorScheme

func NewHueColorScheme(name string, hue int, sat, value float32) *HueColorScheme

NewHueColorScheme creates a new HSV-based color scheme. hue is expected in the 0-255 range (matching the ImGui style editor convention), not degrees. sat and value are also in 0-255 range.

func (*HueColorScheme) Apply

func (s *HueColorScheme) Apply()

func (*HueColorScheme) Name

func (s *HueColorScheme) Name() string

type KeyEvent

type KeyEvent struct {
	Key      imgui.Key
	Pressed  bool
	Modifier KeyModifier
}

KeyEvent represents keyboard input for component action checking

type KeyModifier

type KeyModifier uint8
const (
	ModNone  KeyModifier = 0
	ModCtrl  KeyModifier = 1 << 0
	ModShift KeyModifier = 1 << 1
	ModAlt   KeyModifier = 1 << 2
	ModSuper KeyModifier = 1 << 3
)

type Layout

type Layout interface {
	// Arrange renders the components according to the layout strategy
	Arrange(components map[string]Component, state *State)

	// HandleInput processes user input for layout-specific interactions (resizing, etc)
	HandleInput(state *State)
}

Layout defines how components are arranged and how user interaction is handled

type LocalActionProvider added in v0.0.10

type LocalActionProvider interface {
	LocalActions() *ActionRegistry
}

LocalActionProvider exposes a component's local action registry. this allows traversal code to use local actions directly even when Actions() is used for legacy delegation behavior.

type LogBuffer

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

LogBuffer is a thread-safe circular buffer for log messages.

func NewLogBuffer

func NewLogBuffer(maxSize int) *LogBuffer

NewLogBuffer creates a new log buffer with the specified maximum size.

func (*LogBuffer) Add

func (lb *LogBuffer) Add(msg LogMessage)

Add appends a log message to the buffer. if the buffer is full, the oldest message is overwritten.

func (*LogBuffer) AllText

func (lb *LogBuffer) AllText() string

AllText returns all log messages as a single formatted string.

func (*LogBuffer) Clear

func (lb *LogBuffer) Clear()

Clear removes all messages from the buffer.

func (*LogBuffer) Count

func (lb *LogBuffer) Count() int

Count returns the number of messages in the buffer.

func (*LogBuffer) Messages

func (lb *LogBuffer) Messages() []LogMessage

Messages returns a copy of all messages in the buffer in order.

func (*LogBuffer) Range

func (lb *LogBuffer) Range(f func(index int, msg *LogMessage) bool)

Range calls f for each log message in the buffer while holding the read lock. iteration stops early if f returns false. the message pointer is only valid during the callback.

type LogMessage

type LogMessage struct {
	Time    time.Time
	Level   slog.Level
	Func    string
	Fields  string
	Message string
}

LogMessage represents a single log entry.

type LogViewer

type LogViewer struct {
	Container
	Buffer              *LogBuffer
	AutoScroll          bool
	LevelFilter         slog.Level // minimum level to show
	ShowTime            bool
	ShowFunc            bool
	ShowFields          bool
	ShowDisabledMessage bool
	DisabledMessage     string
}

LogViewer is a component that displays log messages from a LogBuffer.

func NewLogViewer

func NewLogViewer(buffer *LogBuffer) *LogViewer

NewLogViewer creates a new log viewer component.

func (*LogViewer) Draw

func (lv *LogViewer) Draw(state *State)

Draw renders the log viewer.

type MergeableCommand

type MergeableCommand interface {
	Command
	Merge(other Command) bool
}

MergeableCommand extends Command with merge capability. implement this interface when commands can be merged together.

type ModernTheme

type ModernTheme struct{}

ModernTheme implements a predefined dark theme

func (*ModernTheme) Apply

func (m *ModernTheme) Apply()

func (*ModernTheme) Name

func (m *ModernTheme) Name() string

type MultiGrid

type MultiGrid struct {
	Container
	// contains filtered or unexported fields
}

MultiGrid is a flexible component container that separates component management from layout strategy. Components are managed as a named collection, and different layout strategies can be applied to arrange them.

func NewMultiGrid

func NewMultiGrid() *MultiGrid

NewMultiGrid creates a new MultiGrid with no components and no layout

func (*MultiGrid) AddComponent

func (mg *MultiGrid) AddComponent(id string, component Component)

AddComponent adds a named component to the collection

func (*MultiGrid) ComponentIDs

func (mg *MultiGrid) ComponentIDs() []string

ComponentIDs returns all component IDs in the collection

func (*MultiGrid) Draw

func (mg *MultiGrid) Draw(state *State)

Draw renders the MultiGrid using the current layout strategy

func (*MultiGrid) GetComponent

func (mg *MultiGrid) GetComponent(id string) (Component, bool)

GetComponent retrieves a component by ID

func (*MultiGrid) RemoveComponent

func (mg *MultiGrid) RemoveComponent(id string)

RemoveComponent removes a component from the collection

func (*MultiGrid) SetLayout

func (mg *MultiGrid) SetLayout(layout Layout)

SetLayout applies a layout strategy to the component collection

type ScaleConfig

type ScaleConfig struct {
	// Tick marks at normalized positions (0.0-1.0)
	// Example: []float32{0.0, 0.25, 0.5, 0.75, 1.0}
	Marks []float32

	// Labels at specific normalized positions
	// Example: map[float32]string{0.0: "-60dB", 0.5: "-12dB", 1.0: "0dB"}
	Labels map[float32]string

	// Visual appearance
	TickLength  float32 // Length of tick marks in pixels (default: 5.0)
	LabelOffset float32 // Distance from ticks to labels in pixels (default: 3.0)
	Position    string  // "left" or "right" (default: "left")
}

ScaleConfig defines the appearance and content of a fader scale.

func DefaultScaleConfig

func DefaultScaleConfig() ScaleConfig

DefaultScaleConfig returns sensible defaults for a fader scale.

type SizeDebugger

type SizeDebugger struct {
	Margin float32
	// contains filtered or unexported fields
}

func NewSizeDebugger

func NewSizeDebugger() *SizeDebugger

func (*SizeDebugger) Actions

func (sd *SizeDebugger) Actions() *ActionRegistry

func (*SizeDebugger) Draw

func (sd *SizeDebugger) Draw(state *State)

type SlogHandler

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

SlogHandler is a slog.Handler implementation that writes to a LogBuffer. this provides integration with the df/dl logging framework.

func NewSlogHandler

func NewSlogHandler(buffer *LogBuffer, opts *SlogHandlerOptions) *SlogHandler

NewSlogHandler creates a new slog handler that writes to a log buffer.

func (*SlogHandler) Enabled

func (h *SlogHandler) Enabled(_ context.Context, level slog.Level) bool

Enabled implements slog.Handler.

func (*SlogHandler) Handle

func (h *SlogHandler) Handle(_ context.Context, rec slog.Record) error

Handle implements slog.Handler.

func (*SlogHandler) WithAttrs

func (h *SlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs implements slog.Handler.

func (*SlogHandler) WithGroup

func (h *SlogHandler) WithGroup(_ string) slog.Handler

WithGroup implements slog.Handler.

type SlogHandlerOptions

type SlogHandlerOptions struct {
	TrimPrefix string
	MinLevel   slog.Level
	StartTime  time.Time
}

SlogHandlerOptions configures the slog handler integration.

type StampedCommand

type StampedCommand interface {
	Command
	Stamp() time.Time
}

StampedCommand extends Command with timestamp capability. implement this interface when commands need timestamp tracking.

type State

type State struct {
	// Size available for this component to draw in
	Size imgui.Vec2

	// Position where this component should draw (for absolute positioning)
	Position imgui.Vec2

	// IO provides access to imgui's input/output system
	IO *imgui.IO

	// App provides access to the application instance
	App *App

	// Parent component (nil for root)
	Parent Component
}

State provides everything a component needs to draw. this consolidates what Surface scattered across multiple parameters.

type Taper

type Taper interface {
	// Apply taper: normalized (0-1) -> tapered (0-1) for UI positioning
	Apply(normalized float32) float32

	// Invert taper: tapered (0-1) -> normalized (0-1) from UI position
	Invert(tapered float32) float32
}

Taper defines non-linear response curves for faders. Tapers affect the UI feel without changing the underlying value range.

func AudioTaper

func AudioTaper() Taper

AudioTaper returns a standard audio fader taper. Optimized for dB scales, approximates analog audio faders.

func CustomTaper

func CustomTaper(apply, invert func(float32) float32) Taper

CustomTaper creates a taper from user-provided functions. apply: normalized (0-1) -> tapered (0-1) invert: tapered (0-1) -> normalized (0-1)

func DecibelTaper

func DecibelTaper(dbRange float32) Taper

DecibelTaper returns a taper where UI position is linear with decibels. Use this when hardware values are proportional to linear amplitude and you want equal fader travel per dB across the entire range. dbRange is the total dB range (e.g., 72.0 for -60dB to +12dB).

func LinearTaper

func LinearTaper() Taper

LinearTaper returns a taper with no curve (1:1 mapping).

func LogTaper

func LogTaper(steepness float32) Taper

LogTaper returns a logarithmic taper with configurable steepness. steepness controls the curve intensity:

  • 1.0 = gentle curve
  • 3.0 = moderate curve (good default)
  • 10.0 = steep curve

type Theme

type Theme interface {
	Apply() // applies the theme to ImGui style
	Name() string
}

Theme interface allows for extensible theming system

type ToolbarLayout added in v0.1.1

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

ToolbarLayout provides vertical centering helpers for items inside a toolbar.

func (*ToolbarLayout) CenterFrame added in v0.1.1

func (t *ToolbarLayout) CenterFrame()

CenterFrame sets the cursor Y to vertically center a frame-height item (combo, button, input) within the toolbar.

func (*ToolbarLayout) CenterText added in v0.1.1

func (t *ToolbarLayout) CenterText()

CenterText sets the cursor Y to align standalone text with the text baseline of frame-height items (combos, buttons) in the toolbar.

type UndoSystem

type UndoSystem struct {
	// RunF is called whenever a command is executed, useful for tracking modifications
	RunF func(Command)
	// contains filtered or unexported fields
}

UndoSystem manages command history and undo/redo operations.

func NewUndoSystem

func NewUndoSystem() *UndoSystem

NewUndoSystem creates a new undo system.

func (*UndoSystem) CanRedo

func (us *UndoSystem) CanRedo() bool

CanRedo returns true if there are commands that can be redone.

func (*UndoSystem) CanUndo

func (us *UndoSystem) CanUndo() bool

CanUndo returns true if there are commands that can be undone.

func (*UndoSystem) Clear

func (us *UndoSystem) Clear()

Clear removes all commands from both undo and redo stacks.

func (*UndoSystem) HistoryComponent

func (us *UndoSystem) HistoryComponent() Component

HistoryComponent returns a component that displays the undo/redo history. this replaces the original Draw method with dfx's component architecture.

func (*UndoSystem) Redo

func (us *UndoSystem) Redo()

Redo re-executes the last undone command and moves it back to the undo stack.

func (*UndoSystem) Run

func (us *UndoSystem) Run(command Command)

Run executes a command and adds it to the undo stack. if the command is mergeable and can merge with the previous command, they will be merged instead of creating a new stack entry.

func (*UndoSystem) Undo

func (us *UndoSystem) Undo()

Undo reverses the last command and moves it to the redo stack.

type VUMeter added in v0.0.4

type VUMeter struct {
	Container

	// display mode
	Mode VUMeterMode // rendering style (default: VUMeterSolid)

	// fixed size configuration
	Height       float32 // total height in pixels (default: 200)
	ChannelWidth float32 // width of each channel meter (default: 12)

	// segment configuration
	SegmentCount int     // number of vertical segments (default: 20)
	SegmentGap   float32 // gap between segments in pixels (default: 2)
	ChannelGap   float32 // gap between channel meters (default: 4)

	// peak hold configuration
	PeakHoldMs    int     // peak hold duration in ms, 0 = disabled (default: 1000)
	PeakDecayRate float32 // peak decay rate per second (default: 0.5)

	// clip indicator configuration
	ClipHoldMs int // how long clip indicator stays lit in ms (default: 2000)

	// labels (optional, per-channel)
	Labels      []string // custom labels like "L", "R", "Kick", etc.
	LabelHeight float32  // height reserved for labels (default: 16)

	// colors (configurable, with sensible defaults)
	ColorLow  imgui.Vec4 // green zone (0-60%)
	ColorMid  imgui.Vec4 // yellow zone (60-80%)
	ColorHigh imgui.Vec4 // red zone (80-100%)
	ColorOff  imgui.Vec4 // inactive segment color
	ColorPeak imgui.Vec4 // peak indicator color
	ColorClip imgui.Vec4 // clip indicator color (bright red)
	// contains filtered or unexported fields
}

VUMeter is a vertical level meter component. supports any number of channels displayed side by side.

func NewVUMeter added in v0.0.4

func NewVUMeter(channelCount int) *VUMeter

NewVUMeter creates a new VU meter with the specified number of channels.

func (*VUMeter) ChannelCount added in v0.0.4

func (v *VUMeter) ChannelCount() int

ChannelCount returns the number of channels.

func (*VUMeter) Draw added in v0.0.4

func (v *VUMeter) Draw(state *State)

Draw renders the VU meter.

func (*VUMeter) SetChannelCount added in v0.0.4

func (v *VUMeter) SetChannelCount(count int)

SetChannelCount resizes the meter to the specified number of channels.

func (*VUMeter) SetLabel added in v0.0.4

func (v *VUMeter) SetLabel(channel int, label string)

SetLabel sets the label for a single channel.

func (*VUMeter) SetLabels added in v0.0.4

func (v *VUMeter) SetLabels(labels []string)

SetLabels sets labels for all channels at once.

func (*VUMeter) SetLevel added in v0.0.4

func (v *VUMeter) SetLevel(channel int, level float32)

SetLevel sets the level for a single channel (0.0 to 1.0).

func (*VUMeter) SetLevels added in v0.0.4

func (v *VUMeter) SetLevels(levels []float32)

SetLevels sets the levels for all channels at once.

func (*VUMeter) Width added in v0.0.4

func (v *VUMeter) Width() float32

Width returns the calculated total width of the meter.

type VUMeterMode added in v0.0.7

type VUMeterMode int

VUMeterMode defines the visual rendering style of the meter.

const (
	// VUMeterSolid renders a continuous fill with color zones (default).
	VUMeterSolid VUMeterMode = iota
	// VUMeterHighres renders 1px segments with 1px gaps for high resolution display.
	VUMeterHighres
	// VUMeterSegmented renders discrete segments with configurable count and gap.
	VUMeterSegmented
)

type VUWaterfall added in v0.0.7

type VUWaterfall struct {
	Container

	// dimensions
	Height       float32 // total height in pixels (default: 200)
	ChannelWidth float32 // width per channel (default: 40)
	ChannelGap   float32 // gap between channels (default: 4)
	RowHeight    float32 // height of each history row (default: 2)
	RowGap       float32 // gap between rows (default: 0)

	// history configuration
	HistorySize    int           // number of samples to keep (default: 100)
	SampleInterval time.Duration // minimum time between samples (default: 16ms)

	// display mode
	Highres bool // when true, alternates row opacity for scanline effect

	// colors (same as VUMeter for consistency)
	ColorLow  imgui.Vec4 // green zone (0-60%)
	ColorMid  imgui.Vec4 // yellow zone (60-80%)
	ColorHigh imgui.Vec4 // red zone (80-100%)
	ColorOff  imgui.Vec4 // background/inactive
	// contains filtered or unexported fields
}

VUWaterfall is a scrolling history display of VU levels over time. new data appears at the bottom and scrolls upward. each row shows a horizontal bar whose width represents the level at that time slice.

func NewVUWaterfall added in v0.0.7

func NewVUWaterfall(channelCount int) *VUWaterfall

NewVUWaterfall creates a new waterfall display with the specified number of channels.

func (*VUWaterfall) ChannelCount added in v0.0.7

func (w *VUWaterfall) ChannelCount() int

ChannelCount returns the number of channels.

func (*VUWaterfall) Clear added in v0.0.7

func (w *VUWaterfall) Clear()

Clear resets the history buffer.

func (*VUWaterfall) Draw added in v0.0.7

func (w *VUWaterfall) Draw(state *State)

Draw renders the VU waterfall.

func (*VUWaterfall) SetChannelCount added in v0.0.7

func (w *VUWaterfall) SetChannelCount(count int)

SetChannelCount resizes the waterfall to the specified number of channels. this clears the history buffer.

func (*VUWaterfall) SetHistorySize added in v0.0.7

func (w *VUWaterfall) SetHistorySize(size int)

SetHistorySize sets the number of samples to keep and reinitializes the buffer. this clears the history buffer.

func (*VUWaterfall) SetLevel added in v0.0.7

func (w *VUWaterfall) SetLevel(channel int, level float32)

SetLevel sets the level for a single channel and adds a new history entry. note: this creates a new row with only this channel set; prefer SetLevels for multi-channel. If SampleInterval is set, samples are throttled to maintain consistent scroll speed.

func (*VUWaterfall) SetLevels added in v0.0.7

func (w *VUWaterfall) SetLevels(levels []float32)

SetLevels sets levels for all channels at once and adds a new history entry. If SampleInterval is set, samples are throttled to maintain consistent scroll speed.

func (*VUWaterfall) Width added in v0.0.7

func (w *VUWaterfall) Width() float32

Width returns the calculated total width of the waterfall.

type WindowConfig

type WindowConfig struct {
	X         int
	Y         int
	Width     int
	Height    int
	Maximized bool // window maximized state (capture only, restore not yet implemented)
}

WindowConfig holds window position and size configuration

func CaptureWindowState

func CaptureWindowState(app *App) WindowConfig

CaptureWindowState gets current window state from App

func GetDefaultWindowConfig

func GetDefaultWindowConfig() WindowConfig

GetDefaultWindowConfig returns sensible default window configuration

type Workspace

type Workspace struct {
	Container

	// configuration
	ShowSelector  bool    // if true, shows a combo selector at the top
	SelectorLabel string  // label for the combo selector
	SelectorWidth float32 // width of selector (-1 for auto-width)

	// callbacks
	OnSwitch func(oldId, newId string) // called when workspace changes (passes IDs)
	// contains filtered or unexported fields
}

Workspace manages multiple named components and allows switching between them. provides a high-level component for building applications with multiple views/modes. separates stable IDs from display names for flexibility.

func NewWorkspace

func NewWorkspace() *Workspace

NewWorkspace creates a new workspace manager.

func (*Workspace) Actions added in v0.0.10

func (ws *Workspace) Actions() *ActionRegistry

Actions returns the action registry of the current workspace component, enabling action propagation through the workspace to the active component.

func (*Workspace) Add

func (ws *Workspace) Add(id, name string, component Component)

Add adds or replaces a workspace with the given id, display name, and component. if this is the first workspace added, it becomes current. if a workspace with the same id exists, it is replaced.

func (*Workspace) ChildActions added in v0.0.10

func (ws *Workspace) ChildActions() []Component

ChildActions returns the current active workspace component for action traversal.

func (*Workspace) Current

func (ws *Workspace) Current() string

Current returns the id of the current workspace. returns empty string if no workspaces exist.

func (*Workspace) CurrentComponent

func (ws *Workspace) CurrentComponent() Component

CurrentComponent returns the current workspace component. returns nil if no workspaces exist.

func (*Workspace) CurrentName

func (ws *Workspace) CurrentName() string

CurrentName returns the display name of the current workspace. returns empty string if no workspaces exist.

func (*Workspace) GetName

func (ws *Workspace) GetName(id string) string

GetName returns the display name for the given workspace Id. returns empty string if the workspace doesn't exist.

func (*Workspace) LocalActions added in v0.0.10

func (ws *Workspace) LocalActions() *ActionRegistry

LocalActions returns workspace-local actions without delegation.

func (*Workspace) Remove

func (ws *Workspace) Remove(id string)

Remove removes a workspace by id. if the current workspace is removed, switches to the first available workspace.

func (*Workspace) SetName

func (ws *Workspace) SetName(id, name string) bool

SetName changes the display name of a workspace without affecting its Id. returns true if the workspace was found and updated.

func (*Workspace) Switch

func (ws *Workspace) Switch(id string) bool

Switch changes to the workspace with the given id. returns true if the switch was successful.

func (*Workspace) SwitchByIndex

func (ws *Workspace) SwitchByIndex(index int) bool

SwitchByIndex changes to the workspace at the given index. returns true if the switch was successful.

func (*Workspace) WorkspaceIds

func (ws *Workspace) WorkspaceIds() []string

WorkspaceIds returns a copy of the workspace IDs in order.

func (*Workspace) WorkspaceNames

func (ws *Workspace) WorkspaceNames() []string

WorkspaceNames returns a copy of the workspace display names in order.

Jump to

Keyboard shortcuts

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