1
0
mirror of https://github.com/20kdc/OC-KittenOS.git synced 2024-11-27 12:58:05 +11:00

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 -- Control reference
-- x/y/w/h: ints, position/size, 1,1 TL -- x/y/w/h: ints, position/size, 1,1 TL
-- selectable: boolean -- 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) -- touch(window, update, x, y, xI, yI, button)
-- drag(window, update, x, y, xI, yI, button) -- drag(window, update, x, y, xI, yI, button)
-- drop(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(...) return fmt.fmtText(...)
end end
-- UI FRAMEWORK -- -- 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 function rotateSelIndex()
local original = selIndex local original = selIndex
while true do while true do
@ -119,6 +119,7 @@ newNeoux = function (event, neo)
end end
rotateSelIndex() rotateSelIndex()
end end
keyFlags = keyFlags or {}
local function moveIndex(vertical, negative) local function moveIndex(vertical, negative)
if not controls[selIndex] then return end if not controls[selIndex] then return end
local currentMA, currentOA = controls[selIndex].y, controls[selIndex].x local currentMA, currentOA = controls[selIndex].y, controls[selIndex].x
@ -230,6 +231,20 @@ newNeoux = function (event, neo)
end end
end end
elseif ev == "key" then elseif ev == "key" then
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
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 b == 203 then
if c then if c then
moveIndexAU(window, false, true) moveIndexAU(window, false, true)
@ -255,9 +270,6 @@ newNeoux = function (event, neo)
if c1 then doZone(window, c1, cache) end if c1 then doZone(window, c1, cache) end
if c2 then doZone(window, c2, cache) end if c2 then doZone(window, c2, cache) end
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 end
end end
elseif ev == "clipboard" then elseif ev == "clipboard" then
@ -271,7 +283,7 @@ newNeoux = function (event, neo)
elseif ev == "close" then elseif ev == "close" then
closing(window) closing(window)
end end
end, doZone end
end end
neoux.tcrawview = function (x, y, lines) neoux.tcrawview = function (x, y, lines)
return { return {
@ -308,6 +320,7 @@ newNeoux = function (event, neo)
if d then if d then
if a == 13 or a == 32 then if a == 13 or a == 32 then
callback(window) callback(window)
return true
end end
end end
end, end,
@ -335,13 +348,16 @@ newNeoux = function (event, neo)
key = function (window, update, a, c, d) key = function (window, update, a, c, d)
if d then if d then
if a == 13 then if a == 13 then
return true
elseif a == 8 then elseif a == 8 then
local str = textprop() local str = textprop()
textprop(unicode.sub(str, 1, unicode.len(str) - 1)) textprop(unicode.sub(str, 1, unicode.len(str) - 1))
update() update()
return true
elseif a ~= 0 then elseif a ~= 0 then
textprop(textprop() .. unicode.char(a)) textprop(textprop() .. unicode.char(a))
update() update()
return true
end end
end end
end, end,

View File

@ -9,16 +9,7 @@
local holos = neo.requestAccess("c.hologram") local holos = neo.requestAccess("c.hologram")
local icecap = neo.requireAccess("x.neo.pub.base", "filedialogs") local icecap = neo.requireAccess("x.neo.pub.base", "filedialogs")
local window = neo.requireAccess("x.neo.pub.window", "window")(40, 13) local window = neo.requireAccess("x.neo.pub.window", "window")(40, 13)
local fmttext = require("fmttext")
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"] = { -- [true] = {["A"] = {
-- tex = "", -- tex = "",
@ -31,15 +22,209 @@ local boxes = {
[true] = {}, [true] = {},
[false] = {} [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 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 workingOnBox = nil
local programState = "none" local programState = "none"
-- ["state"] = {lines, key, clipboard} -- ["state"] = {lines, keydown, clipboard}
local programStates = { 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 end
local miText = mix .. "," .. miy .. "," .. miz local miText = mix .. "," .. miy .. "," .. miz
local mxText = mxx .. "," .. mxy .. "," .. mxz local mxText = mxx .. "," .. mxy .. "," .. mxz
local text = { local text = programStates[programState][1](miText, mxText)
"Nothing selected. " .. miText, local menu = {
"Enter starts a new box, while |F3 Load", "|F1 New ",
" a box can be selected by its |F4 Save", "|F3 Load",
" key. To print, press F8. |F5 XYXZ" "|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"
} }
for i = 1, 4 do
text[i] = fmttext.pad(text[i], 32, true, true) .. menu[i]
end end
end
text[1] = require("fmttext").pad(text[1], 32, true, true) .. "|F1 New "
window.span(1, line, text[line - 9] or "", 0, 0xFFFFFF) window.span(1, line, text[line - 9] or "", 0, 0xFFFFFF)
end end
end end
@ -245,6 +408,7 @@ local function reset()
xyz = false xyz = false
cx, cy, cz = 1, 1, 1 cx, cy, cz = 1, 1, 1
workingOnBox = nil workingOnBox = nil
programState = "none"
end end
local function loadObj(obj) local function loadObj(obj)
@ -418,68 +582,9 @@ while true do
cz = math.min(16, cz + 1) cz = math.min(16, cz + 1)
end end
refresh() 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 else
local ch = 65 programStates[programState][2](c, d)
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() 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 end
end end

View File

@ -95,7 +95,7 @@ Main functions:
demand and unloaded after use. demand and unloaded after use.
neoux.tcwindow(w, h, controls, neoux.tcwindow(w, h, controls,
closing, bg, fg[, selIndex]): closing, bg, fg[, selIndex], [kf]):
Creates a neoux.create-compatible Creates a neoux.create-compatible
callback for a NeoUX GUI framework callback for a NeoUX GUI framework
window. window.
@ -114,6 +114,20 @@ Main functions:
selIndex, if provided, is the index selIndex, if provided, is the index
of the control that should start of the control that should start
out selected. 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): startDialog(fmt, title, wait):
Shows a text dialog. Shows a text dialog.

View File

@ -77,6 +77,33 @@ Palette advice for artists:
so that they are not wasted if not so that they are not wasted if not
used. 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 -- This is released into
the public domain. the public domain.
-- No warranty is provided, -- No warranty is provided,