Skip to content

PersonPicture

Header: winui/ui/media/PersonPicture.hpp. Spec: winui/ui/media/PersonPicture.hpp.

A circular avatar showing a photo, initials or a placeholder glyph, with an optional badge. It takes no input and never receives focus.

What it shows, in priority order: - the "People" glyph when is_group() is true, even over a set photo - the profile_picture(), clipped to the circle - effective_initials() - the "Contact" glyph

The badge is an accent-filled circle in the top-right corner, at half the picture's size. It shows a positive badge_number(), as "99+" past 99, or else the badge_icon(). Screen readers hear the person's name followed by ", N items", ", icon" or badge_text(). The name is "Group", the display name, the initials or "Person". ui::PersonPicture is the declarative form.

Example:

window.set_content(ui::HorizontalStack{
    .spacing  = 12,
    .content  = {
        ui::PersonPicture{.display_name = "Jane Doe"},  // shows "JD"
        ui::PersonPicture{.display_name = "Jane Doe", .badge_number = 5, .width = 72.0f},
        ui::PersonPicture{.group        = true},              // the People glyph
    },
});

// Imperatively:
auto avatar = std::make_unique<ui::PersonPictureControl>();
avatar->set_display_name("Alex Wilber");
avatar->set_diameter(48.0f);
avatar->set_badge_number(3);
avatar->set_badge_text("3 unread messages"); // spoken instead of ", 3 items"

ui::PersonPicture

A circular avatar with an optional number, glyph or picture badge. It shows a photo, initials or a placeholder glyph, picked in the order ui::PersonPictureControl describes. Builds a ui::PersonPictureControl.

The pictures can be bound like every other field. A Binding doesn't compare its values, only a Property does, so bind a picture through a conversion from another property: bind(choice, [](int i) { ... }).

Example:

ui::Property<int> unread{3};

window.set_content(ui::HorizontalStack{.spacing = 12, .content = {
    ui::PersonPicture{.display_name    = "Jane Doe"}, // shows "JD"
    ui::PersonPicture{.diameter        = 48.0f,
                      .display_name    = "Alex Wilber",
                      .profile_picture = ui::Bitmap::read("alex.png"),
                      .badge_number    = unread,
                      .badge_text      = ui::bind(unread, [](int n) { return std::format("{} unread", n); })},
    ui::PersonPicture{.group           = true},
}});

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

