> For the complete documentation index, see [llms.txt](https://stylizededge-devs.gitbook.io/aqs-doc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://stylizededge-devs.gitbook.io/aqs-doc/building-menus/the-9-row-templates.md).

# The 9 Row Templates

Every setting renders through one of 9 small Widget Blueprints, grouped into 3 families by value type. Build these once per project — every menu you ever create with AQS, simple or complex, reuses the same 9.

Each template's parent class already handles label text, tooltip text, and the value itself. Your job is purely visual: build the control, and make one function call when it changes.

Each template receives, automatically, before OnRowInitialized fires:

* `LabelText` (FText)
* `TooltipText` (FText)
* `Descriptor` (full FAQSSettingDescriptor — has MinValue/MaxValue/FieldName)
* `CurrentFloatValue` (float) — already set to the real current value

Your job in every template: build the visual, read Descriptor.MinValue/MaxValue in OnRowInitialized to configure your control, bind the control's native change event to call **SetFloatValue(NewValue)** on self. That call is the entire logic requirement — it updates CurrentFloatValue and broadcasts OnFloatChanged, which the AutoPanel already listens to.

## The OnValueRefreshed Event — Required For Preset Switching

Every template also has a second event: `OnValueRefreshed`. This fires when a preset is applied via a preset button (`ApplyPresetAndSync`) or when Reset is pressed — it's how your slider/checkbox/dropdown visually moves to match the new value, without re-triggering an apply (that would create a feedback loop).

Implement it identically to `OnRowInitialized`'s value-setting step, just without the range/options setup:

```
Event OnValueRefreshed
  → Set [your control]'s value/state to Current[Float/Bool/Int]Value
```

Skip this and clicking a preset button will apply correctly under the hood, but your sliders won't visually move — the classic "I clicked Low but the menu still shows Ultra" symptom.

***

## WBP\_AQS\_Row\_Slider01

**Use case:** continuous drag bar — Resolution Scale, Gamma, Color Adjustment

**Create:** Right-click `Content/WidgetTemplates/` → User Interface → Widget Blueprint Parent class: search `AQSRowBase_Float` Name: `WBP_AQS_Row_Slider01`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]   name: TXT_Label       (bind Text → LabelText)
├── [Slider]       name: SLD_Value       (fill width)
└── [Text Block]   name: TXT_ValueReadout
```

**Event Graph — Event OnRowInitialized:**

```
Get Descriptor → Break FAQSSettingDescriptor
  MinValue → Set SLD_Value Min Value
  MaxValue → Set SLD_Value Max Value
Get CurrentFloatValue → Set SLD_Value Value
Get CurrentFloatValue → Format Text "{0}" → Set TXT_ValueReadout Text
```

**Event Graph — SLD\_Value On Value Changed:**

```
(New Value) → Set Float Value (self, New Value)
(New Value) → Format Text "{0}" → Set TXT_ValueReadout Text
```

***

## WBP\_AQS\_Row\_Stepper

**Use case:** +/- buttons with centered value — UI Scale, Arrows Trails

**Create:** same as above, name `WBP_AQS_Row_Stepper`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]   name: TXT_Label
├── [Button]       name: BTN_Decrease    child text: "-"
├── [Text Block]   name: TXT_ValueReadout  (fixed width, centered)
└── [Button]       name: BTN_Increase    child text: "+"
```

**Variables to add:** `StepSize` (Float, EditAnywhere, default 1.0)

**Event Graph — Event OnRowInitialized:**

```
Get CurrentFloatValue → Format Text "{0}" → Set TXT_ValueReadout Text
```

**Event Graph — BTN\_Decrease On Clicked:**

```
Get CurrentFloatValue → Subtract StepSize
  → Clamp (Get Descriptor.MinValue, Get Descriptor.MaxValue)
  → Set Float Value (self, Result)
  → Format Text "{0}" → Set TXT_ValueReadout Text
```

**Event Graph — BTN\_Increase On Clicked:**

```
Get CurrentFloatValue → Add StepSize
  → Clamp (Get Descriptor.MinValue, Get Descriptor.MaxValue)
  → Set Float Value (self, Result)
  → Format Text "{0}" → Set TXT_ValueReadout Text
```

***

## WBP\_AQS\_Row\_DirectInput

**Use case:** exact numeric entry via text box

