Magnum::Ui::GenericLayouter class new in Git master

Generic layouter.

Each layout is a function that gets called on a particular node, allowing to arbitrarily modify the node offset and size as well as any associated data.

Setting up a generic layouter instance

If you create a UserInterfaceGL with a style and don't exclude StyleFeature::GenericLayouter, an implicit instance is already provided and available through UserInterface::genericLayouter(). Otherwise, the layouter doesn't have any shared state or configuration, so it's just about constructing it from a fresh AbstractUserInterface::createLayouter() handle and passing it to UserInterface::setGenericLayouterInstance():

ui.setGenericLayouterInstance(
    Containers::pointer<Ui::GenericLayouter>(ui.createLayouter()));

In comparison, if you want to set up a custom generic layouter that's independent of the one exposed through UserInterface::genericLayouter(), pass the newly created instance to AbstractUserInterface::setLayouterInstance() instead:

Ui::GenericLayouter& layouter = ui.setLayouterInstance(
    Containers::pointer<Ui::GenericLayouter>(ui.createLayouter()));

Afterwards, with either of the above, assuming AbstractUserInterface::draw() is called in an appropriate place, the layouter is ready to use.

Adding layouts

A layout is created by calling add() with a NodeHandle to which the layout is assigned, and a function taking a reference to the layouter instance along with mutable references to the associated node offset and size. The node offset and size can be arbitrarily modified, the layouter can be used to query current layout properties of various nodes using nodeOffset(), nodeSize(), nodeMinSize(), nodeMaxSize(), nodeAspectRatio(), nodePadding() and nodeMargin(). For example, the following would scale the filled part of a progress bar to be given percentage of its actual width:

Ui::NodeHandle background = ui.createNode();
Ui::NodeHandle fill = ui.createNode(background, );

Float percentage = 38.4f;

layouter.add(fill, [background, &percentage](const Ui::GenericLayouter& layouter, Vector2&, Vector2& nodeSize) {
    nodeSize.x() = layouter.nodeSize(background).x()*percentage/100.0f;
});

Instead of the percentage being accessed through captured state, you can encode it to the initial node size, which the layouter then just updates. This way you can also animate percentage changes using NodeAnimator, for example.

ui.setNodeSizeX(fill, 38.4f);

layouter.add(fill, [background](const Ui::GenericLayouter& layouter, Vector2&, Vector2& nodeSize) {
    nodeSize.x() *= layouter.nodeSize(background).x()/100.0f;
});

The layout isn't required to update the node offset and size at all — in the following snippet, the progress bar is made out of a single node with a BaseLayer data, and the progress is visualized by outline on the right edge:

Ui::BaseLayer& baseLayer = ;
Ui::NodeHandle progressbar = ui.createNode();
Ui::DataHandle progressbarData = baseLayer.create(, progressbar);

baseLayer.setOutlineWidth(progressbarData, {0.0f, 0.0f, 100.0f - 38.4f, 0.0f});

layouter.add(progressbar, [&baseLayer, progressbarData](const Ui::GenericLayouter& layouter, Vector2&, Vector2&) {
    Float progressbarWidth = layouter.nodeSize(baseLayer.node(progressbarData)).x();
    Float inversePercentage = baseLayer.outlineWidth(progressbarData)[3];
    baseLayer.setOutlineWidth(progressbarData,
        {0.0f, 0.0f, progressbarWidth*inversePercentage/100.0f, 0.0f});
});

Layout execution order

Unlike e.g. SnapLayouter, which performs the layout according to node hierarchy, the GenericLayouter gives no guarantee about the order in which the functions are executed, not even in respect to the sequence in which they were added.

If you require certain ordering, create additional layouter instances and put layout functions that need to be executed after the previous ones into these.

Base classes

class AbstractLayouter new in Git master
Base for layouters.

Constructors, destructors, conversion operators

GenericLayouter(LayouterHandle handle) explicit
Constructor.
GenericLayouter(const GenericLayouter&) deleted
Copying is not allowed.
GenericLayouter(GenericLayouter&&) noexcept
Move constructor.

Public functions

auto operator=(const GenericLayouter&) -> GenericLayouter& deleted
Copying is not allowed.
auto operator=(GenericLayouter&&) -> GenericLayouter& noexcept
Move assignment.
auto usedAllocatedCount() const -> std::size_t
Count of allocated layout functions.
auto add(NodeHandle node, Containers::Function<void(const GenericLayouter&layouter, Vector2&nodeOffset, Vector2&nodeSize)>&& layout) -> LayoutHandle
Add a layout assigned to given node.
void remove(LayoutHandle handle)
Remove a layout.
void remove(LayouterDataHandle handle)
Remove a layout assuming it belongs to this layer.
auto isAllocated(LayoutHandle handle) const -> bool
Whether given layout function is allocated.
auto isAllocated(LayouterDataHandle handle) const -> bool
Whether given layout function is allocated assuming it belongs to this layouter.
auto nodeOffset(NodeHandle node) const -> Vector2
Node offset in current layout, relative to its parent.
auto nodeSize(NodeHandle node) const -> Vector2
Node size in current layout.
auto nodeMinSize(NodeHandle node) const -> Vector2
Minimal node size in current layout.
auto nodeMaxSize(NodeHandle node) const -> Vector2
Maximal node size in current layout.
auto nodeAspectRatio(NodeHandle node) const -> Float
Node aspect ratio in current layout.
auto nodePadding(NodeHandle node) const -> Vector4
Padding inside a node in current layout.
auto nodeMargin(NodeHandle node) const -> Vector4
Margin inside a node in current layout.

