Functions are like questions that you ask of LiveCode. You give LiveCode
some information using a function, and a value is returned to you based on that
information. Some functions, like
the date and
time, return a value reflecting the current state of the system.
The value of a function can change depending on circumstances; LiveCode calculates a function's
current value at the time and under the conditions it is called.
LiveCode provides many built-in functions. They can appear in two forms: the "algebraic" form, in which the arguments are enclosed in parentheses and the "prose" form with no parentheses. So function calls in this format:
put random(15) into myRandom
put sqrt(16) into mySqRt
are functionally identical to function calls in this format:
put the random of 15 into myRandom
put the sqrt of 16 into mySqRt
You can also write your own, custom-made functions to do specialized calculations
and data manipulation. Writing a function handler is very similar to writing
a message handler, except that it begins with the keyword
function instead of
on. It must also include a
return statement as the last statement in the handler. Here is an example of a custom function, which takes as an input the full file path to a file on the local file system and returns the path to the enclosing folder.
function enclosingFolder pFilePath set the itemDelimiter to "/" delete last item of pFilePath return pFilePath end enclosingFolder
Custom functions work just like built-in ones, except that you can only use the "parentheses" form, not the "prose" form that is allowed only for built-in functions. Here is how I could use this custom function, if I wanted to know where the current stack file is saved. I would first create the custom function above,
enclosingFolder, in my stack script, then call it in any handler in that stack, like this:
put enclosingFolder(the filename of this stack) into tFolderPath
More in depth explainations and examples are available in the stack FunctionsLecture.rev, available in the lesson_materials folder on the class web server. You may download it directly by right-clicking (Windows) or Control-clicking (Mac) on the stack name above and choosing Download link or Save link to disk (or whatever wording your web browser uses) from the popup menu. Or, as always, you can open LiveCode and enter
go stack url "http://dight310.byu.edu/lesson_materials/03_functions/FunctionsLecture.rev"
into your message box.
Let’s look at a practical problem that we could solve with a well-written function. In an older DigHT assignment that is no longer used Web-based Content Assignment students were to devise a way to resize the graphics being displayed so that they would fit into the available space on the card. This means that for each referenced image you display, you need to determine how much it would need to be resized in order to fit. The process is similar for each image and can be solved using a generalized algorithm (a set of well-defined steps)—in other words, this is a perfect candidate for a function.
The algorithm for proportionally resizing an image—or indeed any rectangular object—is straightforward:
the formattedWidthin the LiveCode dictionary.)
newHeight = origHeight X resizeFactor
newWidth = origWidth X resizeFactor
In LiveCode the code would look like this:
put the formattedWidth of image "mypic.jpg" into nativeWidth put the formattedHeight of image "mypic.jpg" into nativeHeight put 2 into resizeFactor -- assuming you want to enlarge the image by 2X set the width of image "mypic.jpg" to nativeWidth * resizeFactor set the height of image "mypic.jpg" to nativeHeight * resizeFactor
We’re part of the way there. In the example above we arbitrarily chose a resize factor—a bad practice if you want to write flexible code. What we need instead is a way to figure out the ideal dimensions, height and width, that we want to constrain the image to. One way to do this is to create a rectangle graphic and size it to exactly the maximum height and width that no image should ever exceed. Then we can calculate how much the image would have to grow or shrink to fit within that area.
In the illustration at right the image is both too wide and too tall to fit within the maximum dimensions outlined by the graphic "maxDim". We’ll work first with the width. By dividing the width of the graphic by the width of the image we can come up with the resize factor. Then we simply use that factor in our algorithm:
put the formattedWidth of image "windmills.jpg" into nativeWidth put the formattedHeight of image "windmills.jpg" into nativeHeight put the width of grc "maxDim" / nativeWidth into resizeFactor set the width of image "windmills.jpg" to nativeWidth * resizeFactor set the height of image "windmills.jpg" to nativeHeight * resizeFactor
Now, we could just insert this algorithm into our code, and then repeat it with slight variations to adjust the height, as needed. But we want to create a function that will be more useful in a general sense. So imagine a function that would take as input parameters the image dimensions and the maximum dimensions and return the new dimensions for both the height and the width of the image object. It might look something like this:
on mouseUp put the formattedWidth of image "windmills.jpg" into nativeWdth put the formattedHeight of image "windmills.jpg" into nativeHgt put the width of graphic "maxDim" into maxWdth put the height of graphic "maxDim" into maxHgt # here is the function call put constrainedDimensions(nativeWdth,nativeHgt,maxWdth,maxHgt) into newDimensions set the width of image "windmills.jpg" to item 1 of newDimensions set the height of image "windmills.jpg" to item 2 of newDimensions set the loc of image "windmills.jpg" to the loc of graphic "maxDim" end mouseUp ## this function handler would probably be in the stack or card script function constrainedDimensions oldW,oldH,maxW,maxH # check to see if width is different from the max width if oldW <> maxW then put maxW / oldW into resizeFactor put oldW * resizeFactor into newW put oldH * resizeFactor into newH end if # now check to see if the height is still too large if newH > maxH then put maxH / newH into resizeFactor put newW * resizeFactor into newW put newH * resizeFactor into newH end if # return the new dimensions return newW,newH end constrainedDimensions
While at first glance this may appear a little more complicated than the original code, notice that the new function is written in such a way that you could use it to proportionally resize any object to fit into an ideal-sized area. For example, if I wanted to fit a field into the area defined by graphic "maxDim", while still retaining the field's original height to width ratio, all I would have to do is to call the same function:
put constrainedDimensions(the width of fld "myFld",the height of fld "myFld",the width of grc "maxDim",the height of grc "maxDim") \ into newDims set the width of fld "myFld" to item 1 of newDims set the height of fld "myFld" to item 2 of newDims
A well-written function handler can save you work in the long run by allowing you to reuse code in different settings.
1. Complete the Functions Exercise as outlined in the FunctionsExTemplate.rev stackfile (at http://dight310.byu.edu/lesson_materials/03_functions/FunctionsExTemplate.rev). Download your own copy from the Templates folder and rename it so your name is on the file.
2. Read LiveCode developer Geoff Canyon's article about functions. While I don't agree with his ideas in every detail, it is an excellent discussion of how to write good functions and when to use functions rather than handlers. At the end of the article is a section called Postscript -- Examples where he gives some ideas for cases in which you might want to write a function. Take the third example, Quoting Text, and write a function in your Functions Exercise stack that will do what the example describes. On the last card at the end of your Functions Exercise stack create a demonstration of the use of this new function.
Turn it in to the homework drop folder when you're done. As always, the key to this exericse is in the Keys folder for your reference if you get stuck.