From 093c50a3a757e28590a53b61f98543640015594d Mon Sep 17 00:00:00 2001 From: 20kdc Date: Tue, 17 Apr 2018 23:57:31 +0100 Subject: [PATCH] Fix filewrap, make nbox2018 work to some degree nbox2018 needs refactoring & hologram integration, nprt2018 needs to be written --- code/libs/sys-filewrap.lua | 2 +- repository/apps/app-nbox2018.lua | 462 ++++++++++++++++++++++++++--- repository/apps/app-nprt2018.lua | 1 + repository/data/app-claw/local.lua | 5 +- 4 files changed, 421 insertions(+), 49 deletions(-) create mode 100644 repository/apps/app-nprt2018.lua diff --git a/code/libs/sys-filewrap.lua b/code/libs/sys-filewrap.lua index 36c8d63..a2f891c 100644 --- a/code/libs/sys-filewrap.lua +++ b/code/libs/sys-filewrap.lua @@ -69,6 +69,6 @@ local function create(dev, file, mode) end end return { - createMode = createMode, + ensureMode = ensureMode, create = create } diff --git a/repository/apps/app-nbox2018.lua b/repository/apps/app-nbox2018.lua index b349749..d22f9e8 100644 --- a/repository/apps/app-nbox2018.lua +++ b/repository/apps/app-nbox2018.lua @@ -6,44 +6,152 @@ -- program start +local holos = neo.requestAccess("c.hologram") +local icecap = neo.requireAccess("x.neo.pub.base", "filedialogs") local window = neo.requireAccess("x.neo.pub.window", "window")(40, 13) --- ["A"] = { +local xyz = false +local state = false +local redstone = false +local button = false +local fileLabel = "NB2018" +local fileTooltip = nil + +local cx, cy, cz = 1, 1, 1 +local cursorBlink = false + +-- [true] = {["A"] = { -- tex = "", -- -- numbers are 0 to 15: -- minX = 0, minY = 0, minZ = 0, --- maxX = 0, maxY = 0, maxZ = 0 --- } +-- maxX = 16, maxY = 16, maxZ = 16, +-- rgb = 0xFFFFFF +-- }} local boxes = { - ["A"] = {}, - ["B"] = {}, - ["C"] = {}, - ["D"] = {}, - ["E"] = {}, - ["F"] = {}, - ["G"] = {}, - ["H"] = {}, - ["I"] = {}, + [true] = {}, + [false] = {} } local selectedBox -local workingOnBox = false -local workingOnBoxSt2 = nil -local workingOnBoxSt3 = nil +local workingOnBox = nil -local function cirno(line) +local programState = "none" +-- ["state"] = {lines, key, clipboard} +local programStates = { + ["none"] = { + } +} + +local function onRect(x, y, minX, minY, maxX, maxY) + -- Lines + if x == minX then + return y >= minY and y <= maxY + elseif x == maxX then + return y >= minY and y <= maxY + elseif y == minY then + return x >= minX and x <= maxX + elseif y == maxY then + return x >= minX and x <= maxX + end + return false +end + +local function getPixel(x, y, p) + if p == 1 then + -- plane 1 uses inverted Y + y = 17 - y + if x == cx and y == cy then + return cursorBlink + end + else + if x == cx and y == cz then + return cursorBlink + end + end + if workingOnBox then + local minX, minY, minZ = workingOnBox.minX, workingOnBox.minY, workingOnBox.minZ + local maxX, maxY, maxZ = cx, cy, cz + if workingOnBox.maxX then + maxX, maxY, maxZ = workingOnBox.maxX, workingOnBox.maxY, workingOnBox.maxZ + end + minX, maxX = math.min(minX, maxX), math.max(minX, maxX) + minY, maxY = math.min(minY, maxY), math.max(minY, maxY) + minZ, maxZ = math.min(minZ, maxZ), math.max(minZ, maxZ) + if p == 1 then + if onRect(x, y, minX, minY, maxX, maxY) then + return cursorBlink + end + else + if onRect(x, y, minX, minZ, maxX, maxZ) then + return cursorBlink + end + end + end + for k, v in pairs(boxes[state]) do + if (not selectedBox) or (k == selectedBox) then + if p == 1 then + if onRect(x, y, v.minX + 1, v.minY + 1, v.maxX, v.maxY) then + return true + end + else + if onRect(x, y, v.minX + 1, v.minZ + 1, v.maxX, v.maxZ) then + return true + end + end + end + end + return false +end + +local function render(line) if line < 9 then local textA, textB = "", "" + local bo = (line - 1) * 2 for i = 1, 16 do - -- ▄▀█ and space - textA = textA .. "▄" - textB = textB .. "▄" + for p = 1, 2 do + local pxH, pxL = getPixel(i, bo + 1, p), getPixel(i, bo + 2, p) + local tx + if pxH then + if pxL then + tx = "█" + else + tx = "▀" + end + else + if pxL then + tx = "▄" + else + tx = " " + end + end + if p == 1 then + textA = textA .. tx + else + textB = textB .. tx + end + end + end + if line < 7 then + window.span(1, line, "|" .. textA .. "|" .. textB .. "| ", 0, 0xFFFFFF) + else + if line == 7 then + window.span(1, line, "|" .. textA .. "|" .. textB .. "|F6/F7", 0, 0xFFFFFF) + elseif line == 8 then + local rs = "R0" + local bm = "B0" + if redstone then + rs = "R1" + end + if button then + bm = "B1" + end + window.span(1, line, "|" .. textA .. "|" .. textB .. "|" .. rs .. " " .. bm, 0, 0xFFFFFF) + end end - window.span(1, line, "|" .. textA .. "|" .. textB .. "| ", 0, 0xFFFFFF) for i = 1, 5 do local boxId = string.char(i + ((line - 1) * 5) + 64) - if boxes[boxId] then + if boxes[state][boxId] then if selectedBox == boxId then window.span(35 + i, line, boxId, 0xFFFFFF, 0) else @@ -52,65 +160,327 @@ local function cirno(line) end end elseif line == 9 then - window.span(1, line, "+XZ Ortho--------+XY Ortho-----+-+Boxes", 0, 0xFFFFFF) + local sts = "ON " + if not state then + sts = "OFF" + end + local actA = "---" + local actB = "---" + if not xyz then + actA = "ACT" + else + actB = "ACT" + end + window.span(1, line, "+XY Ortho-" .. actA .. "----+XZ Ortho-" .. actB .. "--+-+S:" .. sts, 0, 0xFFFFFF) elseif line > 9 then + local mix, miy, miz = cx, cy, cz + local mxx, mxy, mxz = cx, cy, cz + if workingOnBox then + if workingOnBox.maxX then + local ax, ay, az = workingOnBox.minX, workingOnBox.minY, workingOnBox.minZ + local bx, by, bz = workingOnBox.maxX, workingOnBox.maxY, workingOnBox.maxZ + mix = math.min(ax, bx) + miy = math.min(ay, by) + miz = math.min(az, bz) + mxx = math.max(ax, bx) + mxy = math.max(ay, by) + mxz = math.max(az, bz) + else + local ax, ay, az = workingOnBox.minX, workingOnBox.minY, workingOnBox.minZ + mix = math.min(ax, cx) + miy = math.min(ay, cy) + miz = math.min(az, cz) + mxx = math.max(ax, cx) + mxy = math.max(ay, cy) + mxz = math.max(az, cz) + end + end + local miText = mix .. "," .. miy .. "," .. miz + local mxText = mxx .. "," .. mxy .. "," .. mxz local text = { - "Nothing selected. |F1 New ", + "Nothing selected. " .. miText, "Enter starts a new box, while |F3 Load", - " the A-Z keys select a box that |F4 Save", - " is already on the board. |F5 XYXZ" + " a box can be selected by its |F4 Save", + " key. To print, press F8. |F5 XYXZ" } if selectedBox then text = { - "Box " .. selectedBox .. " selected. |F1 New ", - "Enter deselects the box, while |F3 Load", - " Delete deletes the box, and the|F4 Save", - " A-Z keys select another box. |F5 XYXZ" + "'" .. selectedBox .. "' " .. boxes[state][selectedBox].tex, + require("fmttext").pad("Tint #" .. string.format("%08x", workingOnBox.rgb), 32, false, true) .. "|F3 Load", + "Enter deselects, Delete deletes,|F4 Save", + " and the A-Z keys still select. |F5 XYXZ" } elseif workingOnBox then - if not workingOnBoxSt1 then + if not workingOnBox.maxX then text = { - "Creating box: Placing Point A. |F1 New ", - "Arrows to move around. Use F5 to|F3 Load", - " swap from XY to XZ or back. |F4 Save", - "Enter confirms, Delete cancels. |F5 XYXZ" - } - elseif not workingOnBoxSt2 then - text = { - "Creating box: Placing Point B. |F1 New ", + "Creating: " .. miText .. "/" .. mxText, "Arrows to move around. Use F5 to|F3 Load", " swap from XY to XZ or back. |F4 Save", "Enter confirms, Delete cancels. |F5 XYXZ" } else - local tex = require("fmttext").pad(unicode.safeTextFormat(workingOnBoxSt2.tex), 30, false, true) + local tex = require("fmttext").pad(unicode.safeTextFormat(workingOnBox.tex), 30, false, true) text = { - "Box Texture Entry: Type & press |F1 New ", - " Enter to confirm, or use the |F3 Load", - " out-of-game clipboard. |F4 Save", + "Box Texture Entry: " .. miText .. "/" .. mxText, + " Press Enter to confirm texture,|F3 Load", + " or paste out-of-game clipboard.|F4 Save", "[" .. tex .. "]|F5 XYXZ" } end end + text[1] = require("fmttext").pad(text[1], 32, true, true) .. "|F1 New " window.span(1, line, text[line - 9] or "", 0, 0xFFFFFF) end end local function refresh() for i = 1, 14 do - cirno(i) + render(i) end end +local function reset() + boxes = {[true] = {}, [false] = {}} + state = false + selectedBox = nil + xyz = false + cx, cy, cz = 1, 1, 1 + workingOnBox = nil +end + +local function loadObj(obj) + fileLabel = obj.label + fileTooltip = obj.tooltip + redstone = obj.emitRedstone + button = obj.buttonMode + local advances = { + [false] = 65, + [true] = 65 + } + for k, v in ipairs(obj.shapes) do + local vs = v.state or false + boxes[vs][string.char(advances[vs])] = { + minX = v[1], + minY = v[2], + minZ = v[3], + maxX = v[4], + maxY = v[5], + maxZ = v[6], + tex = v.texture, + rgb = v.tint or 0xFFFFFF + } + advances[vs] = advances[vs] + 1 + end +end +local function exportBoxes(shapes, st) + local order = {} + for k, v in pairs(boxes[st]) do + table.insert(order, k) + end + table.sort(order) + for _, kv in ipairs(order) do + local v = boxes[st][kv] + local tint = v.rgb + if tint == 0xFFFFFF then + tint = nil + end + table.insert(shapes, { + v.minX, + v.minY, + v.minZ, + v.minX, + v.maxY, + v.maxZ, + texture = v.tex, + state = st, + tint = tint + }) + end +end +local function makeObj() + local tbl = { + label = fileLabel, + tooltip = fileTooltip, + emitRedstone = redstone, + buttonMode = button, + shapes = { + } + } + exportBoxes(tbl.shapes, false) + exportBoxes(tbl.shapes, true) + return tbl +end + +local lastFile = nil +local function waitForDialog(handle) + lastFile = nil + while true do + local event, b, c, d = coroutine.yield() + if event == "k.timer" then + neo.scheduleTimer(os.uptime() + 0.5) + end + if event == "x.neo.pub.window" then + if b == "close" then + return true + end + end + if event == "x.neo.pub.base" then + if b == "filedialog" then + if c == handle then + lastFile = d + return + end + end + end + end +end + +neo.scheduleTimer(os.uptime()) while true do local event, a, b, c, d, e = coroutine.yield() + if event == "k.timer" then + neo.scheduleTimer(os.uptime() + 0.5) + cursorBlink = not cursorBlink + refresh() + end if event == "x.neo.pub.window" then if b == "line" then - cirno(c) + render(c) + end + if b == "clipboard" then + if workingOnBox and workingOnBox.maxX then + workingOnBox.tex = tostring(c) + b = "key" + c = 13 + d = 0 + e = true + end end if b == "key" then if e then - workingOnBox = not workingOnBox - refresh() + --neo.emergency("key " .. tostring(c) .. " " .. tostring(d)) + if d == 59 then + reset() + refresh() + elseif d == 61 then + -- Load + local handle = icecap.showFileDialogAsync(false) + if waitForDialog(handle) then return end + if lastFile then + reset() + local obj = require("serial").deserialize("return " .. lastFile.read("*a")) + loadObj(obj) + refresh() + lastFile.close() + end + elseif d == 62 then + -- Save + local handle = icecap.showFileDialogAsync(true) + if waitForDialog(handle) then return end + if lastFile then + lastFile.write(require("serial").serialize(makeObj()):sub(8)) + lastFile.close() + end + elseif d == 63 then + xyz = not xyz + refresh() + elseif d == 64 then + redstone = not redstone + refresh() + elseif d == 65 then + button = not button + refresh() + elseif d == 66 then + -- Print + neo.executeAsync("app-nprt2018", makeObj()) + elseif c == 9 then + state = not state + selectedBox = nil + -- we can safely switch between states + -- while working on a box + refresh() + elseif d == 203 then + cx = math.max(1, cx - 1) + refresh() + elseif d == 200 then + if not xyz then + cy = math.min(16, cy + 1) + else + cz = math.max(1, cz - 1) + end + refresh() + elseif d == 205 then + cx = math.min(16, cx + 1) + refresh() + elseif d == 208 then + if not xyz then + cy = math.max(1, cy - 1) + else + cz = math.min(16, cz + 1) + end + refresh() + elseif c == 13 then + if not selectedBox then + if not workingOnBox then + workingOnBox = { + minX = cx, + minY = cy, + minZ = cz, + tex = "diamond_block", + rgb = 0xFFFFFF + } + elseif not workingOnBox.maxX then + workingOnBox.maxX = cx + workingOnBox.maxY = cy + workingOnBox.maxZ = cz + else + local ch = 65 + while boxes[state][string.char(ch)] do + ch = ch + 1 + end + local ax, ay, az = workingOnBox.minX, workingOnBox.minY, workingOnBox.minZ + local bx, by, bz = workingOnBox.maxX, workingOnBox.maxY, workingOnBox.maxZ + workingOnBox.minX = math.min(ax, bx) - 1 + workingOnBox.minY = math.min(ay, by) - 1 + workingOnBox.minZ = math.min(az, bz) - 1 + workingOnBox.maxX = math.max(ax, bx) + workingOnBox.maxY = math.max(ay, by) + workingOnBox.maxZ = math.max(az, bz) + selectedBox = string.char(ch) + boxes[state][selectedBox] = workingOnBox + workingOnBox = nil + end + else + selectedBox = nil + end + refresh() + else + if workingOnBox then + if not workingOnBox.maxX then + if c == 8 or c == 127 then + workingOnBox = nil + end + else + if c >= 32 then + workingOnBox.tex = workingOnBox.tex .. unicode.char(c) + elseif c == 8 or c == 127 then + workingOnBox.tex = unicode.sub(workingOnBox.tex, 1, unicode.len(workingOnBox.tex) - 1) + end + end + refresh() + elseif c == 8 or c == 127 then + if selectedBox then + boxes[state][selectedBox] = nil + selectedBox = nil + refresh() + end + else + local cc = unicode.char(c):upper() + if boxes[state][cc] then + selectedBox = cc + end + refresh() + end + end end end if b == "close" then diff --git a/repository/apps/app-nprt2018.lua b/repository/apps/app-nprt2018.lua new file mode 100644 index 0000000..f534deb --- /dev/null +++ b/repository/apps/app-nprt2018.lua @@ -0,0 +1 @@ +Hello World. diff --git a/repository/data/app-claw/local.lua b/repository/data/app-claw/local.lua index 99350a2..0d7d05d 100644 --- a/repository/data/app-claw/local.lua +++ b/repository/data/app-claw/local.lua @@ -47,7 +47,7 @@ return { }, }, ["app-nbox2018"] = { - desc = "NBOX-2018, a 3D printing toolbox", + desc = "NBOX2018 and NPRT2018, a 3D-printing toolbox", v = 0, deps = { "neo" @@ -56,7 +56,8 @@ return { "apps" }, files = { - "apps/app-nbox2018.lua" + "apps/app-nbox2018.lua", + "apps/app-nprt2018.lua" }, }, }