Ok so our aim in these tutorials is to create code and classes that can be reused. We are working up to a standard menu class which can be used in your programs. But we need to build some foundations first, and the good people at Two Lives Left have provided most of the sample code we need. Curious?
Now menus need buttons and buttons need a rounded rectangle, so let's start there. Open up the Codea example program called Sounds Plus. One of the tabs in this project is called RoundRect, which is exactly what we need. Tap on this tab. We want to copy this entire class and use it in our new Menu project. To do this, tap and hold on any of the text in this class to bring up the Selection pop up, then tap on Select All, and then Copy. Dismiss the keyboard and then tap the X in the bottom left corner.
Back at the Codea launch page, tap on Add New Project and call it Menu (or whatever else you want). You will have one class called Main which you would have seen in Tutorial 1. Tap on the + in the top right corner and then tap on Create New Class. Call the new class RoundRect and then tap done. This will generate three boiler plate functions which we don't need. Tap and hold on any of the text in the class, Select All and tap the delete key on the keyboard. Tap and hold on the empty screen to bring up the Paste pop up and tap that.
You should now have the RoundRect class which you copied from the Sounds Plus example code.
Let's have a bit of a look at the rounded rectangle class. I have inserted comments in green to help you understand what is happening.
The roundRect function has 5 variables. These are: roundRect(x, y, w, h, r)
x - the x co-ordinate of the lower left corner of the rounded rectangle y - the y co-ordinate of the lower left corner of the rounded rectangle
w - width of the rounded rectangle h - height of the rounded rectangle
r - radius of the corners
function roundRect(x,y,w,h,r) -- [[ pushStyle() saves the current graphic styles like stroke, width, etc. You can then do your thing and call popStyle at the end to return to this state.]] pushStyle() -- [[ insetPos and insetSize contain the co-ordinates for the internal "fill" rectangle. InsetPos.x = x, insetPos.y = y, insetSize.x = w and insetSize.y = h. In effect this creates a rectangle that is smaller than a factor of "r" within the rectangle co-ordinates specified in roundRect. ]] insetPos = vec2(x+r,y+r) insetSize = vec2(w-2*r,h-2*r) --Copy fill into stroke -- [[ Since Codea 1.3 you can retrieve the style information from all style functions by calling them without arguments. This way you only have to set the fill style once as you would for the normal rectangle function. You can read all about how this rounded rectangle function evolved on the Codea Forums.]] local red,green,blue,a = fill() stroke(red,green,blue,a) -- [[noSmooth() will disable smooth (unaliased) line drawing. It is useful for drawing thin lines. This initial rectangle is used to fill in the centre of your rounded rectangle, it has the usual 90 degree corners. Four lines are then drawn around this to give the rounded corner look. You can see this yourself by commenting out the 4 lines drawn below. ]] noSmooth() rectMode(CORNER) rect(insetPos.x,insetPos.y,insetSize.x,insetSize.y) if r > 0 then -- [[ You have to use smooth() if you want to use the ROUND option for lineCapMode. Four lines are now drawn around the filler rectangle. One on each edge. Because the lines have rounded ends when you overlap them it makes the corners look rounded, albeit a bit like a ball if you get the proportions wrong. Each of the lines are twice the width of the corner radius. ]] smooth() lineCapMode(ROUND) strokeWidth(r*2) line(insetPos.x, insetPos.y, insetPos.x + insetSize.x, insetPos.y) line(insetPos.x, insetPos.y, insetPos.x, insetPos.y + insetSize.y) line(insetPos.x, insetPos.y + insetSize.y, insetPos.x + insetSize.x, insetPos.y + insetSize.y) line(insetPos.x + insetSize.x, insetPos.y, insetPos.x + insetSize.x, insetPos.y + insetSize.y) end popStyle() end
So let's take our copied class for a spin. On my iPad (the original version), the dimensions of the drawing screen is:
Width - 750 pixels Height - 768 pixels
Sidebar: I'm not sure how the extra resolution of the iPad 3 are handled in Codea but I suspect the dimensions will be the same. You can find out your screen dimensions by adding the following two lines to the Hello World project that you created in Tutorial 1. Stick these in the setup() function.
print("Screen Width: "..WIDTH) print("Screen Height: "..HEIGHT)
One of the fab things about Lua is its ability to simply concatenate a string and a number using .. as shown in the print statement above. There is no need to convert the number to a string, it happens automagically.
Sidebar Update: As Hillary mentions in the comment below the iPad 3 has the same screen dimensions in the STANDARD display mode as the iPad 1 and 2. I should have mentioned that Codea lets you set one of three display modes using the function displayMode() - obvious huh. The three display modes available are:
In FULLSCREEN landscape mode the iPad 1 & 2 has screen dimensions of:
Height: 768 pixels Width: 1024 pixels
You can check this out yourself by sticking displayMode(FULLSCREEN) in the setup() function of the Hello World project that we did in Tutorial 1 and using text() in the draw() function to display the HEIGHT and WIDTH constants - note the output from print() is not visible in FULLSCREEN mode.
The iPad 3 has double the resolution of the earlier versions, i.e. in FULLSCREEN landscape mode -
Height: 1536 pixels Width: 2048 pixels
Tap on the Main tab in your Menu class and below the comment -- Do your drawing here add the following line of code. Note that the variables chosen aren't anything special, we are just trying to draw the rectangle near the centre of the screen. Try modifying the variables yourself to see the effect.
roundRect(WIDTH/2 - 150, HEIGHT/2, 300, 20, 30)
Run the program and you should end up with a gray rounded rectangle on your drawing screen. In the next tutorial we will turn this into a button.
Well not really that special - I should have mentioned that Codea is designed for fast prototyping and comes with some groovy functions to assist with this, namely parameter and iparameter.
parameter(name, min, max, initialValue) will populate your run screen with a visual slider which adjusts the value of the global variable called name between the min and max values specified, starting at the initial value. The difference between parameter and iparameter is that parameter gives you a float variable while iparameter will give you an integer. You usually stick these in the setup() function of your Main class.
There are a couple of example projects provided with Codea which illustrate the use of parameters but let's give them a spin on our rounded rectangle class. Update the Main class in our menu project to look like the following.
function setup() print("Rounded Rectangle Fast Prototype") -- parameter provides a float parameter(name, min, max, initialValue) parameter("x", 0, WIDTH, WIDTH/2 - 150) parameter("y", 0, HEIGHT, HEIGHT/2) parameter("w", 0, WIDTH, 300) parameter("h", 0, HEIGHT, 21) parameter("r", 0, 200, 30) end -- This function gets called once every frame function draw() -- This sets a dark background color background(40, 40, 50) -- Do your drawing here roundRect(x, y, w, h, r) end
Now run the program and note how moving the sliders changes the variables which effect your rounded rectangle. You can see how easily you could play with this to get exactly the shape you were after. You could then note down the variables required to reproduce that shape in your code.