Skip to content

ui::Element

Header: winui/ui/Element.hpp.

The base of every node in the UI tree: a control, a panel, a window's content.

Implement it: derive a control from it and override the hooks it needs. You call a verb (measure(), arrange(), render(), tick(), handle_key()) and override its <verb>_override().

Every node measures, arranges, renders, takes input and may take focus. The public verbs apply what is common to all elements (margin, explicit and min/max size, alignment, visibility, requested theme, the visual transform and opacity, animations, the focus ring) and then call the protected *_override() hook a control implements. measure_override() and render_override() are required; the rest default to doing nothing. Pointer and key input is routed: the window offers an event to the element under the pointer, or the focused one, and then to each parent until a hook returns true. Containers own their children through std::unique_ptr and list them through for_each_child(); every tree-wide walk (tick(), clear_dirty(), the focus ring, popups, automation) reaches the children through that, so a container overrides it once instead of forwarding each walk. Setters invalidate through mark_dirty(), which bubbles to the root so the window knows to lay out or redraw.

Elements are rendered as a platform-independent command stream (Renderer), so a control can be measured, arranged, drawn and driven with input without a window or a GPU.

Example:

// A minimal custom control: a color swatch that is clicked with the mouse or Space.
class SwatchControl final : public ui::Element
{
public:
    explicit SwatchControl(ui::Color color) : color_(color) {}

    void set_color(ui::Color color)
    {
        color_ = color;
        mark_dirty(ui::DirtyFlags::Visual); // redraw, no relayout
    }
    void on_click(ui::Callback<void()> handler) { on_click_ = std::move(handler); }

    bool focusable() const override { return true; }

protected:
    bool key_override(const ui::KeyEvent& e) override
    {
        if (e.key != ui::Key::Space)
        {
            return false; // to the parents, the shortcuts and focus moves
        }
        if (e.action == ui::KeyAction::Up && on_click_)
        {
            on_click_();
        }
        return true;
    }
    ui::Size measure_override(ui::Size, const ui::MeasureContext&) const override
    {
        return {32.0f, 32.0f};
    }
    void render_override(ui::Renderer& r, const ui::RenderContext&) const override
    {
        r.fill_rounded_rect(bounds(), 4.0f, color_);
    }
    bool pointer_override(const ui::PointerEvent& e) override
    {
        if (e.action == ui::PointerAction::Down)
        {
            pressed_ = true; // the press holds the pointer until its release
            return true;
        }
        if (e.action == ui::PointerAction::Up)
        {
            // A click is a press and a release, both on the swatch.
            const bool was_pressed = std::exchange(pressed_, false);
            if (was_pressed && bounds().contains(e.position) && on_click_)
            {
                on_click_();
            }
            return true;
        }
        return false;
    }

private:
    ui::Color            color_;
    bool                 pressed_ = false;
    ui::Callback<void()> on_click_;
};

// In a tree: the panel owns it, the caller keeps an observer.
auto*   panel  = window.set_content(
    std::make_unique<ui::StackControl>(ui::Orientation::Vertical));
SwatchControl* swatch = panel->add(std::make_unique<SwatchControl>(ui::Color::from_argb(0xFF0078D4)));
swatch->set_margin(ui::Thickness{4.0f});
swatch->set_horizontal_alignment(ui::Alignment::Center);
swatch->set_tool_tip("Accent blue");
swatch->on_click([] { /* ... */ });

~Element

virtual ~Element()

Leaves keyboard focus bookkeeping consistent (has_focus_within()) when the focused element goes away with its subtree.

Element

Element(const Element&) = delete

Not copyable: a control has a parent link, a stable VisualId and its subscriptions, none of which can be duplicated. A derived control is movable until it is parented (the move operations are protected); in a tree it is owned through unique_ptr and never moved.

operator=

Element& operator=(const Element&) = delete

visual_id

VisualId visual_id() const

Assigned once at construction and never reused; the stable key other systems (VisualTree) use instead of this object's address.

margin

const Thickness& margin() const

DIPs of empty space kept outside the element on each side, taken from the rect the parent offers before measuring and arranging. Zero by default.

set_margin

void set_margin(const Thickness& margin)

Changes the margin; invalidates layout.

width

std::optional<float> width() const

The explicit width, nullopt for Auto. Measure and arrange both fold it into the min/max range. The size wins over the content and min_width() wins over the size. A Stretch-aligned element that ends up narrower than its slot is centered in it.

set_width

void set_width(OptionalFloat value)

Sets the explicit width in DIPs (negative clamps to 0), or nullopt for Auto; invalidates layout.

height

std::optional<float> height() const

The explicit height, as width() is the explicit width; nullopt for Auto.

set_height

void set_height(OptionalFloat value)

Sets the explicit height in DIPs (negative clamps to 0), or nullopt for Auto; invalidates layout.

max_width

float max_width() const

The maximum width in DIPs; infinity (the default) is no limit. min_width() wins over it.

set_max_width

void set_max_width(OptionalFloat value)

Sets the maximum width in DIPs (negative clamps to 0), or nullopt for no limit; invalidates layout.

max_height

float max_height() const

The maximum height, as max_width() is the maximum width; infinity for no limit.

set_max_height

void set_max_height(OptionalFloat value)

Sets the maximum height in DIPs (negative clamps to 0), or nullopt for no limit; invalidates layout.

min_width

float min_width() const

The minimum width in DIPs; 0 (the default) is none. Wins over width() and max_width().

set_min_width

void set_min_width(OptionalFloat value)

Sets the minimum width in DIPs (negative clamps to 0), or nullopt for none; invalidates layout.

min_height

float min_height() const

The minimum height in DIPs; 0 (the default) is none. Wins over height() and max_height().

set_min_height

void set_min_height(OptionalFloat value)

Sets the minimum height in DIPs (negative clamps to 0), or nullopt for none; invalidates layout.

horizontal_alignment

Alignment horizontal_alignment() const

Where the element sits across its slot's width; Alignment::Stretch by default.

set_horizontal_alignment

void set_horizontal_alignment(Alignment alignment)

Changes the horizontal alignment; invalidates layout.

vertical_alignment

Alignment vertical_alignment() const

Where the element sits down its slot's height; Alignment::Stretch by default.

set_vertical_alignment

void set_vertical_alignment(Alignment alignment)

Changes the vertical alignment; invalidates layout.

visibility

Visibility visibility() const

Whether the element is shown. Collapsing marks layout dirty; see Visibility.

set_visibility

void set_visibility(Visibility visibility)

Shows or collapses the element and its subtree; invalidates layout when it changes.

is_effectively_visible

bool is_effectively_visible() const

Whether this element and every ancestor is Visible. The tab ring and the popup layer check this, since a Collapsed container's descendants still answer collect_focusables().

enabled

bool enabled() const

This element's own enabled state, as set_enabled() left it; true by default. Whether it takes input also depends on its ancestors: see is_enabled().

set_enabled

void set_enabled(bool enabled)

Enables or disables this element and everything inside it. A disabled element draws its disabled look, takes no pointer or keyboard input and leaves the tab ring; so does every element inside a disabled one, whatever its own enabled(). Redraws.

