From 829484cb67f39a36b0636efdf7346ff84e80a3a8 Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Sun, 20 Feb 2022 20:56:37 +0100 Subject: [PATCH] real reactive ui --- src/Startup.hx | 16 ++++++++++++---- src/lib/ui/IElement.hx | 2 ++ src/lib/ui/Observable.hx | 28 ++++++++++++++++++++++++++++ src/lib/ui/ReactiveUI.hx | 12 ++++++++++-- src/lib/ui/TextElement.hx | 26 +++++++++++++++++++++----- src/lib/ui/VSplitLayout.hx | 18 ------------------ 6 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 src/lib/ui/Observable.hx delete mode 100644 src/lib/ui/VSplitLayout.hx diff --git a/src/Startup.hx b/src/Startup.hx index e830fd3..90b0a40 100644 --- a/src/Startup.hx +++ b/src/Startup.hx @@ -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"); } } diff --git a/src/lib/ui/IElement.hx b/src/lib/ui/IElement.hx index 9cf7400..8c56a9d 100644 --- a/src/lib/ui/IElement.hx +++ b/src/lib/ui/IElement.hx @@ -1,7 +1,9 @@ package lib.ui; +using tink.CoreApi; import util.Vec.Vec2; interface IElement { public function render(bounds: Vec2): Canvas; + public var changed(default, null):Signal; } diff --git a/src/lib/ui/Observable.hx b/src/lib/ui/Observable.hx new file mode 100644 index 0000000..6413ef7 --- /dev/null +++ b/src/lib/ui/Observable.hx @@ -0,0 +1,28 @@ +package lib.ui; + +using tink.CoreApi; + +class Observable { + private var value: T; + private var callbacks: CallbackList = 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):CallbackLink { + callback.invoke(value); + return callbacks.add(callback); + } +} diff --git a/src/lib/ui/ReactiveUI.hx b/src/lib/ui/ReactiveUI.hx index fcdb024..9849252 100644 --- a/src/lib/ui/ReactiveUI.hx +++ b/src/lib/ui/ReactiveUI.hx @@ -7,12 +7,20 @@ import kernel.ui.WindowContext; class ReactiveUI { private final context:WindowContext; + private final children:Array; - public function new(context: WindowContext) { + public function new(context: WindowContext,children: Array) { this.context = context; + this.children = children; + + for(child in children){ + child.changed.handle(v -> { + render(); + }); + } } - public function render(children: Array) { + public function render() { var size = context.getSize(); var screen = renderChildren(children,size); diff --git a/src/lib/ui/TextElement.hx b/src/lib/ui/TextElement.hx index 4045e36..8210e9e 100644 --- a/src/lib/ui/TextElement.hx +++ b/src/lib/ui/TextElement.hx @@ -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; + private var changedTrigger:SignalTrigger; + + private final text: Observable; private final bg:Color; private final fg:Color; - public function new(text: String,?background: Color = Black,?textColor: Color = White) { + public function new(text: Observable,?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):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}); } diff --git a/src/lib/ui/VSplitLayout.hx b/src/lib/ui/VSplitLayout.hx deleted file mode 100644 index 2398eb3..0000000 --- a/src/lib/ui/VSplitLayout.hx +++ /dev/null @@ -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,childrenRight: Array) { - - } - - public function render(bounds:Vec2):Canvas { - var boundsLeft: Vec2 = { x: Math.ceil(bounds.x / 2), y: bounds.y}; - var boundsRight: Vec2 = { x: Math.floor(bounds.x / 2), y: bounds.y}; - - return null; - } -}