InkToolbar¶
Header: winui/ui/media/InkToolbar.hpp. Spec: winui/ui/media/InkToolbar.hpp.
A row of ink tools bound to a ui::InkCanvasControl. By default it holds a ballpoint pen, a pencil, a highlighter and an eraser, in that order.
Clicking a tool makes it the active tool and sets the target canvas up for it. A pen sets its drawing attributes and Inking mode, and the eraser sets Erasing mode. Clicking the active tool again opens its flyout. A pen's flyout picks a color from the pen's palette and a stroke width with a slider, over a sample stroke. The palette has 30 colors, six for the highlighter, and the width goes from 1 to 24 DIPs, 12 to 64 for the highlighter. The eraser's flyout switches the target canvas between its stroke and point erasers (InkCanvasControl::set_erase_mode()) and offers "Erase all ink", which clears the canvas. The toolbar is one tab stop. The arrow keys move between the tools, and Space or Enter does what a click does.
The app can add tools of its own after the built-in ones. A custom pen draws with attributes it makes from the picked color and width. A custom tool turns the canvas's inking off, so the app handles its input through on_unprocessed_input(), for example for a lasso. A custom toggle sits after the tools. add_stencil_button() adds the button that shows a ruler or a protractor on the canvas. ui::InkToolbar is the declarative form.
Example:
auto canvas = std::make_unique<ui::InkCanvasControl>();
auto toolbar = std::make_unique<ui::InkToolbarControl>();
toolbar->set_target_ink_canvas(canvas.get());
toolbar->on_active_tool_changed([](ui::InkToolbarTool tool)
{ std::println("tool {}", static_cast<int>(tool)); });
toolbar->set_active_tool(ui::InkToolbarTool::Highlighter); // the canvas now highlights
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
stack->add(std::move(toolbar));
canvas->set_height(300.0f);
stack->add(std::move(canvas));
window.set_content(std::move(stack));
ui::InkToolbar¶
A row of ink tools for an InkCanvas. Builds a ui::InkToolbarControl, whose description lists the tools and their flyouts.
.target names the canvas by its handle, and the canvas can be built before or after the toolbar. Until the canvas exists, the tools only change the toolbar's own state. The active tool's attributes reach the canvas once it is linked. .active_tool = tool is two-way.
Example:
ui::Control<ui::InkCanvas> canvas;
ui::Property<ui::InkToolbarTool> tool{ui::InkToolbarTool::BallpointPen};
window.set_content(ui::VerticalStack{.spacing = 8, .content = {
ui::InkToolbar{
.tools = {ui::InkToolbarTool::BallpointPen, ui::InkToolbarTool::Highlighter,
ui::InkToolbarTool::Eraser},
.active_tool = tool,
.target = canvas, // the canvas draws with the active tool
.horizontal_alignment = ui::Alignment::Leading,
.accessibility = {.name = "Drawing tools"},
},
ui::Border{.background = ui::colors::White,
.height = 280.0f,
.content = ui::InkCanvas{.control = canvas}},
}});
Every field, in the order a designated initializer names them:
ui::InkToolbar{
.tools, .custom_pens, .custom_tools, .custom_toggles, .stencil_button, .active_tool,
.orientation, .button_flyout_placement, .target, .style, .margin, .width, .height,
.min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
.vertical_alignment, .visible, .tool_tip, .enabled, .accessibility,
.on_active_tool_changed, .on_ink_drawing_attributes_changed, .on_erase_all_clicked,
.on_stencil_button_checked_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 | |
|---|---|---|---|
tools |
std::vector<ui::InkToolbarTool> |
{ui::InkToolbarControl::AllTools.begin(), ui::InkToolbarControl::AllTools.end()} |
The tools, in order. The first is active unless active_tool names another. |
custom_pens |
std::vector<ui::InkToolbarCustomButton> |
Pens of the app's own, after the tools (InkToolbarControl::add_custom_pen()). | |
custom_tools |
std::vector<ui::InkToolbarCustomButton> |
Tools of the app's own, after the custom pens (InkToolbarControl::add_custom_tool()). | |
custom_toggles |
std::vector<ui::InkToolbarCustomButton> |
Toggles of the app's own, after the tools (InkToolbarControl::add_custom_toggle()). | |
stencil_button |
bool |
false |
The stencil button, showing a ruler or a protractor (InkToolbarControl::add_stencil_button()). |
active_tool |
ui::TwoWayField<ui::InkToolbarTool> |
{ui::InkToolbarTool::BallpointPen} |
The selected tool. Two-way with ui::bind(prop). A tool not in tools is ignored. |
orientation |
ui::Binding<ui::Orientation> |
{ui::Orientation::Horizontal} |
A row, the default, or a column. |
button_flyout_placement |
ui::Binding<ui::InkToolbarButtonFlyoutPlacement> |
{ui::InkToolbarButtonFlyoutPlacement::Auto} |
Where the tool flyouts open. |
target |
ui::ControlLink<ui::InkCanvas> |
The canvas the tools act on, by its handle (InkToolbarControl::set_target_ink_canvas()). | |
on_active_tool_changed |
ui::Callback<void(ui::InkToolbarTool)> |
The new tool, from a click, the keyboard or active_tool. |
|
on_ink_drawing_attributes_changed |
ui::Callback<void(const ui::InkDrawingAttributes&)> |
The active pen's attributes changed. | |
on_erase_all_clicked |
ui::Callback<void()> |
"Erase all ink" cleared the canvas. | |
on_stencil_button_checked_changed |
ui::Callback<void(const ui::InkToolbarStencilChangedArgs&)> |
The stencil button went on or off, with the stencil it shows. | |
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::InkToolbar> |
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::InkToolbarControl; the caller owns it.
ui::InkToolbarControl¶
Derives from ui::Element.
A row of ink tools bound to a ui::InkCanvasControl. By default it holds a ballpoint pen, a pencil, a highlighter and an eraser, in that order.
Clicking a tool makes it the active tool and sets the target canvas up for it. A pen sets its drawing attributes and Inking mode, and the eraser sets Erasing mode. Clicking the active tool again opens its flyout. A pen's flyout picks a color from the pen's palette and a stroke width with a slider, over a sample stroke. The palette has 30 colors, six for the highlighter, and the width goes from 1 to 24 DIPs, 12 to 64 for the highlighter. The eraser's flyout switches the target canvas between its stroke and point erasers (InkCanvasControl::set_erase_mode()) and offers "Erase all ink", which clears the canvas. The toolbar is one tab stop. The arrow keys move between the tools, and Space or Enter does what a click does.
The app can add tools of its own after the built-in ones. A custom pen draws with attributes it makes from the picked color and width. A custom tool turns the canvas's inking off, so the app handles its input through on_unprocessed_input(), for example for a lasso. A custom toggle sits after the tools. add_stencil_button() adds the button that shows a ruler or a protractor on the canvas. ui::InkToolbar is the declarative form.
Example:
auto canvas = std::make_unique<ui::InkCanvasControl>();
auto toolbar = std::make_unique<ui::InkToolbarControl>();
toolbar->set_target_ink_canvas(canvas.get());
toolbar->on_active_tool_changed([](ui::InkToolbarTool tool)
{ std::println("tool {}", static_cast<int>(tool)); });
toolbar->set_active_tool(ui::InkToolbarTool::Highlighter); // the canvas now highlights
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
stack->add(std::move(toolbar));
canvas->set_height(300.0f);
stack->add(std::move(canvas));
window.set_content(std::move(stack));
AllTools¶
static std::array<InkToolbarTool, 4> AllTools {InkToolbarTool::BallpointPen, InkToolbarTool::Pencil, InkToolbarTool::Highlighter, InkToolbarTool::Eraser}
Every built-in tool, in the default order.
InkToolbarControl¶
A toolbar with a button for each of tools, in that order. A repeated tool appears once. The first is the active tool.
~InkToolbarControl¶
tool_button¶
The button for tool, or nullptr when this toolbar has none.
active_tool¶
The selected tool. CustomPen or CustomTool for a custom button. active_tool_button() tells custom buttons apart.
set_active_tool¶
Selects tool and sets the target canvas up for it, raising on_active_tool_changed(). For a pen whose attributes differ, it also raises on_ink_drawing_attributes_changed(). Does nothing when the toolbar has no button for tool. CustomPen and CustomTool select the first button of their kind.
active_tool_button¶
The active tool's button.
set_active_tool_button¶
Selects button, one of this toolbar's, as set_active_tool() does. Does nothing for a button of another toolbar.
add_custom_pen¶
Adds a pen after the tools. It draws with what button.pen makes of the color and width picked in its flyout. Returns the new button.
add_custom_tool¶
Adds a tool after the tools. While it is active, the target canvas inks nothing (InkCanvasInputMode::None) and reports its input through InkCanvasControl::on_unprocessed_input() for the app to act on. Returns the new button.
add_custom_toggle¶
Adds a toggle after the tools and the toggles before it. Returns the new toggle.
toggle_buttons¶
The toggles, in order.
add_stencil_button¶
Adds the stencil button after the tools, before the toggles, and returns it. A second call returns the one already there.
stencil_button¶
The stencil button, or nullptr when there is none.
stencil_button_checked¶
Whether a stencil shows on the target canvas.
set_stencil_button_checked¶
Shows the selected stencil on the target canvas, or hides both. Raises on_stencil_button_checked_changed() on a change. Does nothing without a stencil button.
on_stencil_button_checked_changed¶
Raised when the stencil button turns on or off, with the stencil it shows.
tool_visible¶
Whether the button for tool is shown. False when the toolbar has none.
set_tool_visible¶
Shows or collapses the button for tool. Hiding the active tool leaves it active, so select another tool first.
ink_drawing_attributes¶
What the last active pen draws with. Until a pen has been active, the ballpoint pen's attributes.
orientation¶
Whether the tools form a row or a column. Horizontal by default.
set_orientation¶
Lays the tools out in a row or a column.
button_flyout_placement¶
Where the tool flyouts open. Auto, which is below, by default.
set_button_flyout_placement¶
Sets where the tool flyouts open. Applies to the next flyout opened, and moves the chevron to that side.
target_ink_canvas¶
The canvas the tools drive, or nullptr when none is set or it was destroyed.
set_target_ink_canvas¶
Attaches to canvas and sets it up for the active tool at once. nullptr detaches. The toolbar doesn't own the canvas and lets go of it when the canvas is destroyed, so the canvas may go first. Until a canvas is set, the tools only change the toolbar's own state.
erase_all¶
Clears the target canvas and raises on_erase_all_clicked(), like the eraser flyout's "Erase all ink" item.
open_flyout¶
Opens the flyout of tool's button. Returns false when it has none, as for a hidden or missing tool or an eraser without "Erase all ink".
close_flyout¶
Closes whichever tool flyout is open.
open_flyout_tool¶
The tool whose flyout is open, or nullopt when none is.
on_active_tool_changed¶
Raised with the new tool.
on_ink_drawing_attributes_changed¶
Raised when the active pen's color, width or kind changes.
on_erase_all_clicked¶
Raised after "Erase all ink" has cleared the canvas.
focused¶
Whether the toolbar has keyboard focus.
focusable¶
A tab stop while enabled.
collect_focusables¶
The toolbar is one tab stop. Its buttons aren't.
focused_button¶
The tool under the keyboard cursor while the toolbar is focused. nullptr while the cursor is on a toggle.
for_each_child¶
The internal panel.
automation_children¶
The visible tool buttons (through their flyouts) and the toggles, not the internal panel.
automation_role¶
Exposed to UI Automation as a toolbar, like ui::ToolbarControl.
measure_override¶
The tools in a row or column, 40 DIPs a tool, inside a 2 DIP margin.
arrange_override¶
Places the tools.
render_override¶
The tools, and the focus ring around the tool under the keyboard cursor.
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¶
Puts the keyboard cursor on the active tool when focus arrives.
key_override¶
Left and Right, or Up and Down in a vertical toolbar, move between the visible tools and toggles. Home and End move to the ends. Space and Enter act on the one under the cursor as a click does.
focus_ring_rect¶
Around the tool or toggle under the keyboard cursor.
class InkToolbarToolButtonControl¶
Derives from ui::Element, ui::SelectionItemProvider, ui::ExpandCollapseProvider.
One tool button of a ui::InkToolbarControl: a pen, the eraser or another tool. The toolbar makes these. Reach one through InkToolbarControl::tool_button().
The button is a 36 DIP square with the tool's glyph. A pen button also shows its selected color in the glyph, and holds the palette and the stroke width its flyout edits. The eraser button holds whether its flyout offers "Erase all ink". The active tool's button is drawn selected, with a small chevron toward the flyout it opens on a second click.
Example:
auto toolbar = std::make_unique<ui::InkToolbarControl>();
ui::InkToolbarToolButtonControl* pen = toolbar->tool_button(ui::InkToolbarTool::BallpointPen);
pen->set_selected_brush_index(7); // red, in the default palette
pen->set_selected_stroke_width(6.0f); // within min_stroke_width()..max_stroke_width()
InkToolbarToolButtonControl¶
The button for tool, with that tool's palette, width range and defaults.
InkToolbarToolButtonControl¶
A custom pen or tool button, looking as custom says. tool is CustomPen or CustomTool. A custom pen starts with the ballpoint pen's palette and widths.
~InkToolbarToolButtonControl¶
tool¶
Which tool the button is.
is_pen¶
True for the ballpoint pen, the pencil, the highlighter and a custom pen.
custom¶
What a custom button was made with, or nullptr for a built-in tool.
checked¶
Whether this is the toolbar's active tool.
palette¶
The colors the flyout offers. The ballpoint pen and the pencil share a 30-color palette, and the highlighter has six colors.
set_palette¶
Replaces the palette. The selected index is clamped into it.
selected_brush_index¶
The selected palette index. 0 by default, which is black for the pens and yellow for the highlighter.
set_selected_brush_index¶
Selects a palette color, clamping index into the palette. Updates the drawing attributes when this is the active pen.
selected_color¶
The palette color at the selected index, or black for an empty palette.
min_stroke_width¶
The thinnest stroke width: 1 for the pens, 12 for the highlighter.
max_stroke_width¶
The thickest stroke width: 24 for the pens, 64 for the highlighter.
set_stroke_width_range¶
Sets both ends of the range, swapping them when given backwards, and clamps the selected width into it.
selected_stroke_width¶
The selected stroke width: 2 for the ballpoint pen, 4 for the pencil, 16 for the highlighter.
set_selected_stroke_width¶
Sets the stroke width, clamped into the range. Updates the drawing attributes when this is the active pen.
drawing_attributes¶
What this pen draws with. The ballpoint pen draws with a round nib of the selected width, and the pencil with pencil ink of that width. The highlighter draws as a highlighter, with a chisel a third of the width wide and the width tall. A custom pen draws with what its InkToolbarCustomButton::pen makes of the color and width.
clear_all_visible¶
Whether the eraser's flyout offers "Erase all ink" under its stroke and point erasers. True by default.
set_clear_all_visible¶
Shows or hides the "Erase all ink" item.
extension_glyph_shown¶
Whether the chevron that says a second click opens a flyout shows. It shows on the active tool while it has a flyout and that flyout is closed.
hovered¶
Whether the pointer is over the button.
tool_tip¶
Shows the tool's name.
automation_role¶
Button for the pens, Custom for the eraser and a custom tool.
automation_name_fallback¶
The tool's name, such as "Ballpoint pen", with ", selected" while it is the active tool.
measure_override¶
36 by 36 DIPs. The toolbar adds the 2 DIP margin around it.
render_override¶
The background for the state, the color glyph of a pen, the tool's glyph and the chevron.
pointer_override¶
A left click selects the tool. On the active tool, it opens the tool's flyout.
struct InkToolbarCustomButton¶
How a custom button of a ui::InkToolbarControl looks and what it does. The button is a custom pen, a custom tool or a custom toggle. Each field applies to the kinds its comment names.
The callables are std::function, so they can be copied. The spec lists custom buttons in a braced list, which copies its entries.
Example:
// A calligraphy pen: a flat nib a third as wide as it is tall.
auto toolbar = std::make_unique<ui::InkToolbarControl>();
toolbar->add_custom_pen({.name = "Calligraphy pen",
.icon = ui::IconGlyph{0xEDFB},
.pen = [](ui::Color color, float width)
{
return ui::InkDrawingAttributes{.color = color,
.size = {width / 3.0f, width},
.pen_tip = ui::InkPenTip::Rectangle};
}});
| Field | Type | Default | |
|---|---|---|---|
name |
std::string |
Its tool tip and accessible name. Every kind. | |
icon |
IconSource |
The icon it shows: a Symbol, a glyph, a path or a picture. A glyph of the default symbol font takes the theme's icon font. Every kind. | |
configuration |
std::function<Spec()> |
What a click on the active custom pen or tool opens in its flyout. Without it, a custom pen opens the pens' color and size flyout, and a custom tool opens nothing. | |
pen |
std::function<InkDrawingAttributes(Color color, float width)> |
What a custom pen draws with, made from the color and width picked in its flyout. Without it, the pen draws with a round nib of that color and width. | |
on_checked_changed |
std::function<void(bool checked)> |
Called when a custom toggle turns on or off, with the new state. |
struct InkToolbarStencilChangedArgs¶
What an InkToolbar's on_stencil_button_checked_changed gets: whether the stencil button is on, and the stencil it shows.
| Field | Type | Default | |
|---|---|---|---|
checked |
bool |
false |
The button is on and the stencil shows. |
kind |
InkToolbarStencilKind |
InkToolbarStencilKind::Ruler |
The stencil the button selects. |
class InkToolbarToggleButtonControl¶
Derives from ui::Element, ui::ToggleProvider.
A toggle button on a ui::InkToolbarControl. It turns on or off and sits after the tools. Add one with InkToolbarControl::add_custom_toggle().
Example:
// A toggle that lets touch draw as well as the pen and the mouse.
auto canvas = std::make_unique<ui::InkCanvasControl>();
auto toolbar = std::make_unique<ui::InkToolbarControl>();
ui::InkToolbarToggleButtonControl* touch =
toolbar->add_custom_toggle({.name = "Touch writing", .icon = ui::IconGlyph{0xED5F}});
touch->on_checked_changed([ink = canvas.get()](bool on) {
ink->set_input_device_types(on ? ui::PointerDeviceTypes::All
: ui::PointerDeviceTypes::Pen | ui::PointerDeviceTypes::Mouse);
});
InkToolbarToggleButtonControl¶
A toggle looking as look says, off.
~InkToolbarToggleButtonControl¶
look¶
What the toggle was made with.
checked¶
Whether the toggle is on.
set_checked¶
Turns the toggle on or off, raising on_checked_changed() when the state changes.
on_checked_changed¶
Raised with the new state when the toggle turns on or off, after the look's own handler.
hovered¶
Whether the pointer is over the button.
tool_tip¶
The look's name.
automation_role¶
A button that toggles.
automation_name_fallback¶
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.
measure_override¶
36 by 36 DIPs, like a tool button.
render_override¶
The background for the state, with the selected color while on, and the glyph.
pointer_override¶
A left click flips it.
class InkToolbarStencilButtonControl¶
Derives from ui::Element, ui::ToggleProvider, ui::ExpandCollapseProvider.
The stencil button of a ui::InkToolbarControl, which shows the ruler or the protractor on the target canvas. Add it with InkToolbarControl::add_stencil_button().
A click while it is off turns it on and shows the stencil picked last, the ruler at first. A click while it is on opens its flyout, which picks the ruler or the protractor. Picking the one showing hides it and turns the button off. With only one of the two offered, it is a plain toggle with no flyout.
Example:
auto toolbar = std::make_unique<ui::InkToolbarControl>();
ui::InkToolbarStencilButtonControl* stencils = toolbar->add_stencil_button();
stencils->set_selected_stencil(ui::InkToolbarStencilKind::Protractor);
toolbar->set_stencil_button_checked(true); // the protractor shows on the canvas
InkToolbarStencilButtonControl¶
~InkToolbarStencilButtonControl¶
selected_stencil¶
The stencil the button shows while it is on. The ruler by default.
set_selected_stencil¶
Picks the stencil, and shows it at once while the button is on.
ruler_item_visible¶
Whether the flyout offers the ruler. True by default.
set_ruler_item_visible¶
See ruler_item_visible().
protractor_item_visible¶
Whether the flyout offers the protractor. True by default.
set_protractor_item_visible¶
See protractor_item_visible().
checked¶
Whether the button is on, with a stencil showing.
extension_glyph_shown¶
Whether the chevron that says a click opens the flyout shows. It shows while the button is on, offers both stencils and its flyout is closed.
hovered¶
Whether the pointer is over the button.
tool_tip¶
The selected stencil's name.
automation_role¶
A button that toggles, and expands and collapses its flyout.
automation_name_fallback¶
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.
measure_override¶
36 by 36 DIPs, like a tool button.
render_override¶
The background for the state, the selected stencil's glyph and the chevron.
pointer_override¶
A left click turns it on or opens its flyout.
Enumerations¶
InkToolbarTool¶
A tool on a ui::InkToolbarControl.
| Value | |
|---|---|
BallpointPen |
A round, solid pen. |
Pencil |
Pencil ink. |
Highlighter |
A wide, translucent chisel nib. |
Eraser |
The stroke eraser, with "Erase all ink" in its flyout. |
CustomPen |
A pen the app defines (InkToolbarControl::add_custom_pen()). |
CustomTool |
A tool the app implements (InkToolbarControl::add_custom_tool()). |
InkToolbarStencilKind¶
Which stencil the stencil button shows on the canvas.
| Value | |
|---|---|
Ruler |
The ruler (InkCanvasControl::set_ruler()). |
Protractor |
The protractor (InkCanvasControl::set_protractor()). |
InkToolbarButtonFlyoutPlacement¶
Which side of its button a tool's flyout opens on.
| Value | |
|---|---|
Auto |
Below the button, the same as Bottom. |
Top |
Above the button, left edges lined up. |
Bottom |
Below the button, left edges lined up. |
Left |
Left of the button, centered. |
Right |
Right of the button, centered. |
Tests¶
tests/test_ink_toolbar.cpp