**Create:** same as above, name `WBP_AQS_Row_DirectInput`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]        name: TXT_Label
└── [Editable Text Box] name: ETB_Value   (fixed width ~60px)
```

**Event Graph — Event OnRowInitialized:**

```
Get CurrentFloatValue → Format Text "{0}" → Set ETB_Value Text
```

**Event Graph — ETB\_Value On Text Committed:**

```
(Text) → To Float (Parse)
  → Clamp (Get Descriptor.MinValue, Get Descriptor.MaxValue)
  → Set Float Value (self, Result)
  → Format Text "{0}" → Set ETB_Value Text   (snap back to clamped value)
```

> Use On Text Committed, not On Text Changed — direct input should only apply when the player presses Enter or clicks away, not on every keystroke.

## Bool Family

Parent class for all 3: `UAQSRowBase_Bool`

Same contract as the Float family — LabelText/TooltipText/Descriptor are already populated when OnRowInitialized fires, and CurrentBoolValue already holds the real current value. Your only logic obligation is calling **SetBoolValue(NewValue)** when your control changes.

***

## WBP\_AQS\_Row\_Toggle

**Use case:** standard checkbox — VSync, Bloom, Nanite

**Create:** Right-click `Content/WidgetTemplates/` → User Interface → Widget Blueprint Parent class: search `AQSRowBase_Bool` Name: `WBP_AQS_Row_Toggle`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]  name: TXT_Label   (fill width, bind Text → LabelText)
└── [Check Box]   name: CHK_Value
```

**Event Graph — Event OnRowInitialized:**

```
Get CurrentBoolValue → Set CHK_Value Is Checked
```

**Event Graph — CHK\_Value On Check State Changed:**

```
(New State) → Set Bool Value (self, New State)
```

That's the entire template. This is the simplest of the 9 — good first one to build if you want to confirm the pattern before tackling the rest.

***

## WBP\_AQS\_Row\_BoolDropdown

**Use case:** On/Off as a dropdown — for projects that want every setting to look the same control-shape (some AAA games do this for consistency, even for bool fields)

**Create:** same as above, name `WBP_AQS_Row_BoolDropdown`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]      name: TXT_Label
└── [Combo Box String] name: CMB_Value
```

**Event Graph — Event OnRowInitialized:**

```
Add Option "On"  → CMB_Value
Add Option "Off" → CMB_Value
Get CurrentBoolValue → Branch
  True  → Set Selected Option "On"   (CMB_Value)
  False → Set Selected Option "Off"  (CMB_Value)
```

**Event Graph — CMB\_Value On Selection Changed:**

```
(Selected Item) → Equal (String) "On" → Set Bool Value (self, Result)
```

***

## WBP\_AQS\_Row\_BoolButtonList

**Use case:** two buttons, active one highlighted — the "ON / OFF" button pair style seen in some console-first UIs

**Create:** same as above, name `WBP_AQS_Row_BoolButtonList`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]  name: TXT_Label    (fill width)
├── [Button]      name: BTN_On       child text: "ON"
└── [Button]      name: BTN_Off      child text: "OFF"
```

**Variables to add:**

* `ActiveColor` (Linear Color, EditAnywhere, default teal)
* `InactiveColor` (Linear Color, EditAnywhere, default dark grey)

**Event Graph — Event OnRowInitialized:**

```
Call RefreshButtonStyles (custom function, see below)
```

**Custom Function: RefreshButtonStyles**

```
Get CurrentBoolValue → Branch
  True:
    BTN_On  → Set Background Color (ActiveColor)
    BTN_Off → Set Background Color (InactiveColor)
  False:
    BTN_On  → Set Background Color (InactiveColor)
    BTN_Off → Set Background Color (ActiveColor)
```

**Event Graph — BTN\_On On Clicked:**

```
Set Bool Value (self, true)
Call RefreshButtonStyles
```

**Event Graph — BTN\_Off On Clicked:**

```
Set Bool Value (self, false)
Call RefreshButtonStyles
```

## Int Family

Parent class for all 3: `UAQSRowBase_Int`

Used for discrete quality levels — typically 0=Low, 1=Medium, 2=High, 3=Epic. Descriptor.MinValue/MaxValue define the legal range (already pulled from ClampMin/ClampMax on the source field, or the 0-3 fallback if absent). Your only logic obligation is calling **SetIntValue(NewValue)** when your control changes.

***

## WBP\_AQS\_Row\_SliderStepped

