Select
Extends: UiWidget
A focusable option picker. Its interaction style is controlled by Select.style (see BGE.UI.SelectStyle): inline (the default) cycles through m.options in place with Left/Right, matching Slider's existing interaction pattern; popup expands a full option list on OK; horizontal shows every option side-by-side in one row, with Left/Right moving directly between them.
Properties
options(dynamic)selectedIndex(integer)drawableText(BGE.DrawableText)onChanged(dynamic) — Called after selectedIndex changes - function(select as Select) as voidlastChangedValue(dynamic) — Test accessor: last value an onChanged callback stashed here. Not part ' of the public API - exists purely because a plain local var captured by ' an anonymous sub assigned to onChanged doesn't reliably update under ' brs-cli, so tests need a field on the widget itself to observe.style(BGE.UI.SelectStyle) — Which interaction style this Select uses - see BGE.UI.SelectStyle. ' Defaults to inline (Left/Right cycling), matching this widget's original ' (and only) behavior - popup is opt-in, not a breaking change.expanded(boolean) — popup style only: is the option list currently expanded?highlightedIndex(integer) — popup style only: index within m.options currently highlighted while expanded.lastDrawnRowCount(integer) — Test accessor: how many option rows drawOverlay() drew last call. Not ' part of the public API - exists purely so tests can distinguish ' drawOverlay() actually rendering the popup list from its no-op paths.optionTextDrawables(object) — popup and horizontal styles only: one BGE.DrawableText per unique ' option string, keyed by that string - reused across frames/rows instead ' of drawOverlay()/drawHorizontal() cycling every option's text through ' the single m.drawableText field (also used by draw() for the inline/ ' popup current value), which would defeat DrawableText.getTextImage()'s ' own cache (keyed on the instance's last text/color) every single frame ' the popup stays open or a horizontal Select is drawn. See getOptionText(). ' m.options is a plain public field with no change hook, so entries for ' strings no longer present in m.options are pruned each use (see ' pruneOptionTextCache()) rather than left to accumulate forever across ' an options reassignment (e.g. search/filter results changing over time).repeatThrottle(BGE.UI.RepeatThrottle) — Throttles repeat-while-held Left/Right to one step per ' WIDGET_REPEAT_DELAY_MS - see handleInput().
Constructor
new Select(game: BGE.Game): SelectParameters
game(BGE.Game)
Instance Methods
getValue(): dynamic
Gets the currently selected option's value.
Returns
dynamic
next(): void
Advances to the next option, wrapping to the first after the last.
Returns
void
previous(): void
Goes back to the previous option, wrapping to the last after the first.
Returns
void
handleInput(input: BGE.GameInput): boolean
Left/Right (while focused) cycle the selection and consume the event. Called only while focused - see UiWidget.handleInput()/ BGE.UI.FocusManager.update(). A held Left/Right event is always consumed too - Game.bs synthesizes one alongside every press, and it has to be consumed rather than leaking through to GameEntity.onInput() - but it only CYCLES once WIDGET_REPEAT_DELAY_MS has passed since the last step, so a single tap's press+held pair steps exactly once while a sustained hold still repeats.
Parameters
input(BGE.GameInput)
Returns
boolean
onClick(): void
popup style only: toggles expand/commit on OK click. FocusManager.update() intercepts OK press itself and calls onClick() directly rather than forwarding it to handleInput() - so the popup commits on this SECOND onClick() call (while already m.expanded), not through handleInput(). First click (not expanded): expands, seeding highlightedIndex from selectedIndex. Second click (expanded): commits highlightedIndex to selectedIndex, fires onChanged, and collapses.
Returns
void
onBlur(): void
Collapses the popup list whenever this Select loses focus. Only the currently-focused widget's drawOverlay() runs, so an expanded-but- unfocused Select would be invisible while still holding a stale highlight that the next OK press would immediately commit. Covers every blur path (list navigation, pointer hover-out, analog cursor) in one place.
Returns
void
draw(parent?: UiWidget): void
Parameters
parent(UiWidget, optional, default: "invalid")
Returns
void
drawOverlay(canvas: BGE.Canvas, theme: BGE.UI.Theme): void
Draws the popup option list below this Select's own bounds, one row per option, with the highlighted row visually distinct. No-op unless m.style = popup and m.expanded - fires every frame while expanded via UiWidget.drawOverlay() (called for the currently-focused widget only).
Non-goal: every option draws unclipped/unscrolled, so a list long enough to overflow the canvas bottom is a known limitation, not a bug - no scrolling/clipping here.
Parameters
canvas(BGE.Canvas)theme(BGE.UI.Theme)
Returns
void
getOptionTextDrawableCount(): integer
Test accessor: how many distinct option strings have a cached DrawableText so far. Not part of the public API - exists purely so tests can confirm optionTextDrawables stays bounded by the option list rather than growing every drawOverlay() call.
Returns
integer