Skip to content

StackLayout

A container that overlays children in the same space (z-stack). The last child renders on top.

Basic Usage

csharp
new StackLayout(new ILayoutNode[]
{
    backgroundContent,   // Bottom layer
    overlayContent       // Top layer (renders on top)
})

Use Cases

csharp
new StackLayout(new ILayoutNode[]
{
    // Main content (always visible)
    mainPageContent,

    // Modal overlay (conditionally visible)
    ViewModel.ShowModalChanged
        .Select(show => show
            ? BuildModalDialog()
            : (ILayoutNode)new EmptyNode())
        .AsLayout()
})

Loading Overlay

csharp
new StackLayout(new ILayoutNode[]
{
    // Main content
    dataView,

    // Loading spinner overlay
    ViewModel.IsLoadingChanged
        .Select(loading => loading
            ? Layouts.Vertical()
                .WithChild(new EmptyNode().Fill())
                .WithChild(new SpinnerNode().WithLabel("Loading...").HeightAuto())
                .WithChild(new EmptyNode().Fill())
            : (ILayoutNode)new EmptyNode())
        .AsLayout()
})

Toast Notifications

csharp
new StackLayout(new ILayoutNode[]
{
    mainContent,

    // Toast in bottom-right corner
    ViewModel.ToastMessageChanged
        .Select(msg => string.IsNullOrEmpty(msg)
            ? (ILayoutNode)new EmptyNode()
            : Layouts.Vertical()
                .WithChild(new EmptyNode().Fill())  // Push to bottom
                .WithChild(
                    Layouts.Horizontal()
                        .WithChild(new EmptyNode().WidthFill())  // Push to right
                        .WithChild(
                            new PanelNode()
                                .WithContent(new TextNode(msg))
                                .Width(30)
                                .Height(3))))
        .AsLayout()
})

Render Order

Children are rendered in array order - first child is bottom, last child is top:

csharp
new StackLayout(new ILayoutNode[]
{
    layer1,  // Rendered first (bottom)
    layer2,  // Rendered second
    layer3   // Rendered last (top, visible if overlapping)
})

Transparency

Stack layers can have "transparent" areas by simply not writing to them. Child nodes only overwrite the areas they render to.

API Reference

Constructor

csharp
public StackLayout(IEnumerable<ILayoutNode> children)

Behavior

  • All children receive the same bounds
  • Children render in order (first = bottom, last = top)
  • Last child's content overwrites previous layers where they overlap
  • Empty areas are "transparent" - underlying layers show through

Source Code

View StackLayout implementation
csharp
// Copyright (c) Petabridge, LLC. All rights reserved.
// Licensed under the Apache 2.0 license. See LICENSE file in the project root for full license information.

using Termina.Rendering;

namespace Termina.Layout;

/// <summary>
/// A container that overlays children (like a z-stack).
/// All children occupy the same space, rendered in order (last on top).
/// Useful for modals, overlays, and toasts.
/// </summary>
public sealed class StackLayout : ContainerNode
{
    public StackLayout(IEnumerable<ILayoutNode> children)
    {
        AddChildren(children);
        // Default to fill
        HeightConstraint = new SizeConstraint.Fill();
        WidthConstraint = new SizeConstraint.Fill();
    }

    /// <summary>
    /// Add a child node fluently.
    /// </summary>
    public StackLayout WithChild(ILayoutNode child)
    {
        AddChild(child);
        return this;
    }

    /// <inheritdoc />
    public override Size Measure(Size available)
    {
        if (Children.Count == 0)
            return Size.Zero;

        var maxWidth = 0;
        var maxHeight = 0;

        foreach (var child in Children)
        {
            var childSize = child.Measure(available);
            maxWidth = Math.Max(maxWidth, childSize.Width);
            maxHeight = Math.Max(maxHeight, childSize.Height);
        }

        return new Size(
            WidthConstraint.Compute(available.Width, maxWidth, available.Width),
            HeightConstraint.Compute(available.Height, maxHeight, available.Height));
    }

    /// <inheritdoc />
    public override void Render(IRenderContext context, Rect bounds)
    {
        if (!bounds.HasArea)
            return;

        // Render all children in the same bounds, in order
        foreach (var child in Children)
        {
            child.Render(context, bounds);
        }
    }
}

Released under the Apache 2.0 License.