// Copyright (c) 2026 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT // One Label per console history slot, refreshed only when // Console.consumeDirty() says the history actually changed -- reuses // the normal Label/spritebatch render path instead of the old // hand-rolled mesh-cache renderer. // // These Labels are NOT add()ed as children -- UIElement.add() caps at 8 // children per element, and CONSOLE_HISTORY_MAX (Console.lineCount) is // 16, over that cap. Instead they're driven directly: render()/update() // called explicitly below, and their world position is just their own // x/y (never having a parent means nothing offsets it). class ConsoleOverlay extends UIElement { init() { this.lines = []; for(let i = 0; i < Console.lineCount; i++) { const label = new Label(); label.x = 4; label.y = 4 + i * ConsoleOverlay.LINE_HEIGHT; this.lines.push(label); } this._refresh(); } update() { this.updateChildren(); if(Console.consumeDirty()) this._refresh(); for(let i = 0; i < this.lines.length; i++) this.lines[i].update(); } // Overridden (rather than left to auto-render) so the console can be // hidden entirely without disposing/rebuilding its Labels. render() { this.renderChildren(); if(!Console.visible) return; for(let i = 0; i < this.lines.length; i++) this.lines[i].render(); } // this.lines was never add()ed, so the normal dispose() cascade can't // reach them -- release them explicitly first, or they'd leak their // pool slots. dispose() { for(let i = 0; i < this.lines.length; i++) this.lines[i].dispose(); super.dispose(); } _refresh() { for(let i = 0; i < this.lines.length; i++) { this.lines[i].text = Console.getLine(i); } } } ConsoleOverlay.LINE_HEIGHT = 12; module.exports = ConsoleOverlay;