This commit is contained in:
2022-02-21 15:35:37 +01:00
parent f21e49c520
commit 0ad907f74a
33 changed files with 788 additions and 815 deletions

View File

@@ -8,32 +8,32 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> {
this = [[]];
}
public inline function set(i:Vec2<Int>,pixel:Pixel) {
if (this[i.y] == null){
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 {
public inline function get(i:Vec2<Int>):Pixel {
return this[i.y][i.x];
}
public function keyValueIterator(): KeyValueIterator<Vec2<Int>,Pixel>{
public function keyValueIterator():KeyValueIterator<Vec2<Int>, Pixel> {
return new CanvasKeyValueIterator(this);
}
public function combine(other: Canvas,offset: Vec2<Int>) {
public function combine(other:Canvas, offset:Vec2<Int>) {
for (key => value in other) {
if (value == null){
if (value == null) {
continue;
}
var y = offset.y + key.y;
var x = offset.x + key.x;
if (this[y] == null){
if (this[y] == null) {
this[y] = [];
}
@@ -41,14 +41,14 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> {
}
}
public function hight(): Int {
public function hight():Int {
return this.length;
}
public function maxWidth() {
var max = 0;
for (i in 0...this.length){
if (this[i].length > max){
for (i in 0...this.length) {
if (this[i].length > max) {
max = this[i].length;
}
}
@@ -57,28 +57,28 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> {
}
}
class CanvasKeyValueIterator{
class CanvasKeyValueIterator {
private final canvas:Array<Array<Pixel>>;
private var index:Vec2<Int> = {x: 0,y: 0};
private var index:Vec2<Int> = {x: 0, y: 0};
@:allow(lib.ui.Canvas)
private function new(canvas: Array<Array<Pixel>>) {
private function new(canvas:Array<Array<Pixel>>) {
this.canvas = canvas;
}
public function hasNext():Bool{
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;
public function next():{key:Vec2<Int>, value:Pixel} {
var oldIndex:Vec2<Int> = this.index;
if (index.x >= canvas[index.y].length){
if (index.x >= canvas[index.y].length) {
// Goto next line
index = {x:0,y: index.y + 1};
}else{
index = {x: 0, y: index.y + 1};
} else {
// Goto next pixel in line
index = {x:index.x + 1,y: index.y};
index = {x: index.x + 1, y: index.y};
}
return {

View File

@@ -1,9 +1,10 @@
package lib.ui;
using tink.CoreApi;
import util.Vec.Vec2;
interface IElement {
public function render(bounds: Vec2<Int>): Canvas;
public var changed(default, null):Signal<Noise>;
public function render(bounds:Vec2<Int>):Canvas;
public var changed(default, null):Signal<Noise>;
}

View File

@@ -3,26 +3,26 @@ package lib.ui;
using tink.CoreApi;
class Observable<T> {
private var value: T;
private var callbacks: CallbackList<T> = new CallbackList(true);
private var value:T;
private var callbacks:CallbackList<T> = new CallbackList(true);
public function new(value: T) {
this.value = value;
}
public function new(value:T) {
this.value = value;
}
public function set(value: T) {
if (value != this.value){
this.value = value;
callbacks.invoke(value);
}
}
public function set(value:T) {
if (value != this.value) {
this.value = value;
callbacks.invoke(value);
}
}
public function get(): T {
return value;
}
public function get():T {
return value;
}
public function subscribe(callback: Callback<T>):CallbackLink {
callback.invoke(value);
return callbacks.add(callback);
}
public function subscribe(callback:Callback<T>):CallbackLink {
callback.invoke(value);
return callbacks.add(callback);
}
}

View File

@@ -8,12 +8,12 @@ import kernel.ui.WindowContext;
class ReactiveUI {
private final context:WindowContext;
private final children:Array<IElement>;
public function new(context: WindowContext,children: Array<IElement>) {
public function new(context:WindowContext, children:Array<IElement>) {
this.context = context;
this.children = children;
for(child in children){
for (child in children) {
child.changed.handle(v -> {
render();
});
@@ -23,37 +23,36 @@ class ReactiveUI {
public function render() {
var size = context.getSize();
var screen = renderChildren(children,size);
var screen = renderChildren(children, size);
writeToContext(screen);
}
private function writeToContext(screen: Canvas) {
var currentBg: Color = Black;
var currentFg: Color = White;
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);
context.setCursorPos(0, 0);
for (key => pixel in screen) {
if (key.y != currentLine){
if (key.y != currentLine) {
currentLine = key.y;
context.setCursorPos(key.x,key.y);
context.setCursorPos(key.x, key.y);
}
if (pixel == null){
if (pixel == null) {
context.write(' ');
}else{
if (pixel.bg != currentBg){
} else {
if (pixel.bg != currentBg) {
context.setBackgroundColor(pixel.bg);
currentBg = pixel.bg;
}
if (pixel.textColor != currentFg){
if (pixel.textColor != currentFg) {
context.setTextColor(pixel.textColor);
currentFg = pixel.textColor;
}
@@ -63,13 +62,13 @@ class ReactiveUI {
}
}
public static function renderChildren(children: Array<IElement>,bounds: Vec2<Int>): Canvas {
var rtn: Canvas = new Canvas();
public static function renderChildren(children:Array<IElement>, bounds:Vec2<Int>):Canvas {
var rtn:Canvas = new Canvas();
var writePoint: Vec2<Int> = {x: 0,y: 0};
var writePoint:Vec2<Int> = {x: 0, y: 0};
for (child in children) {
if (bounds.y - writePoint.y <= 0){
if (bounds.y - writePoint.y <= 0) {
// No more space to render children
Log.debug("No more space");
break;
@@ -80,9 +79,9 @@ class ReactiveUI {
y: bounds.y - writePoint.y
});
rtn.combine(childRender,writePoint);
rtn.combine(childRender, writePoint);
writePoint = {x: 0,y: writePoint.y + childRender.hight() };
writePoint = {x: 0, y: writePoint.y + childRender.hight()};
}
return rtn;

View File

@@ -7,41 +7,41 @@ import util.Vec.Vec2;
import util.MathI;
class TextElement implements IElement {
public var changed(default, null):Signal<Noise>;
private var changedTrigger:SignalTrigger<Noise>;
private final text: Observable<String>;
private final bg:Color;
private final fg:Color;
public var changed(default, null):Signal<Noise>;
public function new(text: Observable<String>,?background: Color = Black,?textColor: Color = White) {
private var changedTrigger:SignalTrigger<Noise>;
setupTrigger();
private final text:Observable<String>;
private final bg:Color;
private final fg:Color;
this.text = text;
this.bg = background;
this.fg = textColor;
public function new(text:Observable<String>, ?background:Color = Black, ?textColor:Color = White) {
setupTrigger();
this.text.subscribe(value -> {
this.changedTrigger.trigger(null);
});
}
this.text = text;
this.bg = background;
this.fg = textColor;
private function setupTrigger() {
changedTrigger = Signal.trigger();
changed = changedTrigger.asSignal();
}
this.text.subscribe(value -> {
this.changedTrigger.trigger(null);
});
}
public function render(bounds: Vec2<Int>):Canvas {
private function setupTrigger() {
changedTrigger = Signal.trigger();
changed = changedTrigger.asSignal();
}
public function render(bounds:Vec2<Int>):Canvas {
var rtn = new Canvas();
for (i in 0...MathI.min(Math.floor(text.get().length / bounds.x) + 1,bounds.y)){
var line = (text.get().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});
}
for (i in 0...MathI.min(Math.floor(text.get().length / bounds.x) + 1, bounds.y)) {
var line = (text.get().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;
return rtn;
}
}
}