diff --git a/assets/JS_INIT.js b/assets/JS_INIT.js index deb2d46..286e17a 100644 --- a/assets/JS_INIT.js +++ b/assets/JS_INIT.js @@ -452,7 +452,10 @@ con.addch = function(c) { graphics.putSymbol(c|0); }; con.prnch = function(c) { - print("\x84"+c+"u"); + if (Array.isArray(c)) + print(c.reduce((acc,char)=>acc+`\x84${char}u`, '')); + else + print("\x84"+c+"u"); }; con.mvaddch = function(y, x, c) { con.move(y, x); con.addch(c); diff --git a/assets/disk0/tvdos/tuidev/zfm.js b/assets/disk0/tvdos/tuidev/zfm.js index 83ff8cf..80b51da 100644 --- a/assets/disk0/tvdos/tuidev/zfm.js +++ b/assets/disk0/tvdos/tuidev/zfm.js @@ -24,20 +24,40 @@ let windowFocus = 0 // 0,2: files panel, 1: operation panel, -1: a wild popup me let path = [["A:"], ["A:"]] let scroll = [0, 0] let dirFileList = [[], []] -let cursor = [0, 0] +let cursor = [0, 0] // absolute position! // end of window states + +function bytesToReadable(i) { + return ''+ ( + (i > 9999999) ? (((i / 100000)|0)/100 + "M") : + (i > 9999) ? (((i / 1000)|0)/10 + "K") : + i + ) +} + let filesPanelDraw = (wo) => { let pathStr = path[windowMode].concat(['']).join("\\") - if (windowMode) { - wo.titleLeft = undefined - wo.titleRight = pathStr - } - else { - wo.titleLeft = pathStr - wo.titleRight = undefined + let port = _TVDOS.DRIVES[pathStr[0]] + _TVDOS.DRV.FS.SERIAL._flush(port[0]);_TVDOS.DRV.FS.SERIAL._close(port[0]) + com.sendMessage(port[0], "USAGE") + let response = com.getStatusCode(port[0]) + let usedBytes = undefined + let totalBytes = undefined + let freeBytes = undefined + if (0 == response) { + let rawStr = com.fetchResponse(port[0]).split('/') // USED1234/TOTAL23412341 + usedBytes = (rawStr[0].substring(4))|0 + totalBytes = (rawStr[1].substring(5))|0 + freeBytes = totalBytes - usedBytes } + let diskSizestr = bytesToReadable(freeBytes)+"/"+bytesToReadable(totalBytes) + + wo.titleLeft = pathStr + wo.titleRight = diskSizestr + + // draw list header con.color_pair(COL_HLTEXT, COL_BACK) con.move(wo.y + 1, wo.x + 1); print(" Name") @@ -64,41 +84,36 @@ let filesPanelDraw = (wo) => { fs.sort((a,b) => (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0) dirFileList[windowMode] = ds.concat(fs) + let filesCount = dirFileList[windowMode].length // print entries - for (let i = 0; i < Math.min(dirFileList[windowMode].length - s, LIST_HEIGHT); i++) { + for (let i = 0; i < Math.min(filesCount - s, LIST_HEIGHT); i++) { let file = dirFileList[windowMode][i+s] + let sizestr = bytesToReadable(file.size) - 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(" ") - } + // set bg colour + let backCol = (i == cursor[windowMode] - s) ? COL_BACK_SEL : COL_BACK + // set fg colour (if there are more at the top/bottom, dim the colour) + let foreCol = (i == 0 && s > 0 || i == LIST_HEIGHT - 1 && i + s < filesCount - 1) ? COL_DIMTEXT : COL_TEXT // print filename - con.move(wo.y + 2+i, wo.x + 2) - print(file.name) + con.color_pair(foreCol, backCol) + con.move(wo.y + 2+i, wo.x + 1) + print(((file.isDirectory) ? '\\' : ' ')+file.name) print(' '.repeat(FILELIST_WIDTH - 2 - file.name.length)) - // print filesize + // print | 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 - ) + // print filesize + con.color_pair(foreCol, backCol) con.move(wo.y + 2+i, wo.x + FILELIST_WIDTH + 1) print(' '.repeat(FILESIZE_WIDTH - sizestr.length + 1)) print(sizestr) - } + + con.color_pair(COL_TEXT, COL_BACK) + } let opPanelDraw = (wo) => { function hr(y) { @@ -111,50 +126,70 @@ let opPanelDraw = (wo) => { let xp = wo.x + 1 let yp = wo.y + 1 + // other panel + con.move(yp + 3, xp + 3) + con.prnch((windowMode) ? 0x11 : 0x10) + con.move(yp + 4, xp) + print(` \x1B[38;5;${COL_TEXT}m[\x1B[38;5;${COL_HLACTION}mZ\x1B[38;5;${COL_TEXT}m]`) + + hr(yp+8) + // go up - con.mvaddch(yp + 1, xp + 3, 0x18) - con.move(yp + 2, xp) + con.mvaddch(yp + 9, xp + 3, 0x18) + con.move(yp + 10, xp) print(` \x1B[38;5;${COL_TEXT}mGo \x1B[38;5;${COL_HLACTION}mU\x1B[38;5;${COL_TEXT}mp`) - hr(yp+4) + hr(yp+11) // copy - con.move(yp + 6, xp + 2) - con.prnch(0xDB);con.prnch(0x1A);con.prnch(0xDB) - con.move(yp + 7, xp) + con.move(yp + 12, xp + 2) + con.prnch(0xDB);con.prnch((windowMode) ? 0x1B : 0x1A);con.prnch(0xDB) + con.move(yp + 13, 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) + // move + con.move(yp + 15, xp + 2) + if (windowMode) con.prnch([0xDB, 0x1B, 0xB0]); else con.prnch([0xB0, 0x1A, 0xDB]) + con.move(yp + 16, xp) + print(` \x1B[38;5;${COL_HLACTION}mM\x1B[38;5;${COL_TEXT}move`) + + hr(yp+17) + // delete - con.move(yp + 16, xp + 2) - con.prnch(0xDB);con.prnch(0x1A);con.prnch(0x58) - con.move(yp + 17, xp) + con.move(yp + 18, xp + 2) + if (windowMode) con.prnch([0xDB, 0x1A, 0xF9]); else con.prnch([0xF9, 0x1B, 0xDB]) + con.move(yp + 19, xp) print(` \x1B[38;5;${COL_HLACTION}mD\x1B[38;5;${COL_TEXT}melete`) - hr(yp+19) + hr(yp+20) // mkdir con.move(yp + 21, xp + 2) - con.prnch(0x2B);con.prnch(0xDE);con.prnch(0xDC) - con.move(yp + 23, xp) + con.prnch(0xDB) + con.video_reverse();con.prnch(0x2B);con.video_reverse() + con.prnch(0xDF) + con.move(yp + 22, xp) print(` \x1B[38;5;${COL_TEXT}mm\x1B[38;5;${COL_HLACTION}mK\x1B[38;5;${COL_TEXT}mdir`) - hr(yp+25) + hr(yp+23) - // other panel + // rename + con.move(yp + 24, xp + 2) + con.prnch(0x4E);con.prnch(0x1A);con.prnch(0x52) + con.move(yp + 25, xp) + print(` \x1B[38;5;${COL_HLACTION}mR\x1B[38;5;${COL_TEXT}mename`) + + hr(yp+26) + + // quit con.move(yp + 27, xp + 3) - con.prnch((windowMode) ? 0x11 : 0x10) + con.prnch(0x7F) con.move(yp + 28, xp) - print(` \x1B[38;5;${COL_TEXT}m[\x1B[38;5;${COL_HLACTION}mZ\x1B[38;5;${COL_TEXT}m]`) + print(` \x1B[38;5;${COL_HLACTION}mQ\x1B[38;5;${COL_TEXT}muit`) + + } @@ -167,8 +202,11 @@ let windows = [[ new win.WindowObject(SIDEBAR_WIDTH + 1, 2, WIDTH - SIDEBAR_WIDTH, HEIGHT, ()=>{}, filesPanelDraw), // right panel ]] +const LEFTPANEL = windows[0][0] +const OPPANEL = windows[0][1] +const RIGHTPANEL = windows[0][2] -function draw() { +function drawTitle() { // draw window title con.color_pair(COL_BACK, COL_TEXT) con.move(1,1) @@ -180,29 +218,121 @@ function draw() { con.prnch(0xB3) con.color_pair(COL_BRAND, COL_TEXT) print("fm") +} - // draw panels +function drawFilePanel() { 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() + RIGHTPANEL.drawContents() + RIGHTPANEL.drawFrame() } else { - windows[0][0].drawContents() - windows[0][0].drawFrame() - windows[0][1].drawContents() - windows[0][1].drawFrame() + LEFTPANEL.drawContents() + LEFTPANEL.drawFrame() } } +function drawOpPanel() { + if (windowMode) + OPPANEL.x = 1 + else + OPPANEL.x = WIDTH - SIDEBAR_WIDTH+1 + + OPPANEL.drawContents() + OPPANEL.drawFrame() +} + +function redraw() { + con.clear() + drawTitle() + drawFilePanel() + drawOpPanel() +} + +function scrollFiles(ody) { + let dy = ody + let oldScroll = scroll[windowMode] + let peek = 1 + + // clamp dy + if (cursor[windowMode] + dy > dirFileList[windowMode].length - 1) + dy = (dirFileList[windowMode].length - 1) - cursor[windowMode] + else if (cursor[windowMode] + dy < 0) + dy = -cursor[windowMode] + + let nextRow = cursor[windowMode] + dy + + // update vertical scroll stats + if (dy != 0) { + let visible = LIST_HEIGHT - 1 - peek + + if (nextRow - scroll[windowMode] > visible) { + scroll[windowMode] = nextRow - visible + } + else if (nextRow - scroll[windowMode] < 0 + peek) { + scroll[windowMode] = nextRow - peek // nextRow is less than zero + } + + // NOTE: future-proofing here -- scroll clamping is moved outside of go-up/go-down + // if-statements above because horizontal movements can disrupt vertical scrolls as well because + // "normally" when you go right at the end of the line, you appear at the start of the next line + + // scroll to the bottom? + if (dirFileList[windowMode].length > LIST_HEIGHT && scroll[windowMode] > dirFileList[windowMode].length - LIST_HEIGHT) + // to make sure not show buncha empty lines + scroll[windowMode] = dirFileList[windowMode].length - LIST_HEIGHT + // scroll to the top? (order is important!) + if (scroll[windowMode] <= -1) + scroll[windowMode] = 0 // scroll of -1 would result to show "Line 0" on screen + } + + // move editor cursor + cursor[windowMode] = nextRow + + // update screendraw + drawFilePanel() +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +con.curs_set(0) +redraw() + +let exit = false + +while (!exit) { + + input.withEvent(event => { + let eventName = event[0] + if (eventName == "key_down") { + + let keysym = event[1] + let keycodes = [event[3],event[4],event[5],event[6],event[7],event[8],event[9],event[10]] + let keycode = keycodes[0] + + if (keysym == "q") { + exit = true + } + else if (keysym == 'z') { + windowMode = 1 - windowMode + windowFocus = 2 - windowFocus + redraw() + } + else if (keysym == "") { + scrollFiles(-1) + } + else if (keysym == "") { + scrollFiles(+1) + } + }}) + +} + +con.curs_set(1) con.clear() -draw() -con.move(WHEIGHT,1) - +return 0 \ No newline at end of file