Improve neoux slightly, and hopefully finish most of nbox2018

This commit is contained in:
20kdc 2018-04-19 02:00:03 +01:00
parent 093c50a3a7
commit be85af84c7
4 changed files with 296 additions and 134 deletions

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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,