How do I define my own properties for an object?
This lesson shows how to store custom properties in an object, and how to define getProp/setProp handlers to customize behaviour when getting/setting custom properties
All objects in LiveCode have properties: built-in properties such as the name, width & height of an object, and custom properties which can be used to store any kind of information associated with that object.
The built-in properties often have an immediate effect on the appearance or behaviour of an object, whereas custom properties require some scripting on behalf of the LiveCode programmer to have an effect.
Setting and Getting Custom Properties
The syntax for accessing custom properties is the same as that used to access built-in properties so it is important to choose names for custom properties that are different from the built-in object properties to avoid confusion.
One common approach to custom property naming is to prefix the names of custom properties with a lowerspace 'c' character. As an example, if we wish to store a name and location within an object as a custom property, we could do the following:
set the cName of field "livecode" to "LiveCode Ltd." set the cLocation of field "livecode" to "Edinburgh"
The "name" and "location" properties are built-in and common to all objects, so cannot be used as the names of our custom properties.
getProp and setProp Handlers
If we want our custom properties to be more than just static collections of data, we need a way to script how an object behaves when these properties are accessed. This is done by defining
setProp handlers for each custom property.
Using a getProp handler allows us to define a custom property as a function which returns a value computed at the time the property is requested.
To define a getProp handler for a property, the following syntax is used:
getProp <propertyName> /* the script which calculates the value to return goes here ... */ return <propertyValue> end <propertyName>
The following code shows an example of a getProp handler for a "longestline" property, which gives the longest line in a field or other text-containing object:
getProp longestLine local tLongestLine, tLongestLength, tLineLength put 0 into tLongestLength repeat for each line tLine in the text of me put the number of chars in tLine into tLineLength if tLineLength > tLongestLength then put tLineLength into tLongestLength put tLine into tLongestLine end if end repeat return tLongestLine end longestLine
By adding setProp handlers to an object we can reduce complex operations to simple one-line scripts. As an example, lets consider rotating a polygon through a given angle. The built-in angle property has no effect on freehand polygons, but we can use the utility function revRotatePoly. revRotatePoly modifies the points of a polygon in such a way that repeated uses of the function can deform the points of our polygon, so we also need to save the points of the polygon and restore these original points before rotation. To simplify this process we can encapsulate this behaviour within a setProp handler for a new property "rotation" that acts as an angle property for freehand polygons:
setProp rotation pValue local tPoints, tLoc lock screen put the loc of me into tLoc if the cOldPoints of me is empty then // save the points before rotation put the points of me into tPoints set the cOldPoints of me to tPoints else // restore the saved points put the cOldPoints of me into tPoints set the points of me to tPoints end if if pValue is 0 or pValue is empty then set the cOldPoints of me to empty else revRotatePoly (the long id of me), pValue end if set the loc of me to tLoc unlock screen end rotation
We can now use this property to rotate our polygon simply by setting the rotation property.
Note that defining a getProp or setProp handler for a custom property bypasses LiveCode's normal mechanism for storing custom properties, however we can still store them as normal within the property handler itself. When a property handler for a particular custom property attempts to access that same custom property, rather than invoking the property handler in a infinite recursive loop, the custom property is accessed directly, rather than through the handler.
This example shows how to access and modify a custom property which is otherwise "masked" by the getProp handler:
getProp nextValue local tNextValue // this access of nextValue will not result // in the getProp handler being called again put the nextValue of me into tNextValue if tNextValue is empty then put 1 into tNextValue set the nextValue of me to tNextValue + 1 return tNextValue end nextValue
With this handler, every time we get the nextValue of an object, the stored property is incremented so that the next time we get the nextValue it will have increased by 1.