Skip to content

Text

Header: winui/ui/text/Text.hpp. Spec: winui/ui/text/Text.hpp.

A non-interactive run of text, the label of every form.

A plain string draws in the style the theme's type ramp gives its role() (Body by default), in the theme's window text color. set_text_style(), set_color() and set_foreground() override them. The text can wrap (set_wrapping()), trim with an ellipsis (set_trimming()), align and justify (set_text_alignment()), and carry formatted runs and links (set_inlines()). With set_selection_enabled(), the user can select and copy it. Otherwise it takes no input or focus. In a spec tree it is built by ui::Text.

Example:

ui::Property<int> clicks{0};

window.set_content(ui::VerticalStack{
    .spacing  = 8,
    .content  = {
        ui::Text{.text = "Settings", .role = ui::TextRole::Title},
        ui::Text{.text     = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); }),
                 .wrapping = ui::TextWrapping::WrapWholeWords},
        ui::Button{.text = "Click me", .on_click = [&] { ++clicks; }},
    },
});

// Or imperatively, with formatted runs and a link:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto block = std::make_unique<ui::TextControl>();
block->set_inlines({
    {.text = "Read the "},
    {.text = "release notes", .on_click = [] { /* open them */ }},
    ui::line_break(),
    {.text = "before updating.", .weight = ui::FontWeight::Bold},
});
block->set_wrapping(ui::TextWrapping::WrapWholeWords);
block->set_selection_enabled(true);
ui::TextControl* observer = stack->add(std::move(block)); // the stack owns it now

ui::Text

A run of non-interactive text. Builds a ui::TextControl.

The text is a constant string, or a bind() so the label follows a Property. The font comes from the theme's type ramp through .role, such as TextRole::Caption or TextRole::Subtitle. .text_style sets a style for this label alone.

Example:

ui::Property<int>    clicks{0};
ui::Control<ui::Text> status;

window.set_content(ui::VerticalStack{
    .spacing  = 8,
    .content  = {
        ui::Text{ .text = "Appearance", .role = ui::TextRole::Subtitle },
        ui::Text{ .text = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); }) },
        ui::Text{ .text     = "A longer paragraph that wraps at the width the parent offers.",
                  .wrapping = ui::TextWrapping::Wrap,
                  .control  = status },
    },
});

Every field, in the order a designated initializer names them:

ui::Text{
    .text, .inlines, .selection_enabled, .role, .text_style, .wrapping, .text_alignment,
    .character_spacing, .selection_highlight_color, .foreground, .trimming, .style, .margin,
    .width, .height, .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
    .vertical_alignment, .visible, .tool_tip, .enabled, .accessibility,
    .on_text_trimmed_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
text ui::Binding<std::string> The displayed string (UTF-8). Ignored when .inlines is set.
inlines ui::Binding<std::vector<ui::Inline>> Runs with their own formatting, line breaks and links (ui/text/Inlines.hpp). When set, they are the content and .text is ignored.
selection_enabled ui::Binding<bool> {false} The user can select the text with the pointer or keyboard and copy it.
role ui::Binding<ui::TextRole> {ui::TextRole::Body} The step of the theme's type ramp the text uses, such as Caption or Subtitle. It follows a theme change.
text_style ui::Binding<std::optional<ui::TextStyle>> A style for this label alone. When set, the theme's type ramp no longer applies to this label.
wrapping ui::Binding<ui::TextWrapping> {ui::TextWrapping::NoWrap} Whether the text breaks into lines at the width the parent offers.
text_alignment ui::Binding<ui::TextAlignment> {ui::TextAlignment::Left} How each line sits between the left and right edges.
character_spacing ui::Binding<int> {0} Extra space between characters, in thousandths of an em.
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.
foreground ui::Binding<ui::Paint> The text color: a fixed color, or a theme resource re-read on a theme change. Unset uses the theme's text color.
trimming ui::Binding<ui::TextTrimming> {ui::TextTrimming::None} What shows when the text does not fit: all of it clipped, or an ellipsis (plain text only).
on_text_trimmed_changed ui::Callback<void(bool)> Fires with the new state whenever layout starts or stops cutting the text off. Only with .trimming set.
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::Text> Out: the handle that receives the built control.

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

std::unique_ptr<Element> build()&&

Consumes the spec and returns the built ui::TextControl; the caller owns it.

ui::TextControl

Derives from ui::Element.

A non-interactive run of text, the label of every form.

A plain string draws in the style the theme's type ramp gives its role() (Body by default), in the theme's window text color. set_text_style(), set_color() and set_foreground() override them. The text can wrap (set_wrapping()), trim with an ellipsis (set_trimming()), align and justify (set_text_alignment()), and carry formatted runs and links (set_inlines()). With set_selection_enabled(), the user can select and copy it. Otherwise it takes no input or focus. In a spec tree it is built by ui::Text.

Example:

ui::Property<int> clicks{0};

window.set_content(ui::VerticalStack{
    .spacing  = 8,
    .content  = {
        ui::Text{.text = "Settings", .role = ui::TextRole::Title},
        ui::Text{.text     = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); }),
                 .wrapping = ui::TextWrapping::WrapWholeWords},
        ui::Button{.text = "Click me", .on_click = [&] { ++clicks; }},
    },
});