is_enabled

bool is_enabled() const

Whether the element takes input right now: its own enabled(), a control's own condition (a Button's command), and every ancestor's. What a control reads to draw its disabled look.

focus

bool focus()

Move keyboard focus here, or, when this element takes no focus itself (a panel, a view's host), to the first focus stop inside it. False, and focus stays where it was, when it is in no window or neither is a stop right now (hidden, disabled). Window::push_focus() also remembers what had focus, to give it back.

Example:

ui::Control<ui::TextBox> name;
// ...
name->focus(); // after showing a form, so typing goes into the first field

window

Window* window() const

The window whose tree this element is in, or nullptr while it is in none (built but not yet placed, or taken out).

requested_theme

ElementTheme requested_theme() const

Measure and draw this subtree in the light or dark version of the theme it is handed (Theme::with_dark_mode), and so with every color the subtree reads from the theme (background resources, text, control fills). No effect where the theme has no other mode (the fixed-palette eras, high contrast). Tokens the app edited on the handed theme that are not colors (corner radii, type, motion, focus-ring widths) stay as edited; colors are the other mode's. A popup opened from inside is drawn by the window in the window's theme.

set_requested_theme

void set_requested_theme(ElementTheme theme)

Changes the requested theme; invalidates layout and redraws the subtree.

is_hit_test_visible

bool is_hit_test_visible() const

Whether the element takes pointer input. False keeps pointer input from reaching this element and everything under it. It still draws and still takes keyboard focus. Frame turns it off on pages while a navigation transition plays.

set_hit_test_visible

void set_hit_test_visible(bool visible)

Turns pointer input to this subtree on or off; takes effect with the next event.

opacity

float opacity() const

The opacity, 0..1. The value set, not the one drawn mid-animation (current_opacity()).

set_opacity

void set_opacity(float opacity)

Sets the opacity (1 by default), animating when an opacity transition is set. Only redraws; the layout stays as it is.

translation

Vector3 translation() const

An offset from the layout position that does not affect layout.

set_translation

void set_translation(Vector3 translation)

Sets the translation in DIPs, animating when a translation transition is set.

rotation

float rotation() const

The rotation in clockwise degrees about center_point().

set_rotation

void set_rotation(float degrees)

Sets the rotation in degrees, animating when a rotation transition is set.

scale

Vector3 scale() const

The scale factors, about center_point().

set_scale

void set_scale(Vector3 scale)

Sets the scale factors ({1, 1, 1} by default), animating when a scale transition is set.

center_point

Vector3 center_point() const

The pivot for rotation and scale, relative to the element's top-left corner.

set_center_point

void set_center_point(Vector3 center)

Sets the pivot for rotation() and scale(), DIPs from the top-left corner.

current_opacity

float current_opacity() const

The values as drawn this frame: the property, or a running animation or transition's value. An ExpressionAnimation that reads another element should read these.

current_translation

Vector3 current_translation() const

As current_opacity(), for translation().

current_rotation

float current_rotation() const

As current_opacity(), for rotation().

current_scale

Vector3 current_scale() const

As current_opacity(), for scale().

current_center_point

Vector3 current_center_point() const

As current_opacity(), for center_point().

set_opacity_transition

void set_opacity_transition(std::optional<ScalarTransition> transition)

An implicit transition for set_opacity(). While one is set, every later change to that property animates from the value on screen (see ScalarTransition and Vector3Transition in Animation.hpp). nullopt (the default) makes changes immediate.

set_rotation_transition

void set_rotation_transition(std::optional<ScalarTransition> transition)

As set_opacity_transition(), for set_rotation().

set_translation_transition

void set_translation_transition(std::optional<Vector3Transition> transition)

As set_opacity_transition(), for set_translation().

set_scale_transition

void set_scale_transition(std::optional<Vector3Transition> transition)

As set_opacity_transition(), for set_scale().

opacity_transition

std::optional<ScalarTransition> opacity_transition() const

The transition set_opacity() animates through, or nullopt for immediate changes.

rotation_transition

std::optional<ScalarTransition> rotation_transition() const

The transition set_rotation() animates through, or nullopt.

translation_transition

std::optional<Vector3Transition> translation_transition() const

The transition set_translation() animates through, or nullopt.

scale_transition

std::optional<Vector3Transition> scale_transition() const

The transition set_scale() animates through, or nullopt.

start_animation

void start_animation(AnimatedProperty property, Animation animation)

Run animation on one of this element's visual properties. It replaces whatever runs on any of the same components. A finished DoubleAnimation or KeyFrameAnimation that holds its end (the default) writes its last value into the property, and so does a finished spring. An ExpressionAnimation runs until stop_animation().

stop_animation

void stop_animation(AnimatedProperty property)

Stop the animation on property: the components go back to the property's own value.

is_animating

bool is_animating(AnimatedProperty property) const

Whether an animation or implicit transition is running on any component of property.

transitions

const TransitionList& transitions() const

The transitions this element runs itself (Repositioning when layout moves it, Entrance when it is first laid out, ...).

set_transitions

void set_transitions(TransitionList transitions)

Replaces this element's own transitions.

children_transitions

const TransitionList& children_transitions() const

The transitions every child of this element runs, as if each had them itself. Only meaningful on a container.

set_children_transitions

void set_children_transitions(TransitionList transitions)

Replaces the transitions every child runs.

transition_target

const TransitionTargetState& transition_target() const

The transition target (Animation.hpp's TransitionTargetState) as drawn this frame.

set_transition_target

void set_transition_target(const TransitionTargetState& state)

Drive the transition target directly, for an owner that runs its own item transitions (ListView's) and needs no storyboard on the element.

run_transition

void run_transition(TransitionStoryboard storyboard, Callback<void()> on_completed = {})

Play storyboard on the transition target, replacing one already running; on_completed fires once it ends (not when it is replaced), after the target is back at identity. An empty storyboard has nothing to play: it resets the target and calls on_completed at once, inside this call.

transition_running

bool transition_running() const

Whether a transition storyboard is running.

actual_size

Size actual_size() const

The size from the last arrange pass.

actual_offset

Point actual_offset() const

The layout position relative to the parent's (bounds() are window-absolute here).

visual_transform

Matrix visual_transform() const

The transform this element is drawn through, in window coordinates: scale then rotation about center_point(), then translation, then the transition target, about the layout position. Identity for an element whose visual layer was never touched.

add_subscription

void add_subscription(Subscription subscription)

Take ownership of a Subscription so that its lifetime is exactly this node's lifetime. The tree is single-owner and destroyed hierarchically, so a node's subscriptions die with it and a Property can never dispatch into freed memory. A Property dying first is handled inside Subscription itself (core/Property.hpp).

Called by the spec layer's build() for every reactive field; an app writing imperatively may call it directly to tie a hand-made observer to a node's lifetime.

subscription_count

std::size_t subscription_count() const

How many bindings this node holds: a spec that binds N fields produces N subscriptions. Nothing in the framework branches on it.

clear_subscriptions

void clear_subscriptions()

Drop every binding on this node, leaving whatever values were last written in place. Call it to stop tracking the bound properties and drive the control by hand from then on.

add_shortcut

void add_shortcut(Shortcut shortcut)

Add a shortcut scoped to this element. Window offers every key press to the shortcuts of the focused element and then of each of its ancestors, innermost first, before the focused element's own handle_key() sees it, so a Tabs control's Ctrl+T works wherever focus is inside it. A shortcut added here only fires while focus is in its element.

handle_shortcut

virtual bool handle_shortcut(const KeyEvent& e)

Offers e to this element's shortcuts; true when one handled it. Controls with keys of their own that must work from anywhere inside them (Tabs control's Ctrl+Tab) override this, calling the base first.

handle_global_shortcut

virtual bool handle_global_shortcut(const KeyEvent& e)

The shortcuts that fire wherever focus is. The ones a command surface carries are of this kind (a MenuBar's Ctrl+S, a MenuFlyout item's Delete, an AppBarButton's Ctrl+N), so those controls answer here. Window offers a key that no scoped shortcut took to every element in the window, in tree order, when the focused element and its parents did not handle the key themselves (key_override()). Default: none.

set_tool_tip

void set_tool_tip(std::string text)

A plain-text tool tip on any element. Window shows it beside the pointer once the pointer has rested on the element for 800 ms, and hides it on a click, a key or the pointer moving off. ToolTip (ui/dialogs/ToolTip.hpp) stays the way to give a tip arbitrary content or its own placement.

tool_tip_at

virtual std::string tool_tip_at(Point p) const

The tip for window point p, which Window asks for as the pointer moves: tool_tip() unless the control shows a different tip per part (a TableView cell). A change of text while the pointer stays on the control closes the open tip and starts the wait again.

tool_tip

virtual std::string tool_tip() const

The text Window shows; a control whose tip is derived (an AppBarButton's "Save (Ctrl+S)") overrides this.

cursor

std::optional<CursorShape> cursor() const

The cursor shown while the pointer is over this element (or over a descendant that asks for none). nullopt, the default, asks for nothing, so an ancestor's cursor or the control's own cursor_at() decides, and failing everything the pointer is an arrow.

set_cursor

void set_cursor(std::optional<CursorShape> shape)

Sets or clears (nullopt) the cursor; Window picks it up the next time the pointer moves.

cursor_at

virtual std::optional<CursorShape> cursor_at(Point) const

The control's own cursor at p (window-client DIPs, inside bounds()) when set_cursor() has set none: IBeam over a TextBox's text, Hand over a hyperlink, a resize arrow over a splitter. nullopt (the default) leaves it to the ancestors. Window asks the innermost element under the pointer first, then each parent in turn, and the first answer wins.

accessibility

const Accessibility& accessibility() const

The caller-supplied accessible name, description and decorative flag (a spec's .accessibility). automation_name() prefers its name over the control's own text; empty by default, which is right for any control with visible text.

set_accessibility

void set_accessibility(Accessibility accessibility)

Replaces the accessibility information; read by the next automation query.

automation_role

virtual AutomationRole automation_role() const

What screen readers and other assistive tools see of this node: the role, name, help text and children here, and what a client can do with the node through the providers automation_providers() lists (ui/Automation.hpp).

automation_role() is the role this node reports; Group by default.

automation_name

std::string automation_name() const

The accessible name: accessibility().name when the caller set one, otherwise the control's own visible text. Not virtual, like measure(). A control overrides automation_name_fallback() instead.

automation_help_text

std::string automation_help_text() const

The accessible help text a screen reader offers after the name: accessibility().description when the caller set one, otherwise automation_help_text_fallback().

automation_valid

bool automation_valid() const

Whether screen readers hear the value as valid: false while automation_invalid() says the control holds input it reports as wrong.

automation_children

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

The children an automation client sees under this node, immediate children only. A client walks the tree one level at a time, and the parent comes from parent(). Defaults to every child for_each_child() lists. Override it only to show a client something else: the children in a different order, or without parts that are only decoration. A composite that is one automation node lists nothing.

automation_focus

virtual Element* automation_focus() const

While this element has keyboard focus, the node inside it that has it as automation sees it: the row, tab or menu item a control moves its own cursor over with the arrow keys. Screen readers announce that node. nullptr (the default) is this element itself.

automation_is_native_host

virtual bool automation_is_native_host() const

True only for NativeControl (ui/hosting/NativeControl.hpp). Its child HWND answers automation clients itself, so the automation tree (ui/AutomationTree.hpp) leaves it out and treats it as childless, which keeps it from being described twice.

automation_parent_of

virtual Element* automation_parent_of(const Element& child) const

The automation node between this element and its child child, for a container whose automation tree has a level its element tree lacks (a table's cell around a template cell the table owns). nullptr, the default, makes this element the child's automation parent.

measure

Size measure(Size available, const MeasureContext& context) const

Measure the desired size within available. Unbounded (+infinity) on an axis means no limit; 0 is no room. The result is always finite. Applies the margin and the size limits, then calls measure_override() for the control-specific work. Subclasses implement that hook and don't override measure(). Asked again with the same size, measurer and theme while nothing at or below the element was marked DirtyFlags::Measure, it returns what it returned last time without calling measure_override(): a measure_override() must depend on nothing else, or invalidate_measure() whenever that something changes. The context's measurer and theme must outlive the next measure(): a virtualizing container re-measures from arrange() and render() with the ones it was last measured with.

measure

Size measure(Size available, const TextMeasurer& measurer, const Theme& theme = Theme::default_light()) const

measure() with a context of measurer and theme, for measuring a control on its own. The theme defaults to Theme::default_light(), as render()'s does.

parallel_measure_safe

virtual bool parallel_measure_safe() const

Whether this element's measure() may run on a layout worker thread while its siblings are measured on others (ParallelLayout). Default false, so an element nobody checked is always measured on the UI thread.

Answer true only when measure_override() touches nothing but this element's own state, the children it lists in for_each_child() (each of which answers for itself), the measurer and the theme: it builds no children, reads or writes no Property, subscribes to nothing, invalidates nothing, and uses no cache or static shared with other elements. A part it measures without listing it in for_each_child() makes the answer false. The answer is inherited, so a subclass whose measure_override() does more overrides it back.

arrange

void arrange(const Rect& final_rect)

Place the element at its final position and size within final_rect. Applies margin and alignment, then calls arrange_override() to position any children. The default arrange_override() does nothing, since most leaves need only bounds(). measure() is always called before arrange(). Given the rect it was last given, with nothing at or below it measured or marked DirtyFlags::Arrange since, it does nothing.

bounds

const Rect& bounds() const

The rect the last arrange() gave this element, in window-client DIPs (not relative to the parent), after margin and alignment; excludes the margin. Empty before the first layout, and zero-sized while Collapsed.

hit_region

virtual HitRegion hit_region(Point p) const

Classify p (window-client DIPs, inside bounds()) for Window::hit_region_at(). Each element answers for its whole subtree. The default passes the question to the topmost child under the point, of those for_each_child() lists, and answers Client where there is none, so an ordinary tree is Client everywhere and only a subtree that opts in drags the window. TitleBarControl answers Caption for its own background. DragAreaControl answers Caption for everything but the focusable controls inside it.

title_bar_drag_region

std::optional<bool> title_bar_drag_region() const

Whether a press on this element, inside a TitleBar's content, drags the window. nullopt (the default) lets the TitleBar decide: an enabled focusable control takes the press, anything else drags. true drags even over a control (and, on a container, lets its controls drag too unless they say false). false never drags, over this element or anything inside it. Read on every hit test, so a change takes effect at once.

set_title_bar_drag_region

void set_title_bar_drag_region(std::optional<bool> value)

Sets or clears (nullopt) the drag-region override; read by the next hit test.

render

void render(Renderer& renderer, const RenderContext& context) const

Draw this element: nothing while Collapsed or fully transparent, else render_override() through the visual transform and opacity (visual_transform(), current_opacity() times the transition target's). Emits no extra command for an element whose visual layer is at rest, so a still tree renders exactly what render_override() alone would. A container draws each child through this, handing on the context it got.

render

void render(Renderer& renderer, const Theme& theme = Theme::default_light()) const

Draw this element under theme (Theme::default_light() by default): a control drawn on its own, or the root of a tree.

handle_pointer

bool handle_pointer(const PointerEvent& e)

Deliver a pointer event to this element and everything inside it. It is hit-tested once: the topmost Visible, hit-test visible (is_hit_test_visible()) and enabled element under the pointer gets it in pointer_override(), with its position mapped into that element's layout coordinates (through every visual_transform() and map_to_children() on the way), then each parent up to this one, until one returns true. A press that something handled captures the pointer for that element and its parents until the release, so they get the moves and the release wherever the pointer goes. An element the pointer moves off gets a Leave (once the capture is over, if it holds it), and on_pointer_entered()/on_pointer_exited() are raised. Window calls this on its content; a test can call it on any element, which then routes within its own subtree. Returns whether an element handled the event.

on_pointer_entered

void on_pointer_entered(Callback<void()> handler)

The handler for the pointer moving onto or off this element (a press holds neither back; the pointer leaving the window exits). Hit where the element is drawn, as its input is.

on_pointer_exited

void on_pointer_exited(Callback<void()> handler)

The handler for the pointer leaving the element; see on_pointer_entered().

on_got_focus

void on_got_focus(Callback<void()> handler)

The handler for keyboard focus arriving on this element, or on anything inside it, from outside it. Moving focus between two elements inside it raises nothing here. Window raises it once the focused element has been told (set_focused()).

on_lost_focus

void on_lost_focus(Callback<void()> handler)

The handler for keyboard focus leaving this element and everything inside it; see on_got_focus().

handle_wheel

bool handle_wheel(const PointerEvent& e)

A wheel turn, which Window routes through this instead of handle_pointer(): hit-tested like a pointer event, offered to the element under the pointer in wheel_override() and then to each parent until one returns true, so the innermost scrollable region under the pointer scrolls and the page behind it does not. Returns whether an element reacted to it.

handle_key

bool handle_key(const KeyEvent& e)

A key press or release. Window delivers it to the focused element and then to each parent in turn until one handles it; what nothing handles goes on to the shortcuts, a dialog's default button and arrow-key focus moves. Offers a press to on_key_down() first, then calls key_override(); true when either took it.

on_key_down

void on_key_down(Callback<Handling(const KeyEvent&)> handler)

The handler for a key pressed (or repeating) while focus is on this element or inside it, for app code: an Escape that closes a view, arrow keys that page through it. It sees the key before this element's own handling and after that of the elements inside it that have focus. ui::Handled stops the key there; ui::NotHandled, or returning nothing, lets it go on to this element and then to the ones around it. One handler per element; setting another replaces it.

Example:

ui::Property<bool> details_open{true};
auto               view = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
view->on_key_down([&](const ui::KeyEvent& e) {
    if (e.key != ui::Key::Escape) return ui::NotHandled;
    details_open = false;
    return ui::Handled;
});

on_wheel

void on_wheel(Callback<Handling(const PointerEvent&)> handler)

The handler for a wheel turn over this element or one inside it, for app code: Ctrl+wheel to zoom. It sees the turn before this element scrolls and after the elements inside it under the pointer had theirs; e.position is in this element's coordinates, and e.wheel_delta is positive when the wheel turns toward the user (scroll down). ui::Handled stops the turn there; ui::NotHandled, or returning nothing, lets it go on. One handler per element; setting another replaces it.

Example:

ui::Property<float> zoom{1.0f};
auto                tiles = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
tiles->on_wheel([&](const ui::PointerEvent& e) {
    if (!e.modifiers.ctrl) return ui::NotHandled;
    zoom = std::clamp(zoom.get() + (e.wheel_delta < 0 ? 0.1f : -0.1f), 0.5f, 3.0f); // up zooms in
    return ui::Handled;
});

raise_wheel

bool raise_wheel(const PointerEvent& e)

Offers a wheel turn to on_wheel(), then to wheel_override(); true when either took it. What the wheel dispatch calls for each element under the pointer.

handle_text

bool handle_text(const TextInputEvent& e)

Typed text, routed like a key (focused element first, then its parents). Calls text_override() and returns its answer.

handle_text

bool handle_text(std::string_view text)

handle_text() with the text alone.

focusable

virtual bool focusable() const

Whether this element can take keyboard focus (a leaf control opts in).

takes_tab_key

virtual bool takes_tab_key() const

Whether Tab and Shift+Tab reach this element while it has focus, instead of moving focus (a text box that indents). Ctrl+Tab never moves focus either way. Default: false.

take_menu_access

virtual bool take_menu_access(char32_t letter)

Alt or F10 alone (letter 0), or Alt with a letter nothing else used, asks for the menus. The window offers it to each visible, enabled element in tree order until one takes it: a menu bar takes keyboard focus (and opens the menu whose header starts with letter) and returns true. Default: false.

is_focused

bool is_focused() const

Whether this element has keyboard focus: the window's focused element, or a part a composite control draws as focused on its behalf (a ComboBox's text field). Kept by the window.

takes_focus_at

virtual bool takes_focus_at(Point p) const

Whether a press at p (window DIPs) gives this focusable element focus. Window asks it of every stop in the ring and focuses the innermost that says yes, so a stop inside another wins. The default is the whole of bounds(); a control that is one stop for only part of what it covers answers for that part, or a press on non-focusable space inside the rest would focus it (NavigationShell: its menu, not the page it hosts).

focus_visible

bool focus_visible() const

Whether a focused element draws its focus ring: true when the keyboard moved focus, false after a click gave it. Window writes it; a control checks it next to its own focused state when it renders. True by default, so a control focused without a Window draws its ring.

has_focus_within

bool has_focus_within() const

Whether keyboard focus is on this element or on one inside it. A repeater checks it before clearing an element (a focused element stays realized). Kept by Window through note_keyboard_focus(); an element destroyed while focused takes its part of the count with it.

note_keyboard_focus

void note_keyboard_focus(bool focused)

Window's side of has_focus_within(): this element gained or lost keyboard focus.

collect_focusables

virtual void collect_focusables(std::vector<Element*>& out)

Append focusable elements in tab order, so the Window can build a flat focus ring over the whole tree. The default pushes this element when focusable(), then recurses into every child for_each_child() lists. Override it when the ring differs from the children: a composite that is one tab stop pushes only itself, a focus scope stops recursing (see collect_scope_focusables()), a pager leaves out its hidden pages.

selection_group

virtual const void* selection_group() const

The set of choices this control is one of, or nullptr (the default). Focusable controls that return the same pointer act as one group for the keyboard: Tab stops once on the group, on the member whose SelectionItemProvider says it is selected, or else the first. The arrow keys move between the members in tree order, wrapping, and select the one they reach (SelectionItemProvider::select_item()). Ctrl+arrow only moves. Automation clients see each member's position in the set. A RadioButton bound with ui::selects() returns the property it was bound to.

default_focus

virtual Element* default_focus()

The element Window focuses when this becomes the open modal, or nullptr for the first stop in its tab ring. DialogControl picks something in its content first, else its default button.

focus_scope

bool focus_scope() const

Whether this element is a focus scope. By default a container adds its focusable descendants to the window's one flat tab ring (collect_focusables()), so Tab walks the whole tree leaf by leaf. A focus scope is one tab stop instead. Enter steps into it, Tab then cycles only its own inner ring, and Escape steps back out onto the container (Window::enter_focus_scope() and exit_focus_scope()). A navigation pane of fifteen collapsible groups that are scopes is fifteen Tab stops wide instead of eighty.

Off by default, and set per instance: the same Expander can be a grouping box in one layout and a navigable group in another. A control can serve as a scope only if it overrides collect_scope_focusables() (and scope_step() for scopes that navigate items). Setting the flag on a control that overrides neither has no effect, since Window doesn't enter a scope with an empty inner ring.

set_focus_scope

void set_focus_scope(bool scope)

Makes this element a focus scope (or an ordinary, transparent container again); redraws.

bring_into_view

void bring_into_view()

Ask every scrolling ancestor to reveal this element, innermost first. Window calls it whenever focus lands somewhere, because a tab ring that walks into a scrolled-off region would otherwise park focus on something the user cannot see.

start_bring_into_view

void start_bring_into_view(const BringIntoViewOptions& options = {})

Ask every scrolling ancestor to reveal this element (or options.target_rect of it), placed as the options say. Unlike bring_into_view() the whole element is revealed, focus ring or not, and whatever bring_into_view_area() says.

effective_viewport

Rect effective_viewport() const

What the scrolling ancestors (and the window itself, the root's bounds) leave in view around this element, in arranged coordinates, not clipped to the element's own bounds. Empty when an ancestor shows nothing; a huge rect when nothing above the element clips it at all (an element with no parent).

caret_bounds

virtual std::optional<Rect> caret_bounds() const

Where text typed into this element goes, while it has focus: the caret, in arranged coordinates, or nullopt when it takes no text. The platform puts an input method's candidate window and the emoji panel there (Window::caret_bounds()). A control that hands its typing to an inner text box answers with that box's.

bring_into_view_area

virtual std::optional<Rect> bring_into_view_area() const

What bring_into_view() reveals when focus lands here (arranged coordinates), or nullopt to leave every scrolling ancestor where it is. The element decides, the scroller follows.

Override it when the whole element is not what should come into view. A grid that draws all its cards itself has bounds as tall as its content, so revealing them jumps the viewport to the top on every focus gain; it answers with the current card's rect instead, or nullopt when there is none.

reveal_child

virtual Rect reveal_child(const Rect& area, const BringIntoViewOptions& options)

Reveal area (arranged coordinates) and return where it sits after scrolling, so the next ancestor up works with the new position. That makes a scroller nested in a scroller work without a layout pass in between. options places it (start_bring_into_view()); bring_into_view() passes the defaults, the smallest scroll. Default: nothing to reveal, geometry unchanged. Scroll is the only override.

scroll_info

virtual std::optional<ScrollInfo> scroll_info() const

This element's scrolling, or nullopt for one that does not scroll (the default). Scroll, VirtualList and ListView answer.

parent

Element* parent() const

The container this element sits in (non-owning), or nullptr for a root or an element not yet added anywhere.

for_each_child

virtual void for_each_child(ChildVisitor visit) const

Call visit once for each child this element owns, in order (back to front where they overlap). The one override a container needs beyond measure, arrange and render. The default of every tree-wide walk recurses through it (collect_focusables(), the popup walk, clear_dirty(), build_visual_tree(), sync_composition(), sync_native(), tick() and automation_children()), so a custom container that lists its children here gets focus, popups, dirty clearing, ticks, composition, native controls and automation right without forwarding any of them. Default: no children, a leaf.

List the children the walks should reach, normally every one this element owns. A walk that must see a different set overrides that walk alone: a composite that is one tab stop and one automation node, a split view leaving its closed pane out of focus and popups. A control that parks parts (an unselected page, a hidden button) may leave them out here instead and clear them in clear_dirty_override() (and tick them in tick_override()), so a parked part never stays dirty.

Const so the const walks can use it, though it hands out mutable children: they are owned objects of their own, not part of this element's state. A tick can run a handler that adds or removes children, so a container that allows that walks its list by index.

Example:

class Row : public ui::Element
{
    void for_each_child(ui::ChildVisitor visit) const override
    {
        for (const auto& child : children_)
        {
            visit(*child);
        }
    }

    std::vector<std::unique_ptr<ui::Element>> children_;
};

is_dirty

bool is_dirty(DirtyFlags flags = DirtyFlags::All) const

Whether any of flags is set on this node, for this node or, since flags bubble up, for something below it. A new element starts fully dirty.

dirty_flags

DirtyFlags dirty_flags() const

Every dirty flag currently set on this node.

on_screen

bool on_screen() const

Whether the last frame the Window measured drew some of this element inside the client area: false once it is scrolled out of view, clipped away, collapsed, fully transparent or no longer drawn at all. Only an element that called set_screen_tracking() is told; for any other element, and for one no frame has measured yet, this is true.

on_screen_changed

virtual void on_screen_changed(bool on_screen)

Called after a frame in which on_screen() changed, for an element that called set_screen_tracking(). The frame that brings an element back into view calls it with true, so a control that paused its clock off screen restarts it here (request_tick_in() works from it). The default does nothing.

tick

void tick(Duration delta)

What Window::tick() calls on the root with the time elapsed since the last tick. Elements never read a clock themselves. Advances this element's own animations and transitions (its visual layer), runs tick_override(), then ticks every child for_each_child() lists. Not virtual, so the children are always ticked. A handler run by the tick may remove elements. They are kept alive until the tick returns, and a child removed before its turn is skipped.

sync_native

virtual void sync_native(NativeHost& host)

Called by Window after layout/input changes, with sync_composition()'s cadence. The default only recurses into the children (for_each_child()); NativeControl (winui/ui/hosting/NativeControl.hpp) overrides it to place its child window.

sync_spell_checker

virtual void sync_spell_checker(SpellChecker&)

Hands the focused element the spell checker. This is not called tree-wide. Window calls it from set_focus(), right before set_focused(true), and before every key or character, so a field is checked the moment it gains focus. A field keeps the pointer after losing focus (its squiggles stay, and it still re-checks when the checker's generation() moves on). A field that was never focused is never checked. TextBox overrides it. Composites with an internal TextBox (ComboBox/NumberBox/AutoSuggestBox) do not forward it, since none of them hold prose.

handle_context_menu

virtual bool handle_context_menu(std::optional<Point>, ContextMenuHost&)

Window::handle_context_menu() calls this on the focused element when the user right-clicks or presses Shift+F10/the Menu key, after focusing whatever focusable element sits under the pointer, as a pointer Down would. position is the right-click point (window-client DIPs), or nullopt for a keyboard request, where the element picks its own anchor (TextBox: its caret). host is only valid for this call, so show a menu through it here or not at all. Returns whether a menu was shown; default: none.

on_context_requested

void on_context_requested(Callback<Handling(std::optional<Point>)> handler)

The handler for a right-click, Shift+F10 or the Menu key on this element or one inside it. For a right-click Window asks the innermost element under the pointer and then each ancestor, focusable or not; then, and for the keys, the focused element and each ancestor, innermost first, ahead of handle_context_menu(). The handler is the target asked to act: unless it returns ui::NotHandled it has shown something (a MenuFlyout's show_at(), a CommandBarFlyout) and the request goes no further. position is as handle_context_menu()'s. One handler per element; setting another replaces it.

raise_context_requested

virtual bool raise_context_requested(std::optional<Point> position)

Runs the handler set above, if any; whether it took the request. A wrapper that stands in for the element it wraps in the tab ring (a flyout around its anchor) asks that element too.

allow_drop

bool allow_drop() const

Whether this element is a drop target, getting drag_enter()/drag_over()/drag_leave()/drop() while a drag (DragDrop::start()) is over it.

set_allow_drop

void set_allow_drop(bool allow)

Makes the element a drop target (or not); takes effect for the next drag movement.

drag_enter

virtual void drag_enter(const DragEventArgs& e)

The drop events. drag_over() is asked first on the innermost drop target under the pointer, then on its drop targets up the tree until one accepts; every element asked has heard drag_enter() first and hears drag_leave() once the drag is no longer its business. The one that accepted gets drop(). A control overrides them; the defaults run the handlers set with on_drag_enter()/on_drag_over()/on_drag_leave()/on_drop().

drag_enter(): the drag has come over this element; drag_over() follows at once.

drag_over

virtual DragResponse drag_over(const DragEventArgs& e)

The drag is over this element: answer what a drop here would do. Asked when it arrives and at every move. The default runs the on_drag_over() handler, and refuses without one.

drag_leave

virtual void drag_leave(const DragEventArgs& e)

The drag left this element, was canceled over it, or was dropped on another target.

drop

virtual void drop(const DragEventArgs& e)

The pointer was released over this element while its drag_over() accepted. What the drop did is the operation it accepted.

on_drag_enter

void on_drag_enter(Callback<void(const DragEventArgs&)> handler)

The handler the default drag_enter() runs; one per element, setting another replaces it.

on_drag_over

void on_drag_over(Callback<DragResponse(const DragEventArgs&)> handler)

The handler the default drag_over() runs, which answers for the element.

on_drag_leave

void on_drag_leave(Callback<void(const DragEventArgs&)> handler)

The handler the default drag_leave() runs.

on_drop

void on_drop(Callback<void(const DragEventArgs&)> handler)

The handler the default drop() runs.

drag_completed

virtual void drag_completed(DataPackageOperation result)

A drag this element started has ended. result is what the target did (None when the drag was canceled or dropped nowhere).

transition_opacity

virtual float transition_opacity() const

How far this element's own open or close fade has come, 0 (hidden) to 1 (fully shown), as for a Flyout's open and close fade or a DialogControl's open fade. The control advances it in tick_override(). The window draws everything the element shows at this opacity: a popup owner's floating content, or a modal's scrim together with its content, so one fade covers both. Default 1: fully visible, no fade running.

build_visual_tree

void build_visual_tree(VisualTree& tree, VisualId parent_id) const

Add this node, every child for_each_child() lists under it, and then what build_visual_tree_override() adds, into tree under parent_id (InvalidVisualId for the root). Called by Window::layout() after arrange(), so bounds() reflects the just-computed layout. Not virtual, so the children are always reached.

raise_context_requested_in

static bool raise_context_requested_in(Element& root, std::optional<Point> position)

A context request inside a subtree that is not in the tab ring (an item's content, drawn by an items control that is the one tab stop): raised on the innermost visual child of root under position (or on root for a keyboard request) and bubbled to root. Returns whether a handler took it.

Element

Element() = default

Constructs an element with a visual_id() of its own, fully dirty and in no tree.

automation_providers

virtual void automation_providers(AutomationProviders& out)

Lists what a client can do with this node: set out's field for each pattern this control implements now to this, through the provider interface it inherits privately (ui/Automation.hpp). A pattern that only applies in some states is an if. out arrives empty, and nothing is listed by default.

Example:

class Chip final : public ui::Element, private ui::InvokeProvider
{
protected:
    void automation_providers(ui::AutomationProviders& out) override
    {
        out.invoke = this;
    }

private:
    bool invoke() override
    {
        on_click_();
        return true;
    }
    ui::Callback<void()> on_click_;
};

open_popup

void open_popup(PopupRequest request)

Floats request.content above the tree, hung from request.anchor (this element by default), or updates the popup this element has open. Each element has at most one popup; a control that shows several uses several elements. The window places it after every layout, draws it with its shadow over everything else, routes input inside it to it alone, and on a press outside it or Escape calls request.on_dismiss. It closes with close_popup() or when this element is destroyed. Calling it again while open, from arrange_override() for an anchor that moves, lays the popup out again only when something other than the callbacks changed.

close_popup

void close_popup()

Closes the popup open_popup() opened. Nothing when none is open.

bool popup_open() const noexcept

Whether this element has a popup open.

Element

Element(Element&& other) noexcept

Moves a not-yet-parented element (a factory returning a control by value); see the copy operations' comment. Never move an element that is already in a tree (asserted). The new element gets a visual_id() of its own and starts fully dirty; the ElementWatch objects on the source follow it here. What the moved-from element is left with is only fit to be destroyed.

operator=

Element& operator=(Element&&) = delete

Deleted: an element has an identity (its visual id, the watches on it, the handlers that captured it), so assigning one over another has no sensible meaning.

measure_override

virtual Size measure_override(Size available, const MeasureContext& context) const = 0

Implement these instead of measure() and arrange(). The base class has already applied margin, size limits and alignment by the time these run. measure_override() is pure (every concrete Element must size itself); arrange_override() defaults to a no-op since most leaves need nothing beyond having bounds() set, which the base already did.

arrange_override

virtual void arrange_override(const Rect&, const ArrangeContext&)

Position children within the rect arrange() settled on (also in bounds(), window DIPs). Default: nothing, for a leaf.

render_override

virtual void render_override(Renderer& renderer, const RenderContext& context) const = 0

What the control draws, in layout coordinates; render() has already applied the visual layer. A container draws its children through their render(), never their render_override().

pointer_override

virtual bool pointer_override(const PointerEvent& e)

A pointer event for this element: the element under the pointer, one inside it that did not handle the event, or the element holding the capture. The position is in layout coordinates (handle_pointer()). Return true when the event did something here, and it goes no further up; a handled press also captures the pointer until its release. A control that acts on a press (a click, a toggle, a caret placed, a drag started) returns true for the press and its release, so a list row or a card around it does not act on the same click. Default: false.

handled_pointer_override

virtual void handled_pointer_override(const PointerEvent& e)

A pointer event that an element inside this one handled (its pointer_override() returned true), so it never reached this element's pointer_override(). Called on each element above the one that handled it, innermost first, with the position in this element's layout coordinates. A container that has to see every press inside it, handled or not, overrides it: a swipe that may turn a press on a button into a drag, a table that commits an open edit when a check box in another row is pressed. Default: nothing.

wheel_override

virtual bool wheel_override(const PointerEvent& e)

A wheel turn over this element (handle_wheel()). Return true when it scrolled something here. Default: an element with no children hands it to pointer_override() and returns false; one with children returns false.

hit_test_children

virtual void hit_test_children(Point p, std::vector<Element*>& out) const

The children p (in this element's layout coordinates) is tested against, topmost first. Default: what for_each_child() lists, last first. A container that draws in another order (Panel's z-index), a control with parts for_each_child() does not list, or one whose parts cover others in places (a pane drawn over the content) lists them here.

map_to_children

virtual Point map_to_children(Point p) const

A point in this element's layout coordinates, mapped into its children's: a control that scrolls, zooms or scales its content maps it the way the content is drawn. Default: the point unchanged.

children_hit_clip

virtual std::optional<Rect> children_hit_clip() const

Where the children can be hit, in this element's layout coordinates, or nullopt for anywhere (the default): a scrolling control returns its viewport, so content scrolled out of view is not hit.

hit_test_transparent

virtual bool hit_test_transparent() const

Whether the pointer passes through this element and everything in it to what is behind, as if it were not there: a wrapper with nothing visible in it (ContentHost while its child is missing or collapsed). Default: false, so an element is hit anywhere in its bounds.

covers_children_at

virtual bool covers_children_at(Point p) const

Whether a part of this element drawn over its children is at p (a scroll bar over the content), so the element is hit there instead of a child. Default: false.

capture_pointer

void capture_pointer()

Capture the pointer of the event being handled: keep receiving its events, wherever it goes, until release_pointer() or the release of the button. A handled press does this by itself. Only while handling a pointer event.

release_pointer

void release_pointer()

End a capture_pointer() or the capture a press took.

tick_override

virtual void tick_override(Duration delta)

This element's own part of tick(): a clock of its own (ToolTip's hover delay, an animation's phase, a caret blink). Runs after the visual layer has advanced and before the children are ticked, which tick() does by itself. Tick only parts that for_each_child() does not list here. Default: nothing.

clear_dirty_override

virtual void clear_dirty_override(DirtyFlags flags)

This element's own part of clear_dirty(): clear any part it owns but leaves out of for_each_child() (a parked page, a hidden button), through that part's clear_dirty(). Default: nothing.

build_visual_tree_override

virtual void build_visual_tree_override(VisualTree& tree) const

This element's own part of build_visual_tree(): add any part it owns but leaves out of for_each_child() through that part's build_visual_tree(tree, visual_id()). Default: nothing.

collect_scope_focusables

virtual void collect_scope_focusables(std::vector<Element*>&)

The inner tab ring, built when this scope is entered: a scope's counterpart to collect_focusables(). A container that becomes a scope must stop recursing in collect_focusables() and recurse here instead (Expander is the worked example), since a child in both rings would be reachable without ever entering.

Three meaningful answers: - several elements: an ordinary container scope. Tab cycles them, Escape leaves. - this alone: an item-navigating scope. The control's items are not all elements (ListView creates its rows on demand and destroys them as they scroll out), so focus stays on the control and Tab is routed to scope_step() below. - nothing: there is nothing inside worth entering. Window doesn't enter, and the key that would have entered goes to this element's own handle_key(). That is how Enter expands a collapsed Expander that is marked as a scope.

The one walk that does not default to recursing through for_each_child(): being a scope is something a control opts into, and a default inner ring would make every container enterable while its children still sat in the outer ring too.

scope_step

virtual bool scope_step(int)

Move an item-navigating scope's own inner cursor one step: delta is +1 for Tab and -1 for Shift+Tab. Wrap and return true to keep focus inside the scope (Escape is then the way out, as for an ordinary container scope). Return false to let the step fall out, popping the scope and leaving focus on this control. Never called for a scope whose inner ring is real elements, since Window walks that ring itself.

set_scope_entered

virtual void set_scope_entered(bool)

Called by Window as this scope is entered (before its inner ring takes focus) and again as it is left, so a control can show and hide whatever inner cursor it draws. A container scope whose inner ring is real Elements usually needs nothing here, since the focused child draws its own focus ring, as it would anywhere else.

take_focus_request

virtual FocusRequest take_focus_request()

For a part of the main tree that takes focus when it opens, as SidePane's light-dismissable pane does. It holds the tab ring while open (by answering collect_focusables() with the pane alone) and hands focus back when it closes. Returning a request consumes it; the default never asks. Escape reaches it like any key the focused element inside it leaves alone (key_override()).

focus_request_root

virtual Element* focus_request_root()

The subtree an Enter request focuses into; this by default.

draws_focus_ring

virtual bool draws_focus_ring() const

Whether the window draws this element's focus ring while it is focusable(), is_focused() and focus_visible(). True by default, so a focusable control gets the ring by doing nothing. The window draws it after everything else in the window, or in the popup the element is in, clipped only by the scrolling viewports around the element, and layout never makes room for it. The theme decides where it goes: the Fluent eras draw their two rings just outside focus_ring_rect(), the classic eras their dotted rectangle just inside. Return false only for a control that shows focus in a shape of its own (a text field's accent border) or not at all.

focus_ring_rect

virtual Rect focus_ring_rect(const Theme& theme) const

What the ring goes around, in window DIPs: bounds() by default. A control whose ring goes around one part of it (a slider's thumb, a list's current row) returns that part. theme is the one the element is drawn with, for a ring placed differently in each era.

focus_ring_inside

virtual bool focus_ring_inside() const

Whether the ring goes inside focus_ring_rect() in every era, its outer edge on the rect. False by default, which leaves it to the theme. An item inside a viewport (a list row, a tab, a menu item) returns true, as does a control in a tight spot, so a neighbor or the viewport edge never cuts its ring.

focus_ring_corner_radius

virtual float focus_ring_corner_radius(const Theme& theme) const

The ring's corner radius: the theme's control radius by default.

key_override

virtual bool key_override(const KeyEvent& e)

A key for this element: the focused one, or one inside it that did not handle it. Return true when the key did something here, and it goes no further; false lets it bubble on to the parent and then to the shortcuts, a dialog's default button and arrow-key focus moves. Default: false.

text_override

virtual bool text_override(const TextInputEvent& e)

Typed text for this element, routed like key_override(). Default: false.

focus_changed

virtual void focus_changed(bool focused)

Keyboard focus arrived (true) or left (false); is_focused() already says so. The element is redrawn either way. No-op by default.

focus_visible_changed

virtual void focus_visible_changed(bool visible)

focus_visible() changed; the element is redrawn either way. No-op by default.

enabled_changed

virtual void 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.

set_enabled_gate

void set_enabled_gate(bool open)

A condition of the control's own that is ANDed into is_enabled() (a Button whose command may not run). True by default.

attached

virtual void attached()

The element joined a window's tree: window() is now that window. Called for the root a window takes and for everything inside it, and for a subtree added to a tree already in a window. No-op by default.

detached

virtual void detached()

The element left a window's tree (moved out of it). No-op by default.

automation_name_fallback

virtual std::string automation_name_fallback() const

automation_name()'s fallback when accessibility().name is empty. Default: no inherent name, correct for controls with no visible text of their own (Slider, ProgressBar), which need an explicit accessibility().name from the caller. A control with its own visible text (Button, CheckBox, TextControl, ...) overrides this to return it.

automation_help_text_fallback

virtual std::string automation_help_text_fallback() const

automation_help_text()'s fallback when accessibility().description is empty. Default: none. An input with a description under it returns that text, or its error while set.

automation_invalid

virtual bool automation_invalid() const

True while the control holds input it reports as wrong (an input's error is set); screen readers say so. Default: false.

mark_dirty

void mark_dirty(DirtyFlags flags, std::source_location where = std::source_location::current())

Mark this node dirty and bubble the newly set bits up the parent chain, so an ancestor's flags show that something below it changed without walking the subtree. Bubbling stops at the first ancestor that already has the bit, since every ancestor of a dirty node is dirty in the same way.

Every setter goes through here, so this is where a build with thread checks catches a setter called on an element under a Window from another thread than the window's. Leave where defaulted: it names the setter that called this.

invalidate_measure

void invalidate_measure(std::source_location where = std::source_location::current())

This element's size has to be measured again (and it arranged again): mark_dirty() with DirtyFlags::Layout. For a setter whose value changes the element's desired size.

invalidate_arrange

void invalidate_arrange(std::source_location where = std::source_location::current())

This element has to be arranged again, its size has not changed: mark_dirty() with DirtyFlags::Arrange. For a setter that only moves the element or its children within the space they already have (an alignment, a scroll position that is laid out).

request_tick

void request_tick()

Keep the window ticking: for an element that waits for time to pass without changing anything in the meantime (a caret between blinks, a delay before something opens). A window stops ticking a few seconds after its last tick that changed something, so a longer quiet wait calls this from tick_override() for as long as it lasts. A wait of known length is cheaper with request_tick_in().

request_tick_in

void request_tick_in(Duration delay)

Have the window tick again delay from now (0 or less: at once), for an element whose next change has a known time (the next frame of an animated image). Unlike request_tick() it does not keep the window busy: an otherwise idle window sleeps until then and wakes only for it (Window::next_wake()). Call it from tick_override() or on_screen_changed(). It holds for one tick, so an element that still waits asks again from its next tick_override(), which may come sooner. A hidden or minimized window does not wake for it.

What the same tick_override() changes with mark_dirty() is that step's change (a caret blink, an image's next frame): it is drawn, and it does not make the window busy either. A tick_override() that also animates something calls request_tick() as well, or the window waits for the requested time before its next tick.

set_screen_tracking

void set_screen_tracking(bool on)

Have the Window report on_screen() for this element and call on_screen_changed() when it changes, from the frames it measures from now on. Off by default, and free while off. A control turns it on while its drawing moves on its own (an animated image), to pause while nobody can see it. Turning it off makes on_screen() true again.

check_thread

void check_thread(std::source_location where = std::source_location::current()) const

mark_dirty()'s thread check without the dirtying, for a setter that changes nothing drawn (an event handler, a tip): reports a call from another thread than the one of the Window this element is under. Leave where defaulted: it names the setter that called this.

note_child_deleted

void note_child_deleted()

For a container whose child just started an AddRemoveTransition exit. In the next arrange the children it moves close the gap only once that exit has played, and a child added in the same pass fades in after them, so neither slides over the one still leaving. A RepositionTransition on those children gives way to it for that pass.

desired_content_size

Size desired_content_size() const

What the last measure asked for, without the margin: how large the content is, where bounds() may be the larger slot a stretching parent gave it.

set_parent_of

static void set_parent_of(Element& part, Element* parent)

Record parent as the container part sits in (nullptr: none), when a container adds a child or a part of its own. Dirty flags bubble up this link, and the new parent chain takes on the part's dirty flags and keyboard focus (has_focus_within()) while the old one lets go of the focus, so a container that adopts a dirty part is laid out again without marking itself. Not an ownership transfer: the container already holds the part's unique_ptr.

clear_dirty_of

static void clear_dirty_of(Element& part, DirtyFlags flags = DirtyFlags::All)

Clear flags on part and its subtree, for a clear_dirty_override() clearing a part this element leaves out of for_each_child().

set_focused_of

static void set_focused_of(Element& part, bool focused)

Show part focused or not, for a composite that draws one of its parts as focused while it holds the focus itself (a ComboBox's text field). Hand focus_visible() on with set_focus_visible_of() too, or the part keeps drawing its ring after a click.

set_focus_visible_of

static void set_focus_visible_of(Element& part, bool visible)

Hand the focus-visible state on to a part; see set_focused_of().

key_handled

static bool key_handled(const KeyEvent& e, bool arrow, bool enter, bool shortcut)

The usual answer for a focused control's key_override(): an arrow when arrow (the control uses that arrow), Enter when enter, a shortcut-like key (Ctrl, Alt, Delete, Insert, a function key) when shortcut, never Tab or Escape, and any other key (typing, Space, Home, PageDown) always, since a focused control owns its plain keys.

struct ScrollInfo

What a scrolling element tells something that follows its scrolling, such as a Parallax.

Field Type Default
offset Point how far the view is scrolled into the content (zoomed DIPs)
viewport Size the view's size
extent Size the content's size, unzoomed
zoom float 1.0f the zoom factor; 1 unzoomed
out_of_bounds_pan Size How far past either end the content can be pulled: a tenth of the viewport for a plain scroller, a whole viewport for a zoomable one.
content const Element* nullptr The element that is the content, whose top-left is the content's origin; nullptr when the content is not one element (a list's realized rows).