Posted 22 August 2015 - 04:51 PM
Over the past week or so, I've been working on a somewhat simple menu-based operation system. All so I can get used to working with while loops, events, and file managing. For the last few days, I've been trying to switch from having to write the same code over and over every time I want to add a text field or something somewhere. So, in an attempt to start using objects more, I created a test object for a number picker. I call these things "elements", and if I can get this to work right, I will use them everywhere.
The number picker is supposed to, when selected, allow you to select a number within a a range specified when the object is instantiated. This worked when I was testing it, but when it came to the selection part I decided it would be easier to make elements be relative to the button used to activate them. This is because I already do selection this way.
Inside my screens table, relative to the button I want to have an element associated with it, I create an variable and set it to a new NumberPicker object:
Here is the NumberPicker class. I did my best with indention, but Notpad++ hates me:
Here is my screens table, tScreens:
Here is my drawing code:
And here is my main while loop:
Lastly, here is a the pastebin code for the program as it currently is:
The question is, why does calling element throw nil?
Also, another problem I've been having is when I run the file at startup the screen won't draw until I click, or press a key.
Thank you for reading, and I hope you decide to help
- Searous
The number picker is supposed to, when selected, allow you to select a number within a a range specified when the object is instantiated. This worked when I was testing it, but when it came to the selection part I decided it would be easier to make elements be relative to the button used to activate them. This is because I already do selection this way.
Inside my screens table, relative to the button I want to have an element associated with it, I create an variable and set it to a new NumberPicker object:
element = NumberPicker.new(0,0,4,14)
The first number is the selector's starting value. The second and third are the range of number that can be selected. The fourth is the button ID associated with the object. The reason I don't what to use that to set elements relative to buttons is because it would be much easier to do it this way, instead of rewriting some of my selection and drawing code. When I call this variable later inside, and outside the table it's in, I get an "attempt to index ? (a nil value)" error on the line that element is defined on.Here is the NumberPicker class. I did my best with indention, but Notpad++ hates me:
local NumberPicker = {}
NumberPicker.__index = NumberPicker
NumberPicker.default = 1
NumberPicker.min = 1
NumberPicker.max = 9
NumberPicker.selected = 1
function NumberPicker.new(default,min,max,buttonID)
local this = setmetatable({}, NumberPicker)
this.default = default
this.selected = default
this.min = min
this.max = max
this.active = false
this.buttonID = buttonID
return this
end
function NumberPicker.action(this)
this.active = true
while this.active do
local event,p1,p2,p3 = os.pullEvent()
if event == "key" then
if p1 == keys.left then
this.selected = this.selected - 1
elseif p1 == keys.right then
this.selected = this.selected + 1
end
end
local ok,data = pcall(drawScreen)
if not ok then
bError = true
local ok,data = pcall(drawError, data)
if not ok then
os.shutdown()
end
end
local ok1,data1 = pcall(drawSpecial)
if not ok then
bError = true
local ok,data = pcall(drawError, data)
if not ok then
os.shutdown()
end
end
end
end
function NumberPicker.draw(this)
color("field")
--term.setCursorPos(25,(selected - lowest) + 3)
write(this.selected)
end
Here is my screens table, tScreens:
local tScreens = {
[1] = {"Main Menu",{
----Main Menu----
[1] = {"Login","Login to an existing profile",0,
element = NumberPicker.new(1,1,20,1),
action = function()
tScreens[ 1 ][ 2 ][ 1 ].element:action()
end
},
[2] = {"Create Profile","Create a new profile for use on this system",0,
action = function()
screen = 2
lowest = 1
highest = 5
selected = 1
end
},
[3] = {"System Information","View information about this system",0,
action = function()
end
},
[4] = {"Exit","Exit the system",0,
action = function()
term.setBackgroundColor(colors.black)
bRunning = false
end
}
}},
[2] = {"Create Profile",{
----Create Profile----
[1] = {"Username","This name must be uniqe, and contain NO spaces",0,
action = function()
color("field")
color("background")
term.setCursorPos(25,(selected - lowest) + 3)
write(" ")
term.setCursorPos(25,(selected - lowest) + 3)
tTempVars[1] = read()
end
},
[2] = {"Password","Chose a password",0,
action = function()
color("field")
color("background")
term.setCursorPos(25,(selected - lowest) + 3)
write(" ")
term.setCursorPos(25,(selected - lowest) + 3)
tTempVars[2] = read("*")
end
},
[3] = {"Re-Password","Please retype the pasword you choes above",0,
action = function()
color("field")
color("background")
term.setCursorPos(25,(selected - lowest) + 3)
write(" ")
term.setCursorPos(25,(selected - lowest) + 3)
tTempVars[3] = read("*")
end
},
[4] = {"Moto","Currently, this must remain short. Keep it from going off the screen",0,
action = function()
color("field")
color("background")
term.setCursorPos(25,(selected - lowest) + 3)
write(" ")
term.setCursorPos(25,(selected - lowest) + 3)
tTempVars[4] = read()
end
},
[5] = {"Text Color","The color of this text, and menu name text",0,
action = function()
bLock = true
nSelectedColor = tTempColors[1]
end
},
[6] = {"Field Color","The color of text fields",0,
action = function()
bLock = true
nSelectedColor = tTempColors[2]
end
},
[7] = {"Spacer Color","The color of the spacers",0,
action = function()
bLock = true
nSelectedColor = tTempColors[3]
end
},
[8] = {"Cursor Color","The color of the cursor used to select options",0,
action = function()
bLock = true
nSelectedColor = tTempColors[4]
end
},
[9] = {"Tip Color","The color of info popups",0,
action = function()
bLock = true
nSelectedColor = tTempColors[5]
end
},
[10] = {"Bad Color","The color of inaccesable fields, and locations",0,
action = function()
bLock = true
nSelectedColor = tTempColors[6]
end
},
[11] = {"Menu Color","The color of menu buttons",0,
action = function()
bLock = true
nSelectedColor = tTempColors[7]
end
},
[12] = {"Background Color","The color of the background",0,
action = function()
bLock = true
nSelectedColor = tTempColors[8]
end
},
[13] = {"Cursor","The string of character(s) used as the cursor",0,
action = function()
color("field")
color("background")
term.setCursorPos(25,(selected - lowest) + 3)
write(" ")
term.setCursorPos(25,(selected - lowest) + 3)
tTempVars[5] = read()
tVars[5] = tTempVars[5]
end
},
[14] = {"Permission Level","The permission level of this user",4,
action = function()
local ok, data = pcall(numberPicker)
if not ok then
bError = true
status = data
end
end
},
[15] = {"Create Profile","Accept the above settings, and create a new profile",0,
action = function()
if tTempVars[2] == tTempVars[3] and not fs.exists(".config_"..tTempVars[1]) then
if bLoggedIn then
screen = 4
else
screen = 1
end
selected = 1
lowest = 1
highest = 5
resetVars()
resetColors()
else
color("tip")
term.setCursorPos(25,(selected - lowest) + 3)
write("Invalid Login")
sleep(3)
end
end
},
[16] = {"Cancel","Drop the above settings, and don't create a new profile",0,
action = function()
screen = 1
selected = 1
lowest = 1
highest = 5
resetColors("temp")
resetVars("temp")
end
}
}, {[14] = NumberPicker.new(0,0,4,14)}},
[3] = {"Login",{
}},
[4] = {"Main Menu",{ --Deprecated
[1] = {"test","test",0,
action = function()
end
}
}}
}
Here is my drawing code:
local function drawScreen()
color("background")
clear()
color("text")
print(tScreens[screen][1])
color("spacer")
print("---------------------------------------------------")
color("menu")
--Buttons
local nTemp = lowest
for i = 1, 5, 1 do
color("menu")
if tScreens[screen][2][nTemp] == nil then
print(" ")
else
local string = ""
for i = 1, tVars[5]:len(), 1 do
string = string.." "
end
if tVars[6] < tScreens[ screen ][ 2 ][ nTemp ][ 3 ] then
color("bad")
end
print(string.." "..tScreens[ screen ][ 2 ][ nTemp ][ 1 ])
end
nTemp = nTemp + 1
end
---------
color("spacer")
print("---------------------------------------------------")
color("text")
print(tScreens[ screen ][ 2 ][ selected ][ 2 ])
if selected >= lowest and selected <= highest then
term.setCursorPos(1,(selected - lowest) + 3)
color("cursor")
write(tVars[5])
end
end
local function drawSpecial()
term.setCursorPos(x - tVars[1]:len() + 1,1)
write(tVars[1])
term.setCursorPos(1,1)
if lowest > 1 then
term.setCursorPos(x,3)
write("*")
term.setCursorPos(1,1)
end
if highest < getTableSize(tScreens[ screen ][ 2 ]) then
term.setCursorPos(x,7)
write("*")
term.setCursorPos(1,1)
end
if debug then
color("field")
term.setCursorPos(x - 3,y)
write("h"..highest)
term.setCursorPos(x - 7,y)
write("l"..lowest)
term.setCursorPos(x - 11,y)
write("s"..selected)
term.setCursorPos(1,1)
end
----Screens----
if screen == 2 then
color("field")
local nTemp = lowest
for i = 1, 5, 1 do
term.setCursorPos(25, (nTemp - lowest) + 3)
if tTempVars[nTemp] == nil then
else
color("field")
--write(tTempVars[nTemp])
end
if nTemp == 1 then
term.setCursorPos(25,(nTemp - lowest) + 3)
write(tTempVars[1])
elseif nTemp == 2 then
term.setCursorPos(25,(nTemp - lowest) + 3)
local string = ""
for i = 1, tTempVars[2]:len(), 1 do
string = string.."*"
end
write(string)
elseif nTemp == 3 then
term.setCursorPos(25,(nTemp - lowest) + 3)
local string = ""
for i = 1, tTempVars[3]:len(), 1 do
string = string.."*"
end
write(string)
elseif nTemp == 4 then
term.setCursorPos(25,(nTemp - lowest) + 3)
write(tTempVars[nTemp])
elseif nTemp == 13 then
color("field")
color("background")
term.setCursorPos(25,(nTemp - lowest) + 3)
write(tTempVars[5])
-- elseif nTemp == 14 then
-- color("field")
-- color("background")
-- term.setCursorPos(25,(nTemp - lowest) + 3)
-- write(tTempVars[6])
end
if nTemp >= 5 and nTemp <= 11 then
if term.isColor then
if bLock and selected == nTemp then
paintutils.drawBox(25,(nTemp - lowest) + 3,26,(nTemp - lowest) + 3,getColor(nSelectedColor))
else
paintutils.drawBox(25,(nTemp - lowest) + 3,26,(nTemp - lowest) + 3,getColor(tTempColors[ nTemp - 4 ]))
end
end
end
if selected >= 5 and selected < 14 and bLock then
color("cursor")
color("background")
term.setCursorPos(23,(selected - lowest) + 3)
write("<")
term.setCursorPos(28,(selected - lowest) + 3)
write(">")
end
nTemp = nTemp + 1
end
term.setCursorPos(1,1)
end
----Elements----
if tScreens[ screen ][ 3 ] ~= nil then
local size = #tScreens[ screen ][ 3 ]
local nTemp = lowest
for i = 1, 5 do
if tScreens[ screen ][ 3 ][ nTemp ] ~= nil then
term.setCursorPos(25,(nTemp - lowest) + 3)
tScreens[ screen ][ 3 ][ nTemp ]:draw()
end
nTemp = nTemp + 1
end
end
end
And here is my main while loop:
while bRunning do
if not bStarted then
selected = 1
screen = 1
local ok,data = pcall(registerElements)
if not ok then
bError = true
local ok,data = pcall(drawError,data)
if not ok then
os.shutdown()
end
end
bStarted = true
end
------Input------
if not bError then
local event,p1,p2,p3 = os.pullEvent()
if event == "key" then
if p1 == keys.up or p1 == keys.w then
----Up----
if not bLock then
if selected == 1 then
selected = getTableSize(tScreens[screen][2])
if getTableSize(tScreens[screen][2]) > 5 then
lowest = getTableSize(tScreens[screen][2]) - 5
highest = getTableSize(tScreens[screen][2])
end
else
selected = selected - 1
end
if selected - lowest == 5 then
lowest = lowest + 1
elseif selected < lowest then
lowest = lowest - 1
end
if highest - selected == 5 then
highest = highest - 1
elseif selected > highest then
highest = highest + 1
end
-- local ok, data = pcall(drawScreen)
--- if not ok then
-- os.shutdwon()
-- end
-- local ok, data = pcall(drawSpecial)
-- if not ok then
-- os.shutdwon()
-- end
end
elseif p1 == keys.down or p1 == keys.s then
----Down----
if not bLock then
if selected == getTableSize(tScreens[screen][2]) then
selected = 1
lowest = 1
highest = 5
else
selected = selected + 1
end
if selected - lowest == 5 then
lowest = lowest + 1
elseif selected < lowest then
lowest = lowest - 1
end
if highest - selected == 5 then
highest = highest - 1
elseif selected > highest then
highest = highest + 1
end
end
elseif p1 == keys.enter or p1 == keys.space then
----Select----
if not bLock then
if tVars[6] >= tScreens[ screen ][ 2 ][ selected ][ 3 ] then
tScreens[ screen ][ 2 ][ selected ]:action()
drawScreen()
drawSpecial()
end
else
if screen == 2 then
if selected == 5 then
tTempColors[1] = nSelectedColor
end
bLock = false
end
end
end
elseif event == "mouse_click" then
if not bLock then
if p1 == 1 then
if (p3 > 2 and p3 < 8) and tScreens[ screen ][ 2 ][ p3 - 2 ] ~= nil then
if p2 < (tVars[5].." "..tScreens[ screen ][ 2 ][ lowest + (p3 - 3) ][ 1 ]):len() + 1 then
if selected == lowest + (p3 - 3) then
tScreens[ screen ][ 2 ][ selected ]:action()
else
selected = lowest + (p3 - 3)
end
end
end
end
else
end
elseif event == "mouse_scroll" then
if p1 == -1 then
if not bLock then
if lowest == 1 then
else
lowest = lowest - 1
highest = highest - 1
end
else
end
drawScreen()
drawSpecial()
elseif p1 == 1 then
if not bLock then
if highest == getTableSize(tScreens[ screen ][ 2 ]) then
else
lowest = lowest + 1
highest = highest + 1
end
else
end
drawScreen()
drawSpecial()
end
end
else
local ok, var = pcall(drawError, status)
if not ok then
color("bad")
print("An unexpected error has occurred while throwing the error '"..status.."'")
print(" ")
print("The system will terminate in 10 seconds")
sleep(10)
os.shutdown()
end
end
if not bRunning then
term.setBackgroundColor(colors.black)
clear()
else
local ok, data = pcall(drawScreen)
if not ok then
bError = true
status = data
end
local ok, data = pcall(drawSpecial)
if not ok then
bError = true
status = data
end
end
end
Lastly, here is a the pastebin code for the program as it currently is:
Djw10qEW
There is some code I don't use, and some I haven's used yet.The question is, why does calling element throw nil?
Also, another problem I've been having is when I run the file at startup the screen won't draw until I click, or press a key.
Thank you for reading, and I hope you decide to help
- Searous