RichEditBox¶
Header: winui/ui/text/RichEditBox.hpp. Spec: winui/ui/text/RichEditBox.hpp.
An editable, formatted document that looks like a TextBox.
The document is plain text (\n between paragraphs) with a character format per character. The user edits it as in a multi-line TextBox, formats with Ctrl+B/I/U or the context menu, and undoes with Ctrl+Z/Ctrl+Y. The app reads and writes it as text(), spans() or RTF, and formats the selection with set_selection_format(). Only the user's changes raise on_text_changed(), never changes made from code. In a spec tree it is built by ui::RichEditBox.
Example:
std::string draft; // the saved document, as RTF
auto panel = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto* bold = panel->add(std::make_unique<ui::ButtonControl>("Bold"));
auto* editor = panel->add(std::make_unique<ui::RichEditBoxControl>());
editor->set_header("Notes");
editor->set_placeholder_text("Type here");
editor->set_height(240.0f);
editor->load_rtf(R"({\rtf1\ansi Hello, {\b world}!\par})");
bold->on_click([editor] { editor->toggle_bold(); });
editor->on_text_changed([editor, &draft] { draft = editor->save_rtf(); });
window.set_content(std::move(panel));
ui::RichEditBox¶
Editable rich text: character formatting, undo, RTF in and out. Builds a ui::RichEditBoxControl.
Formatting is applied through the built control (via .control); the spec only sets up the document and its editing rules.
Example:
ui::Control<ui::RichEditBox> editor;
bool dirty = false;
window.set_content(ui::RichEditBox{
.header = "Notes",
.placeholder_text = "Write here",
.height = 200,
.on_text_changed = [&] { dirty = true; },
.control = editor,
});
Every field, in the order a designated initializer names them:
ui::RichEditBox{
.header, .description, .error, .placeholder_text, .text, .max_length, .spell_check,
.read_only, .accepts_return, .character_casing, .disabled_formatting_shortcuts, .wrapping,
.text_alignment, .font_family, .font_size, .foreground, .selection_highlight_color, .style,
.margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
.horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .enabled, .accessibility,
.on_text_changed, .on_selection_changed, .on_pointer_entered, .on_pointer_exited,
.on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
header |
ui::Binding<std::string> |
The label above the control. Empty draws none. | |
description |
ui::Binding<std::string> |
Secondary text under the box, such as what to enter or why; empty draws none. Screen readers offer it as help text. | |
error |
ui::Binding<std::string> |
What is wrong with the value: non-empty shows it in the description's place in the critical color and draws the border in that color, and screen readers report the field invalid. The field shows exactly what it is given, so bind it to a check of the value and decide there when it shows (after the first submit, say). | |
placeholder_text |
ui::Binding<std::string> |
The hint shown while the document is empty. | |
text |
ui::TwoWayField<std::string> |
The document as plain text; a new value replaces it (and its formatting), one equal to what the box holds changes nothing. ui::bind(prop) is two-way: what the user types is written back as plain text, before .on_text_changed runs. |
|
max_length |
ui::Binding<std::size_t> |
{0} |
The most characters the user can type or paste; 0 is no limit. |
spell_check |
ui::Binding<bool> |
{true} |
Whether misspelled words are underlined, with suggestions in the context menu. |
read_only |
ui::Binding<bool> |
{false} |
Selectable and copyable, never edited. |
accepts_return |
ui::Binding<bool> |
{true} |
Enter starts a new paragraph. On by default. |
character_casing |
ui::Binding<ui::CharacterCasing> |
{ui::CharacterCasing::Normal} |
Sets the casing of what the user types or pastes. |
disabled_formatting_shortcuts |
ui::Binding<ui::DisabledFormattingShortcuts> |
{ui::DisabledFormattingShortcuts::None} |
The Ctrl+B/I/U shortcuts to leave out. |
wrapping |
ui::Binding<ui::TextWrapping> |
{ui::TextWrapping::Wrap} |
Whether lines break at the box's width; Wrap by default. |
text_alignment |
ui::Binding<ui::TextAlignment> |
{ui::TextAlignment::Left} |
The alignment of every paragraph. |
font_family |
ui::Binding<std::optional<std::string>> |
The default font family; unset follows the theme. | |
font_size |
ui::Binding<std::optional<float>> |
The default font size, DIPs; unset follows the theme. | |
foreground |
ui::Binding<ui::Paint> |
The color of text without its own: a fixed color or a theme resource; unset follows the theme. | |
selection_highlight_color |
ui::Binding<ui::Paint> |
The color behind selected text: a fixed color or a theme resource, which follows theme switches. Unset is the accent. | |
on_text_changed |
ui::Callback<void(const std::string&)> |
Fired after every change the user makes to the text or its formatting. Handlers in a spec returned from a function must capture by value or capture state that outlives the window (see spec/Spec.hpp). | |
on_selection_changed |
ui::Action |
The caret moved or the selection grew or shrank. | |
on_pointer_entered |
ui::Action |
The pointer moved onto the control. | |
on_pointer_exited |
ui::Action |
The pointer left the control. | |
on_got_focus |
ui::Action |
Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this. | |
on_lost_focus |
ui::Action |
Keyboard focus left the control and everything inside it. | |
on_key_down |
ui::Callback<ui::Handling(const ui::KeyEvent&)> |
A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()). | |
on_wheel |
ui::Callback<ui::Handling(const ui::PointerEvent&)> |
A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()). | |
control |
ui::ControlOut<ui::RichEditBox> |
Out: a non-owning observer of the built control, used to format text or read RTF. |
Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, enabled, accessibility every spec carries (conventions).
build¶
Consumes the spec and returns the built ui::RichEditBoxControl; the caller owns it.
ui::RichEditBoxControl¶
Derives from ui::Element, ui::ValueProvider.
An editable, formatted document that looks like a TextBox.
The document is plain text (\n between paragraphs) with a character format per character. The user edits it as in a multi-line TextBox, formats with Ctrl+B/I/U or the context menu, and undoes with Ctrl+Z/Ctrl+Y. The app reads and writes it as text(), spans() or RTF, and formats the selection with set_selection_format(). Only the user's changes raise on_text_changed(), never changes made from code. In a spec tree it is built by ui::RichEditBox.
Example:
std::string draft; // the saved document, as RTF
auto panel = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto* bold = panel->add(std::make_unique<ui::ButtonControl>("Bold"));
auto* editor = panel->add(std::make_unique<ui::RichEditBoxControl>());
editor->set_header("Notes");
editor->set_placeholder_text("Type here");
editor->set_height(240.0f);
editor->load_rtf(R"({\rtf1\ansi Hello, {\b world}!\par})");
bold->on_click([editor] { editor->toggle_bold(); });
editor->on_text_changed([editor, &draft] { draft = editor->save_rtf(); });
window.set_content(std::move(panel));
UndoLimit¶
Steps kept before the oldest is dropped.
SpellCheckDelayMs¶
How long after the last edit the document is checked again, in milliseconds.
MaxSpellingSuggestions¶
The most suggestions the context menu offers for one misspelling.
CaretBlinkIntervalMs¶
How long the caret stays shown, and then hidden, in milliseconds.
RichEditBoxControl¶
An empty document.
RichEditBoxControl¶
A document of unformatted text, the caret at its end.
text¶
The plain text, a \n for every paragraph mark.
set_text¶
Replaces the document with unformatted text and puts the caret at its end. Like every change made from code, it raises no on_text_changed(). It clears the undo history.
spans¶
The document as runs of one format each, in order.
set_spans¶
Replaces the document with formatted text; as set_text().
load_rtf¶
Replaces the document with RTF. Text that is not RTF at all comes in as plain text.
save_rtf¶
The document as RTF, with font and color tables for the formats it uses. load_rtf() reads it back.
caret¶
The caret's offset into text(): the moving end of the selection.
selection¶
The selection as [start, end) (the caret when they are equal).
has_selection¶
Whether any text is selected (more than a caret).
select¶
Selects [start, end), the caret at end; both are clamped to the text.
select_all¶
Selects the whole document (Ctrl+A).
selected_text¶
The selected text, plain; empty at a bare caret.
selection_format¶
What the whole selection shares, or at a bare caret what will be typed next.
set_selection_format¶
Applies format to the selection as one undo step, or at a bare caret to what is typed next.
range_format¶
What [start, end) shares.
set_range_format¶
Applies format to [start, end), leaving the selection where it is. Not an undo step: it is for markup the app keeps over the document, such as highlighting search hits.
toggle_bold¶
Toggles bold: off when the whole selection has it, on otherwise. Ctrl+B.
toggle_italic¶
As toggle_bold(), for italic. Ctrl+I.
toggle_underline¶
As toggle_bold(), for underline. Ctrl+U.
find_all¶
Searches the whole text, case-insensitive: every match as [start, end).
type_text¶
Replaces the selection as if typed. The maximum length and character casing apply, it is an undo step and it fires on_text_changed(). Line breaks are kept only while accepts_return() is on.
can_undo¶
Whether there is a step to undo.
can_redo¶
Whether there is an undone step to redo.
undo¶
Restores (Ctrl+Z) the text, formats and selection before the last step.
redo¶
Reapplies (Ctrl+Y, Ctrl+Shift+Z) the last undone step.
header¶
The label above the box; empty when none is shown.
set_header¶
The label above the box. Empty draws none.
description¶
The secondary text under the box; empty (the default) draws none.
set_description¶
Sets the description. Empty draws none and takes no room.
error¶
What is wrong with the value, shown in the description's place in the critical color, with the border in the same color; empty (the default) shows the description.
set_error¶
Sets the error. Empty shows the description again.
automation_help_text_fallback¶
The description, or the error while one is set, is the help text a screen reader offers when accessibility().description is empty.
automation_invalid¶
Invalid while an error is set.
automation_name_fallback¶
The header names the control when accessibility().name does not.
placeholder_text¶
The hint shown while the document is empty.
set_placeholder_text¶
Drawn in a secondary text color while the document is empty.
font_family¶
The font family of text without one of its own; unset follows the theme.
set_font_family¶
Sets or clears the default font family; unset follows the theme. Text without a family of its own is drawn in it.
font_size¶
The font size in DIPs of text without one of its own; unset follows the theme.
set_font_size¶
Sets or clears the default font size; unset follows the theme.
foreground¶
The color of text without a color of its own; unset follows the theme.
set_foreground¶
Sets the text color; unset follows the theme. Text without a color of its own is drawn in it.
selection_highlight_color¶
The fixed color behind selected text; nullopt (the default) when unset or a theme resource is set. Unset is the accent.
selection_highlight_resource¶
The color behind selected text as a theme resource, or nullptr.
set_selection_highlight_color¶
Sets the fixed color behind selected text and clears a theme resource; nullopt goes back to the accent.
set_selection_highlight_color¶
Sets the color behind selected text to a theme resource, re-read under every theme, and clears a fixed one.
text_alignment¶
How each line sits between the edges; Left by default.
set_text_alignment¶
Sets the alignment of every paragraph.
base_style¶
The style text without a format of its own is measured and drawn in.
read_only¶
Whether the text is read-only; false by default.
set_read_only¶
Read-only text can be selected and copied but not edited, and shows no caret. A read-only box drops its squiggles. Making it editable again checks the spelling again.
accepts_return¶
Whether Enter starts a new paragraph; true by default.
set_accepts_return¶
Enter starts a new paragraph and pasted line breaks are kept. On by default.
wrapping¶
Whether lines break at the box's width; Wrap by default.
set_wrapping¶
Sets the wrapping mode.
max_length¶
The most characters the user can type or paste; 0 is no limit.
set_max_length¶
The most characters the user can type or paste; 0 (the default) is no limit. Text set from code is not cut.
character_casing¶
How typed text is cased; Normal by default.
set_character_casing¶
Sets the casing of what the user types or pastes from now on.
disabled_formatting_shortcuts¶
Which of Ctrl+B/I/U and the matching context menu commands are off; None by default.
set_disabled_formatting_shortcuts¶
Turns off formatting shortcuts and their menu commands. Combine flags with |, such as Bold | Italic. Takes effect on the next key press or context menu.
on_text_changed¶
Fired after every change the user makes to the text or its formatting, with the text.
on_selection_changed¶
Fired after the user moves the caret or the selection.
add_context_menu_item¶
Adds an item of the app's own to the end of the context menu ("Share", say).
focused¶
Whether the box holds keyboard focus (the caret blinks).
focusable¶
A tab stop while enabled, read-only or not.
spell_check¶
Whether spell checking is on; true by default. Squiggles and the context menu's suggestions work as in TextBox. There is no autocorrection.
set_spell_check¶
Turns spell checking on or off. Turning it off clears the squiggles, and turning it on checks the document again.
spelling_errors¶
The misspellings found in the last check, as offsets into text().
sync_spell_checker¶
Remembers the host's spell checker and schedules a check.
handle_context_menu¶
Spelling suggestions for a misspelled word under position, then Cut, Copy, Paste, Bold, Italic, Underline, Undo, Redo and Select All where they apply, then the items from add_context_menu_item().
caret_visible¶
Whether a focused box draws its caret right now, in its blink cycle.
automation_role¶
AutomationRole::Edit.
caret_bounds¶
The caret, one DIP wide and a line tall, while focused and editable.
measure_override¶
As TextBox: as wide as the text or the placeholder and as tall as its lines, within what is offered, plus the header above.
arrange_override¶
Places the header and the text area.
pointer_override¶
Click places the caret (Shift+click extends), drag selects, double-click selects a word, triple-click a paragraph.
wheel_override¶
Scrolls the text vertically; false when there is nothing to scroll, so an enclosing scroller gets the turn.
tick_override¶
Blinks the caret and runs a pending spell check once its delay has passed.
render_override¶
The header, the field chrome, the placeholder or the formatted text (scrolled), the selection, the squiggles and the caret.
enabled_changed¶
is_enabled() flipped, through set_enabled() here or on an ancestor, or a move to another parent. Drop any press or hover state. The element is redrawn either way. No-op by default.
focus_changed¶
Called by Window as focus moves: restarts the caret blink.
key_override¶
Caret movement, deletion, clipboard, undo/redo and the formatting shortcuts.
text_override¶
Typed text replaces the selection in the typing format, with the max length and character casing applied. Consecutive typing is one undo step.
draws_focus_ring¶
None: the field shows focus with its accent border.
struct CharacterFormat¶
A character format to apply to a range, or read back from one. Applying it sets every field that is set and leaves every unset one alone. When reading, a field is unset where the range mixes values.
control_default lists the color, family and size fields that follow the control's own value. For the background, that means no highlight. When applied, those fields go back to the control's value before the set fields are applied. When read, it lists the fields the whole range leaves to the control.
Example:
auto editor = std::make_unique<ui::RichEditBoxControl>("Hello, world!");
editor->select(0, 5);
editor->set_selection_format({.italic = true, .font_size = 20.0f}); // bold etc. untouched
if (editor->selection_format().bold == true) { /* ... */ } // the whole range is bold
editor->set_selection_format({.control_default = ui::RichTextFormatField::Foreground});
| Field | Type | Default | |
|---|---|---|---|
bold |
std::optional<bool> |
Bold on/off; unset leaves it, or reads as mixed. | |
italic |
std::optional<bool> |
Italic on/off. | |
underline |
std::optional<bool> |
Underline on/off. | |
strikethrough |
std::optional<bool> |
Strikethrough on/off. | |
foreground |
std::optional<Color> |
Text color. | |
background |
std::optional<Color> |
Highlight color. | |
font_family |
std::optional<std::string> |
Font family. | |
font_size |
OptionalFloat |
Font size in DIPs. | |
control_default |
RichTextFormatField |
RichTextFormatField::None |
The fields that follow the control's own value. |
struct RichTextFormat¶
The character format one character of a RichEditBox carries. An unset color, family or size follows the control's own (its foreground(), font_family() and font_size()).
| Field | Type | Default | |
|---|---|---|---|
bold |
bool |
false |
Bold weight. |
italic |
bool |
false |
Italic style. |
underline |
bool |
false |
Underlined. |
strikethrough |
bool |
false |
Struck through. |
foreground |
std::optional<Color> |
Text color; unset is the control's foreground(). | |
background |
std::optional<Color> |
Highlight behind the text; unset paints none. | |
font_family |
std::optional<std::string> |
Font family; unset is the control's font_family(). | |
font_size |
OptionalFloat |
Font size in DIPs; unset is the control's font_size(). |
struct RichTextSpan¶
A stretch of a RichEditBox's text in one format, as spans() hands out and set_spans() takes.
Example:
auto box = std::make_unique<ui::RichEditBoxControl>();
box->set_spans({
{.text = "Hello, "},
{.text = "world", .format = {.bold = true, .foreground = ui::Color::from_argb(0xFFC42B1C)}},
{.text = "!\nA second paragraph."},
});
| Field | Type | Default | |
|---|---|---|---|
text |
std::string |
The text (UTF-8); \n is a paragraph mark. |
|
format |
RichTextFormat |
The format every character of text carries. |
Enumerations¶
RichTextFormatField¶
The fields of a RichTextFormat that can follow the control's own value, as RichEditBoxControl::CharacterFormat::control_default lists them. Flags.
| Value | |
|---|---|
None |
no field |
Foreground |
the text color |
Background |
the highlight (none) |
FontFamily |
the font family |
FontSize |
the font size |
All |
every one of them |
DisabledFormattingShortcuts¶
The Ctrl+B/I/U shortcuts, with their context menu commands, to leave out. Flags.
| Value | |
|---|---|
None |
every shortcut works (the default) |
Bold |
no Ctrl+B / Bold |
Italic |
no Ctrl+I / Italic |
Underline |
no Ctrl+U / Underline |
All |
none of them |
Functions¶
operator|¶
Combines RichTextFormatField flags.
operator&¶
The flags both a and b have.
has_flag¶
Whether set includes any bit of flag.
operator|¶
Combines DisabledFormattingShortcuts flags.
has_flag¶
Whether set includes any bit of flag.
Tests¶
tests/test_rich_edit_box.cpp