This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Creator's profile picture

GUI API Interact spitting out nil values where it should not.

Started by Creator, 15 March 2015 - 03:12 PM
Creator #1
Posted 15 March 2015 - 04:12 PM
Hi guys,

I am writing my owm GUI API and there is a problem I can't solve. When run this code:

Spoiler

--[[
Desktop in ComputerCraft
by Creator
for TheOS
]]--
--Variables--
local textutilsserialize = textutils.serialize
local textutilsunserialize = textutils.unserialize
local w,h = term.getSize()
local Settings = {}
local result = {}
local Main = {}
local QuickSettings = {}
--Functions--
local function readFile(_path)
local file = fs.open(_path,"r")
local data = file.readAll()
file.close()
return data
end
local function split(str,sep)
local buffer = {}
for token in str:gmatch(sep) do
  buffer[#buffer+1] = token
end
return buffer
end
--Loading settings--
local buffer = readFile("TheOS/Desktop/Settings")
Settings = textutils.unserialize( buffer )
--Object table--
Main.ButtonTable = {
quickSettings = {
  name = "quickSettings",
  label = "^",
  xPos = 1,
  yPos = h,
  xLength = 1,
  yLength = 1,
  xTextPos = 1,
  yTextPos = 1,
  fgColor = colors.white,
  bgColor = Settings.bgColor,
  returnValue = "quickSettings",
},
windowPlus = {
  name = "windowPlus",
  label = ">",
  xPos = w,
  yPos = 1,
  xLength = 1,
  yLength = 1,
  xTextPos = 1,
  yTextPos = 1,
  fgColor = colors.white,
  bgColor = Settings.bgColor,
  returnValue = "windowPlus",
},
windowMinus = {
  name = "windowMinus",
  label = "<",
  xPos = 1,
  yPos = 1,
  xLength = 1,
  yLength = 1,
  xTextPos = 1,
  yTextPos = 1,
  fgColor = colors.white,
  bgColor = Settings.bgColor,
  returnValue = "windowMinus",
},
}
QuickSettings.ButtonTable = {
Close = {
  name = "Close",
  label = "X",
  xPos = w,
  yPos = 1,
  xLength = 1,
  yLength = 1,
  xTextPos = 1,
  yTextPos = 1,
  fgColor = colors.black,
  bgColor = colors.white,
  returnValue = "Close",
},
Right = {
  name = "Right",
  label = ">",
  xPos = w-1,
  yPos = 4,
  xLength = 1,
  yLength = 3,
  xTextPos = 1,
  yTextPos = 2,
  fgColor = Settings.bgColor,
  bgColor = colors.white,
  returnValue = "Right",
},
Left = {
  name = "Left",
  label = "<",
  xPos = 2,
  yPos = 4,
  xLength = 1,
  yLength = 3,
  xTextPos = 1,
  yTextPos = 2,
  fgColor = Settings.bgColor,
  bgColor = colors.white,
  returnValue = "Left",
}
}
QuickSettings.ColorFieldTable = {
TopBar = {
  name = "TopBar",
  xPos = 1,
  yPos = 1,
  xLength = w,
  yLength = 1,
  color = colors.white,
}
}
QuickSettings.BetterPaint = {
Restart = {
  xPos = 4,
  yPos = 2,
  name = "Restart",
  path = "TheOS/Desktop/QuickSettings/restart.ico",
  yLength = 5,
  xLength = 7,
  returnValue = "reboot",
  label = "Restart",
  labelFg = colors.black,
  labelBg = colors.lightGray,
},
Shutdown = {
  xPos = 13,
  yPos = 2,
  name = "Shutdown",
  path = "TheOS/Desktop/QuickSettings/shutdown.ico",
  yLength = 5,
  xLength = 7,
  returnValue = "shutdown",
  label = "Shutdown",
  labelFg = colors.black,
  labelBg = colors.lightGray,
},
}
--Initializing GUI components
local gui = Interact.Initialize()
local mainLayout = gui.Layout.new({xPos = 1,yPos = 1,xLength = w,yLength = h})
local quickSettingsLayout = gui.Layout.new({xPos = 1,yPos = h-7,xLength = w,yLength = h, nilClick = true})
--Initializing Buttons--
--Main--
local mainLayoutTable = {}
mainLayoutTable.Button = {}
for i,v in pairs(Main.ButtonTable) do
mainLayoutTable.Button[i] = gui.Button.new(Main.ButtonTable[i])
end
mainLayoutTable.mainBgColor = gui.BackgroundColor.new({color = Settings.bgColor})
--QuickSettings--
local quickSettingsLayoutTable = {}
quickSettingsLayoutTable.Button = {}
for i,v in pairs(QuickSettings.ButtonTable) do
quickSettingsLayoutTable.Button[i] = gui.Button.new(QuickSettings.ButtonTable[i])
end
quickSettingsLayoutTable.quickSettingsBgColor = gui.BackgroundColor.new({color = colors.lightGray})
quickSettingsLayoutTable.TopBar = gui.ColorField.new(QuickSettings.ColorFieldTable.TopBar)
quickSettingsLayoutTable.Restart = gui.BetterPaint.new(QuickSettings.BetterPaint.Restart)
quickSettingsLayoutTable.Shutdown = gui.BetterPaint.new(QuickSettings.BetterPaint.Shutdown)
--Initializing structures--
--Main--
for i,v in pairs(mainLayoutTable.Button) do
mainLayout:addButton(mainLayoutTable.Button[i]:returnData())
end
mainLayout:addBackgroundColor(mainLayoutTable.mainBgColor:returnData())
--QuickSettings--
for i,v in pairs(quickSettingsLayoutTable.Button) do
quickSettingsLayout:addButton(quickSettingsLayoutTable.Button[i]:returnData())
end
quickSettingsLayout:addBackgroundColor(quickSettingsLayoutTable.quickSettingsBgColor:returnData())
quickSettingsLayout:addColorField(quickSettingsLayoutTable.TopBar:returnData())
quickSettingsLayout:addBetterPaint(quickSettingsLayoutTable.Restart)
quickSettingsLayout:addBetterPaint(quickSettingsLayoutTable.Shutdown)
function writeTable()
file = fs.open("TheOS/Desktop/Settings","w")
file.write(textutilsserialize({
  bgColor = colors.blue,
}))
file.close()
end
--writeTable()
--[[term.setCursorPos(1,1)
term.clear()
for i,v in pairs(quickSettingsLayout) do
print(i)
end
os.pullEvent()]]--
--Code--
while true do
mainLayout:draw()
local result = gui.eventHandler(mainLayout)
if result[1] == "Button" then
  if result[2] == "quickSettings" then
   quickSettingsLayout:draw()
   local answer = gui.eventHandler(quickSettingsLayout)
   if answer[1] == "Button" then
	if answer[2] == "reboot" then
	 os.reboot()
	elseif answer[2] == "shutdown" then
	 os.shutdown()
	end
   end
  end
end
end

It throws this error:


Interact:330: attempt to perform arithmetic __add on nil and number

The API is here:

Spoiler

--[[
Interact API in ComputerCraft
by Creator
Complete rewrite in OOP
]]--

local textutilsserialize = textutils.serialize
local textutilsunserialize = textutils.unserialize
--Class declarations--
local Button = {}
local Layout = {}
local Toggle = {}
local BackgroundColor = {}
local ColorField = {}
local BetterPaint = {}
--Class Layout--
--Layout initialization function--
Layout.new = function(input)
local self = {}
setmetatable(self,{__index = Layout})
self.Button = {}
self.Toggle = {}
self.ColorField = {}
self.BetterPaint = {}
self.BackgroundColor = 1
self.xPos = input.xPos or 1
self.yPos = input.yPos or 1
self.xMax = input.xMax or 51
self.yMax = input.yMax or 19
self.nilClick = input.nilClick or false
return self
end
--Add element function--
Layout.addButton = function(self,_elementData)
self.Button[_elementData.name] = _elementData
end
Layout.addToggle = function(self,_elementData)
self.Toggle[_elementData.name] = _elementData
end
Layout.addBackgroundColor = function(self,_elementData)
self.BackgroundColor = _elementData.color
end
Layout.addColorField = function(self,_elementData)
self.ColorField[_elementData.name] = _elementData
end
Layout.addBetterPaint = function(self,_elementData)
self.BetterPaint[_elementData.name] = _elementData
end
Layout.draw = function(self)
local buttonFunctions = {}
local toggleFunctions = {}
local colorFieldFunctions = {}
local betterPaintFunctions = {}
setmetatable(buttonFunctions,{__index = Button})
setmetatable(toggleFunctions,{__index = Toggle})
setmetatable(colorFieldFunctions,{__index = ColorField})
setmetatable(betterPaintFunctions,{__index = BetterPaint})
paintutils.drawFilledBox(self.xPos,self.yPos,self.xMax,self.yMax,self.BackgroundColor)
for i,v in pairs(self.ColorField) do
  colorFieldFunctions.draw(v,self.xPos,self.yPos)
end
for i,v in pairs(self.Button) do
  buttonFunctions.draw(v,self.xPos,self.yPos)
end
for i,v in pairs(self.BetterPaint) do
  betterPaintFunctions.draw(v,self.xPos,self.yPos)
end
for i,v in pairs(self.Toggle) do
  toggleFunctions.draw(v,self.xPos,self.yPos)
end
end
--Class Button--
--Button initialization function
Button.new = function(input)
local self = {}
setmetatable(self,{__index = Button})
self.name = input.name
self.label = input.label
self.xPos = input.xPos
self.yPos = input.yPos
self.fgColor = input.fgColor
self.bgColor = input.bgColor
self.xLength = input.xLength
self.yLength = input.yLength
self.returnValue = input.returnValue
self.xTextPos = input.xTextPos
self.yTextPos = input.yTextPos
return self
end
--Draw function
Button.draw = function(self,layoutX,layoutY,addX,addY)
layoutX = layoutX or 0
layoutY = layoutY or 0
if self.moveX then
  addX = addX or 0
else
  addX = 0
end
if self.moveY then
  addY = addY or 0
else
  addY = 0
end
local finalX = self.xPos + layoutX + addX - 1
local finalY = self.yPos + layoutY + addY - 1
self.finalX = finalX
self.finalY = finalY
local newText
if #self.label > self.xLength then
  newText = string.sub(self.label,1,self.xLength)
else
  newText = self.label
end
paintutils.drawFilledBox(finalX,finalY,finalX+self.xLength-1,finalY+self.yLength-1,self.bgColor)
term.setTextColor(self.fgColor)
term.setCursorPos(finalX+self.xTextPos-1,finalY+self.yTextPos-1)
term.write(newText)
end
--Return function--
Button.returnData = function(self)
local toReturn = {}
for i,v in pairs(self) do
  toReturn[i] = v
end
return toReturn
end
--Sample Input table--
example = [[
example = {
  name = "quickSettings",
  label = ">",
  xPos = 1,
  yPos = 3,
  xLength = 1,
  yLength = 6,
  xTextPos = 1,
  yTextPos = 1,
  fgColor = colors.blue,
  bgColor = colors.lightGray,
  returnValue = "quickSettings",
},
]]
--Class Toggle--
--Initialize Toggle Object--
Toggle.new = function(input)
local self = {}
setmetatable(self,{__index = Toggle})
self.name = input.name or "randomName"
self.state = input.state or true
self.xPos = input.xPos or 1
self.yPos = input.yPos or 1
self.trueColor = input.trueColor or colors.green
self.falseColor = input.falseColor or colors.red
self.trueText = input.trueText or "T"
self.falseText = input.falseText or "F"
self.selectedBg = input.selectedBg or colors.gray
self.notSelectedBg = input.notSelectedBg or colors.lightGray
self.returnValue = input.returnValue or "mmmmmmm"
return self
end
Toggle.draw = function(self,layoutX,layoutY,addX,addY)
layoutX = layoutX or 0
layoutY = layoutY or 0
if self.moveX then
  addX = addX or 0
else
  addX = 0
end
if self.moveY then
  addY = addY or 0
else
  addY = 0
end
local finalX = self.xPos + layoutX + addX - 1
local finalY = self.yPos + layoutY + addY - 1
self.finalX = finalX
self.finalY = finalY
term.setCursorPos(finalX,finalY)
if self.state == false then
  term.setBackgroundColor(self.notSelectedBg)
  term.setTextColor(self.trueColor)
  term.write(string.sub(self.trueText,1,1))
  term.setBackgroundColor(self.selectedBg)
  term.setTextColor(self.falseColor)
  term.write(" "..string.sub(self.falseText,1,1).." ")
elseif self.state == true then
  term.setBackgroundColor(self.selectedBg)
  term.setTextColor(self.trueColor)
  term.write(" "..string.sub(self.trueText,1,1).." ")
  term.setBackgroundColor(self.notSelectedBg)
  term.setTextColor(self.falseColor)
  term.write(string.sub(self.falseText,1,1))
end
end
Toggle.returnData = function(self)
local toReturn = {}
for i,v in pairs(self) do
  toReturn[i] = v
end
return toReturn
end
function Toggle.toggle(self)
if self.state == true then
  self.state = false
else
  self.state = true
end
end
function Toggle.getState(self)
return self.state
end
--BackgroundColor Class--
function BackgroundColor.new(input)
local self = {}
setmetatable(self,{__index = BackgroundColor})
self.color = input.color
return self
end
function BackgroundColor.setColor(self,color)
self.color = color
end
function BackgroundColor.returnData(self)
local toReturn = {}
for i,v in pairs(self) do
  toReturn[i] = v
end
return toReturn
end
--ColorField Class--
function ColorField.new(input)
local self = {}
setmetatable(self,{__index = ColorField})
self.name = input.name
self.xPos = input.xPos
self.yPos = input.yPos
self.xLength = input.xLength
self.yLength = input.yLength
self.color = input.color
return self
end
function  ColorField.draw(self,layoutX,layoutY,addX,addY)
layoutX = layoutX or 0
layoutY = layoutY or 0
if self.moveX then
  addX = addX or 0
else
  addX = 0
end
if self.moveY then
  addY = addY or 0
else
  addY = 0
end
local finalX = self.xPos + layoutX + addX - 1
local finalY = self.yPos + layoutY + addY - 1
self.finalX = finalX
self.finalY = finalY
paintutils.drawFilledBox(finalX,finalY,finalX+self.xLength-1,finalY+self.yLength-1,self.color)
end
function ColorField.returnData(self)
local toReturn = {}
for i,v in pairs(self) do
  toReturn[i] = v
end
return toReturn
end
--BetterPaint Class--
function BetterPaint.new(input)
local self = {}
setmetatable(self,{__index = BetterPaint})
finalX = input.xPos
finalY = input.yPos
self.name = input.name
self.path = input.path
self.xLength = input.xLength
self.yLength = input.yLength
self.returnValue = input.returnValue
self.label = input.label
self.labelBg = input.labelBg
self.labelFg = input.labelFg
return self
end
function BetterPaint.returnData(self)
local toReturn = {}
for i,v in pairs(self) do
  toReturn[i] = v
end
return toReturn
end
function BetterPaint.draw(self,layoutX,layoutY,addX,addY)
if layoutX == nil then layoutX = 0 end
if layoutY == nil then layoutY = 0 end
if self.moveX then
  if laddX == nil then addX = 0 end
else
  addX = 0
end
if self.moveY then
  if addY == nil then addY = 0 end
else
  addY = 0
end
local finalX = self.xPos + layoutX + addX - 1
local finalY = self.yPos + layoutY + addY - 1
self.finalX = finalX
self.finalY = finalY
paint.drawImage(self.path,finalX,finalY)
term.setCursorPos(finalX,finalY+self.yLength+1)
term.setTextColor(self.labelFg)
term.setBackgroundColor(self.labelBg)
term.write(self.label)
--[[print("hi")
print(layoutX)
print(layoutY)]]--
end
--Event handler function--
eventHandler = function(self)
while true do
  local event, p1, p2, p3, p4, p5, p6 = os.pullEvent()
  if event == "mouse_click" then
   for i,v in pairs(self.Button) do
	if v.finalX <= p2 and p2 <= v.finalX + v.xLength-1 and v.finalY <= p3 and p3 <= v.finalY + v.yLength-1 then
	 return {"Button",tostring(v.returnValue)}
	end
   end
   for i,v in pairs(self.Toggle) do
	if v.finalX <= p2 and p2 <= v.finalX + 3 and v.finalY == p3 then
	 return {"Toggle",tostring(v.returnValue)}
	end
   end
   for i,v in pairs(self.BetterPaint) do
	if v.finalX <= p2 and
	p2 <= v.finalX + v.xLength-1 and
	v.finalY <= p3 and p3 <= v.finalY + v.yLength-1 then
	 return {"Button",tostring(v.returnValue)}
	end
   end
   term.setCursorPos(1,1)
   print(self.xPos)
   print(self.yPos)
   os.pullEvent()
   if self.nilClick then
	if not (self.xPos <= p2 and p2 <= self.xLength and self.yPos <= p3 and p3 <= self.yLength) then
	 return {"Nil","Nil"}
	end
   end
  elseif event == "key" then
  
  --elseif event == "monitor_touch" then
   --os.queueEvent("mouse_click", p1, p2, p3, p4, p5, p6)
  end
end
end
--Load Function--
function Initialize()
local toReturn = {}
toReturn.Button = Button
toReturn.Layout = Layout
toReturn.Toggle = Toggle
toReturn.BackgroundColor = BackgroundColor
toReturn.ColorField = ColorField
toReturn.BetterPaint = BetterPaint
toReturn.eventHandler = eventHandler
return toReturn
end

Before you ask, all the apis have been initialized. If you don't believe me, check out this GitHub repo.

Thanks in advance and have a great afternoon (bulgarian time)

~Creator

PS: Line 330 is in the BetterPiant class section ;)/> BetterPaint is awesome!

This line:


local finalX = self.xPos + layoutX + addX - 1

In the BetterPaint.draw() function.
Edited on 15 March 2015 - 03:15 PM
Creator #2
Posted 15 March 2015 - 05:12 PM
Please close this topic, it was a dumb mistake. ;)/> While using notepad++, I replaced all the occurences something with someting else. (not "something", like a variable whose value you dont know) ;)/>