225 lines
5.5 KiB
Lua
225 lines
5.5 KiB
Lua
--
|
|
-- Event-driven GUI library
|
|
--
|
|
--
|
|
|
|
gui = {
|
|
|
|
--
|
|
-- colors
|
|
--
|
|
black = 0,
|
|
dark = 1,
|
|
light = 2,
|
|
white = 3,
|
|
|
|
-- "do nothing" function. Used as default callback
|
|
donothing = function(self)
|
|
end,
|
|
|
|
-- Metatable that hides the field "value" behind a property,
|
|
-- and calls render() after it's set.
|
|
propvalue = {
|
|
__newindex = function(self, index, value)
|
|
if index == "value" then
|
|
self._value = value
|
|
-- extra processing
|
|
self:render()
|
|
else
|
|
rawset(self, index, value)
|
|
end
|
|
end,
|
|
__index = function(self, index )
|
|
if index == "value" then
|
|
return self._value
|
|
else
|
|
return rawget( self, index )
|
|
end
|
|
end
|
|
},
|
|
|
|
--
|
|
-- dialog()
|
|
--
|
|
dialog = function(args)
|
|
local dia = {
|
|
title = args.title,
|
|
w = args.w,
|
|
h = args.h,
|
|
--
|
|
widgets = {},
|
|
-- an indexed array, starting at 1. Used for calling the relevant
|
|
-- callback when a numbered control is clicked.
|
|
callbacks = {},
|
|
|
|
--
|
|
-- dialog.run() --
|
|
--
|
|
run = function(self)
|
|
windowopen(self.w,self.h, self.title or "");
|
|
-- examine all elements
|
|
for _,widget in ipairs(self.widgets) do
|
|
widget:create()
|
|
end
|
|
|
|
repeat
|
|
local button, button2, key = windowdodialog();
|
|
|
|
if button > 0 then
|
|
local c = self.callbacks[button]
|
|
if c ~= nil then
|
|
-- run the callback
|
|
local retvalue = c:click()
|
|
-- stop the form if it returns non-nil
|
|
if retvalue ~= nil then
|
|
windowclose();
|
|
return retvalue;
|
|
end
|
|
end
|
|
end
|
|
until key == 27;
|
|
windowclose();
|
|
end
|
|
}
|
|
local id = 1;
|
|
-- examine all elements
|
|
for _,value in ipairs(args) do
|
|
-- all arguments that are tables are assumed to be widgets
|
|
if type(value)=="table" then
|
|
table.insert(dia.widgets, value)
|
|
-- clickable widgets take up an auto-numbered id
|
|
if (value.click) then
|
|
dia.callbacks[id] = value
|
|
id=id+1
|
|
end
|
|
end
|
|
end
|
|
return dia;
|
|
end,
|
|
|
|
--
|
|
-- button()
|
|
--
|
|
button = function(args)
|
|
local but = {
|
|
x = args.x,
|
|
y = args.y,
|
|
w = args.w,
|
|
h = args.h,
|
|
key = args.key,
|
|
label = args.label,
|
|
click = args.click or gui.donothing,
|
|
create = args.repeatable and function(self)
|
|
windowrepeatbutton(self.x, self.y, self.w, self.h, self.label, self.key or -1);
|
|
end
|
|
or function(self)
|
|
windowbutton(self.x, self.y, self.w, self.h, self.label, self.key or -1);
|
|
end
|
|
}
|
|
return but;
|
|
end,
|
|
|
|
--
|
|
-- label()
|
|
--
|
|
label = function(args)
|
|
local lbl = {
|
|
x = args.x,
|
|
y = args.y,
|
|
_value = args.value,
|
|
format = args.format,
|
|
fg = args.fg or gui.black,
|
|
bg = args.bg or gui.light,
|
|
render = function(self)
|
|
if type(self.format) then
|
|
windowprint(self.x, self.y, string.format(self.format, self._value), self.fg, self.bg);
|
|
else
|
|
windowprint(self.x, self.y, self._value, self.fg, self.bg);
|
|
end
|
|
end,
|
|
}
|
|
lbl.create = lbl.render
|
|
setmetatable(lbl, gui.propvalue)
|
|
return lbl;
|
|
end,
|
|
|
|
--
|
|
-- textbox
|
|
--
|
|
textbox = function(args)
|
|
local txtbox = {
|
|
x = args.x,
|
|
y = args.y,
|
|
nbchar = args.nbchar, -- visible size in characters
|
|
--format = args.format, -- numeric, decimal, path
|
|
decimal = args.decimal or 0,
|
|
min = args.min,
|
|
max = args.max,
|
|
maxchar = args.maxchar, -- internal size
|
|
_value = args.value,
|
|
change = args.change or gui.donothing,
|
|
--fg = args.fg or gui.black,
|
|
--bg = args.bg or gui.light,
|
|
create = function(self)
|
|
windowinput(self.x, self.y, self.nbchar)
|
|
self:render()
|
|
end,
|
|
render = function(self)
|
|
local val = tostring(self._value)
|
|
if string.len(val) < self.nbchar then
|
|
val = string.rep(" ",self.nbchar - string.len(val)) .. val;
|
|
elseif string.len(val) > self.nbchar then
|
|
val = string.sub(val, 1, self.nbchar-1) .. gui.char.ellipsis
|
|
end
|
|
windowprint(self.x, self.y, val, gui.black, gui.light);
|
|
end,
|
|
click = function(self)
|
|
local inputtype
|
|
if (type(self._value) == "number" and ((self.min ~= nil and self.min<0) or self.decimal > 0)) then
|
|
inputtype = 3 -- entry as double
|
|
elseif (type(self._value) == "number") then
|
|
inputtype = 1 -- entry as unsigned int
|
|
else
|
|
inputtype = 0 -- entry as string
|
|
end
|
|
local accept, val = windowreadline(self.x, self.y, self._value, self.nbchar, self.maxchar, self.decimal, inputtype);
|
|
|
|
if accept then
|
|
if (inputtype == 1 or inputtype == 3) then
|
|
val = tonumber(val)
|
|
-- round the decimal places
|
|
val = gui.round(val, self.decimal)
|
|
end
|
|
if (self.min ~= nil and val < self.min) then
|
|
val = self.min
|
|
end
|
|
if (self.max ~= nil and val > self.max) then
|
|
val = self.max
|
|
end
|
|
|
|
self._value = val
|
|
end
|
|
self:render()
|
|
end
|
|
}
|
|
setmetatable(txtbox, gui.propvalue)
|
|
return txtbox;
|
|
end
|
|
|
|
}
|
|
|
|
gui.round = function(val, ipt)
|
|
local mult = 10^ipt
|
|
return math.floor(val * mult + 0.5) / mult
|
|
end
|
|
|
|
-- Character constants. May be useful in screens
|
|
gui.char = {
|
|
ellipsis = string.char(133), -- ...
|
|
arrowup = string.char(24),
|
|
arrowdown = string.char(25),
|
|
arrowleft = string.char(27),
|
|
arrowright = string.char(26),
|
|
vertical = string.char(18), -- double-ended arrow
|
|
horizontal = string.char(29) -- double-ended arrow
|
|
} |