// Or imperatively, with formatted runs and a link:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto block = std::make_unique<ui::TextControl>();
block->set_inlines({
    {.text = "Read the "},
    {.text = "release notes", .on_click = [] { /* open them */ }},
    ui::line_break(),
    {.text = "before updating.", .weight = ui::FontWeight::Bold},
});
block->set_wrapping(ui::TextWrapping::WrapWholeWords);
block->set_selection_enabled(true);
ui::TextControl* observer = stack->add(std::move(block)); // the stack owns it now

TextControl

TextControl() = default

An empty label.

TextControl

TextControl(std::string text)

A label showing text (UTF-8) as one plain run.

text

const std::string& text() const

The content as UTF-8; with inlines, their texts joined (line breaks as \n).

set_text

void set_text(std::string text)

Replaces the content with one plain run, and drops any inlines and the selection.

inlines

const std::vector<Inline>& inlines() const

The formatted runs; empty for plain text (the default, and after set_text()).

set_inlines

void set_inlines(std::vector<Inline> inlines)

Replaces the content with formatted runs. text() becomes the runs' text joined. Clears the selection. An inline with on_click or navigate_uri is a link.

text_alignment

TextAlignment text_alignment() const

How each line sits between the left and right edges; Left by default.

set_text_alignment

void set_text_alignment(TextAlignment alignment)

Sets the line alignment.

character_spacing

int character_spacing() const

Extra space between characters, in thousandths of an em; 0 by default.

set_character_spacing

void set_character_spacing(int spacing)

Sets the extra space between characters, in thousandths of an em (TextStyle::character_spacing).

selection_enabled

bool selection_enabled() const

Whether the user can select and copy the text; false by default. While true the block is focusable.

set_selection_enabled

void set_selection_enabled(bool enabled)

Turns text selection on or off. While on, the user selects by dragging, double-clicking a word or triple-clicking a paragraph. Ctrl+A, Ctrl+C and a context menu with Copy and Select All act on the selection, and a click focuses the block. Turning it off clears the selection.

selection_highlight_color

std::optional<Color> selection_highlight_color() const

The fixed color behind selected text; nullopt (the default) when unset or a theme resource is set. Unset is the accent.

selection_highlight_resource

ThemeColor selection_highlight_resource() const

The color behind selected text as a theme resource, or nullptr.

set_selection_highlight_color

void set_selection_highlight_color(std::optional<Color> color)

Sets the fixed color behind selected text and clears a theme resource; nullopt goes back to the accent.

set_selection_highlight_color

void set_selection_highlight_color(ThemeColor resource)

Sets the color behind selected text to a theme resource, re-read under every theme, and clears a fixed one.

selection

std::pair<std::size_t, std::size_t> selection() const

The selection as [start, end) byte offsets into text() (inlines joined); {0, 0} when none.

select

void select(std::size_t start, std::size_t end)

Selects the byte range [start, end) of text(). The selection shows only while the block has focus and selection is enabled.

select_all

void select_all()

Selects the whole text, as Ctrl+A does.

selected_text

std::string selected_text() const

The selected part of the laid-out text; empty when nothing is selected or before the first measure.

text_style

const TextStyle& text_style() const

The explicit style set by set_text_style(). Meaningful only once set_text_style() was called. Until then the theme's type ramp entry for role() is used.

