Text Components
ml::Text for display labels, TextInput for single-line editable fields, and TextArea for multi-line editing — all built on the RichTextBuffer engine with selection, scrolling, and theme integration.
Text Component Hierarchy
| Class | Purpose | Key feature |
|---|---|---|
ml::Text | Display label — non-editable | Word wrap, full framework trait set (click, hover, drag, flags) |
ml::TextInput | Single-line rich text input | Horizontal scrolling, selection, placeholder, readonly/error states |
ml::TextArea | Multi-line rich text input | Vertical scrolling via embedded ScrollPane, Enter = newline, Ctrl+Enter = submit |
TextInput and TextArea both follow the Settings/Theme/Themeable pattern. ml::Text is a Graphic<sf::Text> — it extends the SFML text API directly.
ml::Text
ml::Text wraps sf::Text inside Graphic<>, giving it click, hover, update subscriptions, flags, draggability, and setPosition()/getGlobalBounds(). It adds two layout helpers on top of the SFML API: setWordWrap() and setMaxWidth().
ml::Text label;
label.setString("Hello, Malena!");
label.setCharacterSize(24);
label.setFillColor(sf::Color::White);
label.setPosition({50.f, 100.f});
addComponent(label);
ml::Text paragraph;
paragraph.setMaxWidth(300.f); // break lines at 300 px
paragraph.setWordWrap(true); // enable — call setString AFTER
paragraph.setString("A longer string that will wrap at 300 pixels "
"according to word boundaries.");
paragraph.setPosition({50.f, 150.f});
addComponent(paragraph);
The word-wrap layout is recomputed each time setString() is called while wordWrap is true. Call setMaxWidth() before enabling word wrap so the layout uses the correct width from the first setString() call.
TextWidth<M> is the manifest-attached variant (note the name — it is expected to be renamed to TextWith<M> in a future release):
class StatusLabel : public ml::TextWidth<UIManifest> {
public:
void setError(bool err) {
enableFlag(UIManifest::Flag::Error);
setFillColor(err ? sf::Color(220, 60, 60) : sf::Color::White);
}
};
TextInput
A single-line editable field built on RichTextBuffer and RichTextRenderer. Content that overflows the visible width scrolls horizontally. Supports text selection (click-drag, double-click to select word, Ctrl+A), placeholder text, read-only mode, and an error visual state. Inherits TextInputSettings and TextInputTheme with automatic theme application via Themeable.
ml::TextInput nameField;
nameField.setSize({300.f, 36.f});
nameField.setPosition({100.f, 150.f});
nameField.setPlaceholder("Enter your name...");
nameField.onChange([](const std::string& value) {
validateName(value);
});
nameField.onSubmit([](const std::string& value) {
submitForm(value);
});
addComponent(nameField);
nameField.setValue("Alice");
std::string v = nameField.getValue();
nameField.clear();
nameField.setEnabled(false); // no keyboard or click events
nameField.setReadOnly(true); // text visible but not editable
nameField.setError(true); // applies error visual state
bool dis = nameField.isEnabled();
bool ro = nameField.isReadOnly();
bool err = nameField.hasError();
nameField.selectAll();
nameField.setSelection(0, 5); // select characters 0–4
std::string sel = nameField.getSelectedText();
// Style the selected run
nameField.setSelectionColor(sf::Color(100, 120, 200));
nameField.setSelectionBold(true);
nameField.setFont(myFont); // lvalue only — rvalue overload deleted
nameField.setCharacterSize(16);
unsigned sz = nameField.getCharacterSize();
sf::Vector2f size = nameField.getSize();
| Flag | State | Meaning |
|---|---|---|
Flag::DISABLED | State::DISABLED | No events, visually dimmed |
Flag::READONLY | — | Visible but not editable |
| — | State::FOCUSED | Has keyboard focus |
| — | State::ERROR | Validation error highlighted |
| — | State::IDLE | Default |
TextArea
Extends TextInput with multi-line support. The canvas grows to fit the full content height and a ScrollPane is embedded internally to clip and scroll it. Enter inserts a newline. Ctrl+Enter fires the onSubmit callback. Mouse wheel and up/down arrow keys scroll the content. The scroll bar appearance is controlled through TextAreaTheme fields.
ml::TextArea editor;
editor.setSize({600.f, 400.f});
editor.setPosition({40.f, 60.f});
editor.setPlaceholder("Start typing...");
editor.onChange([](const std::string& text) {
markUnsaved();
});
editor.onSubmit([](const std::string& text) {
sendMessage(text);
});
addComponent(editor);
editor.setScrollBarColor(sf::Color(100, 100, 160, 220));
editor.setScrollBarTrackColor(sf::Color(30, 30, 50, 180));
editor.setScrollBarWidth(8.f);
All TextInput methods apply to TextArea as well — setValue(), getValue(), clear(), setEnabled(), setReadOnly(), setError(), onChange(), onSubmit(), setFont(), and setCharacterSize().
// applyStyle() requires a type that derives from both
// TextInputSettings and TextAreaTheme
struct EditorStyle : public ml::TextInputSettings,
public ml::TextAreaTheme
{
EditorStyle() {
// TextInputSettings fields
// TextAreaTheme fields
scrollBarWidth = 10.f;
}
};
editor.applyStyle(EditorStyle{});
TextAreaWith<M> adds manifest flags and states on top of TextArea:
class LogView : public ml::TextAreaWith<AppManifest>
{
public:
void appendLine(const std::string& line) {
setValue(getValue() + line + "\n");
}
};