real reactive ui
This commit is contained in:
		
							parent
							
								
									7b33667e04
								
							
						
					
					
						commit
						829484cb67
					
				@ -1,3 +1,4 @@
 | 
			
		||||
import lib.ui.Observable;
 | 
			
		||||
import lib.ui.TextElement;
 | 
			
		||||
import lib.ui.ReactiveUI;
 | 
			
		||||
import kernel.Log;
 | 
			
		||||
@ -36,13 +37,20 @@ class Startup {
 | 
			
		||||
 | 
			
		||||
	static function exampleUI() {
 | 
			
		||||
		var context = WindowManager.instance.createNewContext();
 | 
			
		||||
		var ui = new ReactiveUI(context);
 | 
			
		||||
 | 
			
		||||
		ui.render([
 | 
			
		||||
			new TextElement("Hello world"),
 | 
			
		||||
			new TextElement("Hello world",Green,Red),
 | 
			
		||||
		var text = new Observable("Hello world");
 | 
			
		||||
 | 
			
		||||
		var ui = new ReactiveUI(context,[
 | 
			
		||||
			new TextElement(text),
 | 
			
		||||
			new TextElement(text,Green,Red),
 | 
			
		||||
		]);
 | 
			
		||||
 | 
			
		||||
		ui.render();
 | 
			
		||||
		
 | 
			
		||||
		context.clickSignal.on(data -> {
 | 
			
		||||
			text.set("Holla mundo");
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		WindowManager.instance.focusContextToOutput(context,"main");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,9 @@
 | 
			
		||||
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>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								src/lib/ui/Observable.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/lib/ui/Observable.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
package lib.ui;
 | 
			
		||||
 | 
			
		||||
using tink.CoreApi;
 | 
			
		||||
 | 
			
		||||
class Observable<T> {
 | 
			
		||||
    private var value: T;
 | 
			
		||||
    private var callbacks: CallbackList<T> = new CallbackList(true);
 | 
			
		||||
 | 
			
		||||
    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 get(): T {
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function subscribe(callback: Callback<T>):CallbackLink {
 | 
			
		||||
        callback.invoke(value);
 | 
			
		||||
        return callbacks.add(callback);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -7,12 +7,20 @@ import kernel.ui.WindowContext;
 | 
			
		||||
 | 
			
		||||
class ReactiveUI {
 | 
			
		||||
	private final context:WindowContext;
 | 
			
		||||
	private final children:Array<IElement>;
 | 
			
		||||
	
 | 
			
		||||
	public function new(context: WindowContext) {
 | 
			
		||||
	public function new(context: WindowContext,children: Array<IElement>) {
 | 
			
		||||
		this.context = context;
 | 
			
		||||
		this.children = children;
 | 
			
		||||
 | 
			
		||||
		for(child in children){
 | 
			
		||||
			child.changed.handle(v -> {
 | 
			
		||||
				render();
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public function render(children: Array<IElement>) {
 | 
			
		||||
	public function render() {
 | 
			
		||||
		var size = context.getSize();
 | 
			
		||||
 | 
			
		||||
		var screen = renderChildren(children,size);
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,42 @@
 | 
			
		||||
package lib.ui;
 | 
			
		||||
 | 
			
		||||
import kernel.Log;
 | 
			
		||||
using tink.CoreApi;
 | 
			
		||||
 | 
			
		||||
import util.Color;
 | 
			
		||||
import util.Vec.Vec2;
 | 
			
		||||
import util.MathI;
 | 
			
		||||
 | 
			
		||||
class TextElement implements IElement {
 | 
			
		||||
    private final text:String;
 | 
			
		||||
    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 function new(text: String,?background: Color = Black,?textColor: Color = White) {
 | 
			
		||||
    public function new(text: Observable<String>,?background: Color = Black,?textColor: Color = White) {
 | 
			
		||||
 | 
			
		||||
        setupTrigger();
 | 
			
		||||
 | 
			
		||||
        this.text = text;
 | 
			
		||||
        this.bg = background;
 | 
			
		||||
        this.fg = textColor;
 | 
			
		||||
 | 
			
		||||
        this.text.subscribe(value -> {
 | 
			
		||||
            this.changedTrigger.trigger(null);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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.length / bounds.x) + 1,bounds.y)){
 | 
			
		||||
			var line = (text.substr(i * bounds.x,bounds.x));
 | 
			
		||||
        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});
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user