Skip to content

Rating

Header: winui/ui/input/Rating.hpp. Spec: winui/ui/input/Rating.hpp.

A row of stars the user rates with a click, a drag or the keyboard.

value() is unset until something is rated, then a number in [1, max_rating()]. Interaction always commits a whole number, and a click or drag commits only on release (the stars preview the pointer meanwhile; dragging off the left edge and releasing clears). Clicking the star that already is the rating clears it while is_clear_enabled(). A fractional value set by the app is drawn as a clipped partial star, and a placeholder_value() (say, the average of other users' ratings) is shown while the user has not rated. set_read_only() stops user input but keeps the full-strength look and the tab stop. ui::Rating is the declarative form.

Example:

ui::Property<std::optional<double>> stars;

window.set_content(ui::Rating{
    .value             = stars,
    .placeholder_value = 3.5,            // the community average, until the user rates
    .caption           = "312 ratings",
    .horizontal_alignment           = ui::Alignment::Leading,
    // stars is unset again when cleared
});

// Imperatively, a read-only average:
auto average = std::make_unique<ui::RatingControl>(/*max_rating=*/5, /*value=*/4.5);
average->set_read_only(true);
average->set_caption("4.5 average");

ui::Rating

A star rating. Builds a ui::RatingControl.

Example:

ui::Property<std::optional<double>> stars{3.0};

window.set_content(ui::Rating{
    .value                = stars,
    .caption              = "312 ratings",
    .horizontal_alignment = ui::Alignment::Leading,
});

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

ui::Rating{
    .value, .max_rating, .placeholder_value, .clear_enabled, .initial_set_value, .caption,
    .read_only, .style, .margin, .width, .height, .min_width, .min_height, .max_width,
    .max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .enabled,
    .accessibility, .on_value_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
value ui::TwoWayField<std::optional<double>> The rating; unset until rated.
max_rating ui::Binding<std::size_t> {5} The number of stars.
placeholder_value ui::Binding<std::optional<double>> A grayed hint shown while value is unset; never raises a change.
clear_enabled ui::Binding<bool> {true} Clicking the star that is the current rating clears it.
initial_set_value ui::Binding<int> {1} Where a keyboard step lands from an unset value (at least 1).
caption ui::Binding<std::string> The decorative label right of the stars ("312 ratings"). Empty draws none.
read_only ui::Binding<bool> {false} Ignores input but keeps the enabled look and the tab stop (ui::RatingControl::set_read_only).
on_value_changed ui::Callback<void(std::optional<double>)> The new rating (unset when cleared), from input or a bound value.
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::Rating> 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::RatingControl; the caller owns it.

ui::RatingControl

Derives from ui::Element, ui::RangeValueProvider.

A row of stars the user rates with a click, a drag or the keyboard.

value() is unset until something is rated, then a number in [1, max_rating()]. Interaction always commits a whole number, and a click or drag commits only on release (the stars preview the pointer meanwhile; dragging off the left edge and releasing clears). Clicking the star that already is the rating clears it while is_clear_enabled(). A fractional value set by the app is drawn as a clipped partial star, and a placeholder_value() (say, the average of other users' ratings) is shown while the user has not rated. set_read_only() stops user input but keeps the full-strength look and the tab stop. ui::Rating is the declarative form.

Example:

ui::Property<std::optional<double>> stars;

window.set_content(ui::Rating{
    .value             = stars,
    .placeholder_value = 3.5,            // the community average, until the user rates
    .caption           = "312 ratings",
    .horizontal_alignment           = ui::Alignment::Leading,
    // stars is unset again when cleared
});

// Imperatively, a read-only average:
auto average = std::make_unique<ui::RatingControl>(/*max_rating=*/5, /*value=*/4.5);
average->set_read_only(true);
average->set_caption("4.5 average");

RatingControl

RatingControl(std::size_t max_rating = 5, std::optional<double> value = std::nullopt)

A row of max_rating stars (at least 1) holding value, coerced like set_value().

max_rating

std::size_t max_rating() const

The number of stars; 5 by default.

set_max_rating

void set_max_rating(std::size_t max_rating)

Clamped to >= 1. Re-clamps value()/placeholder_value() into the new range, firing on_value_changed() only if that moves value().

value

std::optional<double> value() const

Unset until rated, otherwise a value in [1, max_rating()] (interaction always lands on a whole number within that range; a fraction is reachable only via set_value()).

set_value

void set_value(std::optional<double> value)

Sets or clears the rating. A value up to 1 rounds up to 1.0, anything above max_rating() clamps down to it. Does nothing, and fires no callback, if the result is the current value.

placeholder_value

std::optional<double> placeholder_value() const

Unset by default. A grayed preview, such as an average rating, shown only while value() is unset and the pointer is not over the control.

set_placeholder_value

void set_placeholder_value(std::optional<double> value)

Clamped to [0, max_rating()], keeping 0 and fractions below 1 as they are, since a placeholder is a display hint. No-op if unchanged; never fires on_value_changed.

is_clear_enabled

bool is_clear_enabled() const

Whether clicking the current rating's star clears it; true by default.

set_clear_enabled

void set_clear_enabled(bool enabled)

Whether clicking the star already representing the current rating clears it (default: true).

initial_set_value

int initial_set_value() const

Where a keyboard step lands from an unset value; 1 by default.

set_initial_set_value

void set_initial_set_value(int value)

The rating a keyboard/gamepad step lands on when stepping from an unset value() (default: 1). Clamped to >= 1.

caption

const std::string& caption() const

The label right of the stars; empty by default.

set_caption

void set_caption(std::string caption)

A decorative label shown to the right of the stars. No interaction reads it. Empty (the default) draws no caption and reserves no width for one.

read_only

bool read_only() const

Whether user input is ignored; false by default. Independent of enabled().

set_read_only

void set_read_only(bool read_only)

Ignores pointer and keyboard input while keeping the enabled look and the tab stop, so a screen reader still reaches the rating. set_value() still works. Turning it on drops any hover or drag preview in progress.

on_value_changed

void on_value_changed(Callback<void(std::optional<double>)> handler)

Fired whenever value() changes: a click/drag release, a keyboard step, or set_value() alike, including clearing it (unset).

focused

bool focused() const

Whether the control has keyboard focus.

focusable

bool focusable() const override

A tab stop while enabled, read-only or not.

hovered

bool hovered() const

Whether the pointer is over the control, which shows the hover preview.

automation_role

AutomationRole automation_role() const override

Custom, with a range value, since UI Automation has no rating role. An unset rating reports 0, because a range value cannot be unset.

measure_override

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

A fixed-size row: max_rating() star-sized cells plus (max_rating() - 1) item-spacing gaps between them, plus caption()'s measured width and a 4 DIP gap when non-empty. value() and hover never change it.

pointer_override

bool pointer_override(const PointerEvent& e) override

Hover and drag update the preview; a left-button release commits the star under the pointer (clamped, so releasing past the left edge clears). Ignored while read-only.

render_override

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

Draws the outline stars, the filled (possibly partial) stars for the preview, value or placeholder, the caption and the focus ring.

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 focused) override

Marks the control for redraw (the focus ring).

key_override

bool key_override(const KeyEvent& e) override

Up/Right add a star and Down/Left remove one (from an unset value, the first step lands on initial_set_value()); Home goes to 0 (clearing, or 1 when clearing is disabled) and End to max_rating(). Ignored while read-only.

Tests

  • tests/test_rating.cpp