From c39051939393f234c051ae7bb93461dee5125311 Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Sat, 8 Jul 2023 14:01:38 +0200 Subject: [PATCH] some ui stuff --- src/kernel/ui/StatelessVirtualTermWriter.hx | 3 + src/lib/HomeContext.hx | 6 +- src/lib/ui/elements/RootElement.hx | 20 ++- src/lib/ui/elements/TextElement.hx | 2 +- src/lib/ui/elements/UIElement.hx | 2 +- src/lib/ui/reactive/ListElement.hx | 74 --------- src/lib/ui/reactive/ReactiveUI.hx | 170 -------------------- src/lib/ui/reactive/TextElement.hx | 77 --------- src/lib/ui/reactive/TurtleController.hx | 60 ------- src/lib/ui/reactive/UIElement.hx | 47 ------ 10 files changed, 26 insertions(+), 435 deletions(-) delete mode 100644 src/lib/ui/reactive/ListElement.hx delete mode 100644 src/lib/ui/reactive/ReactiveUI.hx delete mode 100644 src/lib/ui/reactive/TextElement.hx delete mode 100644 src/lib/ui/reactive/TurtleController.hx delete mode 100644 src/lib/ui/reactive/UIElement.hx diff --git a/src/kernel/ui/StatelessVirtualTermWriter.hx b/src/kernel/ui/StatelessVirtualTermWriter.hx index 84cdc7f..66255f5 100644 --- a/src/kernel/ui/StatelessVirtualTermWriter.hx +++ b/src/kernel/ui/StatelessVirtualTermWriter.hx @@ -40,6 +40,7 @@ class StatelessVirtualTermWriter implements VirtualTermWriter { } if (enabled) { + target.reset(); renderFunc(); renderRequested = false; }else{ @@ -84,6 +85,8 @@ class StatelessVirtualTermWriter implements VirtualTermWriter { }); target = newTarget; + + target.reset(); } public function isEnabled():Bool { diff --git a/src/lib/HomeContext.hx b/src/lib/HomeContext.hx index 3a9f847..f686360 100644 --- a/src/lib/HomeContext.hx +++ b/src/lib/HomeContext.hx @@ -46,6 +46,7 @@ class HomeContext { WindowManager.instance.focusContextToOutput(ctx, "main"); renderer = new RootElement(); + renderer.setTitle("Home"); ctx.delegateEvents(renderer); stateless.setRenderFunc(this.render); @@ -146,7 +147,6 @@ class HomeContext { } private function render() { - ctx.clear(); ctx.setCursorBlink(false); var workspaceIDs:Array = [for (k=>v in workspaces) k]; @@ -163,11 +163,11 @@ class HomeContext { )); } - children.push(new TextElement('Output :${selectedOutput}', {onClick: this.cycleOutput})); + children.push(new TextElement('Output: ${selectedOutput}', {onClick: this.cycleOutput})); children.push(new TextElement('Exit', {onClick: KernelEvents.instance.shutdown})); renderer.setChildren(children); - renderer.render().renderToContext(ctx); + renderer.render(ctx.getSize()).renderToContext(ctx); } } diff --git a/src/lib/ui/elements/RootElement.hx b/src/lib/ui/elements/RootElement.hx index a6f66a0..b8afc2a 100644 --- a/src/lib/ui/elements/RootElement.hx +++ b/src/lib/ui/elements/RootElement.hx @@ -3,6 +3,7 @@ package lib.ui.elements; class RootElement implements UIElement { private var children:Array; private final eventManager:UIEventManager = new UIEventManager(); + private var title:String = ""; public function new(?children:Array) { if (children == null) { @@ -20,14 +21,21 @@ class RootElement implements UIElement { this.children = children; } - public function render():Canvas { + public function render(bounds: Pos):Canvas { var canvas = new Canvas(); var offset = new Pos({x: 0, y: 0}); + if (hasTitle()) { + var title = new TextElement(this.title); + var halfWidth = Math.floor(bounds.x / 2) - Math.floor(this.title.length / 2); + canvas.combine(title.render(bounds), {x: halfWidth, y: offset.y}); + offset = new Pos({x: 0, y: 1}); + } + this.eventManager.clearMap(); for (child in children) { - var childCanvas = child.render(); + var childCanvas = child.render(bounds); var bounds = childCanvas.getBounds(); bounds.offset(offset); @@ -39,4 +47,12 @@ class RootElement implements UIElement { return canvas; } + + public function setTitle(title: String) { + this.title = title; + } + + private inline function hasTitle(): Bool { + return title != ""; + } } diff --git a/src/lib/ui/elements/TextElement.hx b/src/lib/ui/elements/TextElement.hx index c4db0f5..76e81a9 100644 --- a/src/lib/ui/elements/TextElement.hx +++ b/src/lib/ui/elements/TextElement.hx @@ -24,7 +24,7 @@ class TextElement implements UIElement { return uiEvents; } - public function render():Canvas { + public function render(bounds: Pos):Canvas { var canvas = new Canvas(); for (i in 0...this.text.length) { var c = this.text.charAt(i); diff --git a/src/lib/ui/elements/UIElement.hx b/src/lib/ui/elements/UIElement.hx index a5c73d9..a3e21e1 100644 --- a/src/lib/ui/elements/UIElement.hx +++ b/src/lib/ui/elements/UIElement.hx @@ -3,5 +3,5 @@ package lib.ui.elements; import lib.ui.rendere.UIEventDelegate; interface UIElement extends UIEventDelegate { - public function render():Canvas; + public function render(bounds: Pos):Canvas; } diff --git a/src/lib/ui/reactive/ListElement.hx b/src/lib/ui/reactive/ListElement.hx deleted file mode 100644 index 37d1308..0000000 --- a/src/lib/ui/reactive/ListElement.hx +++ /dev/null @@ -1,74 +0,0 @@ -package lib.ui.reactive; - -import lib.Pos; -import util.Rect; -import util.ObservableArray; -import lib.Vec.Vec2; - -class ListElement extends UIElement { - - private final content:ObservableArray; - private var elementMap: Map = new Map(); // Position in the map is relative. - private var offset:Pos; - - public function new(content: ObservableArray) { - var events: UIEvents = { - onClick: (p)->{ - var element = UIElement.getElementInMap((p.pos:Pos) - offset,elementMap); - if (element != null) - if (element.eventListner.onClick != null) - element.eventListner.onClick.invoke(p); - }, - onMouseUp: (p)->{ - var element = UIElement.getElementInMap((p.pos:Pos) - offset,elementMap); - if (element != null) - if (element.eventListner.onMouseUp != null) - element.eventListner.onMouseUp.invoke(p); - }, - onMouseScroll: (p)->{ - var element = UIElement.getElementInMap((p.pos:Pos) - offset,elementMap); - if (element != null) - if (element.eventListner.onMouseScroll != null) - element.eventListner.onMouseScroll.invoke(p); - }, - }; - - super(events); - - this.content = content; - this.content.subscribe(value -> { - this.changedTrigger.trigger(null); - // TODO: subscribe to elements and forward onChange event - }); - } - - public function render(bounds:Vec2,offset: Pos):Canvas { - var canvas: Canvas = new Canvas(); - var writePoint:Pos = {x: 0, y: 0}; - this.offset = offset; - - for(element in this.content.get()){ - if (bounds.y - writePoint.y <= 0) { - // No more space to render children - break; - } - - var childRender = element.render({ - x: bounds.x, - y: bounds.y - writePoint.y - }, offset + writePoint); - - canvas.combine(childRender, writePoint); - elementMap.set(new Rect(writePoint, - { - x: childRender.maxWidth() + writePoint.x, - y: writePoint.y + (childRender.height() - 1), - } - ),element); - - writePoint = {x: 0, y: writePoint.y + childRender.height()}; - } - - return canvas; - } -} diff --git a/src/lib/ui/reactive/ReactiveUI.hx b/src/lib/ui/reactive/ReactiveUI.hx deleted file mode 100644 index f8e5d0f..0000000 --- a/src/lib/ui/reactive/ReactiveUI.hx +++ /dev/null @@ -1,170 +0,0 @@ -package lib.ui.reactive; - -import util.Pos; -import util.Rect; -import util.Color; -import util.Vec.Vec2; -import kernel.ui.WindowContext; - -using tink.CoreApi; - -class ReactiveUI { - private final context:WindowContext; - private final children:Array; - private var elementMap: Map = new Map(); - - public function new(context:WindowContext, children:Array) { - this.context = context; - this.children = children; - - for (child in children) { - child.changed.handle(_ -> { - context.reset(); - render(); - }); - } - - setupEvents(); - } - - private function setupEvents() { - context.onClick.handle(params ->{ - for (k => v in elementMap){ - if (k.isInside(params.pos)){ - 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() { - var size = context.getSize(); - var result = renderChildren(children, size); - this.elementMap = result.map; - - writeToContext(result.canvas); - } - - 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, bounds:Vec2):{canvas: Canvas, map: Map} { - var canvas:Canvas = new Canvas(); - var elementMap: Map = new Map(); - - var writePoint:Pos = {x: 0, y: 0}; - - for (child in children) { - if (bounds.y - writePoint.y <= 0) { - // No more space to render children - break; - } - - var childRender = child.render({ - x: bounds.x, - y: bounds.y - writePoint.y - },writePoint); - - canvas.combine(childRender, writePoint); - elementMap.set(new Rect(writePoint,{x: childRender.maxWidth() + writePoint.x, y: writePoint.y + (childRender.height() - 1)}),child); - - writePoint = {x: 0, y: writePoint.y + childRender.height()}; - } - - return {canvas: canvas,map: elementMap}; - } -} diff --git a/src/lib/ui/reactive/TextElement.hx b/src/lib/ui/reactive/TextElement.hx deleted file mode 100644 index 6bf4673..0000000 --- a/src/lib/ui/reactive/TextElement.hx +++ /dev/null @@ -1,77 +0,0 @@ -package lib.ui.reactive; - -import lib.ui.Dimensions; -import util.ObjMerge; -import lib.Pos; -import util.Observable; -import lib.Color; -import lib.Vec.Vec2; - -using tink.CoreApi; - -typedef TextElementArgs = { - public var ?text:Observable; - public var ?simpleText: String; - public var ?bg:Color; - public var ?fg:Color; - public var ?padding: Dimensions; - public var ?margin: Dimensions; -} - -class TextElement extends UIElement { - private var args:TextElementArgs; - - public function new(args: TextElementArgs,events: UIEvents = null) { - super(events); - this.args = args; - - if (args.text != null) { - args.text.subscribe(value -> { - this.changedTrigger.trigger(null); - }); - }else if (args.simpleText == null) { - throw new Error("text or simpleText must be set"); - } - } - - private function getText() { - if (args.text != null) { - return args.text.get(); - } else { - return args.simpleText; - } - } - - public function render(bounds:Vec2,offset: Pos):Canvas { - var rtn = new Canvas(); - - var fullText = getText(); - - var writePoint: Pos = {x: 0,y: 0}; - - for (pos in 0...fullText.length) { - var char = fullText.charAt(pos); - - if (char == "\n"){ - writePoint = {x: 0, y: writePoint.y + 1}; - continue; - } - - if (writePoint.y >= bounds.y) { - break; - } - - if (writePoint.x >= bounds.x) { - writePoint = {x: 0, y: writePoint.y + 1}; - } - - rtn.set(writePoint, {char: char,textColor: this.args.fg, bg: this.args.bg}); - - writePoint = {x: writePoint.x + 1, y: writePoint.y}; - } - - - - return UIElement.applyPaddignAndMargin(rtn, this.args.padding, this.args.margin); - } -} diff --git a/src/lib/ui/reactive/TurtleController.hx b/src/lib/ui/reactive/TurtleController.hx deleted file mode 100644 index 9cda310..0000000 --- a/src/lib/ui/reactive/TurtleController.hx +++ /dev/null @@ -1,60 +0,0 @@ -package lib.ui.reactive; - -import lib.Debug; -import lib.Vec.Vec2; -import lib.Pos; - -class TurtleController extends UIElement { - - public function new() { - super(); - } - - private function addButton(label:String): Canvas { - var txt = new TextElement({simpleText: '$label', fg: Red,bg: Orange}); - return txt.render({x:3,y:3},{x:0,y:0}); - } - - public function render(bounds:Vec2, offset:Pos):Canvas { - var canvas: Canvas = new Canvas(); - - canvas.combine(addButton("F"),{x:1,y:1}); - canvas.combine(addButton("F"),{x:5,y:2}); - - return canvas; - - } -} - -// var innerText = switch (sqr) { -// case 0: "D"; -// case 1: "F"; -// case 2: "U"; -// case 3: "L"; -// case 4: "B"; -// case 5: "R"; -// case 6: "D"; -// case 7: "D"; -// case 8: "D"; -// default: "?"; -// }; - - // canvas.set({x: offsetX + 0, y: offsetY + 0}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 1, y: offsetY + 0}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 2, y: offsetY + 0}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 3, y: offsetY + 0}, {char: " ",bg: spaceColor,textColor: textColor}); - - // canvas.set({x: offsetX + 0, y: offsetY + 1}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 1, y: offsetY + 1}, {char: innerText,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 2, y: offsetY + 1}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 3, y: offsetY + 1}, {char: " ",bg: spaceColor,textColor: textColor}); - - // canvas.set({x: offsetX + 0, y: offsetY + 2}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 1, y: offsetY + 2}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 2, y: offsetY + 2}, {char: borderChar,bg: bgColor,textColor: textColor}); - // canvas.set({x: offsetX + 3, y: offsetY + 2}, {char: " ",bg: spaceColor,textColor: textColor}); - - // canvas.set({x: offsetX + 0, y: offsetY + 3}, {char: " ",bg: spaceColor,textColor: textColor}); - // canvas.set({x: offsetX + 1, y: offsetY + 3}, {char: " ",bg: spaceColor,textColor: textColor}); - // canvas.set({x: offsetX + 2, y: offsetY + 3}, {char: " ",bg: spaceColor,textColor: textColor}); - // canvas.set({x: offsetX + 3, y: offsetY + 3}, {char: " ",bg: spaceColor,textColor: textColor}); diff --git a/src/lib/ui/reactive/UIElement.hx b/src/lib/ui/reactive/UIElement.hx deleted file mode 100644 index e47fbd9..0000000 --- a/src/lib/ui/reactive/UIElement.hx +++ /dev/null @@ -1,47 +0,0 @@ -package lib.ui.reactive; - -import util.ObjMerge; -import lib.Pos; -import lib.Rect; -import lib.Vec.Vec2; - -using tink.CoreApi; - -abstract class UIElement { - /** - Render the element inside the bounds. `offset` is the offset to the parents position - and can be used to calculate the absolute position of element. - Just save `offset` and pass it to the children. - **/ - abstract public function render(bounds:Vec2, offset: Pos):Canvas; - public var changed(default, null):Signal; - private final changedTrigger:SignalTrigger = Signal.trigger(); - public final eventListner:UIEvents = {}; - - public function new(events: UIEvents = null) { - changed = changedTrigger.asSignal(); - if (events != null){ - this.eventListner = events; - } - } - - public static function getElementInMap(pos: Pos,elementMap: Map):Null{ - for (k => v in elementMap){ - if (k.isInside(pos)){ - return v; - } - } - - return null; - }; - - public static function applyPaddignAndMargin(canvas:Canvas,padding: Dimensions, margin: Dimensions):Canvas{ - var passing = ObjMerge.merge(padding, {top: 0, left: 0, bottom: 0, right: 0}); - var margin = ObjMerge.merge(margin, {top: 0, left: 0, bottom: 0, right: 0}); - var rtn = new Canvas(); - - rtn.combine(canvas,{x:margin.left + padding.left,y: margin.top + padding.top}); - - return rtn; - } -}