Skip to content

ScrollableContainerNode.Render() ignores bounds.Y, overwriting content above it in the layout #300

@Aaronontheweb

Description

@Aaronontheweb

Bug

ScrollableContainerNode.Render() does not call context.CreateSubContext(bounds) before constructing its ScrolledRenderContext. This means the scroll viewport is always anchored to absolute terminal row 0 rather than the slot the layout assigned to the node. Any content above the node (header rows, labels, etc.) gets overwritten by the scrollable content.

Root cause

Every other node in Termina begins Render() by calling context.CreateSubContext(bounds), which offsets the rendering context so that inner writes at row 0 actually land at bounds.Y on screen. ScrollableContainerNode skips this step:

// Current (buggy): outer context starts at terminal row 0.
// When the node is placed below a header, bounds.Y > 0 but content still
// writes at row 0 — overwriting whatever sits above.
ScrolledRenderContext context2 = new ScrolledRenderContext(
    context, 0, -_scrollOffset, width, _contentHeight);
_content.Render(context2, new Rect(0, 0, width, _contentHeight));

Compare to every other node (e.g. SelectionListNode, TextNode, GridNode):

// Correct: CreateSubContext offsets the write origin to bounds.{X,Y}.
var sub = context.CreateSubContext(bounds);
_content.Render(sub, ...);

Expected fix

Call context.CreateSubContext(bounds) (or an equivalent bounds-relative context) before constructing ScrolledRenderContext, consistent with the pattern used by every other node.

Workaround (used in Netclaw until this is fixed)

Wrap ScrollableContainerNode in a borderless PanelNode, which does call CreateSubContext and passes a correctly-offset sub-context to its child:

new PanelNode()
    .WithBorder(BorderStyle.None)
    .WithContent(scrollableNode)
    .Fill()

Reproduction

Place a ScrollableContainerNode inside a vertical layout below a header row. With more items than fit the viewport, the scrollable content renders starting at terminal row 0, overwriting the header rows.

Discovered and diagnosed while fixing netclaw#1424. The decompiled ScrollableContainerNode.Render() from Termina 0.12.1 confirms the missing CreateSubContext call.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions