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

rightclicking menu? Removing only removes visuality, not functionality

Started by Goof, 28 March 2014 - 08:56 PM
Goof #1
Posted 28 March 2014 - 09:56 PM
Hello there


Im working on a rightclick menu function which is used by:

mytbl={
  x=e[3];
  y=e[4];
  content = {
    {
      text="New"; --- text of the menu
      backgroundColor=colors.white; 
      textColor=colors.lime;
      func=true; -- what function it will run
    };
  };
}
setmetatable( mytbl, { __index = tbl } )
clickMenu = mytbl:menu()

My whole program is on Pastebin.com

or if you're bored:
Edit: just fixed the spoilers with code tags.
Spoiler

local BACKGROUNDCOLOR = colors.lightGray
local TEXTCOLOR = colors.white

local tbl = {}
tbl = {
  menu = function( self )
	local content = self.content
	local maxS=0
	for k,v in pairs( content ) do
	  if v.text then
		if string.len( v.text ) > maxS then
		 maxS = string.len( v.text )
		end
	  end
	end
	local menLength = maxS+2
	local menHeight = #content
	for k,v in pairs(content) do
	  if not v.text then
		v.text = string.rep( v.repeatString, menLength )
	  end
	end
	local width, height = term.getSize()
	local _X, _Y = nil, nil
	if self.x > ( width - menLength + 1 ) then
	  _X = width - menLength + 1;
	end
	if self.y > ( height - menHeight + 1 ) then
	  _Y = height - menHeight + 1;
	end
	term.setCursorPos( _X or self.x, _Y or self.y )
	local position = { term.getCursorPos() }
	local curY = position[2]
	for k,v in ipairs( content ) do
	  term.setBackgroundColor( v.backgroundColor )
	  term.setTextColor( v.textColor )
	  term.setCursorPos( math.floor( position[1] ), curY )
	  local startPos = math.floor( position[1] )
	  local xPos = math.floor( position[1] + menLength / 2 - string.len(v.text) / 2 )
	  local endPos = math.floor( position[1] + menLength )
	  local currentPos = { term.getCursorPos() }
	  local yMin = curY;
	  local yMax = curY;
	  local xMin = startPos;
	  local xMax = endPos;
	  for x = startPos, endPos do
		term.setCursorPos( currentPos[1], currentPos[2] )
		if currentPos[1] < xPos then
		  term.write(" ")
		elseif currentPos[1] > xPos then
		  term.write(" ")
		elseif currentPos[1] == xPos then
		  write(v.text)
		end
		currentPos = { term.getCursorPos() }
		x = currentPos[1]
		yPos = currentPos[2]
		if x >= endPos then
		  break
		end
	  end
	  v["position"] = {}
	  v["position"]["xPos"] = xPos;
	  v["position"]["xMin"] = startPos;
	  v["position"]["xMax"] = endPos;
	  v["position"]["yMin"] = yMin;
	  v["position"]["yMax"] = yMax;
	  curY = curY + 1
	end
	return {
	  initialize = function( x, y )
		local con = self.content;
		local flash = function(menu)
		  term.setBackgroundColor( colors.gray )
		  term.setTextColor( colors.white )
		  term.setCursorPos( con[menu]["position"]["xMin"], con[menu]["position"]["yMin"] )
		  local currentPos = { term.getCursorPos() }
		  for y = con[menu]["position"]["yMin"], con[menu]["position"]["yMax"] do
			for x = con[menu]["position"]["xMin"], con[menu]["position"]["xMax"] do
			  term.setCursorPos( currentPos[1], currentPos[2] )
			  if x == con[menu]["position"]["xPos"] then
				write(con[menu].text)
			  else
				term.write(" ")
			  end
			  currentPos = { term.getCursorPos() }
			  x = currentPos[1]
			  if x >= con[menu]["position"]["xMax"] then
				break
			  end
			end
		  end
		  sleep(0.1)
		  term.setBackgroundColor( con[menu].backgroundColor )
		  term.setTextColor( con[menu].textColor )
		  term.setCursorPos( con[menu]["position"]["xMin"], con[menu]["position"]["yMin"] )
		  local currentPos = { term.getCursorPos() }
		  for y = con[menu]["position"]["yMin"], con[menu]["position"]["yMax"] do
			for x = con[menu]["position"]["xMin"], con[menu]["position"]["xMax"] do
			  term.setCursorPos( currentPos[1], currentPos[2] )
			  if x == con[menu]["position"]["xPos"] then
				write(con[menu].text)
			  else
				term.write(" ")
			  end
			  currentPos = { term.getCursorPos() }
			  x = currentPos[1]
			  if x >= con[menu]["position"]["xMax"] then
				break
			  end
			end
		  end
		  sleep(0.1)
		end
		for k,v in pairs(con) do
		  if x >= v["position"]["xMin"]
		  and x < v["position"]["xMax"]
		  and y >= v["position"]["yMin"]
		  and y <= v["position"]["yMax"]
		  then
			if v["func"] then
			  flash(k)
			  --v["func"]()
			  --print("Function started")
			else
			  --print("Did not run function")
			end
			con = nil
			term.setBackgroundColor( BACKGROUNDCOLOR )
			term.clear()
			return true
		  end
		end
		return false
	  end;
	  remove = function()
		local con = self.content;
		term.setBackgroundColor( BACKGROUNDCOLOR )
		term.setTextColor( TEXTCOLOR )
		for menu, v in ipairs(con) do
		  term.setCursorPos( con[menu]["position"]["xMin"], con[menu]["position"]["yMin"] )
		  local currentPos = { term.getCursorPos() }
		  for y = con[menu]["position"]["yMin"], con[menu]["position"]["yMax"] do
			for x = con[menu]["position"]["xMin"], con[menu]["position"]["xMax"] do
			  term.setCursorPos( currentPos[1], currentPos[2] )
			  term.write(" ")
			  currentPos = { term.getCursorPos() }
			  x = currentPos[1]
			  if x >= con[menu]["position"]["xMax"] then
				break
			  end
			end
		  end
		end
		con = nil
		return true
	  end;
	}
  end;
}

