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.
Bug
ScrollableContainerNode.Render()does not callcontext.CreateSubContext(bounds)before constructing itsScrolledRenderContext. 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 callingcontext.CreateSubContext(bounds), which offsets the rendering context so that inner writes at row 0 actually land atbounds.Yon screen.ScrollableContainerNodeskips this step:Compare to every other node (e.g.
SelectionListNode,TextNode,GridNode):Expected fix
Call
context.CreateSubContext(bounds)(or an equivalent bounds-relative context) before constructingScrolledRenderContext, consistent with the pattern used by every other node.Workaround (used in Netclaw until this is fixed)
Wrap
ScrollableContainerNodein a borderlessPanelNode, which does callCreateSubContextand passes a correctly-offset sub-context to its child:Reproduction
Place a
ScrollableContainerNodeinside 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 missingCreateSubContextcall.