diff --git a/claw/repo-claw.lua b/claw/repo-claw.lua index 5791869..f4bbf3a 100644 --- a/claw/repo-claw.lua +++ b/claw/repo-claw.lua @@ -202,7 +202,7 @@ return { }, ["app-tapedeck"] = { desc = "Computronics Tape Drive interface", - v = 0, + v = 1, deps = { "neo", "zzz-license-pd" diff --git a/repository/apps/app-tapedeck.lua b/repository/apps/app-tapedeck.lua index 991b1f2..b63e769 100644 --- a/repository/apps/app-tapedeck.lua +++ b/repository/apps/app-tapedeck.lua @@ -10,6 +10,8 @@ for v in neo.requireAccess("c.tape_drive", "tapedrives").list() do table.insert(tapes, v) end +local tapeRate = 4096 + local event = require("event")(neo) local neoux = require("neoux")(event, neo) @@ -31,7 +33,92 @@ local focused = true local updateTick -local function genPlayer(inst) +local downloadCancelled = false + +local genPlayer -- used to return to player + +local function genDownloading(inst) + local lclLabelText = {"downloading..."} + local lclLabel = neoux.tcrawview(1, 1, lclLabelText) + local thr = { + "/", + "-", + "\\", + "|" + } + local thri = 0 + updateTick = function () + lclLabelText[1] = "downloading... " .. (inst.getPosition() / (1024 * 1024)) .. "MB " .. thr[(thri % #thr) + 1] + thri = thri + 1 + lclLabel.update(window) + end + return 40, 1, nil, neoux.tcwindow(40, 1, { + lclLabel + }, function (w) + downloadCancelled = true + end, 0xFFFFFF, 0) +end + +local function doINetThing(inet, url, inst) + inet = inet.list()() + assert(inet, "No available card") + inst.stop() + inst.seek(-inst.getSize()) + downloadCancelled = false + downloadPercent = 0 + window.reset(genDownloading(inst)) + local req = assert(inet.request(url)) + req.finishConnect() + local tapePos = 0 + local tapeSize = inst.getSize() + while (not downloadCancelled) and tapePos < tapeSize do + local n, n2 = req.read(neo.readBufSize) + if not n then + if n2 then + req.close() + error(n2) + end + break + elseif n == "" then + event.sleepTo(os.uptime() + 0.05) + else + inst.write(n) + tapePos = tapePos + #n + end + end + req.close() + inst.seek(-inst.getSize()) +end + +local function genWeb(inst) + updateTick = nil + local url = "" + local lockout = false + return 40, 3, nil, neoux.tcwindow(40, 3, { + neoux.tcrawview(1, 1, {"URL to write to tape?"}), + neoux.tcfield(1, 2, 40, function (t) + url = t or url + return url + end), + neoux.tcbutton(1, 3, "Download & Write", function (w) + lockout = true + local inet = neo.requestAccess("c.internet") + lockout = false + if inet then + local ok, err = pcall(doINetThing, inet, url, inst) + if not ok then + neoux.startDialog("Couldn't download: " .. tostring(err), "error") + end + end + w.reset(genPlayer(inst)) + end) + }, function (w) + w.reset(genPlayer(inst)) + end, 0xFFFFFF, 0) +end + +-- The actual main UI -- +genPlayer = function (inst) local cachedLabel = inst.getLabel() or "" local cachedState = inst.getState() local function pausePlay() @@ -51,20 +138,19 @@ local function genPlayer(inst) local sp = inst.getPosition() local tapeSize = inst.getSize() inst.seek(-tapeSize) - local tapeReadBuf = 8192 local tapePos = 0 while tapePos < tapeSize do if mode then - local data = inst.read(tapeReadBuf) + local data = inst.read(neo.readBufSize) if not data then break end - tapePos = tapePos + tapeReadBuf + tapePos = tapePos + #data local res, ifo = fh.write(data) if not res then neoux.startDialog(tostring(ifo), "issue") break end else - local data = fh.read(tapeReadBuf) + local data = fh.read(neo.readBufSize) if not data then break end tapePos = tapePos + #data inst.write(data) @@ -75,19 +161,31 @@ local function genPlayer(inst) fh.close() end local elems = { + neoux.tcrawview(1, 1, { + "Label:", + "Contents:" + }), + neoux.tcfield(7, 1, 34, function (tx) + if tx then + inst.setLabel(tx) + cachedLabel = tx + end + return cachedLabel + end), { x = 1, y = 5, - w = 20, + w = 40, h = 1, selectable = true, line = function (w, x, y, lined, bg, fg, selected) local lx = "" local pos = inst.getPosition() + local sz = inst.getSize() if inst.isReady() then -- Show a bar - local tick = inst.getSize() / 13 - for i = 1, 13 do + local tick = sz / 23 + for i = 1, 23 do local alpos = (tick * i) - (tick / 2) if pos > alpos then lx = lx .. "=" @@ -98,13 +196,16 @@ local function genPlayer(inst) else lx = "NO TAPE HERE." end - local sec = pos / 4096 - lx = lx .. string.format(" %03i:%02i", math.floor(sec / 60), math.floor(sec) % 60) + local sec = pos / tapeRate + local secz = sz / tapeRate + lx = lx .. string.format(" %03i:%02i / %03i:%02i ", + math.floor(sec / 60), math.floor(sec) % 60, + math.floor(secz / 60), math.floor(secz) % 60) if selected then bg, fg = fg, bg end window.span(x, y, lx, bg, fg) end, key = function (w, update, a, b, c, kf) - local amount = 40960 + local amount = tapeRate * 10 if kf.shift or kf.rshift then amount = amount * 24 end @@ -123,52 +224,53 @@ local function genPlayer(inst) end end }, - neoux.tcrawview(14, 3, { - "% Vol. ", + neoux.tcrawview(33, 3, { + "% Volume" + }), + neoux.tcrawview(20, 3, { "% Speed" }), - pcbox(9, 3, 0, 100, "vol", inst.setVolume), - pcbox(9, 4, 25, 200, "spd", inst.setSpeed), - neoux.tcbutton(1, 3, "{", function (w) + pcbox(15, 3, 25, 200, "spd", inst.setSpeed), + pcbox(28, 3, 0, 100, "vol", inst.setVolume), + neoux.tcrawview(1, 4, { + "Seeker: use ◃/▹ (shift goes faster)" + }), + neoux.tcbutton(1, 3, "«", function (w) inst.seek(-inst.getSize()) end), - neoux.tcbutton(5, 3, "}", function (w) + neoux.tcbutton(11, 3, "»", function (w) inst.seek(inst.getSize()) end), - neoux.tcbutton(1, 4, ((inst.getState() == "PLAYING") and "Pause") or "Play", function (w) + neoux.tcbutton(4, 3, ((inst.getState() == "PLAYING") and "Pause") or "Play", function (w) pausePlay() end), -- R/W buttons - neoux.tcbutton(1, 2, "Read", function (w) + neoux.tcbutton(11, 2, "Read", function (w) rwButton(true) end), - neoux.tcbutton(8, 2, "Write", function (w) + neoux.tcbutton(17, 2, "Write", function (w) rwButton(false) end), - neoux.tcfield(1, 1, 20, function (tx) - if tx then - inst.setLabel(tx) - cachedLabel = tx - end - return cachedLabel + neoux.tcbutton(24, 2, "Write From Web", function (w) + w.reset(genWeb(inst)) end) } updateTick = function () local lcl = cachedLabel cachedLabel = inst.getLabel() or "" - elems[1].update(window) + elems[3].update(window) if inst.getState() ~= cachedState then window.reset(genPlayer(inst)) elseif lcl ~= cachedLabel then - elems[#elems].update(window) + elems[2].update(window) end end - local n = neoux.tcwindow(20, 5, elems, function (w) + local n = neoux.tcwindow(40, 5, elems, function (w) updateTick = nil running = false w.close() end, 0xFFFFFF, 0) - return 20, 5, inst.address, function (a, ...) + return 40, 5, inst.address, function (a, ...) if a == "focus" then focused = (...) or true end @@ -178,12 +280,12 @@ end local function genList() local elems = {} for k, v in ipairs(tapes) do - elems[k] = neoux.tcbutton(1, k, v.address, function (w) + elems[k] = neoux.tcbutton(1, k, v.address:sub(1, 38), function (w) window.reset(genPlayer(v)) end) end tapes = nil - return 40, #elems, "choose", neoux.tcwindow(40, #elems, elems, function (w) + return 40, #elems, nil, neoux.tcwindow(40, #elems, elems, function (w) running = false w.close() end, 0xFFFFFF, 0)