set_text_style

void set_text_style(TextStyle style)

Fixes the font, size, weight and alignment. From then on it takes precedence over role() and the theme's type ramp.

role

TextRole role() const

The role this label plays in the theme's type ramp; Body by default. The style is looked up in the current theme, so a plain TextControl follows the theme's own fonts, such as MS Sans Serif under Windows95 or Metro's Light and Semilight weights. set_text_style() always takes precedence.

set_role

void set_role(TextRole role)

Sets the type ramp role.

wrapping

TextWrapping wrapping() const

Whether the text breaks into lines; NoWrap by default.

set_wrapping

void set_wrapping(TextWrapping wrapping)

Sets the wrapping mode. Anything but NoWrap wins over the wrapping of a style from set_text_style(). NoWrap, the default, leaves that style's own wrapping in charge. Text wraps only at a bounded width, and a horizontal StackControl offers an unbounded one.

color

std::optional<Color> color() const

The fixed text color, if any. Unset (the default) uses the theme's window text color, so a label without set_color() stays readable under a dark theme.

set_color

void set_color(Color color)

Fixes the text color and clears any set_foreground() resource. A fixed color does not follow a theme change.

set_foreground

void set_foreground(ThemeColor resource)

Sets the text color to a theme resource, re-read whenever the text is drawn so it follows a theme change. Wins over set_color(); nullptr clears it.

trimming

TextTrimming trimming() const

What shows when the text does not fit the arranged box: all of it clipped (None, Clip), or as much as fits followed by an ellipsis, cut between characters or between words. Only the plain-text form trims (not inlines, selectable or justified text).

set_trimming

void set_trimming(TextTrimming trimming)

Sets the trimming mode.

is_text_trimmed

bool is_text_trimmed() const

Whether the last arrange cut the text short.

on_text_trimmed_changed

void on_text_trimmed_changed(Callback<void(bool)> handler)

Fires during arrange with the new is_text_trimmed() value whenever it changes. A typical use is a tooltip that shows the full text.

parallel_measure_safe

bool parallel_measure_safe() const override

True: measuring reads only the text's own state, the measurer and the theme.

focusable

bool focusable() const override

Focusable only while enabled with text selection on.

focused

bool focused() const

Whether the block has keyboard focus (only ever true while focusable()).

handle_context_menu

bool handle_context_menu(std::optional<Point> position, ContextMenuHost& host) override

Offers Copy / Select All while selection is enabled; returns false (no menu) otherwise.

cursor_at

std::optional<CursorShape> cursor_at(Point p) const override

A hand over a link, an I-beam over selectable text.

automation_role

AutomationRole automation_role() const override

Always AutomationRole::Text.

automation_name_fallback

std::string automation_name_fallback() const override

The text, when no accessibility name is set.

automation_children

void automation_children(std::vector<Element*>& out) const override

One node per link inline. Invoking a node follows its link.

measure_override

Size measure_override(Size available, const MeasureContext& context) const override

The text's size in DIPs in the resolved style, wrapped to available.width when wrapping.

arrange_override

void arrange_override(const Rect& final_rect, const ArrangeContext& context) override

Re-flows laid-out content to the arranged width and applies trimming (which may fire on_text_trimmed_changed()).

render_override

void render_override(Renderer& renderer, const RenderContext& context) const override

The text, or the laid-out runs with the selection highlight (while focused) and link underlines.

pointer_override

bool pointer_override(const PointerEvent& e) override

Selection drags and multi-clicks, and link clicks; ignored while disabled.

enabled_changed

void enabled_changed() override

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

void focus_changed(bool) override

Tracks focus. The selection shows only while the block has focus.

key_override

bool key_override(const KeyEvent& e) override

Ctrl+A (select all) and Ctrl+C (copy), only while enabled with selection on.

draws_focus_ring

bool draws_focus_ring() const override

None: selectable text shows focus through its selection.

Enumerations

TextTrimming

enum class TextTrimming

What a TextControl shows when its text does not fit the arranged box.

Value
None All of the text, clipped at the box (the default).
CharacterEllipsis As much as fits, cut between characters, then an ellipsis.
WordEllipsis As much as fits, cut between words, then an ellipsis.
Clip All of the text, clipped at the box.

Tests

  • tests/test_stack.cpp