text input

the text-entry blob wraps the engine text field. it is the one foundation widget that holds text the user types, so it comes in two flavors: uncontrolled, where the entry remembers its own text, and controlled, where your code owns the text and the entry mirrors it.

write it as Goo.TextEntry. the engine also has a Sandbox.UI.TextEntry, so the namespace keeps the two apart.

uncontrolled: the entry owns its text

the simplest entry seeds itself once with InitialText and then keeps its own text as the user types. add a Placeholder for the empty-state hint.

new Goo.TextEntry { InitialText = "type me", Placeholder = "search" }

you read the result through OnSubmit, which fires when the user presses enter, or OnChange, which fires on every keystroke. both hand you the current string.

controlled: your code owns the text

bind Value to a field and update that field from OnChange. your field is then always the latest text, ready to read anywhere else in Build.

string _value = "";

protected override Container Build() => new Container
{
    Children =
    {
        new Goo.TextEntry
        {
            Value = _value,
            Placeholder = "controlled",
            OnChange = v => _value = v,
            OnSubmit = v => Log.Info($"submitted: {v}"),
        },
    },
};

set Value or InitialText, never both. Value means controlled, InitialText means uncontrolled. setting both is ambiguous and the framework flags it. the field-backed pattern here is the same state idea you used for the counter.

numeric entries

set Numeric to accept numbers only. MinValue and MaxValue clamp the range, NumberFormat controls how the value displays, and MaxLength caps how many characters fit.

new Goo.TextEntry
{
    InitialText  = "42.00",
    Numeric      = true,
    MinValue     = 0,
    MaxValue     = 100,
    NumberFormat = "0.00",
    MaxLength    = 8,
}

disabled and multiline

Disabled makes an entry that cannot be focused or edited. pair it with a lower Opacity so it reads as inert.

new Goo.TextEntry { InitialText = "can't focus me", Disabled = true } with { Opacity = 0.5f }

Multiline lets the field hold more than one line. enter inserts a newline instead of submitting, so OnSubmit does not fire on a multiline entry.

new Goo.TextEntry { InitialText = "line one\nline two", Multiline = true }

focus, blur, and cancel

three more callbacks track the field's focus life. OnFocus fires when the entry gains focus, OnBlur fires when it loses focus and hands you the final text, and OnCancel fires when the user presses escape. use them for commit-on-click-out, focus-driven styling, or escape-to-abort.

new Goo.TextEntry
{
    InitialText = "edit me",
    OnFocus  = ()    => Log.Info("focused"),
    OnBlur   = final => Log.Info($"left with: {final}"),
    OnCancel = ()    => Log.Info("escaped"),
}

OnBlur fires on every focus loss, including the ones caused by submitting (enter) and cancelling (escape), which both blur the field before they fire their own callback. so if you wire OnSubmit and OnBlur together, both run on enter, with OnBlur first. branch on the more specific callback when you need to tell a plain click-out apart from a submit or a cancel.

styling

TextEntry carries the full container style surface, the richest facade of any blob: font, padding, border, background, radius, hover and focus colors, the lot. style it exactly as you would a container.

new Goo.TextEntry
{
    InitialText     = "type me",
    FontSize        = 18,
    Padding         = 12,
    BorderRadius    = 6,
    BorderWidth     = 1,
    BorderColor     = new Color(0.3f, 0.3f, 0.35f),
    BackgroundColor = new Color(0.18f, 0.18f, 0.22f),
    FontColor       = new Color(0.95f, 0.95f, 0.97f),
    Width           = 320,
}

content reference

property type notes
Value string? controlled text, bound to your field
InitialText string? uncontrolled seed text, applied once
Placeholder string? hint shown while empty
MaxLength int? cap on typed length
Disabled bool non-focusable, non-editable
Numeric bool accept numbers only
MinValue float? numeric clamp floor (with Numeric)
MaxValue float? numeric clamp ceiling (with Numeric)
NumberFormat string? numeric display format, e.g. "0.00"
Multiline bool allow newlines, suppresses OnSubmit on enter
Key string? stable identity across rebuilds

events and key

TextEntry adds text and focus callbacks on top of the shared mouse events. for the full property surface see textentry reference.

property type notes
OnChange Action? fires per keystroke with current text
OnSubmit Action? fires on enter, single-line only
OnFocus Action? fires when the entry gains focus
OnBlur Action? fires on focus loss with final text, also fires before submit and cancel
OnCancel Action? fires when the user presses escape
OnClick Action? shared mouse events, see events
OnMouseEnter Action?
OnMouseLeave Action?
OnMouseDown Action?
OnMouseUp Action?
OnMouseMove Action?

see also