|
|
@@ -0,0 +1,839 @@ |
|
|
|
os.loadAPI("/lib/util") |
|
|
|
|
|
|
|
function prettyPrintSize(tokens) |
|
|
|
if type(tokens) == "number" then |
|
|
|
return tostring(tokens) |
|
|
|
end |
|
|
|
|
|
|
|
local str = "( " |
|
|
|
for key, token in pairs(tokens) do |
|
|
|
if token.tokentype == "list" then |
|
|
|
str = str .. prettyPrintSize(token) |
|
|
|
elseif token.tokentype == "num" then |
|
|
|
str = str .. token.val .. " " |
|
|
|
elseif token.tokentype == "percent" then |
|
|
|
str = str .. token.val .. "% " |
|
|
|
elseif token.tokentype == "selfpercent" then |
|
|
|
str = str .. token.val .. "$ " |
|
|
|
elseif token.tokentype == "auto" then |
|
|
|
str = str .. "& " |
|
|
|
elseif token.tokentype == "add" then |
|
|
|
str = str .. "+ " |
|
|
|
elseif token.tokentype == "sub" then |
|
|
|
str = str .. "- " |
|
|
|
elseif token.tokentype == "multiply" then |
|
|
|
str = str .. "* " |
|
|
|
elseif token.tokentype == "divide" then |
|
|
|
str = str .. "/ " |
|
|
|
end |
|
|
|
end |
|
|
|
return str .. ")" |
|
|
|
end |
|
|
|
|
|
|
|
function parseSize(size) |
|
|
|
if type(size) == "number" then |
|
|
|
return size |
|
|
|
end |
|
|
|
|
|
|
|
size = size .. " " |
|
|
|
size = string.gsub(size, "center", "50%% - 50$") |
|
|
|
print(size) |
|
|
|
|
|
|
|
local res = { |
|
|
|
tokentype = "list" |
|
|
|
} |
|
|
|
local current = "" |
|
|
|
local parsing = true |
|
|
|
local i = 1 |
|
|
|
while i <= #size do |
|
|
|
local c = string.sub(size, i, i) |
|
|
|
|
|
|
|
if tonumber(c) ~= nil then |
|
|
|
current = current .. c |
|
|
|
elseif current ~= "" then |
|
|
|
local cur = tonumber(current) |
|
|
|
if cur == nil or current == "+" or current == "-" then |
|
|
|
-- Don't do anything because there's no number |
|
|
|
elseif c == "%" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "percent"; |
|
|
|
val = cur; |
|
|
|
}) |
|
|
|
elseif c == "$" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "selfpercent"; |
|
|
|
val = cur; |
|
|
|
}) |
|
|
|
else |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "num"; |
|
|
|
val = cur; |
|
|
|
}) |
|
|
|
end |
|
|
|
current = "" |
|
|
|
end |
|
|
|
|
|
|
|
if c == "(" then |
|
|
|
local substr = "" |
|
|
|
local depth = 1 |
|
|
|
|
|
|
|
while depth > 0 do |
|
|
|
i = i + 1 |
|
|
|
local cc = string.sub(size, i, i) |
|
|
|
if cc == "(" then |
|
|
|
depth = depth + 1 |
|
|
|
elseif cc == ")" then |
|
|
|
depth = depth - 1 |
|
|
|
end |
|
|
|
|
|
|
|
if depth > 0 then |
|
|
|
substr = substr .. cc |
|
|
|
end |
|
|
|
end |
|
|
|
table.insert(res, parseSize(substr)) |
|
|
|
elseif c == "&" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "auto" |
|
|
|
}) |
|
|
|
elseif c == "+" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "add" |
|
|
|
}) |
|
|
|
elseif c == "-" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "sub" |
|
|
|
}) |
|
|
|
elseif c == "*" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "multiply" |
|
|
|
}) |
|
|
|
elseif c == "/" then |
|
|
|
table.insert(res, { |
|
|
|
tokentype = "divide" |
|
|
|
}) |
|
|
|
end |
|
|
|
|
|
|
|
i = i + 1 |
|
|
|
end |
|
|
|
|
|
|
|
return res |
|
|
|
end |
|
|
|
|
|
|
|
function calcSize(tokens, parentSizeArg, selfSizeArg, autoSizeArg) |
|
|
|
if type(tokens) == "number" then |
|
|
|
return tokens |
|
|
|
elseif tokens == nil then |
|
|
|
return nil |
|
|
|
end |
|
|
|
|
|
|
|
local parentSize = 0 |
|
|
|
if type(parentSizeArg) == "function" then |
|
|
|
parentSize = parentSizeArg() |
|
|
|
elseif type(parentSizeArg) == "number" then |
|
|
|
parentSize = parentSizeArg |
|
|
|
end |
|
|
|
local selfSize = 0 |
|
|
|
if type(selfSizeArg) == "function" then |
|
|
|
selfSize = selfSizeArg() |
|
|
|
elseif type(selfSizeArg) == "number" then |
|
|
|
selfSize = selfSizeArg |
|
|
|
end |
|
|
|
local autoSize = 0 |
|
|
|
if type(autoSizeArg) == "function" then |
|
|
|
autoSize = autoSizeArg() |
|
|
|
elseif type(autoSizeArg) == "number" then |
|
|
|
autoSize = autoSizeArg |
|
|
|
end |
|
|
|
|
|
|
|
function getVal(token) |
|
|
|
if token.tokentype == "num" then |
|
|
|
return token.val |
|
|
|
elseif token.tokentype == "percent" then |
|
|
|
return util.percentOf(token.val, parentSize) |
|
|
|
elseif token.tokentype == "selfpercent" then |
|
|
|
return util.percentOf(token.val, selfSize) - 1 |
|
|
|
elseif token.tokentype == "auto" then |
|
|
|
return autoSize |
|
|
|
elseif token.tokentype == "list" then |
|
|
|
return calcSize(token, parentSize, selfSize) |
|
|
|
else |
|
|
|
return 0 |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
local sum = 0 |
|
|
|
local opr = "add" |
|
|
|
|
|
|
|
local i = 1 |
|
|
|
while i <= #tokens do |
|
|
|
local num = getVal(tokens[i]) |
|
|
|
if opr == "add" then |
|
|
|
sum = sum + num |
|
|
|
elseif opr == "sub" then |
|
|
|
sum = sum - num |
|
|
|
elseif opr == "multiply" then |
|
|
|
sum = sum * num |
|
|
|
elseif opr == "divide" then |
|
|
|
sum = sum / num |
|
|
|
else |
|
|
|
error("Unexpected operator: "..opr) |
|
|
|
return 0 |
|
|
|
end |
|
|
|
|
|
|
|
local oprToken = tokens[i + 1] |
|
|
|
if oprToken ~= nil then |
|
|
|
opr = oprToken.tokentype |
|
|
|
else |
|
|
|
opr = "" |
|
|
|
end |
|
|
|
|
|
|
|
i = i + 2 |
|
|
|
end |
|
|
|
|
|
|
|
return math.floor(sum) |
|
|
|
end |
|
|
|
|
|
|
|
function Widget() |
|
|
|
local self = util.newObject() |
|
|
|
util.makeEventListener(self) |
|
|
|
|
|
|
|
local prog = nil |
|
|
|
local focused = false |
|
|
|
local children = {} |
|
|
|
local parent = nil |
|
|
|
local top = 1 |
|
|
|
local bottom = nil |
|
|
|
local left = 1 |
|
|
|
local right = nil |
|
|
|
local width = parseSize("&") |
|
|
|
local height = parseSize("&") |
|
|
|
local background = "black" |
|
|
|
local foreground = "white" |
|
|
|
|
|
|
|
local x = 1 |
|
|
|
local y = 1 |
|
|
|
|
|
|
|
self.getset("prog", |
|
|
|
function() return prog end, |
|
|
|
function(val) prog = val end) |
|
|
|
|
|
|
|
self.getset("focused", |
|
|
|
function() return focused end) |
|
|
|
self.getset("children", |
|
|
|
function() return children end) |
|
|
|
|
|
|
|
self.getset("parent", |
|
|
|
function() return parent end) |
|
|
|
self.getset("_parent", |
|
|
|
function() return parent end, |
|
|
|
function(val) parent = val end) |
|
|
|
|
|
|
|
self.getset("width", |
|
|
|
function() return calcSize(width, parent.width, 0, self.autoWidth) end, |
|
|
|
function(val) width = parseSize(val) end) |
|
|
|
self.getset("height", |
|
|
|
function() return calcSize(height, parent.height, 0, self.autoHeight) end, |
|
|
|
function(val) height = parseSize(val) end) |
|
|
|
|
|
|
|
self.getset("background", |
|
|
|
function() return background end, |
|
|
|
function(val) background = val end) |
|
|
|
self.getset("foreground", |
|
|
|
function() return foreground end, |
|
|
|
function(val) foreground = val end) |
|
|
|
|
|
|
|
self.getset("top", |
|
|
|
function() return calcSize(top, parent.height, self.height, 0) end, |
|
|
|
function(val) top = parseSize(val) end) |
|
|
|
self.getset("bottom", |
|
|
|
function() return calcSize(bottom, parent.height, self.height, 0) end, |
|
|
|
function(val) bottom = parseSize(val) end) |
|
|
|
self.getset("left", |
|
|
|
function() return calcSize(left, parent.width, self.width, 0) end, |
|
|
|
function(val) left = parseSize(val) end) |
|
|
|
self.getset("right", |
|
|
|
function() return calcSize(right, parent.width, self.width, 0) end, |
|
|
|
function(val) right = parseSize(val) end) |
|
|
|
|
|
|
|
self.getset("x", |
|
|
|
function() return x end, |
|
|
|
function(val) x = val end) |
|
|
|
self.getset("y", |
|
|
|
function() return y end, |
|
|
|
function(val) y = val end) |
|
|
|
|
|
|
|
self.focus = function() |
|
|
|
focused = true |
|
|
|
self.emit("focus", self) |
|
|
|
end |
|
|
|
self.unfocus = function() |
|
|
|
focused = false |
|
|
|
self.emit("unfocus", self) |
|
|
|
end |
|
|
|
|
|
|
|
self.onclick = function(x, y) |
|
|
|
for key, child in pairs(self.children()) do |
|
|
|
local cx = child.x() |
|
|
|
local cy = child.y() |
|
|
|
local cw = child.width() |
|
|
|
local ch = child.height() |
|
|
|
|
|
|
|
if x >= cx and x < cx + cw |
|
|
|
and y >= cy and y < cy + ch then |
|
|
|
child.onclick(x, y) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.onchar = function(char) end |
|
|
|
self.onkey = function(key) end |
|
|
|
|
|
|
|
self.setColors = function(screen) |
|
|
|
screen.setTextColor(colors[foreground]) |
|
|
|
screen.setBackgroundColor(colors[background]) |
|
|
|
|
|
|
|
local w = self.width() |
|
|
|
local h = self.height() |
|
|
|
|
|
|
|
local str = "" |
|
|
|
for i = 1, w do |
|
|
|
str = str .. " " |
|
|
|
end |
|
|
|
|
|
|
|
local x = self.x() |
|
|
|
local y = self.y() |
|
|
|
for i = 1, h do |
|
|
|
screen.setCursorPos(x, y + i - 1) |
|
|
|
screen.write(str) |
|
|
|
end |
|
|
|
screen.setCursorPos(x, y) |
|
|
|
end |
|
|
|
|
|
|
|
self.addChild = function(widget) |
|
|
|
if widget.parent() ~= nil then |
|
|
|
error("Widget already has a parent") |
|
|
|
return |
|
|
|
end |
|
|
|
table.insert(children, widget) |
|
|
|
widget._parent(self) |
|
|
|
widget.prog(prog) |
|
|
|
|
|
|
|
widget.on("mustreflow", function() |
|
|
|
self.emit("mustreflow") |
|
|
|
end) |
|
|
|
|
|
|
|
widget.on("mustredraw", function(elem) |
|
|
|
self.emit("mustredraw", elem) |
|
|
|
end) |
|
|
|
|
|
|
|
widget.on("focus", function(elem) |
|
|
|
self.emit("focus", elem) |
|
|
|
end) |
|
|
|
|
|
|
|
widget.on("unfocus", function(elem) |
|
|
|
self.emit("unfocus", elem) |
|
|
|
end) |
|
|
|
|
|
|
|
self.emit("mustreflow") |
|
|
|
end |
|
|
|
|
|
|
|
self.removeChild = function(child) |
|
|
|
local removed = false |
|
|
|
for key, val in pairs(children) do |
|
|
|
if val == child then |
|
|
|
removed = true |
|
|
|
child.unfocus() |
|
|
|
table.remove(children, key) |
|
|
|
end |
|
|
|
end |
|
|
|
if removed then |
|
|
|
self.emit("mustreflow") |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.reflow = util.abstract |
|
|
|
|
|
|
|
self.draw = util.abstract |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function LinearLayout() |
|
|
|
local self = Widget() |
|
|
|
|
|
|
|
local orientation = "vertical" |
|
|
|
local reversed = false |
|
|
|
|
|
|
|
self.getset("orientation", |
|
|
|
function() return orientation end, |
|
|
|
function(val) orientation = val end) |
|
|
|
self.getset("reversed", |
|
|
|
function() return reversed end, |
|
|
|
function(val) reversed = val end) |
|
|
|
|
|
|
|
self.draw = function(screen) |
|
|
|
self.setColors(screen) |
|
|
|
for key, child in pairs(self.children()) do |
|
|
|
child.draw(screen) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.reflow = function(screen, x, y) |
|
|
|
self.x(x) |
|
|
|
self.y(y) |
|
|
|
|
|
|
|
local selfw = self.width() |
|
|
|
local selfh = self.height() |
|
|
|
local offset = 0 |
|
|
|
for key, child in pairs(self.children()) do |
|
|
|
local cx = x |
|
|
|
local cy = y |
|
|
|
local height = child.height() |
|
|
|
local width = child.width() |
|
|
|
local top = child.top() |
|
|
|
local bottom = child.bottom() |
|
|
|
local left = child.left() |
|
|
|
local right = child.right() |
|
|
|
|
|
|
|
if right ~= nil then |
|
|
|
cx = cx + |
|
|
|
selfw - |
|
|
|
width - |
|
|
|
right + 1 |
|
|
|
else |
|
|
|
cx = cx + top - 1 |
|
|
|
end |
|
|
|
if bottom ~= nil then |
|
|
|
cy = cy + |
|
|
|
selfh - |
|
|
|
height - |
|
|
|
bottom + 1 |
|
|
|
else |
|
|
|
cy = cy + top - 1 |
|
|
|
end |
|
|
|
|
|
|
|
if orientation == "vertical" then |
|
|
|
cy = y + offset + top - 1 |
|
|
|
offset = offset + |
|
|
|
top - 1 + |
|
|
|
height + |
|
|
|
(bottom or 1) - 1 |
|
|
|
|
|
|
|
if reversed then |
|
|
|
cy = selfh - cy - height + 2 |
|
|
|
end |
|
|
|
elseif orientation == "horizontal" then |
|
|
|
cx = x + offset + left - 1 |
|
|
|
offset = offset + |
|
|
|
left - 1 + |
|
|
|
width + |
|
|
|
(right or 1) - 1 |
|
|
|
|
|
|
|
if reversed then |
|
|
|
cx = selfw - cx - width + 2 |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
child.reflow(screen, cx, cy) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function FloatingLayout() |
|
|
|
local self = Widget() |
|
|
|
|
|
|
|
self.draw = function(screen) |
|
|
|
self.setColors(screen) |
|
|
|
for key, child in pairs(self.children()) do |
|
|
|
child.draw(screen) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.reflow = function(screen, x, y) |
|
|
|
self.x(x) |
|
|
|
self.y(y) |
|
|
|
|
|
|
|
for key, child in pairs(self.children()) do |
|
|
|
local cx = x |
|
|
|
local cy = y |
|
|
|
if child.right() ~= nil then |
|
|
|
cx = cx + |
|
|
|
self.width() - |
|
|
|
child.width() - |
|
|
|
child.right() + 1 |
|
|
|
else |
|
|
|
cx = cx + child.left() - 1 |
|
|
|
end |
|
|
|
if child.bottom() ~= nil then |
|
|
|
cy = cy + |
|
|
|
self.height() - |
|
|
|
child.height() - |
|
|
|
child.bottom() + 1 |
|
|
|
else |
|
|
|
cy = cy + child.top() - 1 |
|
|
|
end |
|
|
|
|
|
|
|
child.reflow(screen, cx, cy) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.autoWidth = function() |
|
|
|
return self.parent().width() |
|
|
|
end |
|
|
|
self.autoHeight = function() |
|
|
|
return self.parent().height() |
|
|
|
end |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function TextView() |
|
|
|
local self = Widget() |
|
|
|
|
|
|
|
local text = "" |
|
|
|
|
|
|
|
self.getset("text", |
|
|
|
function() return text end, |
|
|
|
function(val) |
|
|
|
local pre = text |
|
|
|
text = tostring(val) |
|
|
|
if #pre == #text then |
|
|
|
self.emit("mustredraw", self) |
|
|
|
else |
|
|
|
self.emit("mustreflow") |
|
|
|
end |
|
|
|
end) |
|
|
|
|
|
|
|
self.reflow = function(screen, x, y) |
|
|
|
self.x(x) |
|
|
|
self.y(y) |
|
|
|
end |
|
|
|
|
|
|
|
self.draw = function(screen) |
|
|
|
self.setColors(screen) |
|
|
|
|
|
|
|
screen.setCursorPos(self.x(), self.y()) |
|
|
|
local w = self.width() |
|
|
|
local h = self.height() |
|
|
|
|
|
|
|
local offy = math.floor(h / 2) |
|
|
|
local offx = math.floor(w - #text - ((w - #text) / 2)) |
|
|
|
screen.setCursorPos(self.x() + offx, self.y() + offy) |
|
|
|
screen.write(text) |
|
|
|
end |
|
|
|
|
|
|
|
self.autoWidth = function() |
|
|
|
return #text |
|
|
|
end |
|
|
|
self.autoHeight = function() |
|
|
|
return 1 |
|
|
|
end |
|
|
|
|
|
|
|
self.onclick = function(x, y) |
|
|
|
-- TextViews don't have any interesting onclick actions |
|
|
|
end |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function TextInput() |
|
|
|
local self = Widget() |
|
|
|
|
|
|
|
local backgroundInactive = "blue" |
|
|
|
local backgroundActive = "red" |
|
|
|
local foregroundInactive = "white" |
|
|
|
local foregroundActive = "white" |
|
|
|
|
|
|
|
local key_backspace = 14 |
|
|
|
local key_left = 203 |
|
|
|
local key_right = 205 |
|
|
|
local key_delete = 211 |
|
|
|
|
|
|
|
local text = "" |
|
|
|
local cursor = 0 |
|
|
|
|
|
|
|
self.getset("text", |
|
|
|
function() return text end, |
|
|
|
function(val) |
|
|
|
local pre = text |
|
|
|
text = tostring(val) |
|
|
|
if #pre == #text then |
|
|
|
self.emit("mustredraw", self) |
|
|
|
else |
|
|
|
self.emit("mustreflow") |
|
|
|
end |
|
|
|
end) |
|
|
|
|
|
|
|
self.getset("backgroundInactive", |
|
|
|
function() return backgroundInactive end, |
|
|
|
function(val) backgroundInactive = val end) |
|
|
|
self.getset("backgroundActive", |
|
|
|
function() return backgroundActive end, |
|
|
|
function(val) backgroundActive = val end) |
|
|
|
self.getset("foregroundInactive", |
|
|
|
function() return foregroundInactive end, |
|
|
|
function(val) foregroundInactive = val end) |
|
|
|
self.getset("foregroundActive", |
|
|
|
function() return foregroundActive end, |
|
|
|
function(val) foregroundActive = val end) |
|
|
|
|
|
|
|
self.reflow = function(screen, x, y) |
|
|
|
self.x(x) |
|
|
|
self.y(y) |
|
|
|
end |
|
|
|
|
|
|
|
self.draw = function(screen) |
|
|
|
if self.focused() then |
|
|
|
self.background(backgroundActive) |
|
|
|
self.foreground(foregroundActive) |
|
|
|
else |
|
|
|
self.background(backgroundInactive) |
|
|
|
self.foreground(foregroundInactive) |
|
|
|
end |
|
|
|
|
|
|
|
self.setColors(screen) |
|
|
|
|
|
|
|
screen.setCursorPos(self.x(), self.y()) |
|
|
|
screen.write("|") |
|
|
|
screen.setCursorPos(self.x() + self.width() - 1, self.y()) |
|
|
|
screen.write("|") |
|
|
|
|
|
|
|
local len = self.width() - 2 |
|
|
|
screen.setCursorPos(self.x() + 1, self.y()) |
|
|
|
screen.write(string.sub(text, 1, len)) |
|
|
|
|
|
|
|
if self.focused() then |
|
|
|
screen.setCursorPos(self.x() + 1 + cursor, self.y()) |
|
|
|
screen.setBackgroundColor(colors.white) |
|
|
|
screen.write(" ") |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.autoWidth = function() |
|
|
|
return #text + 2 |
|
|
|
end |
|
|
|
self.autoHeight = function() |
|
|
|
return 1 |
|
|
|
end |
|
|
|
|
|
|
|
self.onclick = function(x, y) |
|
|
|
local w = self.width() |
|
|
|
if x == self.x() or x == w then |
|
|
|
cursor = #text |
|
|
|
else |
|
|
|
cursor = math.min(x - self.x() - 1, #text) |
|
|
|
end |
|
|
|
self.focus() |
|
|
|
end |
|
|
|
|
|
|
|
self.onchar = function(char) |
|
|
|
local pre = string.sub(text, 1, cursor) |
|
|
|
local post = string.sub(text, cursor + 1, #text) |
|
|
|
text = pre .. char .. post |
|
|
|
cursor = cursor + 1 |
|
|
|
self.emit("mustreflow") |
|
|
|
end |
|
|
|
|
|
|
|
self.onkey = function(key) |
|
|
|
if key == key_backspace then |
|
|
|
local pre = string.sub(text, 1, cursor - 1) |
|
|
|
local post = string.sub(text, cursor + 1, #text) |
|
|
|
text = pre .. post |
|
|
|
if cursor > 0 then |
|
|
|
cursor = cursor - 1 |
|
|
|
end |
|
|
|
self.emit("mustreflow") |
|
|
|
elseif key == key_delete then |
|
|
|
local pre = string.sub(text, 1, cursor) |
|
|
|
local post = string.sub(text, cursor + 2, #text) |
|
|
|
text = pre .. post |
|
|
|
self.emit("mustreflow") |
|
|
|
elseif key == key_left then |
|
|
|
if cursor > 0 then |
|
|
|
cursor = cursor - 1 |
|
|
|
end |
|
|
|
self.emit("mustredraw", self) |
|
|
|
elseif key == key_right then |
|
|
|
if cursor < #text then |
|
|
|
cursor = cursor + 1 |
|
|
|
end |
|
|
|
self.emit("mustredraw", self) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
self.on("focus", function() self.emit("mustredraw", self) end) |
|
|
|
self.on("unfocus", function() self.emit("mustredraw", self) end) |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function Button() |
|
|
|
local self = TextView() |
|
|
|
|
|
|
|
local backgroundInactive = "blue" |
|
|
|
local backgroundActive = "red" |
|
|
|
local foregroundInactive = "white" |
|
|
|
local foregroundActive = "white" |
|
|
|
|
|
|
|
self.getset("backgroundInactive", |
|
|
|
function() return backgroundInactive end, |
|
|
|
function(val) backgroundInactive = val end) |
|
|
|
self.getset("backgroundActive", |
|
|
|
function() return backgroundActive end, |
|
|
|
function(val) backgroundActive = val end) |
|
|
|
self.getset("foregroundInactive", |
|
|
|
function() return foregroundInactive end, |
|
|
|
function(val) foregroundInactive = val end) |
|
|
|
self.getset("foregroundActive", |
|
|
|
function() return foregroundActive end, |
|
|
|
function(val) foregroundActive = val end) |
|
|
|
|
|
|
|
self.background(backgroundInactive) |
|
|
|
self.foreground(foregroundInactive) |
|
|
|
|
|
|
|
local resetTimeout |
|
|
|
|
|
|
|
self.onclick = function(x, y) |
|
|
|
if resetTimeout ~= nil then |
|
|
|
self.prog().cancelTimeout(resetTimeout) |
|
|
|
end |
|
|
|
self.background(backgroundActive) |
|
|
|
self.foreground(foregroundActive) |
|
|
|
self.emit("mustredraw", self) |
|
|
|
|
|
|
|
self.emit("focus", self) |
|
|
|
self.emit("click") |
|
|
|
|
|
|
|
resetTimeout = self.prog().setTimeout(0.3, function() |
|
|
|
self.background(backgroundInactive) |
|
|
|
self.foreground(foregroundInactive) |
|
|
|
self.emit("mustredraw", self) |
|
|
|
end) |
|
|
|
end |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function DummyScreen() |
|
|
|
local self = {} |
|
|
|
|
|
|
|
self.getSize = function() |
|
|
|
return term.getSize() |
|
|
|
end |
|
|
|
self.clear = function() end |
|
|
|
self.write = function() end |
|
|
|
self.setCursorPos = function() end |
|
|
|
self.setTextColor = function() end |
|
|
|
self.setBackgroundColor = function() end |
|
|
|
|
|
|
|
return self |
|
|
|
end |
|
|
|
|
|
|
|
function Gui(prog, screen) |
|
|
|
local self = util.newObject() |
|
|
|
|
|
|
|
if screen == nil then |
|
|
|
screen = term |
|
|
|
end |
|
|
|
|
|
|
|
local focusedWidget = nil |
|
|
|
local rootWidget = nil |
|
|
|
|
|
|
|
self.getset("width", |
|
|
|
function() |
|
|
|
local x, y = screen.getSize() |
|
|
|
return x |
|
|
|
end) |
|
|
|
self.getset("height", |
|
|
|
function() |
|
|
|
local x, y = screen.getSize(); |
|
|
|
return y |
|
|
|
end) |
|
|
|
|
|
|
|
self.getset("screen", |
|
|
|
function() return screen end, |
|
|
|
function(val) screen = val end) |
|
|
|
|
|
|
|
self.getset("focused", |
|
|
|
function() return focusedWidget end) |
|
|
|
|
|
|
|
-- Handle focusing and unfocusing of widgets |
|
|
|
local function onRootChildFocus(widget) |
|
|
|
if focusedWidget ~= nil then |
|
|
|
focusedWidget.unfocus() |
|
|
|
end |
|
|
|
focusedWidget = widget |
|
|
|
end |
|
|
|
|
|
|
|
local function onRootChildUnfocus(widget) |
|
|
|
if widget == focusedWidget then |
|
|
|
focusedWidget = nil |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
local function onRootChildRedraw(widget) |
|
|
|
widget.draw(screen) |
|
|
|
end |
|
|
|
|
|
|
|
self.setRoot = function(root) |
|
|
|
if rootWidget ~= nil then |
|
|
|
rootWidget.removeListener("focus", onRootChildFocus) |
|
|
|
rootWidget.removeListener("unfocus", onRootChildUnfocus) |
|
|
|
rootWidget.removeListener("mustreflow", self.reflow) |
|
|
|
rootWidget.removeListener("mustredraw", onRootChildRedraw) |
|
|
|
end |
|
|
|
rootWidget = root |
|
|
|
root._parent(self) |
|
|
|
root.on("focus", onRootChildFocus) |
|
|
|
root.on("unfocus", onRootChildUnfocus) |
|
|
|
root.on("mustreflow", self.reflow) |
|
|
|
root.on("mustredraw", onRootChildRedraw) |
|
|
|
root.prog(prog) |
|
|
|
end |
|
|
|
|
|
|
|
self.reflow = function() |
|
|
|
if rootWidget == nil then |
|
|
|
return |
|
|
|
end |
|
|
|
screen.clear() |
|
|
|
screen.setCursorPos(1, 1) |
|
|
|
rootWidget.reflow(screen, 1, 1) |
|
|
|
rootWidget.draw(screen) |
|
|
|
end |
|
|
|
|
|
|
|
self.exit = function() |
|
|
|
prog.exit() |
|
|
|
end |
|
|
|
|
|
|
|
prog.on("init", self.draw) |
|
|
|
|
|
|
|
prog.on("exit", function() |
|
|
|
screen.setTextColor(colors.white) |
|
|
|
screen.setBackgroundColor(colors.black) |
|
|
|
screen.clear() |
|
|
|
screen.setCursorPos(1, 1) |
|
|
|
end) |
|
|
|
|
|
|
|
prog.on("mouse_click", function(button, x, y) |
|
|
|
if focusedWidget ~= nil then |
|
|
|
focusedWidget.unfocus() |
|
|
|
end |
|
|
|
if rootWidget ~= nil then |
|
|
|
rootWidget.onclick(x, y) |
|
|
|
end |
|
|
|
end) |
|
|
|
prog.on("char", function(char) |
|
|
|
if focusedWidget ~= nil then |
|
|
|
focusedWidget.onchar(char) |
|
|
|
end |
|
|
|
end) |
|
|
|
prog.on("key", function(key) |
|
|
|
if focusedWidget ~= nil then |
|
|
|
focusedWidget.onkey(key) |
|
|
|
end |
|
|
|
end) |
|
|
|
|
|
|
|
return self |
|
|
|
end |