term.setBackgroundColor( BACKGROUNDCOLOR )
term.setTextColor( TEXTCOLOR )
term.clear()
while true do
  e = { coroutine.yield() }
  if e[1] == "terminate" then
	os.reboot()
  elseif e[1] == "mouse_click" then
	--term.setBackgroundColor( colors.gray )
	--term.clear()
	if e[2] == 1 then
	  if clickMenu ~= nil then
		local resp = clickMenu.initialize( e[3], e[4] )
		clickMenu.remove()
	  else
	  end
	elseif e[2] == 2 then
	  if clickMenu ~= nil then
		clickMenu.remove()
	  end
	  mytbl={
		x=e[3];
		y=e[4];
		content = {
		  {
			text="New";
			backgroundColor=colors.white;
			textColor=colors.lime;
			func=true;
		  };
		  {
			text=false;
			repeatString="-";
			backgroundColor=colors.red;
			textColor=colors.white;
			func=false;
		  };
		  {
			text="Nsd";
			backgroundColor=colors.white;
			textColor=colors.green;
			func=true;
		  };
		  {
			text="Set";
			backgroundColor=colors.white;
			textColor=colors.orange;
			func=true;
		  };
		  {
			text="stp";
			backgroundColor=colors.white;
			textColor=colors.red;
			func=true;
		  };
		};
	  }
	  setmetatable( mytbl, { __index = tbl } )
	  clickMenu = mytbl:menu()
	end
  end
end
term.setCursorPos(1,18)



The result when running my function / program:

Whenever i rightclick the menu pops out fine.
When i click outside / someplace the menu disappears ( thats good ), BUT
then if i click on the X/Y choordinates of the menu, it still flashes .. I have no idea where this stupidity occours…

Could you please help?

Thanks in Advance
Edited on 28 March 2014 - 08:59 PM
CometWolf #2
Posted 28 March 2014 - 10:14 PM
Your clearing the local con variable rather than the actual table contents in your remove function.

				local con = self.content;
				con = nil
so clickMenu will always be ~= nil and it will thus call the init function regardless.

		if e[2] == 1 then
		  if clickMenu ~= nil then
				local resp = clickMenu.initialize( e[3], e[4] )
				clickMenu.remove()

it should instead be

				local con = self.content;
				self.content = nil

