BYU Home pageBRIGHAM YOUNG UNIVERSITY
  Office of Digital Humanities
Back     BYU LiveCode Lessons Gateway

DigHT 310
Custom Functions

Functions

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 the 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.

A Practical Example

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:

  1. Get the "native" height and width of the image. (Look up the formattedHeight and the formattedWidth in the LiveCode dictionary.)
  2. Decide on the resize factor. For example, you may want the image to be 2 times the original size, one-third the original size, or half the original size.
  3. Change both the height and the width by multiplying both by the factor:

    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
rectangle graphic showing dimensions

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.


Functions Exercise

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.


Back     BYU LiveCode Lessons Gateway
Maintained by Devin Asay.
Copyright © 2005 Brigham Young University