initial commit
This commit is contained in:
174
src/kernel/ui/TermBuffer.hx
Normal file
174
src/kernel/ui/TermBuffer.hx
Normal file
@@ -0,0 +1,174 @@
|
||||
package kernel.ui;
|
||||
|
||||
import util.Signal;
|
||||
import util.Vec.Vec2;
|
||||
import util.Color;
|
||||
import lib.TermWriteable;
|
||||
|
||||
@:structInit class Pixel {
|
||||
public var char:String;
|
||||
public var bg:Color;
|
||||
public var textColor:Color;
|
||||
}
|
||||
|
||||
class TermBuffer implements TermWriteable {
|
||||
|
||||
/**
|
||||
format [y][x]. First index is the line. Second index the char in the line.
|
||||
**/
|
||||
private var screenBuffer: Array<Array<Pixel>>;
|
||||
private var cursorPos: Vec2<Int> = {x: 0, y: 0};
|
||||
private var currentTextColor: Color = White;
|
||||
private var currentBgColor: Color = Black;
|
||||
private var size: Vec2<Int> = {x: 51,y:19}; // Default size set to default size of the main terminal
|
||||
|
||||
public function new() {
|
||||
initScreenBuffer(size);
|
||||
}
|
||||
|
||||
private function setSize(size: Vec2<Int>) {
|
||||
if (this.size != size){
|
||||
this._onResize.emit(size);
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
updateScreenBufferSize(size);
|
||||
}
|
||||
|
||||
private function updateScreenBufferSize(size: Vec2<Int>) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
private function initScreenBuffer(size: Vec2<Int>) {
|
||||
screenBuffer = new Array();
|
||||
for (y in 0...size.y){
|
||||
screenBuffer[y] = new Array();
|
||||
for (x in 0...size.x){
|
||||
screenBuffer[y][x] = {
|
||||
char: " ",
|
||||
textColor: White,
|
||||
bg: Black,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function copyBufferToTarget(target: TermWriteable) {
|
||||
target.setCursorPos(0,0);
|
||||
target.setBackgroundColor(Black);
|
||||
target.setTextColor(White);
|
||||
|
||||
var tmpFgColor: Color = White;
|
||||
var tmpBgColor: Color = Black;
|
||||
|
||||
for (y => line in screenBuffer){
|
||||
for(x => pixel in line){
|
||||
if (tmpFgColor != pixel.textColor){
|
||||
tmpFgColor = pixel.textColor;
|
||||
target.setTextColor(pixel.textColor);
|
||||
}
|
||||
|
||||
if (tmpBgColor != pixel.bg){
|
||||
tmpBgColor = pixel.bg;
|
||||
target.setBackgroundColor(pixel.bg);
|
||||
}
|
||||
|
||||
target.setCursorPos(x,y);
|
||||
target.write(pixel.char);
|
||||
}
|
||||
}
|
||||
|
||||
target.setCursorPos(cursorPos.x,cursorPos.y);
|
||||
target.setTextColor(currentTextColor);
|
||||
target.setBackgroundColor(currentBgColor);
|
||||
}
|
||||
|
||||
private function safeWriteScreenBuffer(pos: Vec2<Int>,char: String) {
|
||||
if (screenBuffer.length > pos.y && screenBuffer[pos.y].length > pos.x){
|
||||
screenBuffer[pos.y][pos.x].char = char;
|
||||
screenBuffer[pos.y][pos.x].bg = currentBgColor;
|
||||
screenBuffer[pos.y][pos.x].textColor = currentTextColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// TermWriteable functions
|
||||
//
|
||||
|
||||
public var onResize(get,null):SignalReadonly<Vec2<Int>>;
|
||||
private final _onResize:Signal<Vec2<Int>> = new Signal();
|
||||
|
||||
function get_onResize():Signal<Vec2<Int>> {
|
||||
return _onResize;
|
||||
}
|
||||
|
||||
public function write(text:String) {
|
||||
for (i in 0...text.length){
|
||||
safeWriteScreenBuffer({x: cursorPos.x,y: cursorPos.y},text.charAt(i));
|
||||
cursorPos = {y: cursorPos.y,x: cursorPos.x + 1};
|
||||
}
|
||||
}
|
||||
|
||||
public function scroll(y:Int) {
|
||||
screenBuffer.unshift([for (i in 0...size.x) {
|
||||
char: " ",
|
||||
textColor: White, // TODO: maybe replace with current bg/text color. Check nativ implementation
|
||||
bg: Black
|
||||
}]);
|
||||
}
|
||||
|
||||
public function getCursorPos():Vec2<Int> {
|
||||
return cursorPos;
|
||||
}
|
||||
|
||||
public function setCursorPos(x:Int, y:Int) {
|
||||
cursorPos = {
|
||||
x: x,
|
||||
y: y,
|
||||
};
|
||||
}
|
||||
|
||||
public function getCursorBlink():Bool {
|
||||
throw new haxe.exceptions.NotImplementedException();
|
||||
}
|
||||
|
||||
public function setCursorBlink(blink:Bool) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public function getSize():Vec2<Int> {
|
||||
return size;
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
initScreenBuffer(size);
|
||||
}
|
||||
|
||||
public function clearLine() {
|
||||
if (screenBuffer.length > cursorPos.y){
|
||||
screenBuffer[cursorPos.y] = [for(x in 0...size.x){textColor: White,char: " ",bg: Black}];
|
||||
}
|
||||
}
|
||||
|
||||
public function getTextColor():Color {
|
||||
return currentTextColor;
|
||||
}
|
||||
|
||||
public function setTextColor(colour:Color) {
|
||||
currentTextColor = colour;
|
||||
}
|
||||
|
||||
public function getBackgroundColor():Color {
|
||||
return currentBgColor;
|
||||
}
|
||||
|
||||
public function setBackgroundColor(color:Color) {
|
||||
currentBgColor = color;
|
||||
}
|
||||
|
||||
public function isColor():Bool {
|
||||
throw new haxe.exceptions.NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
164
src/kernel/ui/VirtualTermWriter.hx
Normal file
164
src/kernel/ui/VirtualTermWriter.hx
Normal file
@@ -0,0 +1,164 @@
|
||||
package kernel.ui;
|
||||
|
||||
import util.Signal.SignalListner;
|
||||
import util.Vec.Vec2;
|
||||
import util.Color;
|
||||
import lib.TermWriteable;
|
||||
|
||||
class VirtualTermWriter implements TermWriteable extends TermBuffer {
|
||||
private static final defaultSize:Vec2<Int> = {x: 50,y: 50};
|
||||
|
||||
private var target: TermWriteable;
|
||||
private var enabled:Bool = false;
|
||||
private var onResizeListner: SignalListner<Vec2<Int>>;
|
||||
|
||||
public function new(?target: TermWriteable) {
|
||||
setTarget(target);
|
||||
|
||||
if (enabled){
|
||||
enable();
|
||||
}
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
public function enable() {
|
||||
if (target != null){
|
||||
enabled = true;
|
||||
super.copyBufferToTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
public inline function isEnabled(): Bool {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public function setTarget(newTarget: TermWriteable) {
|
||||
if (newTarget != null){
|
||||
super.setSize(newTarget.getSize());
|
||||
|
||||
// Remove old target event listner
|
||||
if (onResizeListner != null && target != null){
|
||||
target.onResize.remove(onResizeListner);
|
||||
}
|
||||
|
||||
// Add new target event listner
|
||||
onResizeListner = newTarget.onResize.on(newSize -> {
|
||||
setSuperSize(newSize);
|
||||
});
|
||||
|
||||
target = newTarget;
|
||||
}
|
||||
}
|
||||
|
||||
private function setSuperSize(size: Vec2<Int>) {
|
||||
super.setSize(target.getSize());
|
||||
}
|
||||
|
||||
//
|
||||
// TermWriteable functions.
|
||||
//
|
||||
public override function write(text:String) {
|
||||
if (isEnabled()){
|
||||
target.write(text);
|
||||
}
|
||||
|
||||
super.write(text);
|
||||
}
|
||||
|
||||
public override function scroll(y:Int) {
|
||||
if (isEnabled()){
|
||||
target.scroll(y);
|
||||
}
|
||||
super.scroll(y);
|
||||
}
|
||||
|
||||
public override function getCursorPos():Vec2<Int> {
|
||||
if (isEnabled()){
|
||||
return target.getCursorPos();
|
||||
}else{
|
||||
return super.getCursorPos();
|
||||
}
|
||||
}
|
||||
|
||||
public override function setCursorPos(x:Int, y:Int) {
|
||||
if (isEnabled()){
|
||||
target.setCursorPos(x,y);
|
||||
}
|
||||
|
||||
super.setCursorPos(x,y);
|
||||
}
|
||||
|
||||
public override function getCursorBlink():Bool {
|
||||
throw new haxe.exceptions.NotImplementedException();
|
||||
}
|
||||
|
||||
public override function setCursorBlink(blink:Bool) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public override function getSize():Vec2<Int> {
|
||||
// TODO: make sense ?
|
||||
if (target != null){
|
||||
return target.getSize();
|
||||
}
|
||||
|
||||
return defaultSize;
|
||||
}
|
||||
|
||||
public override function clear() {
|
||||
if (isEnabled()){
|
||||
target.clear();
|
||||
}
|
||||
|
||||
super.clear();
|
||||
}
|
||||
|
||||
public override function clearLine() {
|
||||
if (isEnabled()){
|
||||
target.clearLine();
|
||||
}
|
||||
|
||||
super.clearLine();
|
||||
}
|
||||
|
||||
public override function getTextColor():Color {
|
||||
if (isEnabled()){
|
||||
return target.getTextColor();
|
||||
}
|
||||
|
||||
return super.getTextColor();
|
||||
}
|
||||
|
||||
public override function setTextColor(colour:Color) {
|
||||
if (isEnabled()){
|
||||
target.setTextColor(colour);
|
||||
}
|
||||
|
||||
super.setTextColor(colour);
|
||||
}
|
||||
|
||||
public override function getBackgroundColor():Color {
|
||||
if (isEnabled()){
|
||||
return target.getBackgroundColor();
|
||||
}
|
||||
|
||||
return super.getBackgroundColor();
|
||||
}
|
||||
|
||||
public override function setBackgroundColor(color:Color) {
|
||||
if (isEnabled()){
|
||||
target.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
super.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
public override function isColor():Bool {
|
||||
throw new haxe.exceptions.NotImplementedException();
|
||||
}
|
||||
}
|
||||
176
src/kernel/ui/WindowContext.hx
Normal file
176
src/kernel/ui/WindowContext.hx
Normal file
@@ -0,0 +1,176 @@
|
||||
package kernel.ui;
|
||||
|
||||
import util.Color;
|
||||
import util.Signal;
|
||||
import kernel.ui.WindowManager.ButtonType;
|
||||
import util.Vec.Vec2;
|
||||
import lib.TermWriteable;
|
||||
|
||||
class WindowContext implements TermWriteable {
|
||||
private final writer:VirtualTermWriter;
|
||||
|
||||
private final _clickSignal:Signal<{button: ButtonType, pos: Vec2<Int>}> = new Signal();
|
||||
private final _keySignal:Signal<{keyCode: Int, isHeld: Bool}> = new Signal();
|
||||
private final _keyUpSignal:Signal<Int> = new Signal();
|
||||
private final _mouseDragSignal:Signal<{button: ButtonType, pos: Vec2<Int>}> = new Signal();
|
||||
private final _mouseScrollSignal:Signal<{dir: Int,pos: Vec2<Int>}> = new Signal();
|
||||
private final _mouseUpSignal:Signal<{button: ButtonType,pos: Vec2<Int>}> = new Signal();
|
||||
private final _pasteSignal:Signal<String> = new Signal();
|
||||
|
||||
public var clickSignal(get,null):SignalReadonly<{button: ButtonType, pos: Vec2<Int>}>;
|
||||
public var keySignal(get,null):SignalReadonly<{keyCode: Int, isHeld: Bool}>;
|
||||
public var keyUpSignal(get,null):SignalReadonly<Int>;
|
||||
public var mouseDragSignal(get,null):SignalReadonly<{button: ButtonType, pos: Vec2<Int>}>;
|
||||
public var mouseScrollSignal(get,null):SignalReadonly<{dir: Int,pos: Vec2<Int>}>;
|
||||
public var mouseUpSignal(get,null):SignalReadonly<{button: ButtonType,pos: Vec2<Int>}>;
|
||||
public var pasteSignal(get,null):SignalReadonly<String> ;
|
||||
|
||||
public function new(writer: VirtualTermWriter) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
public var onResize(get, null):SignalReadonly<Vec2<Int>>;
|
||||
|
||||
function get_onResize():SignalReadonly<Vec2<Int>> {
|
||||
return writer.onResize;
|
||||
}
|
||||
|
||||
@:allow(kernel.ui)
|
||||
private function setTarget(target: TermWriteable) {
|
||||
writer.setTarget(target);
|
||||
}
|
||||
|
||||
@:allow(kernel.ui)
|
||||
private function enable() {
|
||||
writer.enable();
|
||||
}
|
||||
|
||||
@:allow(kernel.ui)
|
||||
private function disable() {
|
||||
writer.disable();
|
||||
}
|
||||
|
||||
@:allow(kernel.ui)
|
||||
private function isEnabled() {
|
||||
return writer.isEnabled();
|
||||
}
|
||||
|
||||
public function get_clickSignal(){
|
||||
return _clickSignal;
|
||||
}
|
||||
|
||||
public function get_keySignal(){
|
||||
return _keySignal;
|
||||
}
|
||||
|
||||
public function get_keyUpSignal(){
|
||||
return _keyUpSignal;
|
||||
}
|
||||
|
||||
public function get_mouseDragSignal(){
|
||||
return _mouseDragSignal;
|
||||
}
|
||||
|
||||
public function get_mouseScrollSignal(){
|
||||
return _mouseScrollSignal;
|
||||
}
|
||||
|
||||
public function get_mouseUpSignal(){
|
||||
return _mouseUpSignal;
|
||||
}
|
||||
|
||||
public function get_pasteSignal(){
|
||||
return _pasteSignal;
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function click(button:ButtonType ,pos: Vec2<Int>) {
|
||||
_clickSignal.emit({button: button,pos: pos});
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function key(keyCode: Int, isHeld: Bool) {
|
||||
_keySignal.emit({keyCode: keyCode,isHeld: isHeld});
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function keyUp(keyCode: Int) {
|
||||
_keyUpSignal.emit(keyCode);
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function mouseDrag(button: ButtonType, pos: Vec2<Int>) {
|
||||
_mouseDragSignal.emit({button: button,pos: pos});
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function mouseScroll(dir: Int,pos: Vec2<Int>) {
|
||||
_mouseScrollSignal.emit({dir: dir,pos: pos});
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function mouseUp(button: ButtonType,pos: Vec2<Int>) {
|
||||
_mouseUpSignal.emit({button: button,pos: pos});
|
||||
}
|
||||
|
||||
@:allow(kernel.ui.WindowManager) // Package private
|
||||
private function paste(text: String) {
|
||||
_pasteSignal.emit(text);
|
||||
}
|
||||
|
||||
public function write(text:String) {
|
||||
writer.write(text);
|
||||
}
|
||||
|
||||
public function scroll(y:Int) {
|
||||
writer.scroll(y);
|
||||
}
|
||||
|
||||
public function getCursorPos():Vec2<Int> {
|
||||
return writer.getCursorPos();
|
||||
}
|
||||
|
||||
public function setCursorPos(x:Int, y:Int) {
|
||||
writer.setCursorPos(x,y);
|
||||
}
|
||||
|
||||
public function getCursorBlink():Bool {
|
||||
return writer.getCursorBlink();
|
||||
}
|
||||
|
||||
public function setCursorBlink(blink:Bool) {
|
||||
writer.setCursorBlink(blink);
|
||||
}
|
||||
|
||||
public function getSize():Vec2<Int> {
|
||||
return writer.getSize();
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
writer.clear();
|
||||
}
|
||||
|
||||
public function clearLine() {
|
||||
writer.clearLine();
|
||||
}
|
||||
|
||||
public function getTextColor():Color {
|
||||
return writer.getTextColor();
|
||||
}
|
||||
|
||||
public function setTextColor(colour:Color) {
|
||||
writer.setTextColor(colour);
|
||||
}
|
||||
|
||||
public function getBackgroundColor():Color {
|
||||
return writer.getBackgroundColor();
|
||||
}
|
||||
|
||||
public function setBackgroundColor(color:Color) {
|
||||
writer.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
public function isColor():Bool {
|
||||
return writer.isColor();
|
||||
}
|
||||
}
|
||||
155
src/kernel/ui/WindowManager.hx
Normal file
155
src/kernel/ui/WindowManager.hx
Normal file
@@ -0,0 +1,155 @@
|
||||
package kernel.ui;
|
||||
|
||||
import lib.TermWriteable;
|
||||
import kernel.peripherals.Screen;
|
||||
import kernel.peripherals.Peripherals.Peripheral;
|
||||
import haxe.Exception;
|
||||
import util.Vec.Vec2;
|
||||
|
||||
enum ButtonType {
|
||||
Left;
|
||||
Middle;
|
||||
Right;
|
||||
}
|
||||
|
||||
class WindowManager {
|
||||
public static final instance:WindowManager = new WindowManager();
|
||||
private function new() {}
|
||||
|
||||
private var currentMainContext:WindowContext;
|
||||
private final allContexts:Array<WindowContext> = new Array();
|
||||
private final outputMap:Map<String,WindowContext> = new Map();
|
||||
|
||||
public function init() {
|
||||
KernelEvents.instance.on("key",params -> {
|
||||
var keyCode: Int = params[1];
|
||||
var isHeld: Bool = params[2];
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.key(keyCode,isHeld);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("key_up",params -> {
|
||||
var keyCode: Int = params[1];
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.keyUp(keyCode);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("mouse_click",params -> {
|
||||
var button: ButtonType = ccButtonToEnum(params[1]);
|
||||
var clickPos: Vec2<Int> = {
|
||||
x: (params[2]:Int) - 1,
|
||||
y: (params[3]:Int) - 1
|
||||
};
|
||||
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.click(button,clickPos);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("mouse_drag",params -> {
|
||||
var button: ButtonType = ccButtonToEnum(params[1]);
|
||||
var pos: Vec2<Int> = {
|
||||
x: (params[2]:Int) - 1,
|
||||
y: (params[3]:Int) - 1,
|
||||
}
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.mouseDrag(button,pos);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("mouse_scroll",params -> {
|
||||
var dir: Int = params[1];
|
||||
var pos: Vec2<Int> = {
|
||||
x: (params[2]:Int) - 1,
|
||||
y: (params[3]:Int) - 1,
|
||||
}
|
||||
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.mouseScroll(dir,pos);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("mouse_up",params -> {
|
||||
var button: ButtonType = ccButtonToEnum(params[1]);
|
||||
var pos: Vec2<Int> = {
|
||||
x: (params[2]:Int) - 1,
|
||||
y: (params[2]:Int) - 1,
|
||||
}
|
||||
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.mouseUp(button,pos);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("paste",params -> {
|
||||
var text: String = params[1];
|
||||
|
||||
if (currentMainContext != null){
|
||||
currentMainContext.paste(text);
|
||||
}
|
||||
});
|
||||
|
||||
KernelEvents.instance.on("monitor_touch",array -> {
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
public function createNewContext(): WindowContext {
|
||||
var newContext = new WindowContext(new VirtualTermWriter());
|
||||
|
||||
allContexts.push(newContext);
|
||||
|
||||
newContext.setTarget(MainTerm.instance);
|
||||
newContext.enable();
|
||||
currentMainContext = newContext;
|
||||
|
||||
return newContext;
|
||||
}
|
||||
|
||||
|
||||
public function getOutputs(): Array<String> {
|
||||
var arr = Peripheral.instance.getScreens().map(screen -> return screen.getAddr());
|
||||
arr.push("main");
|
||||
return arr;
|
||||
}
|
||||
|
||||
public function focusContextToOutput(context: WindowContext,output: String) {
|
||||
var target: TermWriteable;
|
||||
if (output == "main"){
|
||||
target = MainTerm.instance;
|
||||
}else{
|
||||
target = Peripheral.instance.getScreen(output);
|
||||
|
||||
if (target == null){
|
||||
// output target not found
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (outputMap.exists(output)){
|
||||
outputMap[output].disable();
|
||||
}
|
||||
|
||||
|
||||
outputMap[output] = context;
|
||||
context.setTarget(target);
|
||||
context.enable();
|
||||
}
|
||||
|
||||
private static function ccButtonToEnum(button: Int): ButtonType {
|
||||
switch button {
|
||||
case 1:
|
||||
return Left;
|
||||
case 2:
|
||||
return Middle;
|
||||
case 3:
|
||||
return Right;
|
||||
case _:
|
||||
throw new Exception("Invalid input");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user