ui::PersonPicture{
    .diameter, .display_name, .initials, .group, .profile_picture, .badge_number, .badge_icon,
    .badge_text, .style, .margin, .width, .height, .min_width, .min_height, .max_width,
    .max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip,
    .accessibility, .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
diameter ui::Binding<float> {96.0f} The circle's diameter in DIPs, at least 1.
display_name ui::Binding<std::string> The person's name. Read by screen readers, and the source of the initials when initials is empty.
initials ui::Binding<std::string> Initials to show in place of ones derived from display_name.
group ui::Binding<bool> {false} Shows the "People" glyph, over every picture and initial.
profile_picture ui::Binding<ui::Bitmap> The photo, clipped to the circle. Shown in place of the initials.
badge_number ui::Binding<int> {0} The badge number, shown when positive, as "99+" past 99.
badge_icon ui::Binding<ui::IconSource> The badge icon, shown when the number isn't: a Symbol, a glyph, a path or a picture.
badge_text ui::Binding<std::string> What screen readers hear in place of the default ", N items" or ", icon".
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::PersonPicture> 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, accessibility every spec carries (conventions).

build

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

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

ui::PersonPictureControl

Derives from ui::Element.

A circular avatar showing a photo, initials or a placeholder glyph, with an optional badge. It takes no input and never receives focus.

What it shows, in priority order: - the "People" glyph when is_group() is true, even over a set photo - the profile_picture(), clipped to the circle - effective_initials() - the "Contact" glyph

The badge is an accent-filled circle in the top-right corner, at half the picture's size. It shows a positive badge_number(), as "99+" past 99, or else the badge_icon(). Screen readers hear the person's name followed by ", N items", ", icon" or badge_text(). The name is "Group", the display name, the initials or "Person". ui::PersonPicture is the declarative form.

Example:

window.set_content(ui::HorizontalStack{
    .spacing  = 12,
    .content  = {
        ui::PersonPicture{.display_name = "Jane Doe"},  // shows "JD"
        ui::PersonPicture{.display_name = "Jane Doe", .badge_number = 5, .width = 72.0f},
        ui::PersonPicture{.group        = true},              // the People glyph
    },
});

// Imperatively:
auto avatar = std::make_unique<ui::PersonPictureControl>();
avatar->set_display_name("Alex Wilber");
avatar->set_diameter(48.0f);
avatar->set_badge_number(3);
avatar->set_badge_text("3 unread messages"); // spoken instead of ", 3 items"

PersonPictureControl

PersonPictureControl() = default

A 96 DIP placeholder avatar (the "Contact" glyph) with no badge.

diameter

float diameter() const

The size when no width or height is set, in DIPs. 96 by default.

set_diameter

void set_diameter(float diameter)

Sets the diameter, at least 1 DIP. Updates layout and redraws.

effective_diameter

float effective_diameter() const

The size the picture is drawn at. It is diameter() until an explicit width or height is set, then that one, or the smaller when both are, so the picture stays round.

display_name

const std::string& display_name() const

The person's name. The initials and the accessible name are derived from it.

set_display_name

void set_display_name(std::string name)

Sets the display name. Redraws.

initials

const std::string& initials() const

Explicit initials. When not empty, they replace the initials derived from display_name() (see effective_initials()).

set_initials

void set_initials(std::string initials)

Sets the explicit initials. Redraws.

is_group

bool is_group() const

Whether the picture shows the "People" glyph, even over a set profile picture.

set_group

void set_group(bool group)

Turns the group glyph on or off. Redraws.

profile_picture

const Bitmap& profile_picture() const

A decoded photo, drawn clipped to the circle. An empty Bitmap, the default, falls back to the initials.

set_profile_picture

void set_profile_picture(Bitmap picture)

Sets the photo. Redraws.

badge_number

int badge_number() const

The badge number. 0 or less shows no number.

set_badge_number

void set_badge_number(int number)

Sets the badge number. Measures and redraws, since the badge widens for "99+".

badge_icon

const IconSource& badge_icon() const

The badge icon, shown while badge_number() isn't: a Symbol, a glyph, a path or a picture. It is drawn at 60% of the badge's size in the badge's text color, and a picture keeps its own colors. Empty shows no icon.

set_badge_icon

void set_badge_icon(IconSource icon)

Sets the badge icon. Redraws.

badge_text

const std::string& badge_text() const

What screen readers hear in place of ", N items" or ", icon".

set_badge_text

void set_badge_text(std::string text)

Sets the badge text. It changes only the accessible name, so nothing is redrawn.

badge_content

std::string badge_content() const

The number the badge shows, "99+" past 99. Empty when it shows the icon or nothing.

has_badge

bool has_badge() const

Whether any badge shows.

badge_bounds

Rect badge_bounds() const

Where the badge is drawn for the current bounds: in the top-right corner, half the picture's size tall, moved 4 DIPs up and right. A circle, widened to the left into a pill when the number doesn't fit in one.

effective_initials

std::string effective_initials() const

initials() if set, else initials_from_display_name(display_name()).

automation_role

AutomationRole automation_role() const override

Exposed to UI Automation as text.

automation_name_fallback

std::string automation_name_fallback() const override

"Group", else the display name, else the initials, else "Person", followed by ", N items", ", icon" or badge_text() for a badge.

initials_from_display_name

static std::string initials_from_display_name(std::string_view display_name)

The initials for display_name. For a name in Latin, Cyrillic or a similar script, these are the first characters of the first and last words, upper-cased. A single word gives one initial. A trailing (…), […] or {…} is dropped first, leading punctuation is skipped and combining marks stay with their letter. A name that starts in a script where initials mean nothing, such as CJK, Arabic, Indic or Thai, gives none.

measure_override

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

A square of effective_diameter(), clipped to available on a bounded axis.

render_override

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

Draws the circle with its photo, initials or glyph, then the badge.

Tests

  • tests/test_person_picture.cpp