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

'unpacking' co-ordinates

Started by remiX, 21 March 2013 - 02:48 AM
remiX #1
Posted 21 March 2013 - 03:48 AM
I'm not sure if this is the best title but this is what I'm trying to do:

I made a Button API which is working great, you make one like this:

-- Arguments:
-- buttonText, startX or position, endX or auto if position is given, startY, endY, backgroundColor, textColor

local btn = buttons.initButton( ' - Button ', 'center', nil, 1, 3, colours.red, colours.white )
That would make 'btn' the object for this button now. Using btn:blink( col ) will make it blink colour col for a short time.

I also have a function to use with os.pullEvent() to check if the clicked X and Y pos matches with the co-ordinates with the button.
local function isWithin( cx, cy, sx, sy, ex, ey )
    return cx >= sx and cx <= ex and cy >= sy and cy <= ey
end

I also have a function with the block API called getValue. This will return the value of given data. (works fine)

Now if I want to check if the clicked position is that button, I'd do this:
local _, but, x, y = os.pullEvent( 'mouse_click' )

if isWithin( x, y, btn:getValue( 'startx' ), btn:getValue( 'starty' ), btn:getValue( 'endx' ), btn:getValue( 'endy' ) ) then
    -- The button was clicked
end

Now what I want is an easier way to check if a button was clicked using the isWithin function.
I thought the unpack() function will do the job, but I have no clue how unpack() works and it doesn't work anyway :o/>

So I wanted to make a unpackCoords() function for the button api:
function Buttons.unpackCoords( self )
    return unpack( { self.startx, self.starty, self.endx, self.endy } )
end

Was calling the isWithin function like so:
if isWithin( x, y, btn:unpackCoords() ) then
but errored with 'attempt to index ? (a function value)

If you guys understand what I'm trying to say, is there any way of doing it?
theoriginalbit #2
Posted 21 March 2013 - 04:06 AM
you seem to be going for a very high level abstraction to the buttons, I suggest that maybe instead of a function that the button gets passed into, you just use a method on the button object. so it would be

btn:clickedWithin( mouseX, mouseY )

as for the problem this is the solution

function Buttons.unpackCoords( self )
  return self.startX, self.starty, self.endx, self.endy
end
remiX #3
Posted 21 March 2013 - 04:12 AM
you seem to be going for a very high level abstraction to the buttons, I suggest that maybe instead of a function that the button gets passed into, you just use a method on the button object. so it would be

btn:clickedWithin( mouseX, mouseY )

Yeah, I was thinking of doing that.
Not sure why I'm even bothering with this question but now I'm curious :P/>

as for the problem this is the solution

function Buttons.unpackCoords( self )
  return self.startX, self.starty, self.endx, self.endy
end

I did try that too, should have stated in the OP. It gives the same error.
theoriginalbit #4
Posted 21 March 2013 - 04:17 AM
Yeah, I was thinking of doing that.
Not sure why I'm even bothering with this question but now I'm curious :P/>
What question? the OP?

I did try that too, should have stated in the OP. It gives the same error.
Can you post your api up? or if you dont wanna post it, pm it? because thats essentially how the unpack function works, it returns the values in a table as separate variables.
remiX #5
Posted 21 March 2013 - 04:20 AM
What question? the OP?
Yeah.

