initial commit

This commit is contained in:
2021-12-20 01:55:30 +01:00
commit bd790c1488
38 changed files with 2320 additions and 0 deletions

74
src/lib/ui/Canvas.hx Normal file
View File

@@ -0,0 +1,74 @@
package lib.ui;
import util.Vec.Vec2;
import kernel.ui.TermBuffer.Pixel;
abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> {
inline public function new() {
this = [[]];
}
public inline function set(i:Vec2<Int>,pixel:Pixel) {
if (this[i.y] == null){
this[i.y] = [];
}
this[i.y][i.x] = pixel;
}
public inline function get(i:Vec2<Int>): Pixel {
return this[i.y][i.x];
}
public function keyValueIterator(): KeyValueIterator<Vec2<Int>,Pixel>{
return new CanvasKeyValueIterator(this);
}
public function combine(other: Canvas,offset: Vec2<Int>) {
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;
}
}
}
class CanvasKeyValueIterator{
private final canvas:Array<Array<Pixel>>;
private var index:Vec2<Int> = {x: 0,y: 0};
@:allow(lib.ui.Canvas)
private function new(canvas: Array<Array<Pixel>>) {
this.canvas = canvas;
}
public function hasNext():Bool{
return index.y < canvas.length && index.x < canvas[index.y].length;
}
public function next():{key:Vec2<Int>, value:Pixel}{
var oldIndex: Vec2<Int> = this.index;
if (index.x >= canvas[index.y].length){
// Goto next line
index = {x:0,y: index.y + 1};
}else{
// Goto next pixel in line
index = {x:index.x + 1,y: index.y};
}
return {
key: oldIndex,
value: this.canvas[oldIndex.y][oldIndex.x]
};
}
}

7
src/lib/ui/IElement.hx Normal file
View File

@@ -0,0 +1,7 @@
package lib.ui;
import util.Vec.Vec2;
interface IElement {
public function render(bounds: Vec2<Int>): Canvas;
}

80
src/lib/ui/ReactiveUI.hx Normal file
View File

@@ -0,0 +1,80 @@
package lib.ui;
import kernel.Log;
import util.Color;
import util.Vec.Vec2;
import kernel.ui.WindowContext;
class ReactiveUI {
private final context:WindowContext;
public function new(context: WindowContext) {
this.context = context;
}
public function render(children: Array<IElement>) {
var size = context.getSize();
var screen = renderChildren(children,size);
writeToContext(screen);
}
private function writeToContext(screen: Canvas) {
var currentBg: Color = Black;
var currentFg: Color = White;
var currentLine = 0;
context.setBackgroundColor(currentBg);
context.setTextColor(currentFg);
context.setCursorPos(0,0);
for (key => pixel in screen) {
if (key.y != currentLine){
currentLine = key.y;
context.setCursorPos(key.x,key.y);
}
if (pixel == null){
context.write(' ');
}else{
if (pixel.bg != currentBg){
context.setBackgroundColor(pixel.bg);
currentBg = pixel.bg;
}
if (pixel.textColor != currentFg){
context.setTextColor(pixel.textColor);
currentFg = pixel.textColor;
}
context.write(pixel.char);
}
}
}
public static function renderChildren(children: Array<IElement>,bounds: Vec2<Int>): Canvas {
var rtn: Canvas = new Canvas();
var writePoint: Vec2<Int> = {x: 0,y: 0};
for (child in children) {
if (bounds.y - writePoint.y <= 0){
// No more space to render children
Log.debug("No more space");
break;
}
var childRender = child.render({
x: bounds.x,
y: bounds.y - writePoint.y
});
rtn.combine(childRender,writePoint);
}
return rtn;
}
}

31
src/lib/ui/TextElement.hx Normal file
View File

@@ -0,0 +1,31 @@
package lib.ui;
import kernel.Log;
import util.Color;
import util.Vec.Vec2;
import util.MathI;
class TextElement implements IElement {
private final text:String;
private final bg:Color;
private final fg:Color;
public function new(text: String,?background: Color = Black,?textColor: Color = White) {
this.text = text;
this.bg = background;
this.fg = textColor;
}
public function render(bounds: Vec2<Int>):Canvas {
var rtn = new Canvas();
for (i in 0...MathI.min(Math.floor(text.length / bounds.x) + 1,bounds.y)){
var line = (text.substr(i * bounds.x,bounds.x));
for (char in 0...line.length) {
rtn.set({x: char,y: i},{textColor: fg,char: line.charAt(char),bg: bg});
}
}
return rtn;
}
}

View File

@@ -0,0 +1,18 @@
package lib.ui;
import util.Vec.Vec2;
import kernel.ui.TermBuffer.Pixel;
class VSplitLayout implements IElement{
public function new(childrenLeft: Array<IElement>,childrenRight: Array<IElement>) {
}
public function render(bounds:Vec2<Int>):Canvas {
var boundsLeft: Vec2<Int> = { x: Math.ceil(bounds.x / 2), y: bounds.y};
var boundsRight: Vec2<Int> = { x: Math.floor(bounds.x / 2), y: bounds.y};
return null;
}
}