Posted 12 May 2014 - 01:01 AM
I've recently been trying to create my own custom button api, I know there are others available but I want the experience of creating one myself.
due to quite an unavoidable situation of complicated data structures, I decided to use the privacy approach for my objects, their values and methods. An example can be found here.
This example works inside computercraft, the problem i'm having is that if I store the function newAccount in an api, and load that api, if I try to make reference to that function then I get an error 'test:21: attempt to index? (a nil value)'
The same goes for my button api.
and this is my script that runs in a test file:
Any help would be appreciated :)/>
due to quite an unavoidable situation of complicated data structures, I decided to use the privacy approach for my objects, their values and methods. An example can be found here.
Spoiler
function newAccount (initialBalance)
local self = {balance = initialBalance}
local withdraw = function (v)
self.balance = self.balance - v
end
local deposit = function (v)
self.balance = self.balance + v
end
local getBalance = function () return self.balance end
return {
withdraw = withdraw,
deposit = deposit,
getBalance = getBalance
}
end
acc1 = newAccount(100.00)
acc1.withdraw(40.00)
print(acc1.getBalance()) --> 60
This example works inside computercraft, the problem i'm having is that if I store the function newAccount in an api, and load that api, if I try to make reference to that function then I get an error 'test:21: attempt to index? (a nil value)'
The same goes for my button api.
Spoiler
function aType(n) -- extends type() to include integer's and float's as data types.
if type(n) == 'number' then
if n == math.floor(n) then
return 'integer'
else
return 'float'
end
else
return type(n)
end
end
local function split(s, sep)
sep = sep or "%s"
words = {}
pattern = string.format("[^%s]+", sep)
for word in string.gmatch(tostring(s), pattern) do
table.insert(words, word)
end
return words
end
local buttonTemplate = {
parent = term.native(),
args = {},
width = 10,
height = 5,
textColor = colors.white,
backgroundColorOn = colors.green,
backgroundColorOff = colors.red,
active = false,
visible = true,
align = 'centre',
}
local alignment = {
'left' = true,
'right' = true
'centre' = true,
}
function newButton()
local self = {}
local add = function(o)
local o = o or {}
setmetatable(o, {__index = buttonTemplate})
if aType(o.width) ~= 'integer' then error('[\"width\"] expected integer, got ' .. aType(o.width)) end
if aType(o.height) ~= 'integer' then error('[\"height\"] expected integer, got ' .. aType(o.height)) end
if aType(o.textColor) ~= 'integer' then error('[\"textColor\"] expected integer, got '.. aType(o.textColor)) end
if aType(o.backgroundColorOn) ~= 'integer' then error('[\"backgroundColorOn\"] expected integer, got ' .. aType(o.width)) end
if aType(o.backgroundColorOff) ~= 'integer' then error('[\"backgroundColorOff\"] expected integer, got ' .. aType(o.height)) end
if type(o.active) ~= 'boolean' then error('[\"active\"] expected boolean, got ' .. type(o.active)) end
if type(o.visible) ~= 'boolean' then error('[\"visible\"] expected boolean, got ' .. type(o.active)) end
if type(o.align) ~= 'string' then error('[\"align\"] expected string, got ' .. type(o.align)) end
if type(o.label) ~= 'string' then error('[\"label\"] expected string, got ' .. type(o.align)) end
if type(o.args) ~= 'table' then error('[\"args\"] expected table, got ' .. type(o.args)) end
if type(o.parent) ~= 'table' then error('[\"parent\"] expected table, got ' .. type(o.args)) end
if type(o.func) ~= 'function' then error('[\"args\"] expected function, got ' .. type(o.args)) end
if not alignment[o.align] then error('[\"align\"] expected \"left\", \"right\" or \"centre\", got '.. o.align) end
o.backgroundColor = backgroundColorOff
o.window = window.create(o.parent, o.x, o.y, o.width, o.height)
self[o.label] = o
draw(o.label)
end
local getActive = function(label)
return self[label].active
end
local toggleButton = function(label)
self[label].active = not self[label].active
if self[label].active then
self.[label].backgroundColor = self[label].backgroundColorOn
else
self[label].backgroundColor = self[label].backgroundColorOff
end
self.draw(label)
end
local flashButton = function(label, time)
time = time or 0.1
self.toggleButton(label)
sleep(time)
self.:toggleButton(label)
end
local draw = function(label)
self[label].window.setBackgroundColor(self[label].backgroundColor)
self[label].window.clear()
self.writeText(label)
end
local handleButtonPress = function(x, y)
for _, button in pairs(self) do
if (y >= button.y) and
(y <= (button.y + button.height -1)) and
(x >= button.x) and
(x <= (button.width + button.x -1)) then
button.func(unpack(button.args))
return true
end
end
return false
end
local writeText = function(label)
local x, y
local w, h = self[label].width, self[label].height
local lines = split(string.gsub(label, ' \n'))
if (#lines > h) then
error('[\"label\"] the number of text lines exceed the height of the button')
end
for y, string in pairs(lines) do
if (string.len(string) - w) > w then
error('[\"label\"] text line length longer than button width')
end
if self[label].align == "left" then
x = 1
elseif self[label].align == "centre" then
x = math.floor(w / 2) - math.floor(string.len(string) / 2)
elseif self[label].align == "right" then
x = w - string.len(string) + 1
end
self[label].window.setCursorPos(x, y)
self[label].window.write(string)
end
end
local drawButtons = function ()
for _, button in self do
button.draw(button.label)
end
end
return {
add = add,
getActive = getActive,
toggleButton = toggleButton,
flashButton = flashButton,
drawButtons = drawButtons,
handleButtonPress = handleButtonPress
}
end
and this is my script that runs in a test file:
os.loadAPI("buttongui")
local function getPeripheralsByType(p)
local TabDetected = {}
for _, v in ipairs(peripheral.getNames()) do
if peripheral.getType(v) == p then
table.insert(TabDetected, v)
end
end
return TabDetected
end
for _, v in ipairs(getPeripheralsByType('modem')) do
if peripheral.wrap(v).isWireless() then
rednet.open(v)
end
end
term.clear()
a1 = buttongui.newButton()
Any help would be appreciated :)/>
Edited on 13 May 2014 - 03:23 PM