184 lines
4.1 KiB
Haxe
184 lines
4.1 KiB
Haxe
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<Array<Pixel>>;
|
|
|
|
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<Int> = {x: 51, y: 19}; // Default size set to default size of the main terminal
|
|
|
|
public final onResize:Signal<Vec2<Int>>;
|
|
|
|
private final onResizeTrigger:SignalTrigger<Vec2<Int>> = Signal.trigger();
|
|
|
|
private function new() {
|
|
this.onResize = onResizeTrigger.asSignal();
|
|
initScreenBuffer(size);
|
|
}
|
|
|
|
private function setSize(size:Vec2<Int>) {
|
|
if (this.size != size) {
|
|
this.onResizeTrigger.trigger(size);
|
|
}
|
|
|
|
this.size = size;
|
|
updateScreenBufferSize(size);
|
|
}
|
|
|
|
private function updateScreenBufferSize(size:Vec2<Int>) {
|
|
// TODO
|
|
}
|
|
|
|
private function initScreenBuffer(size:Vec2<Int>) {
|
|
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<Int> {
|
|
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);
|
|
}
|
|
}
|