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

Option selecting program not working the way it should.

Started by Creator, 22 January 2015 - 06:09 PM
Creator #1
Posted 22 January 2015 - 07:09 PM
Hi,

I'm writing a program and the function menu does not work properly. The menu function finction accept a table as argument. The table contains the different menus that are to be displayed. There are two options. If the number of elements id lower than height of display - 4 then it displays everything normally. The problem is when there are more elements. 1st, the elements are displayed in inversed order. 2nd, I want o be able to click on an element with a mouse instead of pressing enter.

Thanks for your help.

Here is the program:

modem = peripheral.wrap("bottom")
iniOpts = {"Reboot All PCs","Change Password","Add Door","Remove Door","Lock All Doors","Open All Doors","Reset All Doors"}
lime = colors.lime
black = colors.black
function clear()
  term.clear()
  term.setCursorPos(1,1)
end
function menu(opts)
doIt = true
currSelect = 1
 
while doIt do
x,y = term.getSize()
clear()
term.setCursorPos(x,1)
term.setBackgroundColor(lime)
print("^")
term.setBackgroundColor(black)
 
if #opts <= y - 4 then
  for i,v in pairs(opts) do
   yPos = 2 + i
   term.setCursorPos(math.floor(x - #v-4)/2,yPos)
   if currSelect == i then
    print("[["..v.."]]")
   else
    print("  "..v.."  ")
   end
  end
 
  event , button , xPos , yPos = os.pullEvent()
  if event == "key" then
   if button == keys.up then
    currSelect = currSelect - 1
   elseif button == keys.down then
    currSelect = currSelect + 1
   elseif button == keys.enter then
    doIt = false
    clear()
   end
  elseif event == "mouse_click" then
   clear()
   doIt = false
   currSelect = yPos - 2
   clear()
  elseif event == "monitor_touch" then
   clear()
   doIt = false
   currSelect = yPos - 2
   clear()
  end
 
  if currSelect == 0 then
   currSelect = #opts
  elseif currSelect == math.floor(#opts + 1) then
   currSelect = 1
  end
 
else
  for i,v in pairs(opts) do
   yPos = math.floor(y/2) - currSelect + i
   term.setCursorPos(math.floor(x - #v-4)/2,yPos)
   if currSelect == i then
    print("[["..v.."]]"..i)
   else
    print("  "..v.."  "..i)
   end
  end
  event , button , xPos , yPos = os.pullEvent()
  if event == "key" then
   if button == keys.up then
    currSelect = currSelect + 1
   elseif button == keys.down then
    currSelect = currSelect - 1
   elseif button == keys.enter then
    doIt = false
    clear()
   end
  elseif event == "mouse_click" then
   doIt = false
   currSelect = yPos - currSelect + math.floor(y/2)
   clear()
  elseif event == "monitor_touch" then
   doIt = false
   currSelect = yPos - math.floor(y/2) + currSelect
   clear()
  end

  if currSelect == 0 then
   currSelect = 1
  elseif currSelect == #opts + 1 then
   currSelect = #opts
  end
 
  if currSelect < 1 then
   currSelect = 1
   doIt = true
  elseif currSelect > #opts then
   currSelect = #opts
   doIt = true
  end
end
  end
 
  return currSelect
end
function rebootPc()
modem.transmit(3721,1,"reboot")
end
function changePass()
clear()
print("These are the available doors:")
print()
fil = {}
fil = fs.list("disk")
print("What password do you wish to change? ")
sel = menu(fil)
clear()
if fs.exists("disk/"..fil[sel]) then
  files = fs.open("disk/"..fil[sel], "r")
  print("Current password is: "..files.readAll())
  files.close()
  files = fs.open("disk/"..fil[sel], "w")
  write("Input new password: ")
  files.write(read())
  files.close()
  rebootPc()
else
  print("This door does not exist!")
  sleep(3)
  changePass()
end
end
function addDoor()
clear()
print("What is the name of the new door? ")
print("(Type <nodoor> if you do not want to create a door.) ")
write(">")
desDoor = read()
if fs.exists("disk/"..desDoor) then
  print("Door does already exist....")
  sleep(2)
  addDoor()
elseif desDoor == "nodoor" then
  clear()
else
  clear()
  write("Input desired password: ")
  doorN = fs.open("disk/"..desDoor,"w")
  newP = read()
  doorN.write(newP)
  doorN.close()
  shell.run("startup")
end
end
function deleteDoor()
clear()
listF = fs.list("disk")
delD = menu(listF)
write("Are you sure you want to delete door "..listF[delD].."? (y/n)")
sureOrNot = read()
if sureOrNot == "y" then
  fs.delete("disk/"..listF[delD])
end
end
function lock()
modem.transmit(3721,1,"lock")
end
function rst()
modem.transmit(3721,1,"reset")
end
function openD()
modem.transmit(3721,1,"open")
end
function options()
if iniSelect == 1 then
  rebootPc()
elseif iniSelect == 2 then
  changePass()
elseif iniSelect == 3 then
  addDoor()
elseif iniSelect == 4 then
  deleteDoor()
elseif iniSelect == 5 then
  lock()
elseif iniSelect == 6 then
  openD()
elseif iniSelect == 7 then
  rst()
end
end
iniSelect = menu(iniOpts)
clear()
options()

shell.run("startup")
Lyqyd #2
Posted 22 January 2015 - 09:02 PM
Moved to Ask a Pro.
KingofGamesYami #3
Posted 22 January 2015 - 10:14 PM
1st, the elements are displayed in inversed order

Probably due to the fact that the top left corner is (1, 1). I'd bet you designed your code believing the bottom left corner was (1, 1).

2nd, I want o be able to click on an element with a mouse instead of pressing enter.

You'll have to track the length of the text, as well as the line you wrote it on. Assemble this in a table, then check the coordinates against it.
Creator #4
Posted 23 January 2015 - 02:31 PM
1st, the elements are displayed in inversed order

Probably due to the fact that the top left corner is (1, 1). I'd bet you designed your code believing the bottom left corner was (1, 1).

2nd, I want o be able to click on an element with a mouse instead of pressing enter.

You'll have to track the length of the text, as well as the line you wrote it on. Assemble this in a table, then check the coordinates against it.

Thank you a lot,

but you should not be concerned about the term.setCursorPos(1,1)
I added that later. The different options are stored in a table.
I tried a lot of combinations, even for debugging i printed the key after the text, but it is always printed in inversed order. I suggest you try the program on a computer.

Thanks again. ;)/>
KingofGamesYami #5
Posted 23 January 2015 - 04:45 PM
but you should not be concerned about the term.setCursorPos(1,1)
I added that later. The different options are stored in a table.
I know they are stored in a table. I did the same thing in my (similar) menu (although it doesn't do click detection and can format new pages).

I'm looking through you code, it's a little hard to understand though. Your indentation is a little off, would it be possible for you to put it on pastebin?
Creator #6
Posted 23 January 2015 - 05:43 PM
http://pastebin.com/ZuGkjpgn

This is the pastebin link you asked for. I hope you are lucky finding the problem.
Thank you.
KingofGamesYami #7
Posted 23 January 2015 - 07:04 PM
I ran the code you have in the pastebin on mimic, a CC emulator, and it came out like this:


Reboot All PCs
Change Password
Add Door
Remove Door
Lock All Doors
Open All Doors
Reset All Doors

Since you said this was inverse order, I made the following modification to line 24:


yPos = 10 - i

It promptly inverted the order.
Creator #8
Posted 23 January 2015 - 08:05 PM
I ran the code you have in the pastebin on mimic, a CC emulator, and it came out like this:


Reboot All PCs
Change Password
Add Door
Remove Door
Lock All Doors
Open All Doors
Reset All Doors

Since you said this was inverse order, I made the following modification to line 24:


yPos = 10 - i

It promptly inverted the order.

Thanks a lot,
but the trouble comes when there are more elements than the screen is high.
So if you add random elements to the table (make sure they are more then 20) retry the programm. then you will understand what im talking about. Sorry for not expressing myself clearly enough.
KingofGamesYami #9
Posted 23 January 2015 - 08:26 PM
Well, in that case you'll want to separate it into multiple tables, then display the appropriate table's contents.

I sort them like this:

        local tArgs = { ... } --#table of things
        local pages = {[1]={}} --#pages
        for i = 1, #tArgs, 1 do --#fill pages
                if #pages[ #pages ] == 7 then
                        pages[ #pages + 1 ] = {} --#make new page
                end
                pages[ #pages ][ #pages[#pages] + 1 ] = tArgs[ i ]
        end
Creator #10
Posted 23 January 2015 - 08:56 PM
Well, in that case you'll want to separate it into multiple tables, then display the appropriate table's contents.

I sort them like this:

		local tArgs = { ... } --#table of things
		local pages = {[1]={}} --#pages
		for i = 1, #tArgs, 1 do --#fill pages
				if #pages[ #pages ] == 7 then
						pages[ #pages + 1 ] = {} --#make new page
				end
				pages[ #pages ][ #pages[#pages] + 1 ] = tArgs[ i ]
		end

Thanks a lot, but I dont get how it works. Couls you please explain.
Thanx
KingofGamesYami #11
Posted 23 January 2015 - 10:31 PM
First, we have a table of things we want to display

Second, we make a table with a table inside of it

Third we iterate through the table of things we want to display
-if the number of items on the current page is 7 (you can change this) it creates a new page
-adds the current argument (tArgs) to the last page, in the next available numeric slot

Fourth: Done! You can now access a page (layed out like your original table) by using pages[ current_page ]. You might need to add some way of switching between pages, but that's about it. If you have more questions, I suggest you try out the code in my pastebin link and set debug to true. It'll show you how my code works.