ui::ControlHeader¶
Header: winui/ui/ControlHeader.hpp.
The Header label an input control (Slider, ComboBox, ToggleSwitch, TextBox, NumberBox, ...) carries above itself. It draws wrapping text in the primary text color, or in the disabled color while the control is disabled, takes no room while empty, and leaves a per-control gap below it.
It is not an Element. The control owns one as a plain member and calls it from its own measure, arrange and render, so the element tree stays the same. arrange() takes the header off the top of the control's rect and leaves the rest as the control's bounds, so hit tests, focus rings and popup anchors still cover only the control itself.
Example:
class LabeledThing final : public ui::Element
{
public:
void set_header(std::string text)
{
if (header_.set_text(std::move(text)))
{
mark_dirty(ui::DirtyFlags::Layout | ui::DirtyFlags::Visual);
}
}
protected:
ui::Size measure_override(ui::Size available, const ui::MeasureContext& context) const override
{
const ui::Size header = header_.measure(available.width, context);
const ui::Size room = ui::ControlHeader::below(available, header);
const ui::Size body{120.0f, std::min(room.height, 32.0f)};
return ui::ControlHeader::above(body, header);
}
void arrange_override(const ui::Rect&, const ui::ArrangeContext&) override
{
header_.arrange(*this); // bounds() is now the body's rect
}
void render_override(ui::Renderer& renderer, const ui::RenderContext& context) const override
{
const ui::Theme& theme = context.theme;
header_.render(renderer, theme, /*enabled=*/true);
renderer.fill_rounded_rect(bounds(), 4.0f, theme.colors().background); // the body
}
private:
ui::ControlHeader header_{4.0f}; // gap below the header, DIPs
};
ControlHeader¶
gap is the space in DIPs between the header and the control below it (4 for a Slider). It applies only while the header has text.
text¶
The header text; empty (the default) collapses the header entirely.
set_text¶
Returns whether the text changed, so the caller knows to mark itself dirty for layout and visuals, since the header's height depends on its text.
empty¶
True while there is no text. The header then takes no room and draws nothing.
measure¶
The room the header takes above the control, in DIPs: its width, and its height plus the gap. Zero when empty. It wraps at available_width when that is bounded (> 0). arrange() uses the height from the last call.
arrange¶
Takes the header (as last measured) off the top of control's bounds(), which are left as the control's own rect. Call it from the control's arrange_override(). A no-op while empty.
render¶
Draws the header where arrange() put it, grayed (and engraved in the classic eras) while the control is disabled.
below¶
available with the header's height taken out, for measuring the control below it. An unbounded height stays unbounded.
above¶
The control's own desired size with the header stacked on top of it: the wider of the two, and the heights summed.