On second thought, clickMenu would probably still not be nil… Personally i prefer to use one main table for the functions, have the new tables inherit that table, then pass the table to those functions, rather than copying the functions themselves to the table. Makes stuff like this easier to deal with :P/>
Edited on 28 March 2014 - 09:29 PM
Goof #3
Posted 28 March 2014 - 11:25 PM
Ohhh… yeah of course!!!

That solved everything ( just made some changes to the final(almost?) rightclick function with my customable menus :D/>/> Yay!

Spoiler

local BACKGROUNDCOLOR = colors.lightGray
local TEXTCOLOR = colors.white

local tbl = {}
tbl = {
  menu = function( self )
    local content = self.content
    local maxS=0
    for k,v in pairs( content ) do
      if v.text then
        if string.len( v.text ) > maxS then
         maxS = string.len( v.text )
        end
      end
    end
    local menLength = maxS+2
    local menHeight = #content
    for k,v in pairs(content) do
      if not v.text then
        v.text = string.rep( v.repeatString, menLength )
      end
    end
    local width, height = term.getSize()
    local _X, _Y = nil, nil
    if self.x > ( width - menLength + 1 ) then
      _X = width - menLength + 1;
    end
    if self.y > ( height - menHeight + 1 ) then
      _Y = height - menHeight + 1;
    end
    term.setCursorPos( _X or self.x, _Y or self.y )
    local position = { term.getCursorPos() }
    local curY = position[2]
    for k,v in ipairs( content ) do
      term.setBackgroundColor( v.backgroundColor )
      term.setTextColor( v.textColor )
      term.setCursorPos( math.floor( position[1] ), curY )
      local startPos = math.floor( position[1] )
      local xPos = math.floor( position[1] + menLength / 2 - string.len(v.text) / 2 )
      local endPos = math.floor( position[1] + menLength )
      local currentPos = { term.getCursorPos() }
      local yMin = curY;
      local yMax = curY;
      local xMin = startPos;
      local xMax = endPos;
      for x = startPos, endPos do
        term.setCursorPos( currentPos[1], currentPos[2] )
        if currentPos[1] < xPos then
          term.write(" ")
        elseif currentPos[1] > xPos then
          term.write(" ")
        elseif currentPos[1] == xPos then
          write(v.text)
        end
        currentPos = { term.getCursorPos() }
        x = currentPos[1]
        yPos = currentPos[2]
        if x >= endPos then
          break
        end
      end
      v["position"] = {}
      v["position"]["xPos"] = xPos;
      v["position"]["xMin"] = startPos;
      v["position"]["xMax"] = endPos;
      v["position"]["yMin"] = yMin;
      v["position"]["yMax"] = yMax;
      curY = curY + 1
    end
    return {
      initialize = function( x, y )
        local con = self.content;
        local flash = function(menu)
          term.setBackgroundColor( colors.gray )
          term.setTextColor( colors.white )
          term.setCursorPos( con[menu]["position"]["xMin"], con[menu]["position"]["yMin"] )
          local currentPos = { term.getCursorPos() }
          for y = con[menu]["position"]["yMin"], con[menu]["position"]["yMax"] do
            for x = con[menu]["position"]["xMin"], con[menu]["position"]["xMax"] do
              term.setCursorPos( currentPos[1], currentPos[2] )
              if x == con[menu]["position"]["xPos"] then
                write(con[menu].text)
              else
                term.write(" ")
              end
              currentPos = { term.getCursorPos() }
              x = currentPos[1]
              if x >= con[menu]["position"]["xMax"] then
                break
              end
            end
          end
          sleep(0.1)
          term.setBackgroundColor( con[menu].backgroundColor )
          term.setTextColor( con[menu].textColor )
          term.setCursorPos( con[menu]["position"]["xMin"], con[menu]["position"]["yMin"] )
          local currentPos = { term.getCursorPos() }
          for y = con[menu]["position"]["yMin"], con[menu]["position"]["yMax"] do
            for x = con[menu]["position"]["xMin"], con[menu]["position"]["xMax"] do
              term.setCursorPos( currentPos[1], currentPos[2] )
              if x == con[menu]["position"]["xPos"] then
                write(con[menu].text)
              else
                term.write(" ")
              end
              currentPos = { term.getCursorPos() }
              x = currentPos[1]
              if x >= con[menu]["position"]["xMax"] then
                break
              end
            end
          end
          sleep(0.1)
        end
        for k,v in ipairs(con) do
          if x >= v["position"]["xMin"]
          and x < v["position"]["xMax"]
          and y >= v["position"]["yMin"]
          and y <= v["position"]["yMax"]
          then
            if v["func"] then
              flash(k)
              --v["func"]()
              return true
              --print("Function started")
            else
              return true
              --print("Did not run function")
            end
            self.content = nil
            term.setBackgroundColor( BACKGROUNDCOLOR )
            term.clear()
            return false
          else
            return true
          end
        end
        return false
      end;
      remove = function()
        local con = self.content;
        term.setBackgroundColor( BACKGROUNDCOLOR )
        term.setTextColor( TEXTCOLOR )
        for menu, v in pairs(con) do
          term.setCursorPos( con[menu]["position"]["xMin"], con[menu]["position"]["yMin"] )
          local currentPos = { term.getCursorPos() }
          for y = con[menu]["position"]["yMin"], con[menu]["position"]["yMax"] do
            for x = con[menu]["position"]["xMin"], con[menu]["position"]["xMax"] do
              term.setCursorPos( currentPos[1], currentPos[2] )
              term.write(" ")
              currentPos = { term.getCursorPos() }
              x = currentPos[1]
              if x >= con[menu]["position"]["xMax"] then
                break
              end
            end
          end
        end
        self.content = nil
        return true
      end;
    }
  end;
}

term.setBackgroundColor( BACKGROUNDCOLOR )
term.setTextColor( TEXTCOLOR )
term.clear()
while true do
  e = { coroutine.yield() }
  if e[1] == "terminate" then
    os.reboot()
  elseif e[1] == "mouse_click" then
    --term.setBackgroundColor( colors.gray )
    --term.clear()
    if e[2] == 1 then
      if clickMenu ~= nil then
        local resp = clickMenu.initialize( e[3], e[4] )
        if resp == true then
          clickMenu.remove()
          clickMenu = nil
        end
      else
      end
    elseif e[2] == 2 then
      if clickMenu ~= nil then
        clickMenu.remove()
        clickMenu = nil
      end
      mytbl={
        x=e[3];
        y=e[4];
        content = {
          {
            text="New";
            backgroundColor=colors.white;
            textColor=colors.lime;
            func=true;
          };
          {
            text=false;
            repeatString="-";
            backgroundColor=colors.red;
            textColor=colors.white;
            func=false;
          };
          {
            text="Nsd";
            backgroundColor=colors.white;
            textColor=colors.green;
            func=true;
          };
          {
            text="Set";
            backgroundColor=colors.white;
            textColor=colors.orange;
            func=true;
          };
          {
            text="stp";
            backgroundColor=colors.white;
            textColor=colors.red;
            func=true;
          };
        };
      }
      setmetatable( mytbl, { __index = tbl } )
      clickMenu = mytbl:menu()
    end
  end
end
term.setCursorPos(1,18)

Thank you!
Edited on 28 March 2014 - 10:25 PM
Goof #4
Posted 29 March 2014 - 12:27 PM
Hello again

I've run into another problem;
After the menu appears, and i click outside it ( to get it disappear ), then it disappears fine,
but when i try to click/rightclick/mousewheelclick anywhere on the screen, it comes with an error:
test:115: Bad argument: Table expected, got nil

And my current code( on pastebin )


I thought that after i used the clickMenu.remove() it removes the whole variable/table "clickMenu", but it doesn't seem to…

Why?

Thanks in Advance
CometWolf #5
Posted 29 March 2014 - 12:48 PM
Simply calling clickMenu.remove in this code will only clear the table clickMenu.content, not clickMenu itself. However you seem to have added clickMenu = nil afterwards, which should be enough. The current problem is unrelated though.
You're only clearing the table if you actually click on an option.

	  if clickMenu ~= nil then
	    local resp = clickMenu.initialize( e[3], e[4] )
	    if resp == true then --remove this if statement
		  clickMenu.remove()
		  clickMenu = nil
	    end
Goof #6
Posted 29 March 2014 - 12:52 PM
Ehh… I still get an error, but its in the remove function…
(line 137 : bad argument: table expected, got nil )

Code


EDIT: Nevermind.. just forgot to remove the self.content = nil xD

Everything works like a charm

Thank you
Edited on 29 March 2014 - 11:55 AM