Skip to content

Instantly share code, notes, and snippets.

@marengohue
Last active December 25, 2023 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marengohue/66f58e16cf2b0d12a23e17ada509ceee to your computer and use it in GitHub Desktop.
Save marengohue/66f58e16cf2b0d12a23e17ada509ceee to your computer and use it in GitHub Desktop.
Stormworks touchscreen
local SIGNAL_IN_N__X = 3
local SIGNAL_IN_N__Y = 4
local SIGNAL_IN_B__IS_TOUCH = 1
local SIGNAL_OUT_N__CMD = 1
local SIGNAL_OUT_N__ARG_A = 2
local SIGNAL_OUT_N__ARG_B = 3
local CMD_OPCODE_NOP = 0
local CMD_ARG_NIL = 0
local CMD_OPCODE_FREENAV = 1
local CMD_OPCODE_SEND_COORD = 2
local CMD_OPCODE_SEND_LOCODE = 2
local UI_GRID_SIZE_PX = 8
function gotoMenuCb(name)
uiState.menu = {}
uiState.currentMenu = name
if ui.menus[name].init ~= nil then
ui.menus[name].init()
end
end
function gotoMenu(name)
return function()
gotoMenuCb(name)
end
end
function add(number)
return function()
uiState.menu.val = uiState.menu.val .. number
end
end
function remove()
return function()
local valueLen = string.len(uiState.menu.val)
if valueLen == 1 then
gotoMenuCb("main")
else
uiState.menu.val =
string.sub(uiState.menu.val, 1, -2)
end
end
end
ui = {
colors = {
fg = { val = 220, jitter = 20 },
bg = { val = 1, jitter = 1 },
hl = { val = 10, jitter = 2 }
},
menus = {
main = {
components = {
{ t = "txt", text = "=NAV=", w = 4 },
{
t = "btn", text = "FREE", y = 1, w = 4,
act = gotoMenu("freeNav")
},
{
t = "btn", text = "SET", y = 2, w = 4,
act = gotoMenu("keypad")
},
{
t = "btn", text = "LOCOD", y = 3, w = 4,
act = gotoMenu("locode")
}
}
},
freeNav = {
init = function()
sendOp(CMD_OPCODE_FREENAV)
end,
components = {
{ t = "banner", text = "FREE", y = 1, w = 4 },
{ t = "banner", text = "NAV", y = 2, w = 4 },
{
t = "btn", text = "<-", y = 3, x = 2, w = 2,
act = gotoMenu("main")
},
}
},
locode = {
components = {
{ t = "banner", text = "LOCODE", y = 1, w = 4 },
{ t = "banner", text = "TBD", y = 2, w = 4 },
{
t = "btn", text = "<-", y = 3, x = 2, w = 2,
act = gotoMenu("main")
},
}
},
keypad = {
init = function()
uiState.menu.val = "+"
end,
components = {
{
t = "txt", w = 3,
text = function()
return uiState.menu.val
end
},
{ t = "btn", text = "1", y = 1, act = add(1) },
{ t = "btn", text = "2", x = 1, y = 1, act = add(2) },
{ t = "btn", text = "3", x = 2, y = 1, act = add(3) },
{ t = "btn", text = "X", x = 3, y = 1, act = remove() },
{ t = "btn", text = "4", y = 2, act = add(4) },
{ t = "btn", text = "5", x = 1, y = 2, act = add(5) },
{ t = "btn", text = "6", x = 2, y = 2, act = add(6) },
{
t = "btn",
x = 3, y = 2,
text = function()
if uiState.menu.val == "+" then
return "-"
elseif uiState.menu.val == "-" then
return "+"
else
return "0"
end
end,
act = function()
if uiState.menu.val == "+" then
uiState.menu.val = "-"
elseif uiState.menu.val == "-" then
uiState.menu.val = "+"
else
uiState.menu.val
= uiState.menu.val .. "0"
end
end
},
{ t = "btn", text = "7", y = 3, act = add(7)},
{ t = "btn", text = "8", x = 1, y = 3, act = add(8) },
{ t = "btn", text = "9", x = 2, y = 3, act = add(9) },
{
t = "btn", text = "V", x = 3, y = 3,
act = function()
if uiState.menu.x == nil then
uiState.menu.x
= tonumber(uiState.menu.val)
uiState.menu.val = "+"
else
sendOp(
CMD_OPCODE_SEND_COORD,
uiState.menu.x,
tonumber(uiState.menu.val)
)
gotoMenuCb("main")
end
end
},
}
}
}
}
uiState = {
currentMenu = "main",
colors = {},
menu = {}
}
touchCtl = {}
function sendOp(op, a, b)
output.setNumber(SIGNAL_OUT_N__CMD, op or CMD_OPCODE_NOP)
output.setNumber(SIGNAL_OUT_N__ARG_A, a or CMD_ARG_NIL)
output.setNumber(SIGNAL_OUT_N__ARG_B, b or CMD_ARG_NIL)
end
function clearScreen()
useColor(uiState.colors.bg)
screen.drawClear()
end
function useColor(color)
screen.setColor(color, color, color)
end
function isOver(component)
local x, y, w, h = getBounds(component)
return touchCtl.x > x and touchCtl.x < (x + w - 1)
and touchCtl.y > y and touchCtl.y < (y + h - 1)
end
function jitterScreen()
uiState.colors.fg = ui.colors.fg.val + math.random(0, ui.colors.fg.jitter)
uiState.colors.bg = ui.colors.bg.val + math.random(0, ui.colors.bg.jitter)
uiState.colors.hl = ui.colors.hl.val + math.random(0, ui.colors.hl.jitter)
end
function getBounds(component)
return
(component.x or 0) * UI_GRID_SIZE_PX,
(component.y or 0) * UI_GRID_SIZE_PX,
(component.w or 1) * UI_GRID_SIZE_PX,
(component.h or 1) * UI_GRID_SIZE_PX
end
function renderComponent(c)
local x, y, w, h = getBounds(c)
if c.t == "txt" then
useColor(uiState.colors.fg)
screen.drawText(x + 2, y + 1, getText(c))
elseif c.t == "btn" then
if touchCtl.isTouch and isOver(c) then
useColor(uiState.colors.fg)
screen.drawRectF(x + 1, y, w - 2, h - 1)
useColor(uiState.colors.hl)
else
useColor(uiState.colors.hl)
screen.drawRectF(x + 1, y, w - 2, h - 1)
useColor(uiState.colors.fg)
end
screen.drawText(x + 2, y + 1, getText(c))
elseif c.t == "banner" then
useColor(uiState.colors.fg)
screen.drawTextBox(x, y, w, h, getText(c), 0, 0)
end
end
function getText(component)
if type(component.text) == "function" then
return component.text()
else
return component.text
end
end
function renderMenu()
local currentMenuDefn = ui.menus[uiState.currentMenu]
for _, component in ipairs(currentMenuDefn.components) do
renderComponent(component)
end
end
function onTick()
touchCtl.isRelease = touchCtl.isTouch
and not input.getBool(SIGNAL_IN_B__IS_TOUCH)
touchCtl.isTouch = input.getBool(SIGNAL_IN_B__IS_TOUCH)
if touchCtl.isTouch then
touchCtl.x = input.getNumber(SIGNAL_IN_N__X)
touchCtl.y = input.getNumber(SIGNAL_IN_N__Y)
end
if touchCtl.isRelease then
local currentMenuDefn = ui.menus[uiState.currentMenu]
for _, component in ipairs(currentMenuDefn.components) do
if isOver(component) and component.act ~= nil then
component.act()
end
end
else
sendOp(CMD_OPCODE_NOP)
end
end
function onDraw()
jitterScreen()
clearScreen()
renderMenu(width)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment