mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-12-26 02:48:06 +11:00
Improve neoux slightly, and hopefully finish most of nbox2018
This commit is contained in:
parent
093c50a3a7
commit
be85af84c7
@ -7,7 +7,7 @@
|
||||
-- Control reference
|
||||
-- x/y/w/h: ints, position/size, 1,1 TL
|
||||
-- selectable: boolean
|
||||
-- key(window, update, char, code, down)
|
||||
-- key(window, update, char, code, down) (If this returns something truthy, defaults are inhibited)
|
||||
-- touch(window, update, x, y, xI, yI, button)
|
||||
-- drag(window, update, x, y, xI, yI, button)
|
||||
-- drop(window, update, x, y, xI, yI, button)
|
||||
@ -94,7 +94,7 @@ newNeoux = function (event, neo)
|
||||
return fmt.fmtText(...)
|
||||
end
|
||||
-- UI FRAMEWORK --
|
||||
neoux.tcwindow = function (w, h, controls, closing, bg, fg, selIndex)
|
||||
neoux.tcwindow = function (w, h, controls, closing, bg, fg, selIndex, keyFlags)
|
||||
local function rotateSelIndex()
|
||||
local original = selIndex
|
||||
while true do
|
||||
@ -119,6 +119,7 @@ newNeoux = function (event, neo)
|
||||
end
|
||||
rotateSelIndex()
|
||||
end
|
||||
keyFlags = keyFlags or {}
|
||||
local function moveIndex(vertical, negative)
|
||||
if not controls[selIndex] then return end
|
||||
local currentMA, currentOA = controls[selIndex].y, controls[selIndex].x
|
||||
@ -230,34 +231,45 @@ newNeoux = function (event, neo)
|
||||
end
|
||||
end
|
||||
elseif ev == "key" then
|
||||
if b == 203 then
|
||||
if c then
|
||||
moveIndexAU(window, false, true)
|
||||
if controls[selIndex] and controls[selIndex].key then
|
||||
if controls[selIndex].key(window, function () doZone(window, controls[selIndex]) end, a, b, c) then
|
||||
return
|
||||
end
|
||||
elseif b == 205 then
|
||||
if c then
|
||||
moveIndexAU(window, false, false)
|
||||
end
|
||||
elseif b == 200 then
|
||||
if c then
|
||||
moveIndexAU(window, true, true)
|
||||
end
|
||||
elseif b == 208 then
|
||||
if c then
|
||||
moveIndexAU(window, true, false)
|
||||
end
|
||||
elseif a == 9 then
|
||||
if c then
|
||||
local c1 = controls[selIndex]
|
||||
rotateSelIndex()
|
||||
local c2 = controls[selIndex]
|
||||
local cache = {}
|
||||
if c1 then doZone(window, c1, cache) end
|
||||
if c2 then doZone(window, c2, cache) end
|
||||
end
|
||||
elseif controls[selIndex] then
|
||||
if controls[selIndex].key then
|
||||
controls[selIndex].key(window, function () doZone(window, controls[selIndex]) end, a, b, c)
|
||||
end
|
||||
if b == 29 then
|
||||
keyFlags.ctrl = c
|
||||
elseif b == 157 then
|
||||
keyFlags.rctrl = c
|
||||
elseif b == 42 then
|
||||
keyFlags.shift = c
|
||||
elseif b == 54 then
|
||||
keyFlags.rshift = c
|
||||
elseif not (keyFlags.ctrl or keyFlags.rctrl or keyFlags.shift or keyFlags.rshift) then
|
||||
if b == 203 then
|
||||
if c then
|
||||
moveIndexAU(window, false, true)
|
||||
end
|
||||
elseif b == 205 then
|
||||
if c then
|
||||
moveIndexAU(window, false, false)
|
||||
end
|
||||
elseif b == 200 then
|
||||
if c then
|
||||
moveIndexAU(window, true, true)
|
||||
end
|
||||
elseif b == 208 then
|
||||
if c then
|
||||
moveIndexAU(window, true, false)
|
||||
end
|
||||
elseif a == 9 then
|
||||
if c then
|
||||
local c1 = controls[selIndex]
|
||||
rotateSelIndex()
|
||||
local c2 = controls[selIndex]
|
||||
local cache = {}
|
||||
if c1 then doZone(window, c1, cache) end
|
||||
if c2 then doZone(window, c2, cache) end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif ev == "clipboard" then
|
||||
@ -271,7 +283,7 @@ newNeoux = function (event, neo)
|
||||
elseif ev == "close" then
|
||||
closing(window)
|
||||
end
|
||||
end, doZone
|
||||
end
|
||||
end
|
||||
neoux.tcrawview = function (x, y, lines)
|
||||
return {
|
||||
@ -308,6 +320,7 @@ newNeoux = function (event, neo)
|
||||
if d then
|
||||
if a == 13 or a == 32 then
|
||||
callback(window)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
@ -335,13 +348,16 @@ newNeoux = function (event, neo)
|
||||
key = function (window, update, a, c, d)
|
||||
if d then
|
||||
if a == 13 then
|
||||
return true
|
||||
elseif a == 8 then
|
||||
local str = textprop()
|
||||
textprop(unicode.sub(str, 1, unicode.len(str) - 1))
|
||||
update()
|
||||
return true
|
||||
elseif a ~= 0 then
|
||||
textprop(textprop() .. unicode.char(a))
|
||||
update()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
@ -9,16 +9,7 @@
|
||||
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)
|
||||
|
||||
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
|
||||
local fmttext = require("fmttext")
|
||||
|
||||
-- [true] = {["A"] = {
|
||||
-- tex = "",
|
||||
@ -31,15 +22,209 @@ local boxes = {
|
||||
[true] = {},
|
||||
[false] = {}
|
||||
}
|
||||
local redstone = false
|
||||
local button = false
|
||||
local fileLabel = "NB2018"
|
||||
local fileTooltip = nil
|
||||
|
||||
-- program
|
||||
|
||||
local xyz = false
|
||||
local state = false
|
||||
|
||||
local cx, cy, cz = 1, 1, 1
|
||||
local cursorBlink = false
|
||||
|
||||
local selectedBox
|
||||
|
||||
local tintDigi = 0
|
||||
|
||||
-- minX/minY/minZ are +1 from the usual values
|
||||
-- tex/rgb are defaults until edited
|
||||
-- maxX/maxY/maxZ only present after 2nd point placed
|
||||
-- final corrections performed on submission to boxes table
|
||||
local workingOnBox = nil
|
||||
|
||||
local programState = "none"
|
||||
-- ["state"] = {lines, key, clipboard}
|
||||
-- ["state"] = {lines, keydown, clipboard}
|
||||
local programStates = {
|
||||
["none"] = {
|
||||
none = {
|
||||
function (miText, mxText)
|
||||
-- This state handles both box selected & box not selected,
|
||||
-- because the box can get deselected out of program control
|
||||
if selectedBox then
|
||||
local targetBox = boxes[state][selectedBox]
|
||||
return {
|
||||
"'" .. selectedBox .. "' " .. targetBox.tex,
|
||||
"Tint #" .. string.format("%06x", targetBox.rgb),
|
||||
"Enter deselects, Delete deletes.",
|
||||
"F9 and F10 change texture/tint."
|
||||
}
|
||||
end
|
||||
local str = string.format("%02i, %02i, %02i", cx, cy, cz)
|
||||
return {
|
||||
"Nothing selected. " .. str,
|
||||
"Enter starts a new box, while ",
|
||||
" a box can be selected by its ",
|
||||
" key. To print, press F8. "
|
||||
}
|
||||
end,
|
||||
function (ka, kc)
|
||||
if ka == 13 then
|
||||
if selectedBox then
|
||||
selectedBox = nil
|
||||
else
|
||||
-- Beginning box!
|
||||
workingOnBox = {
|
||||
minX = cx,
|
||||
minY = cy,
|
||||
minZ = cz,
|
||||
tex = "",
|
||||
rgb = 0xFFFFFF
|
||||
}
|
||||
programState = "point2"
|
||||
end
|
||||
elseif kc == 67 then
|
||||
-- Texture
|
||||
if selectedBox then programState = "texture" end
|
||||
elseif kc == 68 then
|
||||
-- Tint
|
||||
if selectedBox then tintDigi = 1 programState = "tint" end
|
||||
else
|
||||
local cc = unicode.char(ka):upper()
|
||||
if boxes[state][cc] then
|
||||
selectedBox = cc
|
||||
end
|
||||
end
|
||||
end,
|
||||
function (text)
|
||||
end
|
||||
},
|
||||
point2 = {
|
||||
function (miText, mxText)
|
||||
return {
|
||||
"Placing Point 2:" .. miText .. "/" .. mxText,
|
||||
"Enter confirms.",
|
||||
"Arrows move 2nd point.",
|
||||
"Delete/Backspace cancels."
|
||||
}
|
||||
end,
|
||||
function (ka, kc)
|
||||
if ka == 127 or ka == 8 then
|
||||
workingOnBox = nil
|
||||
programState = "none"
|
||||
elseif ka == 13 then
|
||||
workingOnBox.maxX = cx
|
||||
workingOnBox.maxY = cy
|
||||
workingOnBox.maxZ = cz
|
||||
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
|
||||
programState = "none"
|
||||
end
|
||||
end,
|
||||
function (text)
|
||||
end
|
||||
},
|
||||
texture = {
|
||||
function (miText, mxText)
|
||||
local targetBox = boxes[state][selectedBox]
|
||||
local fieldContent = unicode.safeTextFormat(targetBox.tex)
|
||||
fieldContent = fmttext.pad(fieldContent, 30, false, false)
|
||||
fieldContent = unicode.sub(fieldContent, math.max(1, unicode.len(fieldContent) - 29))
|
||||
return {
|
||||
"Texturing Box:" .. miText .. "/" .. mxText,
|
||||
"Type texture ID or use clipboard",
|
||||
"[" .. fieldContent .. "]",
|
||||
"Enter to confirm."
|
||||
}
|
||||
end,
|
||||
function (ka, kc)
|
||||
local targetBox = boxes[state][selectedBox]
|
||||
if ka == 127 or ka == 8 then
|
||||
targetBox.tex = unicode.sub(targetBox.tex, 1, unicode.len(targetBox.tex) - 1)
|
||||
elseif ka == 13 then
|
||||
programState = "none"
|
||||
elseif ka >= 32 then
|
||||
targetBox.tex = targetBox.tex .. unicode.char(ka)
|
||||
end
|
||||
end,
|
||||
function (text)
|
||||
boxes[state][selectedBox].tex = text
|
||||
programState = "none"
|
||||
end
|
||||
},
|
||||
tint = {
|
||||
function (miText, mxText)
|
||||
local targetBox = boxes[state][selectedBox]
|
||||
local a = "#"
|
||||
local b = " "
|
||||
local rgb = targetBox.rgb
|
||||
local div = 0x100000
|
||||
for i = 1, 6 do
|
||||
a = a .. string.format("%01x", math.floor(rgb / div) % 16)
|
||||
if tintDigi == i then
|
||||
b = b .. "^"
|
||||
else
|
||||
b = b .. " "
|
||||
end
|
||||
div = math.floor(div / 16)
|
||||
end
|
||||
return {
|
||||
"Tinting Box:" .. miText .. "/" .. mxText,
|
||||
a,
|
||||
b,
|
||||
"Enter hexadecimal digits."
|
||||
}
|
||||
end,
|
||||
function (ka, kc)
|
||||
local targetBox = boxes[state][selectedBox]
|
||||
local shifts = {
|
||||
20,
|
||||
16,
|
||||
12,
|
||||
8,
|
||||
4,
|
||||
0
|
||||
}
|
||||
local hexChars = {
|
||||
[48] = 0, [65] = 10, [97] = 10,
|
||||
[49] = 1, [66] = 11, [98] = 11,
|
||||
[50] = 2, [67] = 12, [99] = 12,
|
||||
[51] = 3, [68] = 13, [100] = 13,
|
||||
[52] = 4, [69] = 14, [101] = 14,
|
||||
[53] = 5, [70] = 15, [102] = 15,
|
||||
[54] = 6,
|
||||
[55] = 7,
|
||||
[56] = 8,
|
||||
[57] = 9,
|
||||
}
|
||||
if hexChars[ka] then
|
||||
local shift = math.floor(2^shifts[tintDigi])
|
||||
local low = targetBox.rgb % shift
|
||||
local high = math.floor(targetBox.rgb / (shift * 16)) * (shift * 16)
|
||||
targetBox.rgb = low + high + (hexChars[ka] * shift)
|
||||
tintDigi = 1 + (tintDigi or 1)
|
||||
if tintDigi == 7 then
|
||||
tintDigi = nil
|
||||
programState = "none"
|
||||
end
|
||||
end
|
||||
end,
|
||||
function (text)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,38 +382,16 @@ local function render(line)
|
||||
end
|
||||
local miText = mix .. "," .. miy .. "," .. miz
|
||||
local mxText = mxx .. "," .. mxy .. "," .. mxz
|
||||
local text = {
|
||||
"Nothing selected. " .. miText,
|
||||
"Enter starts a new box, while |F3 Load",
|
||||
" a box can be selected by its |F4 Save",
|
||||
" key. To print, press F8. |F5 XYXZ"
|
||||
local text = programStates[programState][1](miText, mxText)
|
||||
local menu = {
|
||||
"|F1 New ",
|
||||
"|F3 Load",
|
||||
"|F4 Save",
|
||||
"|F5 XYXZ"
|
||||
}
|
||||
if selectedBox then
|
||||
text = {
|
||||
"'" .. 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 workingOnBox.maxX then
|
||||
text = {
|
||||
"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(workingOnBox.tex), 30, false, true)
|
||||
text = {
|
||||
"Box Texture Entry: " .. miText .. "/" .. mxText,
|
||||
" Press Enter to confirm texture,|F3 Load",
|
||||
" or paste out-of-game clipboard.|F4 Save",
|
||||
"[" .. tex .. "]|F5 XYXZ"
|
||||
}
|
||||
end
|
||||
for i = 1, 4 do
|
||||
text[i] = fmttext.pad(text[i], 32, true, true) .. menu[i]
|
||||
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
|
||||
@ -245,6 +408,7 @@ local function reset()
|
||||
xyz = false
|
||||
cx, cy, cz = 1, 1, 1
|
||||
workingOnBox = nil
|
||||
programState = "none"
|
||||
end
|
||||
|
||||
local function loadObj(obj)
|
||||
@ -418,68 +582,9 @@ while true do
|
||||
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
|
||||
programStates[programState][2](c, d)
|
||||
refresh()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -95,7 +95,7 @@ Main functions:
|
||||
demand and unloaded after use.
|
||||
|
||||
neoux.tcwindow(w, h, controls,
|
||||
closing, bg, fg[, selIndex]):
|
||||
closing, bg, fg[, selIndex], [kf]):
|
||||
Creates a neoux.create-compatible
|
||||
callback for a NeoUX GUI framework
|
||||
window.
|
||||
@ -114,6 +114,20 @@ Main functions:
|
||||
selIndex, if provided, is the index
|
||||
of the control that should start
|
||||
out selected.
|
||||
kf, if provided, is a table that
|
||||
is used for extended information:
|
||||
ctrl: True when left Ctrl key
|
||||
is down, nil or false when it's
|
||||
up.
|
||||
rctrl: True when right Ctrl key
|
||||
is down, nil or false when it's
|
||||
up.
|
||||
shift: True when left Shift key
|
||||
is down, nil or false when it's
|
||||
up.
|
||||
rshift: True when right Shift key
|
||||
is down, nil or false when it's
|
||||
up.
|
||||
|
||||
startDialog(fmt, title, wait):
|
||||
Shows a text dialog.
|
||||
|
@ -77,6 +77,33 @@ Palette advice for artists:
|
||||
so that they are not wasted if not
|
||||
used.
|
||||
|
||||
Notes on UI design:
|
||||
|
||||
The UI design is heavily monochrome.
|
||||
|
||||
core (neoux supported):
|
||||
"[textheretext]": This means a text
|
||||
field. It should preferably right-
|
||||
align text if too much is inside,
|
||||
ensuring that what is being written
|
||||
can be read.
|
||||
The enter button should do nothing,
|
||||
and the backspace/delete buttons
|
||||
should both remove the last Unicode
|
||||
character.
|
||||
"<texthere>": This means a button.
|
||||
Space or enter should activate it.
|
||||
|
||||
additional:
|
||||
"◢": Resize widget. Drag-dropping
|
||||
should cause a resize. This
|
||||
need not occur until the drop
|
||||
is completed.
|
||||
Standardized by Izaya.
|
||||
The non-GUI way to do this is
|
||||
for ctrl-arrows to resize
|
||||
the window.
|
||||
|
||||
-- This is released into
|
||||
the public domain.
|
||||
-- No warranty is provided,
|
||||
|
Loading…
Reference in New Issue
Block a user