reckfellENGINE

Containers: space allocation and scrolling

A complete C# layout: Expand/Fill, width bounds, ratios and revealing a list item.

On this page

Choose the layout owner

ContainerPurpose
HBoxContainer / VBoxContainerRow / column
GridContainerA grid with a chosen column count
FlowContainer and variantsWrap items onto the next row/column
MarginContainerPadding around content
PanelContainerThemed background and content space
CenterContainer / AspectRatioContainerCentering / aspect ratio
ScrollContainerA scrollable visible region
TabContainer / SplitContainerTabs / split panes

A container sorts eligible direct child Controls. An intermediate plain Entity breaks that relationship. Nest containers to build rows and columns. Do not stack several children directly in PanelContainer when they need sequential layout: put a VBox/HBox inside it.

Ordinary layout includes direct child Controls that are visible and not TopLevel. If an item falls out of a row, check these conditions before changing anchors. TopLevel excludes a Control from ordinary container sorting; it does not pin Position within the row.

Run the example

Add UiSampleStyle.cs. Attach ContainersDemo.cs to a Control root, build and run with F6. The top row shows A/B/C allocation; twenty buttons scroll below it. Navigate with Tab: FollowFocus reveals the selected item. Call RevealLast from your own jump-to-end button if needed.

ContainersDemo.cs
C#
using Reckfell;

public partial class ContainersDemo : Control
{
    public HBoxContainer Row { get; private set; } = null!;
    public PanelContainer A { get; private set; } = null!;
    public PanelContainer B { get; private set; } = null!;
    public PanelContainer C { get; private set; } = null!;
    public ScrollContainer Scroll { get; private set; } = null!;
    public Button Last { get; private set; } = null!;

    public override void _Ready()
    {
        UiSampleStyle.Prepare(this);
        var margin = new MarginContainer(); AddChild(margin);
        margin.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect, margin: 16);
        var column = new VBoxContainer(); margin.AddChild(column);
        column.AddChild(new Label { Text = UiSampleStyle.Text("Контейнеры и прокрутка", "Containers and scrolling") });
        Row = new HBoxContainer(); column.AddChild(Row);
        A = Item("A", 64); B = Item("B", 64); C = Item("C", 64);
        A.CustomMaximumSize = new Vector2(140, -1);
        A.SizeFlagsHorizontal = SizeFlags.ExpandFill; B.SizeFlagsHorizontal = SizeFlags.ExpandFill;
        B.SizeFlagsStretchRatio = 2; C.SizeFlagsHorizontal = SizeFlags.Fill;
        Row.AddChild(A); Row.AddChild(B); Row.AddChild(C);
        Scroll = new ScrollContainer
        {
            SizeFlagsVertical = SizeFlags.ExpandFill, FollowFocus = true,
            HorizontalScrollMode = ScrollContainer.ScrollMode.Disabled
        };
        column.AddChild(Scroll);
        var list = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill }; Scroll.AddChild(list);
        for (int i = 1; i <= 20; i++)
        {
            Last = new Button { Text = UiSampleStyle.Text("Пункт ", "Item ") + i, CustomMinimumSize = new Vector2(0, 40) };
            list.AddChild(Last);
        }
    }

    private static PanelContainer Item(string text, float width)
    {
        var panel = new PanelContainer { CustomMinimumSize = new Vector2(width, 60) };
        panel.AddChild(new Label { Text = text, HorizontalAlignment = HorizontalAlignment.Center });
        return panel;
    }

    public void RevealLast()
    {
        Last.GrabFocus();
        Callable.From(() => Scroll.EnsureControlVisible(Last)).CallDeferred();
    }
}

Fill and Expand have different jobs

FlagResult
FillFill the rectangle allocated by the container
ExpandParticipate in allocating extra space
ExpandFillReceive extra space and fill it
ShrinkBegin / Center / EndUse a smaller size with the chosen alignment
MaximizeExtra priority/use of a maximum in a supporting container; not a synonym for FullRect

A and B use ExpandFill, but A is capped at 140. B receives released space; C does not expand. SizeFlagsStretchRatio is a relative weight, not an exact percentage of final width: minima, maxima and gaps participate. In BoxContainer, Maximize boosts stretch priority for Expand; other items' minima and maximum bounds still apply. Check flag semantics for the specific container.

Scroll without expanding the window

The ScrollContainer receives available height through ExpandFill. It contains one column of twenty items whose vertical minimum exceeds the visible area. Horizontal scrolling is disabled and the column fills the available width. A nonshrinking label wider than the window still needs wrapping or a different structure; hiding a scrollbar does not fix its content.

EnsureControlVisible() needs a descendant of that ScrollContainer and current rectangles. Wait for container sorting after dynamically changing the tree. RevealLast defers the request; Size immediately after AddChild is not necessarily final layout. FollowFocus helps keyboard use but does not define the entire focus route.

Diagnostics

ProblemCause / action
Position resets itselfThe parent container owns it
A direct child is not laid outIt must be a visible Control without TopLevel; wait for sorting after changes
Fill does not expand a rowFill uses the allocated share; Expand participates in extra-space distribution
Two items do not divide space 1:2Minima, maxima and other participants also count
A hidden item leaves spaceCheck which Control is hidden and wait for sorting
Window grows instead of scrollingExcessive ScrollContainer minimum or incorrect parent SizeFlags
Revealing an item fails immediatelyLayout has not updated, or the object is not a descendant
Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.