mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-23 10:58:06 +11:00
Fix filewrap, make nbox2018 work to some degree
nbox2018 needs refactoring & hologram integration, nprt2018 needs to be written
This commit is contained in:
parent
a9670637d1
commit
093c50a3a7
@ -69,6 +69,6 @@ local function create(dev, file, mode)
|
||||
end
|
||||
end
|
||||
return {
|
||||
createMode = createMode,
|
||||
ensureMode = ensureMode,
|
||||
create = create
|
||||
}
|
||||
|
@ -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
|
||||
|
1
repository/apps/app-nprt2018.lua
Normal file
1
repository/apps/app-nprt2018.lua
Normal file
@ -0,0 +1 @@
|
||||
Hello World.
|
@ -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"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user