Skip to content

ui::TextInteraction

Header: winui/ui/text/Inlines.hpp.

Selection and link state over laid-out inline text, shared by TextControl, RichText and RichTextOverflow. Offsets are the TextLayout's. A RichText and its overflow containers each have their own layout over the same content, so they share one selection.

A building block for a custom text element. Keep one as a member and pass it the element's pointer and key events together with its TextLayout. Redraw when it reports a change, and let it fill the layout's paint when rendering.

Example:

class Article : public ui::Element
{
protected:
    bool pointer_override(const ui::PointerEvent& e) override
    {
        const bool held = interaction_.pressed_link || interaction_.dragging;
        if (interaction_.pointer(e, layout_, ui::Point{bounds().x, bounds().y}, 0, bounds(), true, links_))
        {
            mark_dirty(ui::DirtyFlags::Visual);
        }
        return held || interaction_.pressed_link || interaction_.dragging; // a link or selection press
    }
    bool key_override(const ui::KeyEvent& e) override
    {
        const bool acted = interaction_.key(e, layout_);
        if (acted)
        {
            mark_dirty(ui::DirtyFlags::Visual);
        }
        return acted;
    }
    // Programmatic selection: interaction_.select(0, 5); interaction_.selected_text(layout_);

private:
    ui::TextLayout                 layout_;
    ui::TextInteraction            interaction_;
    std::vector<const ui::Inline*> links_; // from to_layout_paragraphs()
};

anchor

std::size_t anchor = 0

Where the selection started (the fixed end), as a layout offset.

caret

std::size_t caret = 0

The moving end of the selection, as a layout offset; equal to anchor when nothing is selected.

dragging

bool dragging = false

Whether a selection drag is in progress.

std::optional<std::size_t> hover_link {}

The index of the link under the pointer; unset when there is none.

std::optional<std::size_t> pressed_link {}

The index of the link pressed and not yet released; unset when there is none.

range

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

The selection as an ordered [begin, end) pair of layout offsets.

has_selection

bool has_selection() const

Whether any text is selected.

select

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

Selects the layout offsets [begin, end); end becomes the caret.

pointer

bool pointer(const PointerEvent& e, const TextLayout& layout, Point origin, std::size_t first_line, const Rect& bounds, bool selectable, const std::vector<const Inline*>& links, bool sole_view = true)

Handles pointer input over layout. The top of the first drawn line sits at origin, and first_line is the layout line drawn there. A press on a link arms it, and a release on the same link invokes it. Elsewhere, when selectable, a press places the selection and a drag extends it. A double click selects the word, a triple click the paragraph, and Shift extends. sole_view means the layout is the content's only view, so a drag carries on past its edges. One of several linked views, such as a RichText and its overflow containers, only follows the pointer while it is over that view. Returns whether anything visible changed.

key

bool key(const KeyEvent& e, const TextLayout& layout)

Ctrl+A selects everything, and Ctrl+C copies the selection to ui::clipboard(). Returns whether it acted.

context_menu

void context_menu(Point anchor_point, const TextLayout& layout, ContextMenuHost& host)

Shows the context menu of a selectable text block, with Copy and Select All.

selected_text

std::string selected_text(const TextLayout& layout) const

The selected text as UTF-8 (empty without a selection).

paint

void paint(TextLayout::Paint& paint, const Theme& theme, bool show_selection, std::optional<Color> highlight) const

Fills the paint's link colors, and its selection when show_selection. The paint keeps a pointer to this object and to theme for the duration of the render.