From edea9648d9034491a69ca9146ebab6451a3d5518 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Tue, 10 Jan 2023 00:20:23 +0900 Subject: [PATCH] another try at tui --- assets/JS_INIT.js | 2 + assets/disk0/tvdos/bin/command.js | 2 +- assets/disk0/tvdos/include/wintex.js | 84 +++++++ assets/disk0/tvdos/tuidev/doc.md | 35 +++ assets/disk0/tvdos/tuidev/zfm.js | 208 ++++++++++++++++++ terranmon.txt | 2 +- .../torvald/tsvm/GraphicsJSR223Delegate.kt | 3 + 7 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 assets/disk0/tvdos/include/wintex.js create mode 100644 assets/disk0/tvdos/tuidev/doc.md create mode 100644 assets/disk0/tvdos/tuidev/zfm.js diff --git a/assets/JS_INIT.js b/assets/JS_INIT.js index d9081fe..deb2d46 100644 --- a/assets/JS_INIT.js +++ b/assets/JS_INIT.js @@ -495,6 +495,8 @@ con.resetkeybuf = function() { con.video_reverse = function() { print("\x1B[7m"); }; +con.get_color_fore = function() { return graphics.getTextFore() } +con.get_color_back = function() { return graphics.getTextBack() } con.color_fore = function(n) { // 0..7; -1 for transparent if (n < 0) print("\x1B[38;5;255m"); diff --git a/assets/disk0/tvdos/bin/command.js b/assets/disk0/tvdos/bin/command.js index af33fc1..20ee266 100644 --- a/assets/disk0/tvdos/bin/command.js +++ b/assets/disk0/tvdos/bin/command.js @@ -841,7 +841,7 @@ if (exec_args[1] !== undefined) { goInteractive = true } else if ("/fancy" == firstSwitch) { - graphics.setBackground(2,3,4) + graphics.setBackground(34,51,68) goFancy = true goInteractive = true } diff --git a/assets/disk0/tvdos/include/wintex.js b/assets/disk0/tvdos/include/wintex.js new file mode 100644 index 0000000..0b6fd76 --- /dev/null +++ b/assets/disk0/tvdos/include/wintex.js @@ -0,0 +1,84 @@ +class WindowObject { + + constructor(x, y, w, h, inputProcessor, drawContents, title, drawFrame) { + this.isHighlighted = false + this.x = x + this.y = y + this.width = w + this.height = h + this.inputProcessorFun = inputProcessor + this.drawContentsFun = drawContents + this.title = title + this.titleLeft = undefined + this.titleRight = undefined + this.titleBack = 0 // default value + this.titleBackLeft = 245 // default value + this.titleBackRight = 245 // default value + this.drawFrameFun = drawFrame || (() => { + let oldFore = con.get_color_fore() + let oldBack = con.get_color_back() + + let charset = (this.isHighlighted) ? [0xC9, 0xBB, 0xC8, 0xBC, 0xCD, 0xBA, 0xB5, 0xC6] : [0xDA, 0xBF, 0xC0, 0xD9, 0xC4, 0xB3, 0xB4, 0xC3] + let colour = (this.isHighlighted) ? 230 : 253 + let colourText = (this.isHighlighted) ? 230 : 254 + + // set fore colour + print(`\x1B[38;5;${colour}m`) + + // draw top horz + con.mvaddch(this.y, this.x, charset[0]); con.curs_right() + print(`\x84${charset[4]}u`.repeat(this.width - 2)) + con.addch(charset[1]) + // draw vert + for (let yp = this.y + 1; yp < this.y + this.height - 1; yp++) { + con.mvaddch(yp, this.x , charset[5]) + con.mvaddch(yp, this.x + this.width - 1, charset[5]) + } + // draw bottom horz + con.mvaddch(this.y + this.height - 1, this.x, charset[2]); con.curs_right() + print(`\x84${charset[4]}u`.repeat(this.width - 2)) + con.addch(charset[3]) + + // draw title + if (this.title !== undefined) { + let tt = ''+this.title + con.move(this.y, this.x + ((this.width - 2 - tt.length) >>> 1)) + if (this.titleBack !== undefined) print(`\x1B[48;5;${this.titleBack}m`) + print(`\x84${charset[6]}u`) + print(`\x1B[38;5;${colourText}m${tt}`) + print(`\x1B[38;5;${colour}m\x84${charset[7]}u`) + if (this.titleBack !== undefined) print(`\x1B[48;5;${oldBack}m`) + } + if (this.titleLeft !== undefined) { + let tt = ''+this.titleLeft + con.move(this.y, this.x) + print(`\x84${charset[0]}u`) + if (this.titleBackLeft !== undefined) print(`\x1B[48;5;${this.titleBackLeft}m`) + print(`\x1B[38;5;${colourText}m`);print(tt) + if (this.titleBackLeft !== undefined) print(`\x1B[48;5;${oldBack}m`) + print(`\x1B[38;5;${colour}m`);print(`\x84${charset[4]}u`) + } + if (this.titleRight !== undefined) { + let tt = ''+this.titleRight + con.move(this.y, this.x + this.width - tt.length - 2) + print(`\x84${charset[4]}u`) + if (this.titleBackRight !== undefined) print(`\x1B[48;5;${this.titleBackRight}m`) + print(`\x1B[38;5;${colourText}m${tt}`) + if (this.titleBackRight !== undefined) print(`\x1B[48;5;${oldBack}m`) + print(`\x1B[38;5;${colour}m\x84${charset[1]}u`) + } + + + // restore fore colour + print(`\x1B[38;5;${oldFore}m`) + print(`\x1B[48;5;${oldBack}m`) + }) + } + + drawContents() { this.drawContentsFun(this) } + drawFrame() { this.drawFrameFun(this) } + processInput(event) { this.inputProcessor(this, event) } + +} + +exports = { WindowObject } diff --git a/assets/disk0/tvdos/tuidev/doc.md b/assets/disk0/tvdos/tuidev/doc.md new file mode 100644 index 0000000..96ec9cc --- /dev/null +++ b/assets/disk0/tvdos/tuidev/doc.md @@ -0,0 +1,35 @@ + +DATA STRUCTURE + +``` +[ + [main Window Objects], + [popup Window Objects] +] +``` + +Window Object + +```javascript +{ + "isFocused": false, + "inputProcessor": (this, inputEvent) => { ... }, + "drawFrame": (this) => { ... }, + "drawContents": (this) => { ... }, + "width": 20, + "height": 12, + "x": 1, + "y": 3, + "title": undefined +} +``` + +BEHAVIOUR + +1. Key event is parsed +2. If key is Tab, move focus to the next Window Object within the current window +3. If not, pass the event to the currently focused Window Object + +No key combination will allow navigating between windows +e.g. Tabbing on the question popup will just loop through the Ok/Cancel buttons, until the buttons are pressed. + diff --git a/assets/disk0/tvdos/tuidev/zfm.js b/assets/disk0/tvdos/tuidev/zfm.js new file mode 100644 index 0000000..83ff8cf --- /dev/null +++ b/assets/disk0/tvdos/tuidev/zfm.js @@ -0,0 +1,208 @@ +const win = require("wintex") +const COL_TEXT = 253 +const COL_BACK = 255 +const COL_BACK_SEL = 81 +const COL_HLTEXT = 230 +const COL_HLACTION = 39 +const COL_DIR = COL_TEXT +const COL_SUPERTEXT = 239 +const COL_DIMTEXT = 249 +const COL_LNUMBACK = 18 +const COL_LNUMFORE = 253 +const COL_BRAND = 161 +const COL_BRAND_PAL = [241, 248] +const [WHEIGHT, WIDTH] = con.getmaxyx();const HEIGHT = WHEIGHT - 1 +const SIDEBAR_WIDTH = 9 +const LIST_HEIGHT = HEIGHT - 3 +const FILESIZE_WIDTH = 7 +const FILELIST_WIDTH = WIDTH - SIDEBAR_WIDTH - 3 - FILESIZE_WIDTH + +let windowMode = 0 // 0 == left, 1 == right +let windowFocus = 0 // 0,2: files panel, 1: operation panel, -1: a wild popup message appeared + +// window states +let path = [["A:"], ["A:"]] +let scroll = [0, 0] +let dirFileList = [[], []] +let cursor = [0, 0] +// end of window states + +let filesPanelDraw = (wo) => { + let pathStr = path[windowMode].concat(['']).join("\\") + if (windowMode) { + wo.titleLeft = undefined + wo.titleRight = pathStr + } + else { + wo.titleLeft = pathStr + wo.titleRight = undefined + } + + // draw list header + con.color_pair(COL_HLTEXT, COL_BACK) + con.move(wo.y + 1, wo.x + 1); print(" Name") + con.mvaddch(wo.y + 1, wo.x + FILELIST_WIDTH, 0xB3) + con.curs_right(); print(" Size") + + + con.color_pair(COL_TEXT, COL_BACK) + // draw list + let directory = files.open(pathStr) + let fileList = directory.list() + let s = scroll[windowMode] + + // sort fileList + let ds = [] + let fs = [] + fileList.forEach((file)=>{ + if (file.isDirectory) + ds.push(file) + else + fs.push(file) + }) + ds.sort((a,b) => (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0) + fs.sort((a,b) => (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0) + dirFileList[windowMode] = ds.concat(fs) + + // print entries + for (let i = 0; i < Math.min(dirFileList[windowMode].length - s, LIST_HEIGHT); i++) { + let file = dirFileList[windowMode][i+s] + + let backCol = (i == cursor[windowMode]) ? COL_BACK_SEL : COL_BACK + + con.move(wo.y + 2+i, wo.x + 1) + if (file.isDirectory) { + con.color_pair(COL_DIR, backCol) + print("\\") + } + else { + con.color_pair(COL_TEXT, backCol) + print(" ") + } + + // print filename + con.move(wo.y + 2+i, wo.x + 2) + print(file.name) + print(' '.repeat(FILELIST_WIDTH - 2 - file.name.length)) + + // print filesize + con.color_pair(COL_TEXT, backCol) + con.mvaddch(wo.y + 2+i, wo.x + FILELIST_WIDTH, 0xB3) + + let sizestr = ''+ ( + (file.size > 9999999) ? (((file.size / 100000)|0)/100 + "M") : + (file.size > 9999) ? (((file.size / 1000)|0)/10 + "K") : + file.size + ) + con.move(wo.y + 2+i, wo.x + FILELIST_WIDTH + 1) + print(' '.repeat(FILESIZE_WIDTH - sizestr.length + 1)) + print(sizestr) + + } +} +let opPanelDraw = (wo) => { + function hr(y) { + con.move(y, xp) + print(`\x84196u`.repeat(SIDEBAR_WIDTH - 2)) + } + + con.color_pair(COL_TEXT, COL_BACK) + + let xp = wo.x + 1 + let yp = wo.y + 1 + + // go up + con.mvaddch(yp + 1, xp + 3, 0x18) + con.move(yp + 2, xp) + print(` \x1B[38;5;${COL_TEXT}mGo \x1B[38;5;${COL_HLACTION}mU\x1B[38;5;${COL_TEXT}mp`) + + hr(yp+4) + + // copy + con.move(yp + 6, xp + 2) + con.prnch(0xDB);con.prnch(0x1A);con.prnch(0xDB) + con.move(yp + 7, xp) + print(` \x1B[38;5;${COL_HLACTION}mC\x1B[38;5;${COL_TEXT}mopy`) + + hr(yp+9) + + // move + con.move(yp + 11, xp + 2) + con.prnch(0xB0);con.prnch(0x1A);con.prnch(0xDB) + con.move(yp + 12, xp) + print(` \x1B[38;5;${COL_HLACTION}mM\x1B[38;5;${COL_TEXT}move`) + + hr(yp+14) + + // delete + con.move(yp + 16, xp + 2) + con.prnch(0xDB);con.prnch(0x1A);con.prnch(0x58) + con.move(yp + 17, xp) + print(` \x1B[38;5;${COL_HLACTION}mD\x1B[38;5;${COL_TEXT}melete`) + + hr(yp+19) + + // mkdir + con.move(yp + 21, xp + 2) + con.prnch(0x2B);con.prnch(0xDE);con.prnch(0xDC) + con.move(yp + 23, xp) + print(` \x1B[38;5;${COL_TEXT}mm\x1B[38;5;${COL_HLACTION}mK\x1B[38;5;${COL_TEXT}mdir`) + + hr(yp+25) + + // other panel + con.move(yp + 27, xp + 3) + con.prnch((windowMode) ? 0x11 : 0x10) + con.move(yp + 28, xp) + print(` \x1B[38;5;${COL_TEXT}m[\x1B[38;5;${COL_HLACTION}mZ\x1B[38;5;${COL_TEXT}m]`) +} + + + + +let windows = [[ + new win.WindowObject(1, 2, WIDTH - SIDEBAR_WIDTH, HEIGHT, ()=>{}, filesPanelDraw), // left panel + new win.WindowObject(WIDTH - SIDEBAR_WIDTH+1, 2, SIDEBAR_WIDTH, HEIGHT, ()=>{}, opPanelDraw), +// new win.WindowObject(1, 2, SIDEBAR_WIDTH, HEIGHT, ()=>{}, opPanelDraw), + new win.WindowObject(SIDEBAR_WIDTH + 1, 2, WIDTH - SIDEBAR_WIDTH, HEIGHT, ()=>{}, filesPanelDraw), // right panel +]] + + +function draw() { + // draw window title + con.color_pair(COL_BACK, COL_TEXT) + con.move(1,1) + print(' '.repeat(WIDTH)) + con.move(1, WIDTH/2 - 2) + con.color_pair(COL_BRAND_PAL[0], COL_TEXT) + print("z") + con.color_pair(COL_BRAND_PAL[1], COL_TEXT) + con.prnch(0xB3) + con.color_pair(COL_BRAND, COL_TEXT) + print("fm") + + + // draw panels + windows[0].forEach((panel, i)=>{ + panel.isHighlighted = (i == windowFocus) + }) + if (windowMode) { + windows[0][2].drawContents() + windows[0][2].drawFrame() + windows[0][1].drawContents() + windows[0][1].drawFrame() + } + else { + windows[0][0].drawContents() + windows[0][0].drawFrame() + windows[0][1].drawContents() + windows[0][1].drawFrame() + } +} + + + +con.clear() +draw() +con.move(WHEIGHT,1) + diff --git a/terranmon.txt b/terranmon.txt index cc84bcf..59fae2f 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -443,7 +443,7 @@ Background Colour Packet - uint16 0xFEFF uint8 Red (0-255) uint8 Green (0-255) - uint8 Blue (0x255) + uint8 Blue (0-255) uint8 0x00 (pad byte) diff --git a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt index 543f573..065d7e3 100644 --- a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -47,6 +47,9 @@ class GraphicsJSR223Delegate(private val vm: VM) { getFirstGPU()?.let { it.ttyBack = b } } + fun getTextFore() = getFirstGPU()?.ttyFore + fun getTextBack() = getFirstGPU()?.ttyBack + /*fun loadBulk(fromAddr: Int, toAddr: Int, length: Int) { getFirstGPU()?._loadbulk(fromAddr, toAddr, length) }