render method
Renders the widget onto the provided buffer within the specified area.
Implementation
@override
void render(Buffer buffer, Rect area) {
_updateFlatNodes();
adjustScroll(area.height);
final activeSelectedStyle = focused
? selectedStyle
: Style(
foreground: selectedStyle.foreground,
background: CharmColors.char,
modifiers: selectedStyle.modifiers,
);
for (var i = 0; i < area.height; i++) {
final nodeIdx = _scrollOffset + i;
if (nodeIdx >= _flatNodes.length) break;
final flat = _flatNodes[nodeIdx];
final isSelected = nodeIdx == _selectedIndex;
var x = 0;
// 1. Ancestor guide lines
for (var depthIdx = 0; depthIdx < flat.depth - 1; depthIdx++) {
if (x >= area.width) break;
final isLast = flat.ancestorIsLast[depthIdx];
final part = isLast ? ' ' : '│ ';
buffer.writeString(
area.x + x,
area.y + i,
part,
isSelected ? activeSelectedStyle : lineStyle,
);
x += 3;
}
// 2. Active node guide line
if (flat.depth > 0 && x < area.width) {
final isLast = flat.ancestorIsLast.last;
final part = isLast ? '└── ' : '├── ';
buffer.writeString(
area.x + x,
area.y + i,
part,
isSelected ? activeSelectedStyle : lineStyle,
);
x += 4;
}
// 3. Expander indicator
if (x < area.width) {
final indicator = flat.node.isLeaf
? ' '
: (flat.node.isExpanded ? '▼ ' : '▶ ');
buffer.writeString(
area.x + x,
area.y + i,
indicator,
isSelected ? activeSelectedStyle : lineStyle,
);
x += 2;
}
// 4. Label
final remainingWidth = area.width - x;
if (remainingWidth > 0) {
final labelChars = flat.node.label.characters;
final labelText = labelChars.length > remainingWidth
? labelChars.take(remainingWidth).toString()
: labelChars.toString() +
(' ' * (remainingWidth - labelChars.length));
buffer.writeString(
area.x + x,
area.y + i,
labelText,
isSelected ? activeSelectedStyle : unselectedStyle,
);
}
}
}