NumberBox¶
Header: winui/ui/text/NumberBox.hpp. Spec: winui/ui/text/NumberBox.hpp.
A text box for a number, validated and formatted when committed. It can have spin buttons, arithmetic input, stepping by keyboard and wheel, and a header.
value() is the number that counts. The user can type anything, and the text is committed on Enter, on losing focus and before each step. Text that parses is clamped to [min, max] and formatted again. Text that doesn't is replaced by the last value's text. An unset value (the default) means no number, and the box is empty and shows the placeholder. The box is one focus stop and owns its inner TextBox. In a spec tree it is built by ui::NumberBox.
Example:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
double quantity = 5.0;
auto box = std::make_unique<ui::NumberBoxControl>(/*value=*/5.0, /*min=*/0.0, /*max=*/100.0);
box->set_header("Quantity");
box->set_spin_button_placement(ui::NumberBoxSpinButtonPlacementMode::Inline);
box->set_step(1.0);
box->set_large_step(10.0);
box->set_accepts_expression(true); // "2 * 3" commits 6
box->set_number_formatter(ui::DecimalFormatter{.fraction_digits = 2});
box->on_value_changed([&](std::optional<double> v) { quantity = v.value_or(0.0); });
ui::NumberBoxControl* quantity_box = stack->add(std::move(box));
// Or declaratively:
ui::Property<std::optional<double>> price{9.5};
stack->add(ui::NumberBox{
.header = "Price",
.placeholder_text = "0.00",
.value = price,
.min = 0.0,
.spin_button_placement = ui::NumberBoxSpinButtonPlacementMode::Compact,
}.build());
ui::NumberBox¶
A numeric field, with spin buttons when asked for. Builds a ui::NumberBoxControl.
Typed text is committed on Enter or when focus leaves. It is parsed, or evaluated with .accepts_expression, clamped to [min, max] and reported through .on_value_changed. A bound value outside [min, max] is clamped too, and a two-way property gets the clamped value written back. The arrow keys, the wheel and the spin buttons step by .step.
Example:
ui::Property<std::optional<double>> quantity{1.0};
window.set_content(ui::NumberBox{
.header = "Quantity",
.value = quantity,
.min = 0.0,
.max = 99.0,
.spin_button_placement = ui::NumberBoxSpinButtonPlacementMode::Inline,
.accepts_expression = true,
});
Every field, in the order a designated initializer names them:
ui::NumberBox{
.header, .description, .error, .placeholder_text, .value, .min, .max, .step, .large_step,
.spin_button_placement, .accepts_expression, .number_formatter, .validation_mode,
.wrap_enabled, .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_text_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 | |
|---|---|---|---|
header |
ui::Binding<std::string> |
The label above the control. Empty draws none. | |
description |
ui::Binding<std::string> |
Secondary text under the box, such as what to enter or why; empty draws none. Screen readers offer it as help text. | |
error |
ui::Binding<std::string> |
What is wrong with the value: non-empty shows it in the description's place in the critical color and draws the border in that color, and screen readers report the field invalid. The field shows exactly what it is given, so bind it to a check of the value and decide there when it shows (after the first submit, say). | |
placeholder_text |
ui::Binding<std::string> |
The hint shown while the box is empty. | |
value |
ui::TwoWayField<std::optional<double>> |
Unset (the default) is no number: an empty box showing the placeholder. | |
min |
double |
-std::numeric_limits<double>::infinity() |
Minimum; committed values below it are clamped. Unbounded by default. |
max |
double |
std::numeric_limits<double>::infinity() |
Maximum; committed values above it are clamped. Unbounded by default. |
step |
ui::Binding<double> |
{1.0} |
What the arrow keys and spin buttons step by; 0 disables stepping. |
large_step |
ui::Binding<double> |
{10.0} |
What PageUp and PageDown step by. |
spin_button_placement |
ui::Binding<ui::NumberBoxSpinButtonPlacementMode> |
{ui::NumberBoxSpinButtonPlacementMode::Hidden} |
Where the spin buttons show; Hidden by default. |
accepts_expression |
ui::Binding<bool> |
{false} |
Typed arithmetic is evaluated. |
number_formatter |
ui::Binding<std::optional<ui::DecimalFormatter>> |
Formats the value and parses the text. Unset keeps the default: ten significant digits, no padding. | |
validation_mode |
ui::Binding<ui::NumberBoxValidationMode> |
{ui::NumberBoxValidationMode::InvalidInputOverwritten} |
What happens to input that does not parse. By default it is overwritten with the last valid value. |
wrap_enabled |
ui::Binding<bool> |
{false} |
When true, a step past max lands on min, and a step past min lands on max. |
on_value_changed |
ui::Callback<void(std::optional<double>)> |
Fires whenever the value changes, from a committed edit, a spin button or an arrow key step. | |
on_text_changed |
ui::Callback<void(const std::string&)> |
Fires on every user edit with the raw, not yet parsed text. | |
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::NumberBox> |
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¶
Consumes the spec and returns the built ui::NumberBoxControl; the caller owns it.
ui::NumberBoxControl¶
Derives from ui::Element, ui::RangeValueProvider.
A text box for a number, validated and formatted when committed. It can have spin buttons, arithmetic input, stepping by keyboard and wheel, and a header.
value() is the number that counts. The user can type anything, and the text is committed on Enter, on losing focus and before each step. Text that parses is clamped to [min, max] and formatted again. Text that doesn't is replaced by the last value's text. An unset value (the default) means no number, and the box is empty and shows the placeholder. The box is one focus stop and owns its inner TextBox. In a spec tree it is built by ui::NumberBox.
Example:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
double quantity = 5.0;
auto box = std::make_unique<ui::NumberBoxControl>(/*value=*/5.0, /*min=*/0.0, /*max=*/100.0);
box->set_header("Quantity");
box->set_spin_button_placement(ui::NumberBoxSpinButtonPlacementMode::Inline);
box->set_step(1.0);
box->set_large_step(10.0);
box->set_accepts_expression(true); // "2 * 3" commits 6
box->set_number_formatter(ui::DecimalFormatter{.fraction_digits = 2});
box->on_value_changed([&](std::optional<double> v) { quantity = v.value_or(0.0); });
ui::NumberBoxControl* quantity_box = stack->add(std::move(box));
// Or declaratively:
ui::Property<std::optional<double>> price{9.5};
stack->add(ui::NumberBox{
.header = "Price",
.placeholder_text = "0.00",
.value = price,
.min = 0.0,
.spin_button_placement = ui::NumberBoxSpinButtonPlacementMode::Compact,
}.build());
NumberBoxControl¶
NumberBoxControl(std::optional<double> value = std::nullopt, double min = -std::numeric_limits<double>::infinity(), double max = std::numeric_limits<double>::infinity())
value unset is an empty box. The range is unbounded by default; max below min is raised to min (see set_range()).
~NumberBoxControl¶
NumberBoxControl¶
operator=¶
min¶
Minimum; committed and stepped values are clamped to it. -infinity by default.
max¶
Maximum; committed and stepped values are clamped to it. +infinity by default.
set_range¶
Sets the range and clamps the current value into it, as SliderControl::set_range() does. Fires on_value_changed() when that changes the value. A max below min becomes min.
value¶
The committed number, unset for none. Not what is being typed until it commits.
set_value¶
Sets the value, clamped to [min, max] under InvalidInputOverwritten, and formats the text to match. Fires on_value_changed() only when the value changed. Unset or NaN means no number, and the box is empty.
step¶
What the arrow keys and spin buttons step by; 1 by default.
set_step¶
Sets how far a spin button click or an Up or Down key press moves the value. Zero turns both off. Negative values count as 0.
large_step¶
What PageUp/PageDown step by. 10 by default.
set_large_step¶
Sets what PageUp and PageDown step by. Negative values count as 0.
spin_button_placement¶
Where the spin buttons show; Hidden by default.
set_spin_button_placement¶
Sets where the spin buttons show: Hidden, Compact or Inline.
accepts_expression¶
Whether committed text is evaluated as arithmetic ("1 + 2^2" is 5). False by default.
set_accepts_expression¶
Committed text is evaluated as arithmetic.
number_formatter¶
The formatter the value is shown and typed text parsed with. The default shows up to ten significant digits with the user's regional separators.
set_number_formatter¶
Sets the formatter the value is shown and the text parsed with. Formats the text again at once.
validation_mode¶
What happens to input that does not parse; InvalidInputOverwritten by default.
set_validation_mode¶
Sets what happens to input that does not parse. Takes effect from the next commit or step, and the current value is not validated again.
wrap_enabled¶
Whether stepping wraps around the range. False by default.
set_wrap_enabled¶
When true, a step past max lands on min, and a step past min lands on max.
placeholder_text¶
The inner TextBox's placeholder; empty by default.
set_placeholder_text¶
The hint shown while the box is empty (the value unset).
text¶
The text as typed, not validated. It can differ from value until it is committed, on Enter, on losing focus, or before a spin button or arrow key step. set_text() does not fire on_text_changed().
set_text¶
header¶
The header text; empty by default.
set_header¶
The label above the control. Empty (the default) draws none and takes no room.
description¶
The secondary text under the box; empty (the default) draws none.
set_description¶
Sets the description. Empty draws none and takes no room.
error¶
What is wrong with the value, shown in the description's place in the critical color, with the border in the same color; empty (the default) shows the description.
set_error¶
Sets the error. Empty shows the description again.
automation_help_text_fallback¶
The description, or the error while one is set, is the help text a screen reader offers when accessibility().description is empty.
automation_invalid¶
Invalid while an error is set.
automation_name_fallback¶
The header names the control when accessibility().name does not.
on_text_changed¶
Fired after every user edit of the text, such as typing, Backspace or Delete, with the text. on_value_changed() fires only once a parsed, clamped value changes.
on_value_changed¶
Fired whenever value changes, from a committed text edit, a spin button click or an arrow key step.
focused¶
Whether the box holds keyboard focus. The inner TextBox shows the caret then.
caret_bounds¶
The inner text box's caret.
focusable¶
A tab stop while enabled.
for_each_child¶
Visits the internal TextBox.
collect_focusables¶
One tab stop: the internal TextBox is part of this control, not a stop of its own.
automation_children¶
One automation node: the internal TextBox is not listed as a child.
handle_context_menu¶
Shows Cut, Copy, Paste and Select All, with no spelling suggestions.
cursor_at¶
The text field's cursor over the text field: an I-beam, or an arrow over its buttons.
automation_role¶
AutomationRole::SpinButton.
up_visual_state¶
The inline up button's state: Disabled at the top of the range (unless wrapping), with no value, or while the box is disabled; else Pressed/Hover/Normal from the pointer.
down_visual_state¶
The inline down button's state, as up_visual_state() at the bottom of the range.
measure_override¶
Desired width is the internal TextBox's own desired width plus the spinner column; desired height is the TextBox's own single-line height.
arrange_override¶
Places the header, the inner TextBox and the spin-button columns (or Compact's indicator).
pointer_override¶
Spin-button presses step (and repeat while held); everything else goes to the TextBox.
covers_children_at¶
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.
wheel_override¶
The wheel steps the value while the box has focus. It then doesn't also scroll whatever holds the box.
render_override¶
Draws the header, the inner TextBox, and the inline spin buttons or Compact's indicator.
tick_override¶
Ticks the inner TextBox, then advances the spin-button press-and-hold repeat countdown while a button is held.
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.
focus_changed¶
Focus reaches the inner TextBox; losing it commits the typed text.
key_override¶
Up/Down step by step(), PageUp/PageDown by large_step(), Enter commits; the other keys edit the text.
text_override¶
Typed characters go to the inner TextBox; they are parsed only when committed.
draws_focus_ring¶
None: the field shows focus with its accent border.
Enumerations¶
NumberBoxSpinButtonPlacementMode¶
Where a ui::NumberBox shows its spin buttons.
| Value | |
|---|---|
Hidden |
No spin buttons (the default); the keyboard and the wheel still step. |
Compact |
A small indicator in the box; while it has focus, an up/down button pair floats beside it. Aero, Luna and the classic themes have no such popup and show the Inline buttons instead. |
Inline |
Up and down buttons side by side at the box's right edge; the box is at least 120 DIPs wide. Aero stacks them in one narrow column inside the field. |
NumberBoxValidationMode¶
What a ui::NumberBox does with input that is not a number.
| Value | |
|---|---|
InvalidInputOverwritten |
The default: text that does not parse is replaced by the value's text, and committed values are clamped to [min, max]. |
Disabled |
No validation: out-of-range values stand and unparsable text is left as typed. |
Tests¶
tests/test_number_box.cpp