ListNode<T>
Namespace: Hex1b
Assembly: Hex1b.dll
Render node for . Supports two render modes:
Default mode — no `ItemTemplate` set: each row is rendered
as a single line of `item?.ToString()` with the themed selection
indicator and selected/hover background, identical to the original
visuals.
Template mode — `ItemTemplate` set: each row is reconciled
into a child widget tree the template returns. The template owns all
visual chrome and styles itself from
.
public class ListNode<T> : Hex1bNode, ILayoutProviderInheritance
Object → Hex1bNode → ListNode<T>
Implements
Properties
ClipMode
The clip mode for this layout region.
Returns: ClipMode
public ClipMode ClipMode { get; }ClipRect
The effective clipping rectangle for this layout region.
Returns: Rect
public Rect ClipRect { get; }DataSource
Optional virtualized data source. When set, is ignored and the node materialises only a window of items around the visible viewport on each frame. Subscribes to if the source supports it.
Returns: IListDataSource<<T>>
public IListDataSource<T>? DataSource { get; set; }EffectiveItemCount
The total number of items, either from the in-memory list or the cached count from . Returns 0 until the first async count completes.
Returns: Int32
public int EffectiveItemCount { get; }FocusedIndex
The currently selected index. Preserved across reconciliation.
Returns: Int32
public int FocusedIndex { get; set; }FocusedItem
The currently selected item, or default if the list is empty or the selected row hasn't been loaded yet (virtualized mode).
Returns: <T>
public T? FocusedItem { get; }FocusedText
The text of the currently selected item (via ), or null if the list is empty / not yet loaded.
Returns: String
public string? FocusedText { get; }HasLoadedCount
True once the item count is known (always true for in-memory lists; for virtualized sources, true after the first completes). Used to gate the empty-state widget so it doesn't flash while a data source is still resolving.
Returns: Boolean
public bool HasLoadedCount { get; }HoveredItemIndex
The index of the row currently under the mouse cursor, or -1 if the list isn't hovered or the cursor sits past the last item. Updated by and reset to -1 when flips to false.
Returns: Int32
public int HoveredItemIndex { get; }IsFocusable
Returns true if this node can receive focus.
Returns: Boolean
public override bool IsFocusable { get; }IsFocused
Gets or sets whether this node is currently focused. Only meaningful for focusable nodes (where IsFocusable is true).
Returns: Boolean
public override bool IsFocused { get; set; }IsHovered
Gets or sets whether the mouse is currently hovering over this node. Set by Hex1bApp based on mouse position during each frame. Only set on focusable nodes (tracked via FocusRing hit testing).
Returns: Boolean
public override bool IsHovered { get; set; }IsMultiSelectEnabled
True when this list's multi-select feature is enabled. Reconciled from . Affects keybindings, the default row renderer, and .
Returns: Boolean
public bool IsMultiSelectEnabled { get; }IsScrollable
Whether the list needs scrolling (more items than fit in the viewport).
Returns: Boolean
public bool IsScrollable { get; }IsVirtualized
Whether the node is operating in virtualized mode.
Returns: Boolean
public bool IsVirtualized { get; }ItemHeight
The fixed row height in terminal rows. Defaults to 1. Always at least 1.
Returns: Int32
public int ItemHeight { get; set; }Items
The list items to display.
Returns: IReadOnlyList<<T>>
public IReadOnlyList<T> Items { get; set; }MaxScrollOffset
The maximum scroll offset based on item count and visible item count.
Returns: Int32
public int MaxScrollOffset { get; }ParentLayoutProvider
The parent layout provider, if any. Set when this provider becomes the current layout provider and there was already one active. Used to ensure nested clipping works correctly.
Returns: ILayoutProvider
public ILayoutProvider? ParentLayoutProvider { get; set; }ScrollOffset
The scroll offset (index of the first visible item). Preserved across reconciliation.
Returns: Int32
public int ScrollOffset { get; set; }SelectedIndices
The current checked-set indices (a read-only snapshot). Always empty when is false.
Returns: IReadOnlyCollection<Int32>
public IReadOnlyCollection<int> SelectedIndices { get; }SourceWidget
The source widget that was reconciled into this node.
Returns: ListWidget<<T>>
public ListWidget<T>? SourceWidget { get; set; }ViewportHeight
Returns: Int32
public int ViewportHeight { get; }VisibleItemCount
The number of items that fit in the viewport at the current .
Returns: Int32
public int VisibleItemCount { get; }Methods
ArrangeCore(Rect)
Override this method to implement arranging logic for this node. The base implementation saves previous bounds, marks dirty on change, and sets bounds.
Parameters:
bounds(Rect):
protected override void ArrangeCore(Rect bounds)ClipString(int, int, string)
Clips a string that starts at the given position, returning only the visible portion. Implementations should also consult the ParentLayoutProvider if present.
Parameters:
x(Int32): Starting absolute X position.y(Int32): Absolute Y position.text(String): The text to potentially clip.
Returns: ValueTuple<Int32, String>
A tuple containing:
- adjustedX: The X position to start rendering (may be > x if left-clipped)
- clippedText: The portion of text that should be rendered (may be empty)
public (int adjustedX, string clippedText) ClipString(int x, int y, string text)ConfigureDefaultBindings(InputBindingsBuilder)
Default binding configuration uses 's rebindable actions. The override redirects to the legacy action ids so existing rebind code keeps working.
Parameters:
bindings(InputBindingsBuilder):
public override void ConfigureDefaultBindings(InputBindingsBuilder bindings)GetChildren()
Gets the direct children of this node for structural tree traversal. Container nodes should override this to return their children.
Returns: IEnumerable<Hex1bNode>
public override IEnumerable<Hex1bNode> GetChildren()GetFocusableNodes()
Item child nodes are render-only in v1 — the list itself is the only focusable surface. Interactive widgets inside an item template will not receive focus.
Returns: IEnumerable<Hex1bNode>
public override IEnumerable<Hex1bNode> GetFocusableNodes()GetVisibleWindow(int)
Computes the absolute range of rows to materialize for the current scroll position: visible window plus rows above and below. Used by both data-source pre-fetch and templated child reconciliation.
Parameters:
totalCount(Int32):
Returns: ValueTuple<Int32, Int32>
public (int Start, int End) GetVisibleWindow(int totalCount)HandleMouseClick(int, int, Hex1bMouseEvent)
Handles a mouse click event (after mouse bindings have been checked). Override this in nodes to handle clicks that weren't matched by any mouse binding. The coordinates in the event are local to this node's bounds (0,0 is top-left of node).
Parameters:
localX(Int32): The X coordinate relative to this node's bounds.localY(Int32): The Y coordinate relative to this node's bounds.mouseEvent(Hex1bMouseEvent): The original mouse event (with absolute coordinates).
Returns: InputResult
Handled if the click was consumed, NotHandled otherwise.
public override InputResult HandleMouseClick(int localX, int localY, Hex1bMouseEvent mouseEvent)LoadDataAsync(int, int, CancellationToken)
Loads count items starting at startIndex from the data source, cancelling any in-flight load. No-op when no is set.
Parameters:
startIndex(Int32):count(Int32):cancellationToken(CancellationToken):
Returns: ValueTask
public ValueTask LoadDataAsync(int startIndex, int count, CancellationToken cancellationToken = default)MeasureCore(Constraints)
Override this method to implement measuring logic for this node.
Parameters:
constraints(Constraints):
Returns: Size
protected override Size MeasureCore(Constraints constraints)OnHoverMove(int, int)
Called whenever the mouse moves while this node is the hovered (hit-tested) node, even if doesn't change. Nodes that style themselves based on the mouse's position within their bounds (e.g. a list highlighting the row under the cursor) override this and mark themselves dirty when the derived state changes. Coordinates are absolute (screen-space), not local.
Parameters:
mouseX(Int32): Absolute X coordinate of the cursor.mouseY(Int32): Absolute Y coordinate of the cursor.
public override void OnHoverMove(int mouseX, int mouseY)Render(Hex1bRenderContext)
Renders the node to the given context.
Parameters:
context(Hex1bRenderContext):
public override void Render(Hex1bRenderContext context)ShouldRenderAt(int, int)
Determines if a character at the given absolute position should be rendered. Implementations should also check the ParentLayoutProvider if present.
Parameters:
x(Int32): Absolute X position in terminal coordinates.y(Int32): Absolute Y position in terminal coordinates.
Returns: Boolean
True if the character should be rendered, false if it should be clipped.
public bool ShouldRenderAt(int x, int y)TryGetEffectiveItem(int, out T)
Attempts to resolve an item by absolute index. Returns false for indices not currently cached (virtualized mode only). In non-virtualized mode this always succeeds when absoluteIndex is in range.
Parameters:
absoluteIndex(Int32):item(<T>):
Returns: Boolean
public bool TryGetEffectiveItem(int absoluteIndex, out T item)