198 lines
3.8 KiB
Haxe
198 lines
3.8 KiB
Haxe
package lib.ui;
|
|
|
|
import kernel.ui.WindowContext;
|
|
import lib.Pos;
|
|
import lib.Rect;
|
|
import kernel.ui.Pixel;
|
|
|
|
abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> from Array<Array<Pixel>>{
|
|
inline public function new() {
|
|
this = [[]];
|
|
}
|
|
|
|
public inline function set(i:Pos, pixel:Pixel) {
|
|
if (this[i.y] == null) {
|
|
this[i.y] = [];
|
|
}
|
|
|
|
this[i.y][i.x] = pixel;
|
|
}
|
|
|
|
public inline function get(i:Pos):Null<Pixel> {
|
|
if (this[i.y] == null) {
|
|
return null;
|
|
}
|
|
|
|
return this[i.y][i.x];
|
|
}
|
|
|
|
public function keyValueIterator():KeyValueIterator<Pos, Pixel> {
|
|
return new CanvasKeyValueIterator(this);
|
|
}
|
|
|
|
public function combine(other:Canvas, offset:Pos) {
|
|
for (key => value in other) {
|
|
if (value == null) {
|
|
continue;
|
|
}
|
|
|
|
var y = offset.y + key.y;
|
|
var x = offset.x + key.x;
|
|
|
|
if (this[y] == null) {
|
|
this[y] = [];
|
|
}
|
|
|
|
this[y][x] = value;
|
|
}
|
|
}
|
|
|
|
public function height():Int {
|
|
return this.length;
|
|
}
|
|
|
|
public function maxWidth() {
|
|
var max = 0;
|
|
for (i in 0...this.length) {
|
|
if (this[i] != null && this[i].length > max) {
|
|
max = this[i].length;
|
|
}
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
public function getBounds(): Rect {
|
|
return new Rect({x:0,y:0},{
|
|
x: maxWidth() - 1,
|
|
y: height() - 1
|
|
});
|
|
}
|
|
|
|
/**
|
|
Renders the canvas directly to the context
|
|
**/
|
|
public function renderToContext(ctx: WindowContext){
|
|
var lastBgColor: Color = null;
|
|
var lastTextColor: Color = null;
|
|
|
|
for (lineIndex => line in this) {
|
|
if (line == null || line.length == 0) {
|
|
// Line is empty
|
|
continue;
|
|
}
|
|
|
|
ctx.setCursorPos(0, lineIndex);
|
|
|
|
var pritableLine = "";
|
|
|
|
for (pixelIndex => pixel in line) {
|
|
if (pixel == null) {
|
|
// If the pixel is null we need to skip it with setCurosrPos.
|
|
// Otherwise we will print an empty space with bg color
|
|
ctx.write(pritableLine);
|
|
pritableLine = "";
|
|
ctx.setCursorPos(pixelIndex + 1, lineIndex);
|
|
continue;
|
|
}
|
|
|
|
if (pixel.bg != lastBgColor) {
|
|
// The background color has changed, we need to print the current line and set the new background color
|
|
ctx.write(pritableLine);
|
|
pritableLine = "";
|
|
|
|
// Set the new background color
|
|
ctx.setBackgroundColor(pixel.bg);
|
|
lastBgColor = pixel.bg;
|
|
}
|
|
|
|
// Same as above but for the text color
|
|
if (pixel.textColor != lastTextColor) {
|
|
// The text color has changed, we need to print the current line and set the new text color
|
|
ctx.write(pritableLine);
|
|
pritableLine = "";
|
|
|
|
// Set the new text color
|
|
ctx.setTextColor(pixel.textColor);
|
|
lastTextColor = pixel.textColor;
|
|
}
|
|
|
|
pritableLine += pixel.char;
|
|
}
|
|
|
|
ctx.write(pritableLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
class CanvasKeyValueIterator {
|
|
private final canvas:Array<Array<Pixel>> ;
|
|
private var index:Null<Pos> = {x: 0, y: 0};
|
|
private var nextIndex:Null<Pos> = null;
|
|
|
|
@:allow(lib.ui.Canvas)
|
|
private function new(canvas:Array<Array<Pixel>>) {
|
|
this.canvas = canvas;
|
|
|
|
if (!isValidPos(this.index)){
|
|
this.index = nextValidPixel();
|
|
}
|
|
|
|
this.nextIndex = nextValidPixel();
|
|
}
|
|
|
|
private function isValidPos(pos: Pos): Bool {
|
|
if (this.canvas[pos.y] == null) {
|
|
return false;
|
|
}
|
|
|
|
if (this.canvas[pos.y][pos.x] == null) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function hasNext():Bool {
|
|
return this.index != null;
|
|
}
|
|
|
|
private function nextValidPixel(): Null<Pos> {
|
|
if (this.index == null) {
|
|
return null;
|
|
}
|
|
|
|
var startX = this.index.x + 1;
|
|
|
|
for (y in this.index.y...this.canvas.length){
|
|
if (this.canvas[y] == null) {
|
|
continue;
|
|
}
|
|
|
|
for (x in startX...(this.canvas[y].length)){
|
|
if (this.canvas[y][x] == null) {
|
|
continue;
|
|
}
|
|
|
|
return {x: x, y: y};
|
|
}
|
|
|
|
startX = 0;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function next():{key:Pos, value:Pixel} {
|
|
var rtn = {
|
|
key: this.index,
|
|
value: this.canvas[this.index.y][this.index.x]
|
|
};
|
|
|
|
this.index = this.nextIndex;
|
|
this.nextIndex = nextValidPixel();
|
|
|
|
|
|
return rtn;
|
|
}
|
|
}
|