From 46f03fbfe4099757eaaef460d2b1ce8bbf5b8158 Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Fri, 4 Mar 2022 13:28:52 +0100 Subject: [PATCH] improved reactive ui and events --- src/kernel/ui/WindowContext.hx | 56 ++++++++++++------------ src/kernel/ui/WindowManager.hx | 25 +++++------ src/lib/ui/UIEvents.hx | 15 +++++++ src/lib/ui/reactive/ReactiveUI.hx | 70 ++++++++++++++++++++++++++++-- src/lib/ui/reactive/TextElement.hx | 8 +--- src/lib/ui/reactive/UIElement.hx | 11 +++-- 6 files changed, 128 insertions(+), 57 deletions(-) create mode 100644 src/lib/ui/UIEvents.hx diff --git a/src/kernel/ui/WindowContext.hx b/src/kernel/ui/WindowContext.hx index 1a60928..47a10d1 100644 --- a/src/kernel/ui/WindowContext.hx +++ b/src/kernel/ui/WindowContext.hx @@ -13,42 +13,42 @@ import lib.TermWriteable; class WindowContext implements TermWriteable { private final writer:VirtualTermWriter; - public var clickSignal(default, null):Signal<{button:ButtonType, pos:Vec2}>; - public var keySignal(default, null):Signal<{keyCode:Int, isHeld:Bool}>; - public var keyUpSignal(default, null):Signal; - public var mouseDragSignal(default, null):Signal<{button:ButtonType, pos:Vec2}>; - public var mouseScrollSignal(default, null):Signal<{dir:Int, pos:Vec2}>; - public var mouseUpSignal(default, null):Signal<{button:ButtonType, pos:Vec2}>; - public var pasteSignal(default, null):Signal; + public var onClick(default, null):Signal<{button:ButtonType, pos:Vec2}>; + public var onKey(default, null):Signal<{keyCode:Int, isHeld:Bool}>; + public var onKeyUp(default, null):Signal; + public var onMouseDrag(default, null):Signal<{button:ButtonType, pos:Vec2}>; + public var onMouseScroll(default, null):Signal<{dir:Int, pos:Vec2}>; + public var onMouseUp(default, null):Signal<{button:ButtonType, pos:Vec2}>; + public var onPaste(default, null):Signal; - @:allow(kernel.ui.WindowManager) private final clickTrigger:SignalTrigger<{button:ButtonType, pos:Vec2}>; - @:allow(kernel.ui.WindowManager) private final keyTrigger:SignalTrigger<{keyCode:Int, isHeld:Bool}>; - @:allow(kernel.ui.WindowManager) private final keyUpTrigger:SignalTrigger; - @:allow(kernel.ui.WindowManager) private final mouseDragTrigger:SignalTrigger<{button:ButtonType, pos:Vec2}>; - @:allow(kernel.ui.WindowManager) private final mouseScrollTrigger:SignalTrigger<{dir:Int, pos:Vec2}>; - @:allow(kernel.ui.WindowManager) private final mouseUpTrigger:SignalTrigger<{button:ButtonType, pos:Vec2}>; - @:allow(kernel.ui.WindowManager) private final pasteTrigger:SignalTrigger; + @:allow(kernel.ui.WindowManager) private final onClickTrigger:SignalTrigger<{button:ButtonType, pos:Vec2}>; + @:allow(kernel.ui.WindowManager) private final onKeyTrigger:SignalTrigger<{keyCode:Int, isHeld:Bool}>; + @:allow(kernel.ui.WindowManager) private final onKeyUpTrigger:SignalTrigger; + @:allow(kernel.ui.WindowManager) private final onMouseDragTrigger:SignalTrigger<{button:ButtonType, pos:Vec2}>; + @:allow(kernel.ui.WindowManager) private final onMouseScrollTrigger:SignalTrigger<{dir:Int, pos:Vec2}>; + @:allow(kernel.ui.WindowManager) private final onMouseUpTrigger:SignalTrigger<{button:ButtonType, pos:Vec2}>; + @:allow(kernel.ui.WindowManager) private final onPasteTrigger:SignalTrigger; @:allow(kernel.ui.WindowManager) private function new(writer:VirtualTermWriter) { this.writer = writer; this.onResize = writer.onResize; - this.clickTrigger = Signal.trigger(); - this.keyTrigger = Signal.trigger(); - this.keyUpTrigger = Signal.trigger(); - this.mouseDragTrigger = Signal.trigger(); - this.mouseScrollTrigger = Signal.trigger(); - this.mouseUpTrigger = Signal.trigger(); - this.pasteTrigger = Signal.trigger(); + this.onClickTrigger = Signal.trigger(); + this.onKeyTrigger = Signal.trigger(); + this.onKeyUpTrigger = Signal.trigger(); + this.onMouseDragTrigger = Signal.trigger(); + this.onMouseScrollTrigger = Signal.trigger(); + this.onMouseUpTrigger = Signal.trigger(); + this.onPasteTrigger = Signal.trigger(); - this.clickSignal = clickTrigger.asSignal(); - this.keySignal = keyTrigger.asSignal(); - this.keyUpSignal = keyUpTrigger.asSignal(); - this.mouseDragSignal = mouseDragTrigger.asSignal(); - this.mouseScrollSignal = mouseScrollTrigger.asSignal(); - this.mouseUpSignal = mouseUpTrigger.asSignal(); - this.pasteSignal = pasteTrigger.asSignal(); + this.onClick = onClickTrigger.asSignal(); + this.onKey = onKeyTrigger.asSignal(); + this.onKeyUp = onKeyUpTrigger.asSignal(); + this.onMouseDrag = onMouseDragTrigger.asSignal(); + this.onMouseScroll = onMouseScrollTrigger.asSignal(); + this.onMouseUp = onMouseUpTrigger.asSignal(); + this.onPaste = onPasteTrigger.asSignal(); } public var onResize(default, null):Signal>; diff --git a/src/kernel/ui/WindowManager.hx b/src/kernel/ui/WindowManager.hx index efb749b..5199e2f 100644 --- a/src/kernel/ui/WindowManager.hx +++ b/src/kernel/ui/WindowManager.hx @@ -8,48 +8,51 @@ class WindowManager { Depends on: KernelEvents, Peripheral **/ public static var instance:WindowManager; + private var currentMainContext:WindowContext; + private final allContexts:Array = new Array(); + private final outputMap:Map = new Map(); @:allow(kernel.Init) private function new() { KernelEvents.instance.onKey.handle(params -> { if (currentMainContext != null) { - currentMainContext.keyTrigger.trigger(params); + currentMainContext.onKeyTrigger.trigger(params); } }); KernelEvents.instance.onKeyUp.handle(keyCode -> { if (currentMainContext != null) { - currentMainContext.keyUpTrigger.trigger(keyCode); + currentMainContext.onKeyUpTrigger.trigger(keyCode); } }); KernelEvents.instance.onMouseClick.handle(params -> { if (currentMainContext != null) { - currentMainContext.clickTrigger.trigger(params); + currentMainContext.onClickTrigger.trigger(params); } }); KernelEvents.instance.onMouseDrag.handle(params -> { if (currentMainContext != null) { - currentMainContext.mouseDragTrigger.trigger(params); + currentMainContext.onMouseDragTrigger.trigger(params); } }); KernelEvents.instance.onMouseScroll.handle(params -> { if (currentMainContext != null) { - currentMainContext.mouseScrollTrigger.trigger(params); + currentMainContext.onMouseScrollTrigger.trigger(params); } }); KernelEvents.instance.onMouseUp.handle(params -> { - if (currentMainContext != null) { - currentMainContext.mouseUpTrigger.trigger(params); - } + // if (currentMainContext != null) { + currentMainContext.onMouseUpTrigger.trigger(params); + // } }); KernelEvents.instance.onPaste.handle(text -> { if (currentMainContext != null) { - currentMainContext.pasteTrigger.trigger(text); + currentMainContext.onPasteTrigger.trigger(text); } }); @@ -58,10 +61,6 @@ class WindowManager { }); } - private var currentMainContext:WindowContext; - private final allContexts:Array = new Array(); - private final outputMap:Map = new Map(); - public function createNewContext():WindowContext { var newContext = new WindowContext(new VirtualTermWriter()); diff --git a/src/lib/ui/UIEvents.hx b/src/lib/ui/UIEvents.hx new file mode 100644 index 0000000..44722d4 --- /dev/null +++ b/src/lib/ui/UIEvents.hx @@ -0,0 +1,15 @@ +package lib.ui; + +import util.Vec.Vec2; +import kernel.ButtonType; +using tink.CoreApi; + +typedef UIEvents = { + public var ?onClick:Callback<{button:ButtonType, pos:Vec2}>; + public var ?onKey:Callback<{keyCode:Int, isHeld:Bool}>; + public var ?onKeyUp:Callback; + public var ?onMouseDrag:Callback<{button:ButtonType, pos:Vec2}>; + public var ?onMouseScroll:Callback<{dir:Int, pos:Vec2}>; + public var ?onMouseUp:Callback<{button:ButtonType, pos:Vec2}>; + public var ?onPaste:Callback; +} diff --git a/src/lib/ui/reactive/ReactiveUI.hx b/src/lib/ui/reactive/ReactiveUI.hx index b3ed562..e4cc38a 100644 --- a/src/lib/ui/reactive/ReactiveUI.hx +++ b/src/lib/ui/reactive/ReactiveUI.hx @@ -28,13 +28,76 @@ class ReactiveUI { } private function setupEvents() { - context.clickSignal.handle(params ->{ - for (k => v in this.elementMap){ + context.onClick.handle(params ->{ + for (k => v in elementMap){ if (k.isInside(params.pos)){ - v.handleClickEvent(params.pos,params.button); + if (v.eventListner.onClick != null){ + v.eventListner.onClick.invoke(params); + } } } }); + + // context.onKey.handle(params ->{ + // for (k => v in elementMap){ + // if (k.isInside(params.pos)){ + // if (v.eventListner.onKey != null){ + // v.eventListner.onKey.invoke(params); + // } + // } + // } + // }); + + // context.onKeyUp.handle(params ->{ + // for (k => v in elementMap){ + // if (k.isInside(params.pos)){ + // if (v.eventListner.onKeyUp != null){ + // v.eventListner.onKeyUp.invoke(params); + // } + // } + // } + // }); + + // context.onMouseDrag.handle(params ->{ + // for (k => v in elementMap){ + // if (k.isInside(params.pos)){ + // if (v.eventListner.onMouseDrag != null){ + // v.eventListner.onMouseDrag.invoke(params); + // } + // } + // } + // }); + + context.onMouseScroll.handle(params ->{ + for (k => v in elementMap){ + if (k.isInside(params.pos)){ + if (v.eventListner.onMouseScroll != null){ + v.eventListner.onMouseScroll.invoke(params); + } + } + } + }); + + context.onMouseUp.handle(params ->{ + for (k => v in elementMap){ + if (k.isInside(params.pos)){ + if (v.eventListner.onMouseUp != null){ + v.eventListner.onMouseUp.invoke(params); + } + } + } + }); + + // context.onPaste.handle(params ->{ + // for (k => v in elementMap){ + // if (k.isInside(params.pos)){ + // if (v.eventListner.onPaste != null){ + // v.eventListner.onPaste.invoke(params); + // } + // } + // } + // }); + } public function render() { @@ -88,7 +151,6 @@ class ReactiveUI { for (child in children) { if (bounds.y - writePoint.y <= 0) { // No more space to render children - Log.debug("No more space"); break; } diff --git a/src/lib/ui/reactive/TextElement.hx b/src/lib/ui/reactive/TextElement.hx index f7fd7a5..85c1150 100644 --- a/src/lib/ui/reactive/TextElement.hx +++ b/src/lib/ui/reactive/TextElement.hx @@ -14,8 +14,8 @@ class TextElement extends UIElement { private final bg:Color; private final fg:Color; - public function new(text:Observable, ?background:Color = Black, ?textColor:Color = White) { - super(); + public function new(text:Observable, ?background:Color = Black, ?textColor:Color = White, events: UIEvents = null) { + super(events); this.text = text; this.bg = background; @@ -38,8 +38,4 @@ class TextElement extends UIElement { return rtn; } - - public override function handleClickEvent(pos: Vec2,button: ButtonType):Void { - Log.debug('Click: ${this.text.get()}'); - } } diff --git a/src/lib/ui/reactive/UIElement.hx b/src/lib/ui/reactive/UIElement.hx index 6509ffa..339aa63 100644 --- a/src/lib/ui/reactive/UIElement.hx +++ b/src/lib/ui/reactive/UIElement.hx @@ -1,7 +1,5 @@ package lib.ui.reactive; -import kernel.Log; -import kernel.ButtonType; import util.Vec.Vec2; using tink.CoreApi; @@ -10,11 +8,12 @@ abstract class UIElement { abstract public function render(bounds:Vec2):Canvas; public var changed(default, null):Signal; private final changedTrigger:SignalTrigger = Signal.trigger(); + public final eventListner:UIEvents = {}; - public function new() { + public function new(events: UIEvents = null) { changed = changedTrigger.asSignal(); - } - - public function handleClickEvent(pos: Vec2,button: ButtonType):Void { + if (events != null){ + this.eventListner = events; + } } }