package kernel.ui; import lib.ScreenPos; import lib.Vec.Vec2; import lib.Color; import kernel.ui.ITermWriteable; using tink.CoreApi; /** A virtual terminal. With this a GUI program can still write to its "screen" even if its not displayed right now. When the GUI gets displayed again this buffer will be written to the screen. **/ class TermBuffer implements ITermWriteable { /** format [y][x]. First index is the line. Second index the char in the line. **/ private var screenBuffer:Array>; private var cursorPos:ScreenPos = {x: 0, y: 0}; private var currentTextColor:Color = White; private var currentBgColor:Color = Black; private var cursorBlink:Bool = false; private var size:Vec2 = {x: 51, y: 19}; // Default size set to default size of the main terminal public final onResize:Signal>; private final onResizeTrigger:SignalTrigger> = Signal.trigger(); private function new() { this.onResize = onResizeTrigger.asSignal(); initScreenBuffer(size); } private function setSize(size:Vec2) { if (this.size != size) { this.onResizeTrigger.trigger(size); } this.size = size; updateScreenBufferSize(size); } private function updateScreenBufferSize(size:Vec2) { // TODO } private function initScreenBuffer(size:Vec2) { screenBuffer = new Array(); for (y in 0...size.y) { screenBuffer[y] = new Array(); for (x in 0...size.x) { screenBuffer[y][x] = { char: " ", textColor: White, bg: Black, } } } } private function copyBufferToTarget(target:ITermWriteable) { target.setCursorPos(0, 0); target.setBackgroundColor(Black); target.setTextColor(White); var tmpFgColor:Color = White; var tmpBgColor:Color = Black; for (y => line in screenBuffer) { for (x => pixel in line) { if (tmpFgColor != pixel.textColor) { tmpFgColor = pixel.textColor; target.setTextColor(pixel.textColor); } if (tmpBgColor != pixel.bg) { tmpBgColor = pixel.bg; target.setBackgroundColor(pixel.bg); } target.setCursorPos(x, y); target.write(pixel.char); } } target.setCursorPos(cursorPos.x, cursorPos.y); target.setTextColor(currentTextColor); target.setBackgroundColor(currentBgColor); target.setCursorBlink(cursorBlink); } private function safeWriteScreenBuffer(pos:ScreenPos, char:String) { if (screenBuffer.length > pos.y && screenBuffer[pos.y].length > pos.x) { screenBuffer[pos.y][pos.x].char = char; screenBuffer[pos.y][pos.x].bg = currentBgColor; screenBuffer[pos.y][pos.x].textColor = currentTextColor; } } // // TermWriteable functions // public function write(text:String) { for (i in 0...text.length) { safeWriteScreenBuffer({x: cursorPos.x, y: cursorPos.y}, text.charAt(i)); cursorPos = {y: cursorPos.y, x: cursorPos.x + 1}; } } public function scroll(y:Int) { screenBuffer.unshift([ for (i in 0...size.x) { char: " ", textColor: White, // TODO: maybe replace with current bg/text color. Check nativ implementation bg: Black } ]); } public function getCursorPos():ScreenPos { return cursorPos; } public function setCursorPos(x:Int, y:Int) { cursorPos = { x: x, y: y, }; } public function getCursorBlink():Bool { return this.cursorBlink; } public function setCursorBlink(blink:Bool) { this.cursorBlink = blink; } public function getSize():Vec2 { return size; } public function clear() { initScreenBuffer(size); } public function clearLine() { if (screenBuffer.length > cursorPos.y) { screenBuffer[cursorPos.y] = [for (x in 0...size.x) {textColor: White, char: " ", bg: Black}]; } } public function getTextColor():Color { return currentTextColor; } public function setTextColor(color:Color) { currentTextColor = color; } public function getBackgroundColor():Color { return currentBgColor; } public function setBackgroundColor(color:Color) { currentBgColor = color; } public function isColor():Bool { return true; // Lets return true for now. } public function reset() { this.setBackgroundColor(Black); this.setTextColor(White); this.clear(); this.setCursorPos(0, 0); } }