Can you post your api up? or if you dont wanna post it, pm it? because thats essentially how the unpack function works, it returns the values in a table as separate variables.
PM'd
theoriginalbit #6
Posted 21 March 2013 - 04:21 AM
PM'd
Reading…
KaoS #7
Posted 21 March 2013 - 05:33 AM
I find that using tables for arguments helps. it makes it possible to enter variable amounts of information without confusing things (for the user lol. sometimes coding it isn't easy)

also using for i=1,2 statements and maths helps me a ton

I'll quickly type you out a probably broken but most likely explanative example


local position = { x={1, 5}, y={1, 3} }
local colors = { colors.black, colors.white }
local btn = buttons.initButton("text",position,colors)

then what you can do is allow users to use it in many ways, they can enter tables, numbers, strings etc and you just treat them differently


local buttons = {}
function buttons.initButton( text, position, colors )
  local size = { term.getSize() }
  local alignments = { center=size[1]/2-text:len()/2, left=1, right=size[1]-text:len() }
  local newButton = {}
  newButton.position = {}
  for axis = 1, 2 do
	for part=1,2 do
	  newButton.position.[ ( part==1 and "start" or "end" ) .. ( axis==1 and "X" or "Y" ) ] =
        type(position)=="table" and
          (
          type(position[axis])=="table" and
            math[part==1 and "min" or "max"](unpack(position[axis]))
          or
            position[axis]
          )
        or
          type(position)=="string" and
            (
            part==1 and
              alignments[position[axis]]
            or part==2 and
              position[axis]
            )
	end
  end
  newButton.colors.text = type(colors)=="table" and colors[1] or colors
  newButton.colors.backGround = type(colors)=="table" and colors[2]

  --ADD WORKING FUNCTIONS LIKE POSITION.UNPACK ETC

  return newButton
end

that way you can say buttons.initButton("myText","center",colors.red) OR buttons.initButton("myText",{3,4},{colors.gray,colors.white} OR buttons.initButton("myText",{{1,2,3},{5,6,4}},colors.blue) OR EVEN buttons.initButton("myText",{{4,6},1})

CASES
1: use alignment center with text color red and background color nil
2: use startX 3 endX 3 startY 4 endY 4 text color gray and background color white
3: use startX 1 endX 3 startY 4 endY 6 text color blue and background color nil
4: use startX 4 endX 6 startY 1 endY 1 text color nil and background color nil

essentially making it foolproof to use and almost never error

EDIT: forgot to mention that you should adapt case 2 to automatically make endX = startX+text:len(). there is actually an almost limitless amount of stuff you can still add onto this example

EDIT 2: derpy derpy derp… the color assignment should not be in the for loop, corrected

EDIT 3: split the enormous line using my new line splitting technique inspired by remiX's awesome idea
Edited on 21 March 2013 - 05:00 AM
remiX #8
Posted 21 March 2013 - 05:41 AM
The button api uses metatables for OOP.
I just made my api for my CCYouTube program for now. It doesn't have much at the moment so no point of publishing it.
When more functions come into mind and added, I'll probably publish it then.

This is my current initButton function:
function initButton( text, pos, startX, startY, endY, bgCol, txtCol )
	local buttonObject = {
		name = text,
		pos = pos,
		startx =
			pos == 'center' and getCenter( #text, 1, screenX )
			or pos == 'centerLeft' and getCenter( #text, 1, math.floor( screenX / 2 ) )
			or pos == 'centerRight' and getCenter( #text, math.ceil( screenX / 2 ), screenX )
			or startX,
		endx =
			pos == 'center' and getCenter( #text, 1, screenX ) + #text - 1
			or pos == 'centerLeft' and getCenter( #text, 1, math.floor( screenX / 2 ) ) + #text - 1
			or pos == 'centerRight' and getCenter( #text, math.ceil( screenX / 2 ), screenX ) + #text - 1
			or startX + #text - 1,
		starty = startY,
		endy = endY,
		bgcol = bgCol,
		txtcol = txtCol
	}
	--
	return setmetatable(buttonObject, Buttons)
end

But I know what you mean by using tables helps users a lot.
You all scrammed the main part into one line lol :P/>/>
I honestly don't see why you should make a function that foolproof, the function should just be used in the correct way :P/>/>
KaoS #9
Posted 21 March 2013 - 05:52 AM
I like how you use OOP metatables, it reduces the number of functions you define drastically. metatables FTW :D/>

I honestly don't see why you should make a function that foolproof, the function should just be used in the correct way :P/>

I'm a perfectionist :)/> when I release something I want it to be the best it possibly can be, it must never break and must work as advertised even if you have no clue how to use it (which is why my current semi-active/spare time project bugs me so much. I released it too early)

You all scrammed the main part into one line lol :P/>

yeah, I had to. breaking that into multiple lines but keeping the same efficiency requires you to:
define additional variables,
repeat code or
use unnecessary functions

EDIT: your multiline approach is quite interesting… you just say "var = " and continue splitting lines. I expected you to at least need brackets around it. a very nice approach I must say


But I know what you mean by using tables helps users a lot.

it worries me though because I am not sure if Lua or more specifically LuaJ disposes of these random tables that you keep defining, if not then it is bad practice and I will have to find a better way
remiX #10
Posted 21 March 2013 - 05:59 AM
I'm a perfectionist :)/>/> when I release something I want it to be the best it possibly can be, it must never break and must work as advertised even if you have no clue how to use it (which is why my current semi-active/spare time project bugs me so much. I released it too early)
That's true I guess. There are some people that have no idea how to use a few things, even the easiest things.

yeah, I had to. breaking that into multiple lines but keeping the same efficiency requires you to:
define additional variables,
repeat code or
use unnecessary functions

EDIT: your multiline approach is quite interesting… you just say "var = " and continue splitting lines. I expected you to at least need brackets around it. a very nice approach I must say
Yeah that's what I meant. Why don't you split them into a few lines for easy-reading
I always do this, I never let the screen in Notepad++ to need to 'scroll' to the right, except for tables from paintutils.loadImage or something.
KaoS #11
Posted 21 March 2013 - 06:03 AM
Yeah that's what I meant. Why don't you split them into a few lines for easy-reading
I always do this, I never let the screen in Notepad++ to need to 'scroll' to the right, except for tables from paintutils.loadImage or something.

ok, edited. to be honest I didn't use n++, I typed that out in the forums <code> BBC code inserter thing
theoriginalbit #12
Posted 21 March 2013 - 03:05 PM
I'm a perfectionist :)/> when I release something I want it to be the best it possibly can be, it must never break and must work as advertised even if you have no clue how to use it (which is why my current semi-active/spare time project bugs me so much. I released it too early)
I actually agree with remiX an API shouldn't conform to the developer, the developer should conform to the API. The API is there to make their life easier. however that being said, instead of just some random error popping up somewhere, there should be asserts checking the parameters and telling them they gave a wrong parameter, instead of a silent error.

EDIT: your multiline approach is quite interesting… you just say "var = " and continue splitting lines. I expected you to at least need brackets around it. a very nice approach I must say
Languages that ignore whitespace FTW!


it worries me though because I am not sure if Lua or more specifically LuaJ disposes of these random tables that you keep defining, if not then it is bad practice and I will have to find a better way
tables that are parameters, get deallocated after the function has run along with the local variables and the auto generated args variable (which is a table of all the parameters)
KaoS #13
Posted 22 March 2013 - 01:47 AM
I'm a perfectionist :)/> when I release something I want it to be the best it possibly can be, it must never break and must work as advertised even if you have no clue how to use it (which is why my current semi-active/spare time project bugs me so much. I released it too early)
I actually agree with remiX an API shouldn't conform to the developer, the developer should conform to the API. The API is there to make their life easier. however that being said, instead of just some random error popping up somewhere, there should be asserts checking the parameters and telling them they gave a wrong parameter, instead of a silent error.

I don't mean it should silently error, I mean your API should figure out what they want and do it, even from the incorrect input

you may be correct about developers needing to use an API correctly but I think you can easily enough put in multiple correct methods, why not?
theoriginalbit #14
Posted 22 March 2013 - 01:52 AM
I don't mean it should silently error, I mean your API should figure out what they want and do it, even from the incorrect input

you may be correct about developers needing to use an API correctly but I think you can easily enough put in multiple correct methods, why not?
Well I normally tell them where they went wrong from their input. :)/>

True, but who wants to go to all that work :P/> other than you. have you ever heard of the Convention Over Configuration Design Paradigm?
KaoS #15
Posted 22 March 2013 - 02:13 AM
never heard of it :)/>

the way I see it why code at all? it's to make stuff, to learn and get better. why not make better, more intelligent stuff? if I am willing to put in the effort to code I am most certainly willing to put in the effort to code more thoroughly
theoriginalbit #16
Posted 22 March 2013 - 02:24 AM
never heard of it :)/>
The Convention Over Configuration Design Paradigm is all about reducing decisions of the developer and creating 'conventions' that they have to adhere to or the API, System Libraries, or Frameworks will not work and all they will get is errors. Android development heavily relies on this paradigm, but it is also found in OSes and iOS development too.


the way I see it why code at all? it's to make stuff, to learn and get better. why not make better, more intelligent stuff? if I am willing to put in the effort to code I am most certainly willing to put in the effort to code more thoroughly
Oh I don't disagree with creating more intelligent stuff, but I feel that an API doesn't need intelligence for developer interaction. Yes it can have intelligence for operation and front end stuff, just developer end shouldn't need it imo.

anyways this has got way off topic :P/>