Function documentation

Magnum::Ui::GenericLayouter::GenericLayouter(LayouterHandle handle) explicit

Constructor.

Parameters
handle Layouter handle returned from AbstractUserInterface::createLayouter()

Magnum::Ui::GenericLayouter::GenericLayouter(GenericLayouter&&) noexcept

Move constructor.

Performs a destructive move, i.e. the original object isn't usable afterwards anymore.

std::size_t Magnum::Ui::GenericLayouter::usedAllocatedCount() const

Count of allocated layout functions.

Always at most usedCount(). Counts all layout functions that capture non-trivially-copyable state or state that's too large to be stored in-place. The operation is done with a $ \mathcal{O}(n) $ complexity where $ n $ is capacity().

LayoutHandle Magnum::Ui::GenericLayouter::add(NodeHandle node, Containers::Function<void(const GenericLayouter&layouter, Vector2&nodeOffset, Vector2&nodeSize)>&& layout)

Add a layout assigned to given node.

Parameters
node Node to assign the layout to
layout Function to perform the layout operation
Returns New layout handle

Expects that the layout is not nullptr. The function gets called as part of layout update if node is visible. When executed, the function can query nodeOffset(), nodeSize(), nodeMinSize(), nodeMaxSize(), nodeAspectRatio(), nodePadding() and nodeMargin() functions on the passed layouter instance and use that information to update the nodeOffset and nodeSize arguments. Leaving either or both untouched is allowed as well, for example if the layout affects something else than node positioning.

Delegates to AbstractLayouter::add(), see its documentation for detailed description of all constraints.

void Magnum::Ui::GenericLayouter::remove(LayoutHandle handle)

Remove a layout.

Expects that handle is valid. Calls a destructor on the captured layout function state, if it's not trivially destructible. Delegates to AbstractLayouter::remove(LayoutHandle), see its documentation for detailed description of all constraints.

void Magnum::Ui::GenericLayouter::remove(LayouterDataHandle handle)

Remove a layout assuming it belongs to this layer.

Compared to remove(LayoutHandle) delegates to AbstractLayouter::remove(LayouterDataHandle) instead.

bool Magnum::Ui::GenericLayouter::isAllocated(LayoutHandle handle) const

Whether given layout function is allocated.

Returns true if given layout function captures non-trivially-copyable state or state that's too large to be stored in-place, false otherwise. Expects that handle is valid.

bool Magnum::Ui::GenericLayouter::isAllocated(LayouterDataHandle handle) const

Whether given layout function is allocated assuming it belongs to this layouter.

Like isAllocated(LayoutHandle) const but without checking that handle indeed belongs to this animator. See its documentation for more information.

Vector2 Magnum::Ui::GenericLayouter::nodeOffset(NodeHandle node) const

Node offset in current layout, relative to its parent.

Compared to AbstractUserInterface::nodeOffset() contains the value calculated by all previous layouters until this one. Expects that node is valid, can only be called from within the layout functions passed to add().

Vector2 Magnum::Ui::GenericLayouter::nodeSize(NodeHandle node) const

Node size in current layout.

Compared to AbstractUserInterface::nodeSize() contains the value calculated by all previous layouters until this one. Expects that node is valid, can only be called from within the layout functions passed to add().

Vector2 Magnum::Ui::GenericLayouter::nodeMinSize(NodeHandle node) const

Minimal node size in current layout.

Contains the value calculated by all layers advertising LayerFeature::Layout and all previous layouters until this one. If nothing specified any min size, the default is all components being 0.0f. Expects that node is valid, can only be called from within the layout functions passed to add().

Vector2 Magnum::Ui::GenericLayouter::nodeMaxSize(NodeHandle node) const

Maximal node size in current layout.

Contains the value calculated by all layers advertising LayerFeature::Layout and all previous layouters until this one. If nothing specified any max size, the default is all components being Constants::inf(). Expects that node is valid, can only be called from within the layout functions passed to add().

Float Magnum::Ui::GenericLayouter::nodeAspectRatio(NodeHandle node) const

Node aspect ratio in current layout.

Contains the value calculated by all layers advertising LayerFeature::Layout and all previous layouters until this one. If nothing specified any aspect ratio, the default is 0.0f. Expects that node is valid, can only be called from within the layout functions passed to add().

Vector4 Magnum::Ui::GenericLayouter::nodePadding(NodeHandle node) const

Padding inside a node in current layout.

Contains the value calculated by all layers advertising LayerFeature::Layout and all previous layouters until this one. If nothing specified any padding, the default is all components being 0.0f. Expects that node is valid, can only be called from within the layout functions passed to add().

Vector4 Magnum::Ui::GenericLayouter::nodeMargin(NodeHandle node) const

Margin inside a node in current layout.

Contains the value calculated by all layers advertising LayerFeature::Layout and all previous layouters until this one. If nothing specified any margin, the default is all components being 0.0f. Expects that node is valid, can only be called from within the layout functions passed to add().