**Use case:** discrete-step bar — Shadow Quality, Texture Quality, View Distance

**Create:** Right-click `Content/WidgetTemplates/` → User Interface → Widget Blueprint Parent class: search `AQSRowBase_Int` Name: `WBP_AQS_Row_SliderStepped`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]  name: TXT_Label
├── [Slider]      name: SLD_Value      (fill width, Step Size = 1)
└── [Text Block]  name: TXT_ValueReadout
```

> In the Slider's Details panel, set **Step Size = 1** so dragging always lands on a whole number — this is what makes a continuous Slider widget behave like a discrete stepped control without any extra logic.

**Event Graph — Event OnRowInitialized:**

```
Get Descriptor → Break FAQSSettingDescriptor
  MinValue → Set SLD_Value Min Value
  MaxValue → Set SLD_Value Max Value
Get CurrentIntValue → To Float → Set SLD_Value Value
Get CurrentIntValue → To String → Set TXT_ValueReadout Text
```

**Event Graph — SLD\_Value On Value Changed:**

```
(New Value) → Round → Set Int Value (self, Result)
(New Value) → Round → To String → Set TXT_ValueReadout Text
```

***

## WBP\_AQS\_Row\_IntDropdown

**Use case:** Low/Medium/High/Epic as readable text options — the Total War / AC Origins style ("Shadow Detail: Very High")

**Create:** same as above, name `WBP_AQS_Row_IntDropdown`

**Designer hierarchy:**

```
[Horizontal Box]
├── [Text Block]       name: TXT_Label
└── [Combo Box String] name: CMB_Value
```

**Variables to add:**

* `LevelLabels` (Array of String, EditAnywhere) Default: `["Low", "Medium", "High", "Epic"]` This array maps index → label. If a field's range is wider than 4 levels, extend this array in the Blueprint's Class Defaults to match.

**Event Graph — Event OnRowInitialized:**

```
For Each Loop (LevelLabels)
  Add Option (Array Element) → CMB_Value
Get CurrentIntValue → Get (LevelLabels, Index) → Set Selected Option (CMB_Value)
```

**Event Graph — CMB\_Value On Selection Changed:**

```
(Selected Item) → Find Index (LevelLabels, Selected Item)
  → Set Int Value (self, Result)
```

***

## WBP\_AQS\_Row\_IntButtonList

**Use case:** row of quality-level buttons, active one highlighted — the COD Mobile style ("LOW | MEDIUM | HIGH | ULTRA" as 4 buttons)

**Create:** same as above, name `WBP_AQS_Row_IntButtonList`

**Designer hierarchy:**

```
[Vertical Box]
├── [Text Block]      name: TXT_Label
└── [Horizontal Box]  name: HB_Buttons    (empty — filled at runtime)
```

**Variables to add:**

* `LevelLabels` (Array of String, EditAnywhere, default `["Low","Medium","High","Epic"]`)
* `ActiveColor` (Linear Color, EditAnywhere, default teal)
* `InactiveColor` (Linear Color, EditAnywhere, default dark grey)
* `SpawnedButtons` (Array of Button, private — created at runtime)

**Event Graph — Event OnRowInitialized:**

```
For Each Loop (LevelLabels), Array Index
  Create Widget [Button] → store as LocalButton
  Set LocalButton child text → Array Element
  Add Child to Horizontal Box (HB_Buttons, LocalButton)
  Add to SpawnedButtons array
  Bind LocalButton On Clicked → custom event OnLevelButtonClicked, passing Array Index
Call RefreshButtonStyles
```

> Binding On Clicked with a captured loop index has the same "which button fired" problem the old per-demo widgets hit. Reuse the same fix — either give each spawned button a custom index-carrying Button subclass (see AQSDemo\_PresetButton.h from the earlier demos for the exact pattern), or store index alongside the button reference in a small local struct array and look it up after the fact. Either approach works; pick whichever you're already comfortable with.

**Custom Function: RefreshButtonStyles**

```
For Each Loop (SpawnedButtons), Array Index
  Array Index == CurrentIntValue → Branch
    True:  Set Background Color (ActiveColor)
    False: Set Background Color (InactiveColor)
```

**Custom Event: OnLevelButtonClicked (Index)**

```
Set Int Value (self, Index)
Call RefreshButtonStyles
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://stylizededge-devs.gitbook.io/aqs-doc/building-menus/the-9-row-templates.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
