gum-forms-controls
Reference guide for Forms controls — classes inheriting from FrameworkElement. Load this when working on Button, CheckBox, ListBox, ComboBox, TextBox, ScrollViewer, or any class in Gum.Forms.Controls (or FlatRedBall.Forms.Controls). Also load when working on FrameworkElement itself, the Visual/InteractiveGue relationship, state machines, DefaultVisuals, or ReactToVisualChanged.
Best use case
gum-forms-controls is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Reference guide for Forms controls — classes inheriting from FrameworkElement. Load this when working on Button, CheckBox, ListBox, ComboBox, TextBox, ScrollViewer, or any class in Gum.Forms.Controls (or FlatRedBall.Forms.Controls). Also load when working on FrameworkElement itself, the Visual/InteractiveGue relationship, state machines, DefaultVisuals, or ReactToVisualChanged.
Teams using gum-forms-controls should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/gum-forms-controls/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How gum-forms-controls Compares
| Feature / Agent | gum-forms-controls | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Reference guide for Forms controls — classes inheriting from FrameworkElement. Load this when working on Button, CheckBox, ListBox, ComboBox, TextBox, ScrollViewer, or any class in Gum.Forms.Controls (or FlatRedBall.Forms.Controls). Also load when working on FrameworkElement itself, the Visual/InteractiveGue relationship, state machines, DefaultVisuals, or ReactToVisualChanged.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Gum Forms Controls Reference
## What They Are
Forms controls are classes inheriting from `FrameworkElement` (`MonoGameGum/Forms/Controls/FrameworkElement.cs`). Their names and API intentionally mirror WPF (Button, CheckBox, ListBox, TextBox, etc.), but the visual and layout engine is Gum (`GraphicalUiElement`/`InteractiveGue`), not WPF.
**WPF conventions that do NOT apply here:**
- No `Margin`, `Padding`, `HorizontalAlignment`, `VerticalAlignment` (in the WPF sense) on `FrameworkElement`
- No direct `Background`, `Foreground`, or `BorderBrush` properties — visual styling is done through states
- No WPF grid/dock/wrap panel auto-layout — sizing and positioning follow Gum's unit system (`X`, `Y`, `XUnits`, `YUnits`, `Width`, `Height`, `WidthUnits`, `HeightUnits`)
## The Visual / FrameworkElement Split
Every `FrameworkElement` has a `Visual` property of type `InteractiveGue` (which is `GraphicalUiElement`). The Visual owns all layout and rendering; the `FrameworkElement` is a logical/behavioral layer on top.
- `Visual.FormsControlAsObject` — back-link from the `InteractiveGue` to its `FrameworkElement`
- `FrameworkElement.X/Y/Width/Height/etc.` — all forward to `Visual`; there is no separate logical sizing
- `ActualWidth` / `ActualHeight` — computed pixel values, read from `Visual.GetAbsoluteWidth/Height()`
## Two Construction Paths
**Forms-first** (`new Button()`): The default constructor calls `GetGraphicalUiElementFor(this)` which looks up `DefaultFormsTemplates` (or the older `DefaultFormsComponents`) to find the registered visual type, instantiates it with `createFormsInternally: false`, and assigns it as `Visual`. This path requires the type to be registered before the constructor runs.
**Visual-first** (`new ButtonVisual()`): The `DefaultVisuals` classes (in `MonoGameGum/Forms/DefaultVisuals/`) are `InteractiveGue` subclasses that construct all child runtimes, set up the state machine, and then call `FormsControlAsObject = new Button(this)` in their constructor. The two-bool constructor `(bool fullInstantiation, bool tryCreateFormsObject)` controls this — `tryCreateFormsObject: false` skips creating the Forms object, used when the visual is being instantiated by a Forms-first control.
## ReactToVisualChanged
When `Visual` is assigned, `ReactToVisualChanged()` fires. Subclasses override this to grab references to named children:
```csharp
protected override void ReactToVisualChanged()
{
textComponent = Visual.GetGraphicalUiElementByName("TextInstance");
coreTextObject = textComponent?.RenderableComponent as IText;
base.ReactToVisualChanged();
}
```
Named child lookup is the standard pattern — controls depend on specific child names being present in the visual. Properties like `Button.Text` silently no-op (or throw in `FULL_DIAGNOSTICS` mode) if the expected child is absent.
## Visual States (Not WPF Styles)
Appearance changes are driven by a `StateSaveCategory` on the Visual. `UpdateState()` is called whenever interaction state changes and applies the correct state by name:
```csharp
Visual.SetProperty("ButtonCategoryState", stateName);
```
Common state names are defined as constants on `FrameworkElement` (`EnabledStateName`, `DisabledStateName`, `HighlightedStateName`, `PushedStateName`, `FocusedStateName`, etc.). The `GetState(string stateName)` method searches all categories on the Visual.
To customize appearance, either replace the Visual with a custom one that has different state variable values, or get and modify states directly via `control.GetState(...)`. For a deep dive into how variable values flow from save data through runtime application and how `RefreshStyles` pushes style changes to live Forms controls, see the **gum-variable-deep-dive** skill.
## Class Hierarchy
```
FrameworkElement
├── ButtonBase (IInputReceiver)
│ ├── Button
│ ├── ToggleButton
│ ├── RadioButton
│ └── CheckBox
├── ItemsControl (→ ScrollViewer)
│ ├── ListBox
│ └── ComboBox
├── ScrollViewer
│ └── (also base of ItemsControl)
├── TextBoxBase (IInputReceiver)
│ ├── TextBox
│ └── PasswordBox
├── Panel
│ └── StackPanel
├── Label
├── Slider (RangeBase)
├── ScrollBar (RangeBase)
├── ListBoxItem
├── MenuItem
├── UserControl
└── Splitter
```
## Key Files
| Path | Purpose |
|------|---------|
| `MonoGameGum/Forms/Controls/FrameworkElement.cs` | Base class: Visual link, layout forwarding, state constants, construction |
| `MonoGameGum/Forms/Controls/Primitives/ButtonBase.cs` | Push/click/hold input handling |
| `MonoGameGum/Forms/Controls/ItemsControl.cs` | Items collection, InnerPanel management, ListBoxItemsInternal sync |
| `MonoGameGum/Forms/DefaultVisuals/` | Pre-built `InteractiveGue` subclasses that create state machines and Forms objects |
| `MonoGameGum/Forms/Controls/FrameworkElementExt.cs` | Extension helpers (AddToRoot, etc.) |
## Non-Obvious Behaviors
**Layout is Gum layout, not WPF layout.** A `Button` with default `Width = 128` and `WidthUnits = Absolute` is 128 pixels wide regardless of content — there is no WPF-style `Auto` sizing unless `WidthUnits = RelativeToChildren`. Do not expect WPF layout rules.
**`IsVisible` vs `Visibility`**: There is no `Visibility` enum. `IsVisible` maps directly to `Visual.Visible` (bool).
**No color shortcut on the control.** To change a button's color, either modify the state's variables on the Visual, or access the child runtime directly (`(listBox.Visual as ButtonVisual)?.Background.Color = ...`). There is no `Background` property on `Button`.
**`ReactToVisualChanged` can fire before child references exist.** If `Visual` is reassigned at runtime, all `GetGraphicalUiElementByName` lookups re-run. Code that caches Visual children must refresh inside `ReactToVisualChanged`, not in the constructor.
**`ParentFrameworkElement` walks the Visual parent chain**, skipping non-Forms Gue nodes, until it finds a Gue whose `FormsControlAsObject` is a `FrameworkElement`. It does not just return the direct parent.Related Skills
gum-forms-itemscontrol
Reference guide for ItemsControl and ListBox — the Items/ListBoxItems relationship, templates, InnerPanel sync, and gotchas. Load this when working on ItemsControl, ListBox, ListBoxItem, VisualTemplate, FrameworkElementTemplate, Items collection behavior, ListBoxItems desync, or adding/removing items from a list box.
gum-forms-default-visuals
Reference guide for Forms DefaultVisuals — the code-only visual classes that back Forms controls. Load when working on ButtonVisual, any *Visual class in DefaultVisuals/, Styling, DefaultFormsTemplates registration, or building custom code-only Forms visuals.
gum-forms-behaviors
Covers Gum's behaviors system and the design-time → runtime Forms wrapping lifecycle. Load this when working on BehaviorSave, ElementBehaviorReference, StandardFormsBehaviorNames, FormsUtilities.RegisterFromFileFormRuntimeDefaults, DefaultFromFileXxxRuntime classes, or when investigating why Forms properties cannot be set at design time in the Gum tool.
validate-code-changes
Validate all code changes on the current branch. Spawns QA and refactoring agents in parallel to review for correctness, edge cases, code quality, and pattern adherence. Use when ready to review branch changes before merging.
skills-writer
Creates and updates skill files (.claude/skills/*/SKILL.md) by reading source code and condensing knowledge into concise reference guides. Use when asked to create a new skill, update an existing skill, or document a subsystem for Claude Code agent context.
gum-variable-deep-dive
Deep dive into the full variable lifecycle — from VariableSave on ElementSave through runtime application on GraphicalUiElement and Forms controls. Load this when working on styling, theming, RefreshStyles, or when you need to understand how variable values flow from save data to live visuals.
gum-unit-tests
Reference guide for writing unit tests in the Gum repository. Load this when writing or modifying tests in Gum.ProjectServices.Tests, Gum.Cli.Tests, or any other Gum test project.
gum-tool-viewmodels
Reference guide for Gum tool ViewModel conventions. Load this when working on ViewModels, XAML views, data binding, DependsOn, or visibility properties in the Gum tool.
gum-tool-variable-references
Reference guide for Gum's variable reference system — Excel-like cross-instance/cross-element variable binding using Roslyn-parsed assignment syntax. Load this when working on VariableReferenceLogic, EvaluatedSyntax, ApplyVariableReferences, VariableChangedThroughReference, or the VariableReferences VariableListSave.
gum-tool-variable-grid
Reference guide for Gum's Variables tab and DataUiGrid system. Load this when working on the Variables tab, DataUiGrid control, MemberCategory, InstanceMember, category population, property grid refresh, or category expansion state persistence.
gum-tool-undo
Reference guide for Gum's undo/redo system. Load this when working on undo/redo behavior, the History tab, UndoManager, UndoPlugin, UndoSnapshot, or stale reference issues after undo.
gum-tool-selection
Reference guide for Gum's editor selection system. Load this when working on click/drag selection, the rectangle/marquee selector, input handlers (move, resize, rotate, polygon points), the IsActive flag, locked instance behavior, SelectionManager coordination, or the selection event cascade (plugin events, forced default state, tree view sync).