New LiveCode User Guide: Version 2016 8.1
New LiveCode User Guide: Version 2016 8.1
LCB
LCB
LCB
LCB
bug xes
bug xes
bug xes
bug xes
(8.1.0-rc-1)
(8.1.0-dp-3)
(8.1.0-dp-2)
(8.1.0-dp-1)
Properties
Specic extension bug xes (8.1.0-dp-3)
Dictionary additions
Previous release notes
LiveCode Script
Introduction
Welcome
Where to Begin
System Requirements
All Operating Systems
Requirements for Windows Systems
Requirements for Linux Systems
Requirements for Mac OS X Systems
Using the Documentation
Documentation Conventions
Menu Reference
Keyboard Shortcuts
Screen Snapshots
Navigating the Documentation
Start Center
Social Media Links
Recent Stacks
Quick Links
Dictionary
LiveCode APIs
LiveCode User Guides
RevOnline
Additional Resources
Developer Community
Technical Support
Getting Started
Prerequisites
Event Driven Programming
Object-Based Programming
The Edit and Run Mode
Structuring your Application
Cards, Stacks & Files
3
Implicit Parameters
Passing Parameters by Reference
Empty parameters
Returning Values
Returning an Error from a Message Handler
Summary
Variables
Variable Scope
Local Variables
Script Local Variables
Global Variables
Variable Names
Special Variable Types
Parameter variables
Environment variables
Command-line argument variables
The special variable "it"
Array Variables
Deleting Elements of an Array
Listing the Elements in an Array
Listing Nested Elements within an Element
Transforming a List of Data into an Array
Combining the Elements of an Array into a List
Nesting an Array
More Information
Constants
Built-in constants
User-dened constants
Containers, Operators & Sources of Value
What is a Container?
Setting and Retrieving Data from Containers
What are Sources of Value?
Getting and Setting Properties
What are Literal Strings?
Using Literal Strings
Quoting strings
What are Operators?
Numeric Operators
String operators
Logical Operators
Binary versus Unary Operators
Conversion of Values
Operator Precedence
Using the Grouping Operator ()
Factors and Expressions
Dening Factors
When it matters
Making Decisions
If then else
Switch
Extending the Message Path
Creating a Code Library
Using backScripts
Using frontScripts
Using a Stack's Script with start using
Sending Messages Directly to Objects
The send Command versus the call Command
Writing reusable code using behaviors
Timer Based Messaging
Delivering a Message in the Future
Repeating a Timer Message
Canceling a Timer Message
Displaying a List of Pending Timer Messages
Tips for Writing Good Code
Variable naming
Variable scope
Use of comments
Use of functions
Explicit Variables
Programming a User Interface
Introduction
Referring to Objects
Referring to objects by name
Referring to objects by number
Referring to objects by ID
Referring to objects by ordinal
The special descriptor this
Control references
Nested Object References
Properties
7
Virtual Properties
When to use virtual properties
Handlers for a virtual property
Creating new object properties
Property Proles
Prole names
The master prole
Switching between proles
Creating a prole in a handler
Adding prole settings in a handler
Managing Windows, Palettes and Dialogs
Moving a window
Changing a window's layer
The active window
Creating a backdrop
Open, Closed, and Hidden Windows
The states of a stack
Window Types and the Mode Property
Window Appearance
The Decorations Property
Making a stack resizable
Irregularly-Shaped and Translucent Windows
Programming Menus & Menu Bars
Menu Types
Button Menus
Creating Cascading Menus
Ticks, Dashes & Checks in Menus
Menu Bars on Linux and Windows Systems
Menu Bars on Mac OS X Systems
Stack Menus
Displaying Context Sensitive Menus
Searching and Navigating Cards using the Find Command
Using Drag and Drop
Initiating a Drag Drop
Tracking During a Drag Drop Operation
Responding to a Drag and Drop
Prevent Dragging and Dropping to a Field
Error Handling & Debugging
Introduction
Common Techniques for Solving Problems
Errors During Execution
9
12
Test
How Can I Colorize Individual Lines in a Table?
Attached Files
Coloring a Single Line
The Default Custom Column Behavior
Working With Data Grid Forms
How Do I Create a Form With Variable Line Heights?
Turn O "Empty row height"
Edit Row Template
Turn O dontWrap Property
Edit Row Behavior
Script Field to Resize to Fit Height
Refresh Data Grid Contents
How Do I Sort Records by a Specic Key's Values?
Example
Option Menu Code
The Result
How Do I Create Rows That Can Expand/Contract?
Attached Files
Expanding and Contracting Rows
Setting the Data Grid Properties
Updating the Row Behavior Script
How Can I Speed Up Drawing When "Fixed Row Height" Is False?
CalculateFormattedHeight
Using the Built-in Field Editor
How Do I Open a Table Cell for Editing?
What You Need to Know
EditFieldText
EditValue
EditCell and EditCellOfIndex
CloseFieldEditor
How Can the User Edit Field Content in a Data Grid Form?
What You Need to Know
EditFieldText
EditValue
EditKey and EditKeyOfIndex
CloseFieldEditor
How Can I Edit the Text as UTF-8, UTF-16 or HTML?
15
Character Chunk
Segment Chunk
Item Chunk and the itemDelimiter Property
Line Chunk and the lineDelimiter Property
Other chunks
Specifying a Chunk
Negative Indexes in Chunk Expressions
Complex Chunk Expressions
Using Parentheses in Chunk Expressions
Nonexistent Chunks
Nonexistent character or segment:
Nonexistent item:
Nonexistent line:
Specifying a Range
Counting the Number of segments, Lines or Items
Comparing and Searching
Checking if a Part is within a Whole
Case Sensitivity
Checking if text is True, False, a Number, an Integer, a Point,
a Rectangle, a Date or a Color
Check if a segment, Item or Line Matches Exactly
Check if one String Starts or Ends With Another
Replacing Text
Retrieving the Position of a Matching Chunk
Chunks Summary
Regular Expressions
Searching using a Regular Expression
Replacing using a Regular Expression
Filtering using a Wildcard Expression
International Text Support
What are Text Encodings?
What are scripts?
Introduction to Unicode
18
19
Absolute le paths
Relative le paths
Finding the current folder
Going up to the parent folder
Going up multiple levels
Starting at the home directory
When to use relative and absolute le paths
Special Folders
File Types, Application Signatures & File Ownership
Windows File Extensions and Ownership
Applications that don't own les
Applications that own their own les
Installing custom icons
Custom application icons
Custom le icons
File extensions
OS X File Types and Creators
Applications that don't own les
Applications that own their own les
Creating Files
File extensions
Mac OS X Classic File Types and Creators
Applications that don't own les
Applications that own their own les
Installing custom icons
Custom application icons
Linux File Extensions
Working with URLs
An Overview of URLs
URL Schemes
The http scheme
The ftp scheme
Directories on an FTP server
The le scheme
File path syntax and the le scheme:
Conversion of end-of-line markers
The binle scheme
The resle scheme
Creating a resource fork
20
File Menu
Edit Menu
Tools Menu
Object Menu
Text Menu
Development Menu
View Menu
Window menu
Help Menu
Breakpoint Management
The Script Editor Menubar
The
The
The
The
The
File Menu
Edit Menu
Debug Menu
Handler Menu
Window Menu
24
Mac Deployment
Introduction
64-bit engine features
The IDE
How to deploy a 64-bit Mac standalone
Building
Testing
Reporting bugs
Extending LiveCode
Introduction
LiveCode Builder Extensions
Creating LiveCode Builder Extensions
Extension Builder
Create your Own Simple Widget
Create a .lcb le
Declare Type and Identier
Declare Meta Data
Importing libraries
Core Handlers
Draw a Pink Circle
Test the Code
Properties
Loading and Saving widget data
Understanding Error Messages
LiveCode Builder API
Creating Libraries
Loading and Creating Widgets Manually
Composed Widgets
A simple composed widget
Documenting Your Extension
Adding API Markup
Adding a User Guide
Packaging Extensions
Package requirements
Other ways to extend the Built-in Capabilities
Communicating with other process and applications
Reading and writing to the command shell
Launching other applications
Closing another application
25
26
Statements
Variable Statements
If Statements
Repeat Statements
Throw Statements
Return Statements
Transfer Statements
Call Statements
Bytecode Statements
Unsafe Statements
Expressions
Constant Value Expressions
Variable Expressions
Result Expressions
List Expressions
Array Expressions
Call Expressions
LiveCode Builder Style Guide
Introduction
Copyright headers
Naming
Module name
Naming variables and parameters
Naming handlers
Documenting the source code
Named constants
Whitespace
Indentation
Handler declarations, denitions and calls
LiveCode Documentation Format Reference
Introduction
Format
Element names
Name (required)
Synonyms
Type (required)
Syntax (required for API-level entries)
Summary (required)
Associated
Introduced
OS
Platforms
27
Example
Parameters
Value and return parameters
Description (required)
References
Tags
Other documentation syntax
Separate docs les
Inline documentation
Separate docs les examples
Dictionary example
Library example
Inline examples
LiveCode Builder syntax example
LiveCode Builder handler example
LiveCode script handler example
28
Overview
LiveCode 8.1 provides important improvements for delivering high-quality cross-platform
applications!
LiveCode Indy and Business editions now come with the tsNet external, which supercharges
LiveCode's Internet features and performance. LiveCode 8.1 also introduces mergHealthKit,
for accessing activity, sport and health data on iOS devices.
The standalone builder now has a greatly-improved user experience for including externals,
script libraries and LiveCode Builder extensions in your cross-platform application. Usually,
it'll now do the right thing automatically, but you can still select the specic inclusions you
need.
The IDE has lots of other upgrades, too: a keyboard-navigable Project Browser that
highlights any scripts that failed to compile, an improved dictionary user interface, and
access to the message box just by starting to type.
The player control can be used in Windows application without any need for users to install
any additional libraries or dependencies, thanks to a brand new player implementation
based on DirectShow. For most apps, it should now be unnecessary to install or use
QuickTime at all.
The LiveCode Builder programming language has had some enhancements as part of the
Innite LiveCode project. Variables now get initialised by default, unsafe blocks and
handlers can be used to ag sections of code that do dangerous things, and you can even
include raw bytecode if necessary.
29
Known issues
The installer will currently fail if you run it from a network share on Windows. Please copy the
installer to a local disk before launching on this platform.
The browser widget does not work on 32-bit Linux.
64-bit standalones for Mac OS X do not have support for audio recording or the
revVideoGrabber external.
30
Platform support
The engine supports a variety of operating systems and versions. This section describes the
platforms that we ensure the engine runs on without issue (although in some cases with reduced
functionality).
Windows
LiveCode supports the following versions of Windows:
Windows
Windows
Windows
Windows
Windows
Windows
Windows
Note: On 64-bit Windows installations, LiveCode runs as a 32-bit application through the WoW
layer.
Linux
LiveCode supports the following Linux distributions, on 32-bit or 64-bit Intel/AMD or compatible
processors:
Ubuntu 14.04 and 16.04
Fedora 23 & 24
Debian 7 (Wheezy) and 8 (Jessie) [server]
CentOS 7 [server]
LiveCode may also run on Linux installations which meet the following requirements:
Required dependencies for core functionality:
glibc 2.13 or later
GLib 2.0 or later
Optional requirements for GUI functionality:
GTK/GDK 2.24 or later
Pango with Xft support
esd (optional, needed for audio output)
mplayer (optional, needed for media player functionality)
lcms (optional, required for color prole support in images)
gksu (optional, required for privilege elevation support)
Note: If the optional requirements are not present then LiveCode will still run but the specied
features will be disabled.
Note: The requirements for GUI functionality are also required by Firefox and Chrome, so if your
31
Mac
The Mac engine supports:
10.6.x (Snow Leopard) on Intel
10.7.x (Lion) on Intel
10.8.x (Mountain Lion) on Intel
10.9.x (Mavericks) on Intel
10.10.x (Yosemite) on Intel
10.11.x (El Capitan) on Intel
iOS
iOS deployment is possible when running LiveCode IDE on a Mac, and provided Xcode is installed
and has been set in LiveCode Preferences (in the Mobile Support pane).
Currently, the supported versions of Xcode are:
Xcode
Xcode
Xcode
Xcode
Xcode
It is also possible to set other versions of Xcode, to allow testing on a wider range of iOS
simulators. For instance, on Yosemite, you can add Xcode 5.1 in the Mobile Support preferences,
to let you test your stack on the iOS Simulator 7.1.
We currently support the following iOS Simulators:
6.1
7.1
8.2
9.2
9.3
Android
LiveCode allows you to save your stack as an Android application, and also to deploy it on an
Android device or simulator from the IDE.
Android deployment is possible from Windows, Linux and Mac OSX.
The Android engine supports devices using ARMv6, ARMv7 or ARMv8 processors. It will run on the
following versions of Android:
32
2.3.3-2.3.7 (Gingerbread)
4.0 (Ice Cream Sandwich)
4.1-4.3 (Jelly Bean)
4.4 (KitKat)
5.0-5.1 (Lollipop)
6.0 (Marshmallow)
To enable deployment to Android devices, you need to download the Android SDK, and then use
the 'Android SDK Manager' to install:
the latest "Android SDK Tools"
the latest "Android SDK Platform Tools"
You also need to install the Java Development Kit (JDK). On Linux, this usually packaged as
"openjdk". LiveCode requires JDK version 1.6 or later.
Once you have set the path of your Android SDK in the "Mobile Support" section of the LiveCode
IDE's preferences, you can deploy your stack to Android devices.
Some users have reported successful Android Watch deployment, but it is not ocially supported.
HTML5
LiveCode applications can be deployed to run in a web browser, by running the LiveCode engine in
JavaScript and using modern HTML5 JavaScript APIs.
HTML5 deployment does not require any additional development tools to be installed.
LiveCode HTML5 standalone applications are currently supported for running in recent versions of
Mozilla Firefox, Google Chrome or Safari. For more information, please see the "HTML5
Deployment" guide in the LiveCode IDE.
33
Setup
Installation
Each version of LiveCode installs can be installed to its own, separate folder. This allow multiple
versions of LiveCode to be installed side-by-side. On Windows (and Linux), each version of
LiveCode has its own Start Menu (or application menu) entry. On Mac OS X, each version has its
own app bundle.
On Mac OS X, install LiveCode by mounting the .dmg le and dragging the app bundle to the
Applications folder (or any other suitable location).
For Windows and Linux, the default installation locations when installing for "All Users" are:
Platform
Path
Windows
Linux
/opt/livecode/livecode-<version>
Path
Windows
Linux
~/.runrev/components/livecode-<version>
Note: If installing for "All Users" on Linux, either the gksu tool must be available, or you must
manually run the LiveCode installer executable as root (e.g. using sudo or su).
Uninstallation
On Windows, the installer hooks into the standard Windows uninstall mechanism. This is accessible
from the "Add or Remove Programs" applet in the windows Control Panel.
On Mac OS X, drag the app bundle to the Trash.
On Linux, LiveCode can be removed using the setup.x86 or setup.x86_64 program located in
LiveCode's installation directory.
Path
Windows 2000/XP
Windows Vista/7
<users folder>/<user>/AppData/Local/RunRev/Logs
Linux
<home>/.runrev/logs
Command-line installation
It is possible to invoke the installer from the command-line on Linux and Windows. When doing
command-line installation, no GUI will be displayed. The installation process is controlled by
arguments passed to the installer.
Run the installer using a command in the form:
where <installer> should be replaced with the path of the installer executable or app (inside
the DMG) that has been downloaded. The result of the installation operation will be written to the
console.
The installer understands any of the following OPTION s:
Option
Description
-allusers
Install the IDE for "All Users". If not specied, LiveCode will be installed
for the current user only.
desktopshortcut
-startmenu
-location
LOCATION
The folder to install into. If not specied, the LOCATION defaults to those
-log LOGFILE
Note: the command-line installer does not do any authentication. When installing for "All Users",
you will need to run the installer command as an administrator.
As the installer is actually a GUI application, it needs to be run slightly dierently from other
command-line programs.
On Windows, the command is:
Command-line uninstallation
It is possible to uninstall LiveCode from the command-line on Windows and Linux. When doing
command-line uninstallation, no GUI will be displayed.
Run the uninstaller using a command of the form:
Where is .setup.exe on Windows, and .setup.x86 on Linux. This executable, for both of the
platforms, is located in the folder where LiveCode is installed.
The result of the uninstallation operation will be written to the console.
Note: the command-line uninstaller does not do any authentication. When removing a version of
LiveCode installed for "All Users", you will need to run the uninstaller command as an
administrator.
where <livecode> should be replaced with the path to the LiveCode executable or app that has
been previously installed.
This loads license information from the manual activation le LICENSEFILE , decrypts it using the
given SECRET passphrase, and installs a license le for all users of the computer. Manual
activation les can be downloaded from the My Products page in the LiveCode account
management site.
36
<livecode> deactivate
Since LiveCode is actually a GUI application, it needs to be run slightly dierently from other
command-line programs.
On Windows, the command is:
37
Engine changes
Change in empty is among the items of 1,2,3, behavior
(8.1.0-rc-2)
In previous versions of LiveCode is among the items of behaved incorrectly when a trailing
delimiter was present. Trailing delimiters are generally ignored in the LiveCode engine and legacy
behaviors where they are not are documented anomalies that are maintained for backwards
compatibility reasons. This change resolves the anomaly detailed in bug report 16297
For example:
put the number of items of "1,2,3," is 3 --> puts true in all engines
put empty is among the items of "1,2,3," --> puts true in LiveCode 6
put empty is among the items of "1,2,3," --> puts false in LiveCode 8
Warning If your stacks depend on the legacy anomalous behavior they should be
checked to ensure all trailing empty items are wrapped by an item delimiter
Filtering array keys and elements has been added to the lter
command (8.1.0-rc-1)
The lter command now supports the ltering of arrays by matching keys or elements.
Example:
local tArray
put true into tArray["foo"]
put false into tArray["bar"]
filter keys of tArray with "f*"
put the keys of tArray is "foo"
Use the scriptStatus of <object> to determine the status of the last time the script
property was set or the script was compiled when the stack was opened.
return files("/path/to/target/directory")
When running in a command handler, the 'return ... for value' form will cause execution of the
handler to halt, and control to return to the calling handler. At this point the 'it' variable in the
40
calling handler will be set to 'value' and 'the result' will be set to empty. In contrast, the 'return ...
for error' form will cause the 'it' variable in the calling handler to be set to empty and 'the result' to
be set to 'value'.
When running in a function handler, the 'return ... for value' form will cause execution of the
handler to halt, and control to return to the calling handler. At this point the return value of the
function call will be 'value', and 'the result' will be set to empty. In contrast, the 'return ... for error'
form will cause the return value of the function call to be empty, and 'the result' will be set to
'value'.
These forms of return are designed to be used by script library functions to allow them to have
the same ability as built-in engine functions and commands - namely the ability to return a value
(in it for commands, or return value for functions) or return a status (in the result).
vectorDotProduct(tArray1, tArray2)
Will compute:
If the two arrays do not have the same set of keys, then an error is thrown.
the state of the key at the time the function was called. However, it is often desireable to check
the state of the key at the time the event was generated and this is not possible using these
functions.
New functions called "eventAltKey", "eventShiftKey", etc have been added; these return the state
of the key at the time the event began processing. This is useful in keyDown and rawKeyDown
handlers to check whether a modier was pressed at the time the key the event relates to was
pressed (if the non-event forms are used instead, there is a chance the modier key has been
released and the wrong result will be generated).
Note that the "eventXXXKey" functions should not be called after a wait; their value is undened
after any form of wait has occurred.
mobileGetLocationHistory
mobileSetLocationHistoryLimit
mobileGetLocationHistoryLimit
42
Whenever a system locationChanged event occurs, the location reading is pushed onto the
front of a list. The list is capped at the length set by the location history limit, dropping any old
samples over this length.
The mobileGetLocationHistory function returns a numerically keyed array of all accumulated
samples since the last time it was called with lower indices being older samples. Calling the
function clears the internal history.
Each element in the array is the same format as the detailed location array as returned from the
mobileSensorReading function.
If an application wants historical access to all samples, then it should set the location history limit
to the maximum number of samples it ever wants to record, or 0 to record the entire history
(between calls to mobileGetLocationHistory ).
The best way to use the history is to fetch the list in locationChanged and process each sample
in turn, rather than the sample provided with the locationChanged event (which will always be
the last sample in the history). e.g.
on locationChanged
local tHistory
put mobileGetLocationHistory() into tHistory
repeat for each element tSample in tHistory
processLocationChanged tSample
end repeat
end locationChanged
The default history limit is 1 meaning that only one sample is ever kept at a time.
then the 'SVG Path' widget and all its dependencies will be included.
The standalone builder 'Search for required inclusions...' option now supports mobile deployment,
both to device and simulator.
Property Changes
On Windows, the behaviour of some properties of the player control have changed.
The loadedTime property previously did not work on Windows, but now does.
The alwaysBuer, enabledTracks, mediaTypes, mirrored, trackCount and tracks
properties do not currently work, but will be re-enabled in a subsequent release.
On all platforms, the following player control properties, which are specic to QuickTime and QTVR,
have been deprecated: constraints, currentNode, movieControllerId, nodes, pan, tilt, and
zoom.
<key>com.apple.developer.homekit</key>
<true/>
44
savingStandalone and standaloneSaved should only be sent once when building for
multiple platforms
For external libUrl drivers, call the external function lvExtIsBlocked() to check for
existing blocking connections
18261
Fixed crash on 64-bit iOS simulator when tsNet/Internet lib is included in the
standalone
Clean up empty folders after moving Copy files to resources folder in Mac
standalones
45
18220 Ensure all relevant LCB interface les are present in IDE
18222 Fix widgets not being saved when on substack but not on main stack
18226 Make sure database drivers are included in the standalone
18248 Display appropriate error when trying to build script only standalones
18251 Fix video of player not automatically resized when setting lename
6530
7214
7344
Correct named shades of gray (Gray1-100) to match the X11 color names
Return an empty item instead of a random value if altitude reading is not available on
iOS
47
IDE changes
Script compilation errors are now indicated on the project
browser (8.1.0-rc-1)
The Project Browser will now indicate objects that have scripts that were not able to be compiled.
The script line number indicator will appear red for scripts with errors.
My LiveCode/Interactive Tutorials/courses/Database
Course/tutorials/SQLite/lessons/1. Introduction.txt
There is now an 'Inclusions' pane which allows the user to select from a complete list of available
inclusions. The list contains information about which platforms are supported.
The 'Inclusions' pane signicantly improves the cross-platform development experience provided
by LiveCode (since the iOS and Android panes no longer have separate check boxes for the
various built-in externals such as revxml), as well as paving the way for much better extensibility
in the future.
17693 Correctly identify the stack when building a standalone from the project browser
17696 Player control's default video doesn't work in Windows player
17863 Improve message box autocompletion and error handling
17870 Improved speed of formatting scripts
17902 Ensure apply button on variable visualiser enables correctly
17925 Ensure LCB modules are recompiled when lc-compile is updated
17991 Make Windows systemVersion handling in revDeleteFolder more robust
18026 Maintain scroll when focussing in on inclusions card in standalone build
18047 Fix object grouping menu items from contextual menus
18053 Use appropriate cursors for selection handles
18134 Colorize the message box with script colorization settings
18140 Move text properties to text pane of PI
18158
[Project Browser] Fix distorted view with nested groups and object_type_indicator ==
name
18166 Windows menu now shows stack names while the LC script window is on top
18169 [Extension Builder] Make sure scrollbar is visible when console_content > eld_height
18170 [Extension Builder] Make console content selectable and thus enable copying
18174 Sort Script Editor handler list alphabetically per each dierent type
18175 Present a warning dialog if preserving stack le version will result in data loss
18183 Give the focus to the search box in the API Reference when it opens
18208 Make sure that le selector for eld contents allows "All Files"
18214 Typo in LiveCode Builder doc
18249 Removed double extension of script only stacks on Linux and Windows
4695
50
7157
Make sure "move" command results in smooth movement when executed from the
msg box
296
8985
51
Variables
Out parameters are now initialized by default to a suitable empty value at the start of the
handler. For example:
52
repeat 5 times
variable tVar as optional String
-- tVar is reset to "nothing" every time the loop runs
end repeat
Variables in an inner block can now shadow those in an outer block. For example, the
following is valid:
variable tX as Array
repeat 5 times
variable tX as Number
repeat 4 times
variable tX as String
end repeat
end repeat
Typed variables are now initialised by default to a suitable empty value. For example:
Bytecode Blocks
bytecode can now be directly written in handlers using a bytecode block:
bytecode
register tTemp
assign_constant tTemp, 1
end bytecode
for more details on what bytecode operations can be used see the LiveCode Builder
Bytecode Reference
bytecode blocks are not for general use and the current set of bytecode operations are
53
subject to change
Unsafe Attributes
The compiler now understands the idea of 'safety' of handlers and blocks of code.
Handlers can be marked as being 'unsafe', e.g.
unsafe
... do unsafe things ...
end unsafe
54
55
Marker styles
The markerStyles of the line graph can now be set to a return delimited list of:
circle
lled circle
square
lled square
diamond
lled diamond
Setting the markerStyles to empty will cause the lines of the chart to draw without markers and
set the showLines of the chart to true.
56
Dictionary additions
deleteAudioclip (message) has been added to the dictionary.
deleteVideoclip (message) has been added to the dictionary.
eventAltKey (function) has been added to the dictionary.
eventCapsLockKey (function) has been added to the dictionary.
eventCommandKey (function) has been added to the dictionary.
eventControlKey (function) has been added to the dictionary.
eventOptionKey (function) has been added to the dictionary.
eventShiftKey (function) has been added to the dictionary.
libURLSetDriver (command) has been added to the dictionary.
minStackFileVersion (property) has been added to the dictionary.
mobileGetLocationHistory (function) has been added to the dictionary.
mobileGetLocationHistoryLimit (function) has been added to the dictionary.
mobileSetLocationHistoryLimit (command) has been added to the dictionary.
newAudioclip (message) has been added to the dictionary.
newVideoclip (message) has been added to the dictionary.
scriptStatus (property) has been added to the dictionary.
vectorDotProduct (function) has been added to the dictionary.
57
58
LiveCode Script
Introduction
Before getting started with LiveCode, there are a number of things you may want to know. This
guide introduces LiveCode, tells you where to begin, how to install, register and how to use the
documentation.
Welcome
LiveCode makes it easy to turn your concepts, ideas or designs into powerful applications. You can
create desktop, Internet, database and network applications. LiveCode includes a complete
graphical user interface builder, as well as the tools you need to produce faceless or background
applications.
LiveCode is easy to learn. If you are a complete beginner to the world of programming, you will
nd you can become productive quickly. If you are an experienced programmer, you will nd the
environment extremely powerful and one of the most productive you have used.
LiveCodes programming language is object-based. This makes it easy to write modules of code
that are attached directly to individual objects. Unlike other languages, LiveCode lets you both run
and edit an application live. Traditionally the run, edit, compile and debug cycle in programming
takes up a lot of time. In LiveCode all of these activities can take place together.
If youre coming from another language, youll appreciate that the LiveCode language is typeless,
with data automatically stored in the most ecient format and converted, so you dont have to
learn how to deal with dierent types of data. Memory management is fully automatic. LiveCode
applications are not interpreted in the traditional sense, so they provide excellent performance. A
LiveCode graphical application will often feel more responsive to use than a Java application, and
take less time to write.
A LiveCode application is completely cross-platform. That means you can run any application you
create on all major modern operating systems, including Windows, Linux, Unix and Mac OS. Unlike
most other cross-platform frameworks, a LiveCode application will always look and feel native on
each platform that you deliver it on. You can take advantage of many platform specic features on
each platform.
LiveCode removes the need to learn how to access most individual programming interfaces for
each operating system. This saves you the time and eort of learning thousands of platformspecic interface calls.
The goal of this manual is to provide the most accessible, comprehensive and useful guide to
LiveCode possible. We aim to provide a level of depth that covers the advanced feature set, while
remaining accessible to beginners. We hope you nd this material useful and enjoy using
LiveCode.
Where to Begin
We recommend you start by taking a look at our online resources. There is a wide variety of
introductory material there, including step-by-step examples and guides for performing common
tasks.
59
System Requirements
Memory and disk requirements below are for the LiveCode development environment, not for
applications created by LiveCode. Applications created with LiveCode will require sucient free
system resources to load, display, process and interact with the content of the application.
Because this will vary considerably depending on the application created, it is not possible to
publish a list of requirements for applications built with LiveCode. You will need to test your
application to determine the minimum requirements. Many LiveCode applications will run on a
moderately powerful computer and require substantially fewer resources than those listed for the
development environment, others will require more.
LiveCode runs on as wide a variety of systems as possible. To achieve this, the engine has been
implemented to have minimal direct dependencies on system software, and will gracefully
degrade in feature set if it cannot nd the libraries it needs. Generally any recent linux distribution
including Gnome/GTK support will have the required libraries for full feature support for example,
Ubuntu 7 supports all these features (although alpha blended window shape support requires you
to be running with 'Advance Desktop Eects' turned on).
code blocks
Menu Reference
When you are told to choose an item from a menu, the menu name is written, followed by an
arrow, followed by the menu item. For example File -> New means choose "New" from the "File"
menu.
Keyboard Shortcuts
Many menu items have keyboard equivalents. These items can be accessed by holding down a
modier key and pressing another key. The modier keys used throughout this document are
61
generally the modier keys used on Windows, Linux and Unix. If you are using Mac OS, you may
need to substitute modier keys using the table below. For example, if you are using a Mac, where
we say press control-x in this documentation, you may need to press command-x.
Windows and Linux keyboard shortcuts
Mac equivalent
Control
Command
Alt
Option
Tip: This style of note tells you about an alternative way to do something or
describes a shortcut.
Important: This style of note describes an aspect of LiveCode that may confuse you
if you don't know about it and tells you how to avoid unexpected behavior.
Note: This style of note provides some additional information that may be useful, or
emphasizes a key point.
Caution: This style of note warns you about a potential problem that might cause an
error or loss of data.
Start Center
The purpose of the Start Center is to introduce you to LiveCode and provide you with enough
knowledge to start implementing your own projects. It can be accessed by choosing Help ->
Start Center.
The rst time you open the Start Center you will see an invitation to take the Interactive Tour, a
step-by-step tutorial that guides you through creation of a simple project in LiveCode. If you
choose to skip the tour you may always enter it later by clicking the Interactive Welcome button in
62
The Start Center itself is split across three sectionsquick links to the LiveCode pages on various
social media sites; a collection of quick link buttons, which take you to various helps and guides;
and a list of your most recently opened stacks.
63
Enter the Interactive Tour, a step-by-step tutorial that guides you through creation of a simple
project in LiveCode.
New
Click this button to create a new stack. You will see a menu of common stack types and sizes to
choose from. Once you choose your stack size or type the new stack will be created and the Start
Center menu will close.
Sample Projects
64
The Sample Projects button opens an online repository of sample stacks submitted by LiveCode
developers. The repository contains dozens of stacks that you can download for free and use as
you wish.
Tutorials
Opens the LiveCode online tutorial web page. From here you can choose one of dozens of lessons
and how-to tutorials that give you step-by-step instructions on how to create things, from a
simple "hello world" application to simple games to sophisticated graphical eects.
In Depth Guides
Opens the LiveCode Dictionary. Here you can choose to enter the API documentation, the
denitive reference of all of the terms in the LiveCode scripting language. Or you can open one of
several user guides, which describe in detail how to develop and deploy apps in LiveCode.
Forums
LiveCode has a very active and friendly user community. We encourage all new users to sign up to
our mailing list and user forums as they are a great way to get technical help, meet new people
and keep up-to-date with what is going on in the world of LiveCode. The User Forums section
provides a link to our forum registration page as well as a list of links to the most recent posts
which have been made.
Blog
This button takes you to LiveCode's online blog, where LiveCode engineers and developers
regularly post updates about what's new in LiveCode, how-to tutorials, and announcements of
interest to the LiveCode developer community.
Account
Click this button to log in to your LiveCode online store account. There you can see your
purchases, as well as look for useful add-ons to make LiveCode and even more powerful
development tool.
Dictionary
The LiveCode Dictionary contains detailed reference materials for developing applications with
LiveCode. It is divided into two main sectionsthe LiveCode API reference and the LiveCode
Guides. It can be accessed by choosing Dictionary (API) from the Help menu, or by clicking the
Dictionary icon on the LiveCode Toolbar.
LiveCode APIs
The LiveCode Application Programming Interface, or API, reference contains the complete syntax
65
for all LiveCode components, including LiveCode Script, LiveCode Builder, and all installed widgets
and libraries. If you are new to LiveCode you will likely spend most of your time in LiveCode Script,
the scripting language used in developing LiveCode applications. The examples that follow will be
taken from the LiveCode Script API, but the API documentation for all components uses the same
format and layout.
To search one of the API lists, click on the API tab at top left, then choose the API you want to
search from the option list. For example, to search for a LiveCode Script term, choose LiveCode
Script.
Searching. If you know what term you want to look up, or if you have a good idea of what it might
be, just start typing it into the search box, and a list of terms that match your search term will
appear in the entries list.
66
Filtering. If, on the other hand, you dont know the name of the term, but have a general idea of
what terms you want to look at you can lter the list of terms by clicking on a lter topic. For
instance, to see a list of messages that buttons can respond to, click "message" under the type
category and "button" under associations. You can clear a lter by clicking again on the selected
lter.
Note that the entries list displays only the entry name, token type, and syntax for the entry. You
can view the complete entry by clicking on the desired line in the list. This will show the entry in the
area underneath the entries list. Each LiveCode scripting term is thoroughly documented with the
proper syntax, detailed examples, a detailed description, related terms, and more.
67
68
RevOnline
RevOnline gives you the opportunity to upload and share your projects as well as download those
created by other members of the LiveCode online community. It can be accessed via the
RevOnline button located in the menu bar. The main interface can be seen below:
69
The interface is designed to organise the online content into various categories to aid you in
nding the kind of content you wish to download. You will nd three main types of content in
RevOnline, stacks (LiveCode programs), externals and code snippets. Externals are libraries that
can extend the functionality of the LiveCode language using a lower level language. A code
snippet is a portion of LiveCode script that you can paste into and incorporate into your own
projects.
The results of searching or browsing through the RevOnline content are displayed in the search list
area. This is an explaination of the controls you can use to adjust the parameters of your search:
Search
eld
Enter text and press return or click Go to search. Matches will be made against
the titles of uploaded content, the authors name and content descriptions.
Type list
Highlight one of the items in this list lter search to only show results of that type.
Selecting All will display content of all three types.
Tag list
Tag your own and others peoples content with a word or phrase. All tags are
listed here alphabetically. Selecting a tag will lter the search results for uploads
that have been tagged accordingly. Selecting All will remove the ltering.
Search
order
Change the order in which the search results are displayed. There are four
options. A to Z lists content alphabetically by title, Popularity by the number
of times it has been downloaded, Rating by the average user rating (out of ve
stars) and Date by the date on which the content was uploaded to RevOnline
Order
The direction (ascending/descending) of the search order can be changed by
direction clicking on the arrow to the right of the sort control.
70
View
mode
The search list area can be viewed in two modes, a vertical scrolling list or a grid.
In list mode 10 results will be displayed per page, in grid mode the number of
results displayed will be dependent upon the size of the RevOnline stack. Whilst in
grid mode the viewing pane area will not be visible.
User
lter
If you apply user lter to a search, the users name will appear above the type
and tag lists (see below), subsequently only content by that user will be returned
in the search results. Clicking on the button or text of the user lter will remove it.
The search list area displays a preview of the results your search has returned. At the top of this
list you will see the page controls which allow you to navigate forwards and backwards through the
pages of your search should it return more results than can be displayed on one page.
71
At the top of the preview is the contents name. You can also see its average user rating out of
ve stars, the total number of times it has been downloaded, the authors name and a list of tags
applied to this upload. The download button at the bottom will download and launch this
particular stack, it also tells you the size of the download. The preview image can either be a
custom screenshot as above or one of three standard images. These are black for stacks, red for
code snippets and green for externals. The type icon in the lower left corner of the preview image
also indicates the type, these are shown below for a stack, code snippet and external respectively:
72
73
74
Clicking on the preview image or content title will update the right hand viewing pane with more
detailed information about this upload. Clicking on the authors name will display the authors user
prole in the viewing pane and introduce a user lter to the search results. When the search list is
in grid mode the viewing pane will be hidden, doing either of the above operations will cause the
search list to switch back to list mode and display the associated content in the viewing pane.
The viewing pane displays detailed information on users and uploads.
75
If you are a viewing stack details as shown above, in addition to the information provided by the
preview you will also see a headline, description and a revision number which is incremented
whenever the author uploads a new version of their stack, code snippet or external. Clicking on
the authors name or user prole image will display their prole view. Clicking on the content type
or any of the tags in the list of applied tags will apply these lters to the search controls. When
viewing an external your will see an additional Platform: eld that indicates which platforms the
external library is compatible with, make sure your operating system is supported before
downloading and installing an external. If you are currently logged in to your Rev Online account
you will be able to give the upload a rating by hovering over the rating control and clicking when
the rating you wish to submit is displayed, this can only be done once per upload. You can also tag
the upload by clicking on the add tag control which brings up following dialog:
76
As you type into the text entry eld, tag suggestions will appear in a drop down menu that can be
selected using the arrow keys. Once you have nished typing press the ok button to submit your
tag, you must be logged in to complete this operation.
The status bar at the bottom of the RevOnline interface displays the number of results your
search has returned as well as a progress bar indicating the progression of searches and
downloads. You will also see text feedback in response to the operations you perform such as
Retrieving stack details ... and Content tagged etc.
In the top right corner of RevOnline you will nd the login controls which will display your current
login status as shown below:
In order to upload, rate and tag content in RevOnline you must have an account, this account is
also required for making comments in the wiki docs detailed elsewhere. To register for an account
just click on the Sign Up control and enter your email in the dialog that appears. Your email
address will be used as your username for logging in, a password will be emailed to you upon
signing up. After receiving this email you must hit the activation link in the email before your
account can be accessed. Once activated, you can login to your account using the Log In
control pictured above which will bring up the following dialog:
77
The Remember me check box will cause RevOnline to maintain your username in the Email :
eld between login attempts. The Sign in automatically check box will mean that you are
automatically signed in upon opening RevOnline, however if you explicitly sign out you will have to
re-enter your password regardless of this preference. If you forget your password at any time you
can use the Forgot your password? link in the login dialog to have a new one emailed to you.
Upon logging in and viewing your prole for the rst time you will be presented with your prole
view in edit mode where you have the opportunity to enter information about into the highlighted
elds and change your prole picture using the change prole picture control as shown below:
78
Clicking on the change prole picture control will bring up the following dialog:
79
Use the Position Controls to move the centre of the image up, down, left or right. You can zoom in
or out using the Zoom controls. Pressing the Re-centre image button will reset the image to its
original position and zoom level. Once you are happy with orientation of your picture click ok, or
cancel to discard your changes. This dialog is also used to change stack preview pictures.
When you have nished editing your prole you can hit the save changes button to submit your
information, a minimum of a rst and last name must be entered before you can save. You can
also choose to display your email or not and change your password to one of your choosing using
the Change password control. You can reach this prole at any time by clicking on the My
Account control in the login controls which will both display your prole and display all your
80
uploads in the search list. To exit this view simply remove the user lter or hit the My Account
control again.
To upload content to RevOnline simply click on the upload content in the login controls, you will
then be presented with the content browser view.
Clicking on the tabs at the top of this view will change the content type. Above you can see the
code snippet view, it simply requires you to paste a section of code into the code entry eld and
press ok, if you have your code snippet stored in your clipboard you can simply press the paste
button. For stacks you can either select a stack from the list of recently opened stacks or browse
to the les location using the browse button. For externals you need to check which platforms
your external will support and then browse to the appropriate le you wish to upload (shown
below). The default le types for extensions on each platform are; .dll for Windows , .bundle for
Mac OS X and .so for Linux.
81
When uploading a code snippet or external RevOnline will place the code or le into an installer
stack. The installer stacks give you the option to install or try an external le or copy to
clipboard a code snippet. When using the try option with an external the le will be removed from
your installation when you next exit LiveCode.
Once you have pressed ok you will be presented with the edit mode view for the le you are
uploading. Here you can enter a name description and change the preview picture for your upload
(note you cannot edit the title of an external upload it must be the name of one of the les you
have included). If you attempt to upload a le that has already been uploaded to RevOnline, you
will be taken to the existing version of that le to edit, this avoids duplicate uploads.
Whenever you are viewing content that you have uploaded or your own prole whilst logged in the
edit controls will appear above the viewing pane, shown below:
By clicking on the edit prole or edit content (for stacks etc.) button you are entering edit
mode which allows you to make changes to the information shown. When editing your prole you
can simply save or discard the changes you have made. When editing an upload you have the
additional options of deleting and updating the uploaded le. The delete control will permanently
remove your upload from RevOnline. The update control allows you to replace the stack le, code
snippet or external library with a newer version. Clicking on this control will present you with the
content browser view discussed earlier. After you have chosen a replacement le you need to
save your changes in order for the new le to be submitted.
82
The list of tags applied to your own uploads can be altered by using the Add/Delete tags control
(shown above) which will bring up the following dialog:
83
This works in a similar way to the previously explained tag dialog except that you can view the
entire list of tags and edit which ones you wish to be displayed. When hitting return after entering
the name for your tag a new tag item will appear in the list (also achieved by pressing the add tag
button). Tags can be removed by clicking on the appropriate remove tag button. If your tag list is
84
too large for one page you can browse through the pages of tags using the page controls at the
bottom of the dialog. Once you have nished editing the list you can submit your changes by
clicking the ok button.
Additional options for the RevOnline interface can be set in the RevOnline tab of the preferences
stack. As pictured below:
Here you can set the remember password and user name preferences and change your password
to one of your choosing. The search results in RevOnline are cached to speed up performance. You
can tweak the size and time for which this cache remains valid using the two slider controls. A
larger cache will give you faster performance but will take longer to pickup changes made to the
online content made by other users. If the text only searches option is checked RevOnline will only
retrieve the text data for the search list previews which can also improve performance.
Additional Resources
If you have a question that isn't answered in this documentation, you can nd additional
information to help you on our web site. You can also connect with the LiveCode developer
community, which includes many experienced developers who oer their expertise for the
common good to answer questions and help their fellow developers. You'll nd example code,
information on planned enhancements, and the latest updates. Visit:
http://www.livecode.com
85
Developer Community
There are a number of ways to engage with the LiveCode community:
The forums (section 1.6.3 above), are available for getting help from other developers, for
discussing feature requests and future directions, and for receiving announcements from
LiveCode.
Ask a question on stackoverow.
Talk about LiveCode on the LiveCode subreddit.
Join the LiveCode user group on Facebook.
Use the LiveCode mailing list is also available.
Tip: Tip: You can use the Google search engine to search the list archives, using this
link
Technical Support
LiveCode oers up and running technical support to all users to assist you in getting the
development environment working on your system.
Many editions include additional technical support for more advanced problems and questions.
Where support is not included, a separate technical support contract for advanced support can be
purchased.
Contact us here or at [email protected].
Getting Started
Creating a simple graphical application in LiveCode can take just minutes. First you create a user
interface, including any windows, palettes, dialogs you require. Then you populate the user
interface with controls, like push buttons, check boxes, text elds or menus. Finally, you use
LiveCodes English-like programming language to tell your application how to behave.
Prerequisites
Before you get started, you should be familiar with how to use your computer. You should also be
familiar with common applications such as a web browser, word processor and email client. If you
are using Linux or Unix, you should be familiar with basic use of the command line. If you are not
familiar with using a computer, we recommend you spend some time getting acquainted before
trying to learn LiveCode.
message to the button. You place code within the button that tells it how to respond to being
clicked on.
There are a wide range of possible events. When a user clicks on a button, a series of events are
sent to the button. For example, when the mouse rst moves within the border of the button a
mouseEnter message is sent. Then a series of mouseMove messages are sent as the mouse
moves over the button. When the mouse button is depressed a mouseDown message is sent.
When the mouse is released a mouseUp message is sent. You dont have to respond to all of
these events. You simply place code within an object to handle the events you want your
application to respond to.
Events that are not handled by individual objects can be handled in a number of ways at dierent
levels of your application, in libraries, or they can be ignored. The rules that govern what happen
to events that are not processed by an object are described in the section The Message
Hierarchy.
Well return to Event Driven Programming in more detail in the section Coding in LiveCode.
Object-Based Programming
Any graphical application you build using LiveCode will be based on objects. With LiveCode you
typically create the objects of your application before writing any code. You can start by drawing
the buttons, text elds, and other controls that make up your application. LiveCode operates like
other layout, drawing or application development environment. You can select controls by clicking
them, move them by dragging them around, resize them, and change their layer to move them
closer or further from the top of the interface.
Once you have the objects in place, you can proceed to attach code to each object to respond to
the events you want. LiveCode includes a complete graphical development environment that
makes it easy to create and edit any kind of user interface. It includes objects for all the basic
operating system elements, including buttons, checkboxes, text elds, menus, graphics, and
many more. In addition you can create and customize your own objects that look and behave
however you want.
If you are writing a non-graphical application, you can choose to create objects to assist in
organizing your code into sections and load these objects o screen, or you can simply write your
code in a text le and run the text le directly. This method is commonly used to communicate
with Apache and other web browsers when using LiveCode to build server-side or network
applications.
Object-Based programming is covered in more detail in the section Building a User Interface.
Non-graphical applications are covered in more detail in the section Building a Web Application.
causing the button's script to run if you've designed it to respond to the mouseUp message.
When in edit mode, objects do not receive messages when you click on them, and you can move,
resize or edit the properties for objects.
Tip: To temporarily stop all messages being sent to your application while editing it,
choose Suppress Messages from the Development menu or Toolbar.
There few other dierences between the two tool modes. You can view and edit properties and
code in either mode. Your application does not stop running while you make changes to it. Only
mouse interaction with objects is suspended in edit mode to allow you to edit them more easily.
Because LiveCode is constantly live, you can easily make simple changes and watch each change
take eect as you make it. This allows you to design and experiment using an iterative process,
resulting in a more productive and satisfying development experience.
88
Dialog boxes and palettes are commonly stored as substacks of the main application window,
which is typically a mainstack. This allows you to store code and common functions used by all the
substacks in the mainstack's script. Because mainstacks are part of the object hierarchy of their
substacks, the substacks can call this functionality from scripts within the substack.
90
Tip: When importing images, use the Image Library, or create a library card that
contains all the originals, then reference those objects throughout your project. For
more details on referencing images, see the section on the button object.
For details of the image formats supported natively, see the section on the Image object. For
details of the audio formats supported natively, see the section on the audioClip object. For
details on how to control a movie, see the section on the Player object.
91
Unlimited
Unlimited
Unlimited
Unlimited
Unlimited
65,536 characters
255 characters
65,536 characters
92
Unlimited
Unlimited
Unlimited
64K
Unlimited
Unlimited
93
94
Run
mode
Click to enter run mode. When in run mode, objects receive all the normal
messages that drive a LiveCode application. For example, clicking on a button in
run mode will cause a mouseUp message to be sent to it and the script will run.
Edit
mode
Click to enter edit mode. When in edit mode, objects do not receive messages
when you click on them, and you can move, resize or edit the properties for
objects. For more details about the run and Edit mode, see the section The Edit
and Run Mode.
Widget
objects
Button
objects
Field
objects
Scrollbar
objects
Image &
Player
Drag any object within these areas onto an editable stack to create a new object.
Double-click an object to create a object of that type in the center of the front
most editable stack. For more details on all of these objects, see the section
about each object type later in this chapter.
Vector
Graphics
Press the grey triangle at the bottom right of the Image & Player area to hide and
show this section. Click to choose the type of new graphic you want to create. Use
the ll bucket to choose the ll color, the ll pencil to choose the line color, the
line thickness menu to choose the line thickness, and the optional shape menu to
choose preferences specic to the type of graphic selected. Click and drag in an
editable stack to create the new graphic.
Bitmap
graphics
The paint tools allow you to edit bitmap graphics that have been imported into
LiveCode or create your own. To use them, create an image object and paint
within that area, or modify an existing image. You cannot use the paint tools to
edit an image that has its lename property set, as that image data is stored
outside LiveCode. For more details on working with images, see the section on
Images later in this chapter and the chapter on Working with Media.
Tip: You can also create objects using the New Control sub-menu in the Object
menu, or by typing create [object type] in the Message box. For more information
on creating objects using the Message Box, see the section on Building Interfaces
Using Scripts, later in this chapter.
To open a system-standard color chooser, double-click on color chooser popup menus at the
bottom of the Vector Graphics or Bitmap Graphics sections of the tools palette.
Alignment & Layering
95
96
Lock
size and
position
Locks the object so that its size and position cannot be adjusted interactively with
the mouse when in edit mode. This also prevents images, groups and players
from automatically resizing to display their entire content whenever the card that
they are on is reopened. For more details see the entry for lockLocation in the
LiveCode Dictionary.
Width &
Height
Allows you to set the width and height of the object(s) currently being operated on
by the Property Inspector. Objects are resized from their center. For more details,
see the width and height properties in the LiveCode Dictionary.
Fit
Content
Automatically sizes the object large enough to display its content. In the case of
buttons, the content is the text and any icon. For images, this is the native width
and height of the original image before any scaling. For more details, see the
entry for formattedWidth and formattedHeight in the LiveCode Dictionary.
Location
Sets the objects position (the center of the object) relative to the top left of the
card.
Left,
Top,
Right &
Bottom
Layer
Sets the layer of the object. The buttons with arrows allow you to send an object
to the back, move an object back one layer, bring an object forward one layer and
bring an object to the front. Layer determines which objects are displayed in front
or behind others, as well as the objects number and tabbing order. Note that you
cannot relayer objects that are grouped unless you are in edit background mode,
or have the relayerGroupedControls set to true. For more details, see the section
on Group & Backgrounds. For more details on tabbing order see the section on
The Keyboard Focus below.
Use the Align Objects Inspector to resize objects relative to other objects, to reposition objects
and/or to relayer objects.
97
Align Objects from the menu at the top of the Inspector. The Align Objects pane will automatically
be displayed if you select multiple objects of dierent types.
Important: The Align Objects Inspector resizes objects relative to each other. Always
select the object you want to use as a reference rst, then select other objects that
you want to make the same as that object next. If you want to distribute objects,
select them in the order that you would like them to be distributed.
Equalize
Make objects the same width, height, or have exactly the same rectangle.
Align
Aligns the objects by their left, right, top or bottom edges, or by their horizontal
center or vertical center, using the rst object selected as a reference.
Distribute
Distributes the objects with an equal dierence between them, using the order
they were selected. First to last selected will distribute objects evenly between
the edges of the rst and last objects selected. Edge to edge will distribute the
objects so that their edges touch each other exactly. Across card will distribute
the objects evenly over the entire card area.
Nudge
Nudge the selected object the number of pixels specied in the center of the
arrows. To change the number of pixels, click on the number.
Relayer
First to last selected will relayer the objects in the selection in the order they
were selected. 'Last to rst" will relayer the objects in reverse order. Use these
buttons to set the tab order of a set of objects. For more information on the
tabbing order, see the section on The Keyboard Focus below.
This topic discusses the way windows are implemented in LiveCode applications; how to change
window appearance; and how to control the behavior of the various window types. This topic does
not cover the organization of stacks within a stack le, which is covered in detail in the section
Structuring Your Application.
Caution: Do not start your stack name with "rev". Stacks with names starting with
"rev" are reserved by the LiveCode development environment.
You create a new stack which can then be displayed in any number of modes (as described
below) by choosing File -> New Mainstack. You can edit stack properties by choosing Object
-> Stack Inspector.
Window Types and the Mode of a Stack
The nature of a stack's window depends on the stack's style property and on what command was
used to open the stack. You can either specify the window type when opening the stack, or allow
the stack's style property to determine the type of window it is displayed in.
Note: We recommend you specify the mode you want a stack to be opened in as
part of the command you use to open the stack, rather than using the style property.
This makes it easy to switch a stack between editable mode in the development
environment, and for example, a dialog in the runtime environment.
The Standard Window Types
LiveCode windows are usually one of four types: editable or topLevel windows, modal or
modeless dialog boxes, or palette windows.
Important: You will normally create a new stack and edit it while it is in editable
mode. If you want to create a dialog, create the stack like any other stack. Then when
opening it, specify in the script that it should be displayed as a dialog, or a palette,
etc. The appropriate commands for doing this are detailed with each type of window
below.
You can test out these commands as you work on your window layout and scripts, using the
Message Box (see section of the same name), or using the window context menu (see Modal
Dialog Boxes, below). For more details on wr it ing scripts in general, see the section on Coding in
LiveCode.
Most windows are editable or topLevel windows, and this is the default mode for LiveCode stacks.
If you open a stack using the go command (without specifying a mode), or using the Open Stack
menu item, then the stack is displayed as an editable window unless its style property species
another window type.
Editable Windows for documents
An editable window has the appearance and behavior of a standard document window. It can be
interleaved with other windows, and you can use any of LiveCode's tools to create, select, move,
or delete objects in the stack.
100
Stacks whose style property is set to "topLevel" always open as editable windows, regardless of
what command you use to open them.
Note: If the stack's cantModify property is set to true, the window retains its
standard appearance, but tools other than the Browse tool can no longer be used in
it. In other words, every tool behaves like the Browse tool when clicking in an
unmodiable stack's window.
Modeless Dialog Boxes for alerts and settings
Modeless dialog boxes are similar to editable windows. Like editable windows, they can be
interleaved with other windows in the application. Their appearance may dier slightly from the
101
Stacks whose style property is set to "modeless" always open as modeless dialog boxes,
regardless of what command you use to open them.
Modal Dialog Boxes for alerts and settings
A modal dialog box is a window that blocks other actions while the window is displayed. You cannot
bring another window in the application to the front until the dialog box is closed, nor can you edit
102
the stack using the tools in the Tools palette. While a modal dialog box is being displayed, the
handler that displayed it pauses until the dialog box is closed.
Stacks whose style property is set to "modal" always open as modal dialog boxes, regardless of
what command you use to open them.
Palettes for accessory and tool windows
A palette has a slightly dierent appearance, with a narrower title bar than an editable window.
Like dialog box windows, a palette does not allow use of tools other than the Browse tool.
103
Stacks whose style property is set to "palette" always open as palettes, regardless of what
command you use to open them.
Ask Question Dialog for asking a question
The ask question dialog is a special type of window that is designed to make it easy to ask the
user a question. It includes special syntax for opening the dialog with question text and returning
any answer to the script that called it. You can also specify the window title, as well as an icon to
be displayed in the window. The font, object positions, button order and icon will automatically
change to reect the operating system. However, if you do require more exibility than is provided
in this dialog, you should create your own modal dialog box instead (see above).
104
Tip: You can try this example out right now by coping and pasting it into Tools ->
Message Box, then pressing return.
The word question species the icon, and may be any of question | information | error warning.
To change the miniature application icon shown in the Mac OS X platform picture above, see the
entry for gREVAppIcon in the LiveCode Dictionary.
The result is returned in the special variable it.
For complete details on the syntax, see the ask command in the LiveCode Dictionary.
105
106
if it is "Rome" then
answer information "That was the correct answer."
end if
For complete details on the syntax, see the answer command in the LiveCode Dictionary.
The answer dialog is implemented internally as a stack attached to the LiveCode IDE. For details
on customizing the IDE, see the section on Editing the LiveCode User Interface.
Tip: If you're not sure what a stack's name is, you can use the mouseStack function
to nd out. Enter the following in the Message Box (Tools -> Message Box), then
move the mouse pointer over the stack window and press Return:
put the mouseStack
File Selector Dialogs
The le selector dialogs allow you to display the system standard dialogs. These dialogs allow the
user to select a le or a set of les, select a directory, or specify a name and location to save a
le.
The syntax for bringing up the le selector dialogs mirrors the syntax for the alert and question
dialogs detailed above. However, unlike these dialogs, the le selector dialogs are displayed using
the system standard dialogs where available. The notable exception at the time of this writing is
Linux platform, where a built-in dialog is used instead due to more limited OS support. (You can
force the other platforms to use this built-in stack based le selector by setting the
systemFileSelector global property.)
107
The le path to the le selected by the user is returned in the special variable it. If the user
cancelled the dialog, the special variable it will be empty and "cancel" will be returned by the
result function.
For complete details on the syntax, see the answer le with type command in the LiveCode
Dictionary.
108
The le path to the le to be saved is returned in the special variable it. If the user cancelled the
dialog, the it variable will be empty and cancel will be returned by the result function.
For complete details on the syntax, see the ask le with type in the LiveCode Dictionary.
109
The le path to the folder selected by the user is returned in the special variable it. If the user
cancelled the dialog, the it variable will be empty and "cancel" information will be returned by the
result function.
For complete details on the syntax, see answer folder in the LiveCode Dictionary.
Color Chooser Dialog
The answer color dialog allows you to display the operating systems standard color picker
dialog.
110
111
answer color
The color chosen is returned in the special variable it. If the user cancelled the dialog, it will be
empty and "cancel" will be returned by the result function.
For complete details on the syntax, see answer color in the LiveCode Dictionary.
Printer Dialogs
The printer dialogs allow you to display the standard printer and page setup dialogs.
112
113
114
Note: Note the answer, answer le, answer folder, ask, ask le, and answer
115
folder commands (see above) all include an ...as sheet form, so you can display
these dialog boxes as sheets on Mac OS X. You can safely use the as sheet form on
cross-platform application as on systems other than OS X, the sheet command
displays the stack as an ordinary modal dialog box.
Drawers Mac OS X only
A drawer is a subwindow that slides out from underneath one edge of a window, and slides back in
when you close it. You usually use a button in the main window to open and close a drawer.
To display a stack as a drawer, you use the drawer command:
On systems other than OS X, the drawer command displays the stack as an editable window.
Because this does not map well to other platforms, we recommend you only use drawers for
applications that are only being developed for Mac OS X.
Use drawers to hold settings, lists of favorites, and similar controls that are accessed frequently
but that don't need to be constantly visible.
Stack menus for displaying non-standard menus
Note: Usually a menu in a LiveCode application is implemented as a button. We
recommend that menus are implemented using buttons, as these will automatically
be drawn with the native theme on each platform. For more details, see the section
on Menus below
It is also possible to display a stack as a pulldown, popup, or option menu. Stack menus are used
when a menu needs to contain something other than just text. For example, a popup menu
containing a slider, or an option menu consisting of icons instead of text, can be implemented as
a stack menu.
To display the stack menu, you create a button and set its menuName property to the stack's
name. When the user clicks the button, the stack is displayed with the behavior of a menu.
Internally, the menu is implemented as a window, and you can use the popup, pulldown, or
option command to display any stack as one of these menu types.
Stack Decorations for Window Appearance
Stack decorations allow you to specify how the title bar and border of a window will be drawn. You
can access the stack decorations options in Object -> Stack Inspector.
Apart from the dierences in appearance between dierent window modes, the appearance and
functionality of a window can vary depending on the stack's properties and the platform it is being
displayed on.A window's title bar displays the window's title, as well as a close box, minimize box
or collapse box, and maximize box or zoom box.
116
117
Icons allow you to provide a wide range of functionality. For example you can create a roll over
eect by setting a hover icon. Or you can create a custom check box by setting an icon and a
highlight icon doing so will replace the system standard check box and display your icon in each
state depending on whether the button has been pressed or depressed.
119
120
121
122
123
either be completely blank, or will contain any shared groups from the previous card.
Groups & Backgrounds for organizing, and sharing controls
Groups, LiveCode's most versatile object type, are used for several purposes: radio button
clusters; menu bars; for creating scrollable object areas within cards; and as backgrounds for
displaying sets of objects that are shared between cards. Groups can also be used for creating a
simple card and stack database, by holding elds that contain a dierent record on each card.
What Is a Group?
A group is a single object that holds a set of objects. Objects are grouped by selecting the
controls you want to include in the group, then using the group command or choosing Object
> Group Selected.
Once you've created the group, it becomes an object in its own right. You can select, copy, move,
and resize the group, and all the objects in the group come with it. The objects in the group
maintain their own identities, and you can add objects to the group or delete them, but the
objects are owned by the group instead of the card.
A group has its own properties and its own script. Groups can be any size, can be shown or
hidden, and can be moved to any location in the stack window, just like any other control. Like
other controls, groups can be layered in any order with the other controls on the card. Groups can
also display a border around a set of objects.
124
Both the term group and the term background can be used to refer to groups. The terms are
125
interchangeable in some circumstances and mean dierent things in others. The dierences are
explained in more detail below.
In general, the term group refers to groups that are placed on a card, while the term
background refers to all the groups in a stack that are available for use as backgrounds (see
below). The expression
evaluates to the number of groups on the current card. The expression the number of
backgrounds evaluates to the number of background groups in the current stack, including
groups that are not placed on the current card.
Tip: When you refer to a group by number, if you use the word group, the number is
interpreted as referring to the groups on the referenced card, in order by layer. If you
use the word background, the number is interpreted as referring to the groups in
the stack, in the order of their creation.
For example, the expression the name of group 1 evaluates to the name of the lowest-layered
group on the current card, while the expression the name of background 1 evaluates to the
name of the rst group that was created in the stack--whether or not that particular group is
placed on the current card, or appears on any card at all.
The term background can be also used to refer to the set of cards that share a particular group.
The following statement goes to the third card on which the group named "Navigation" is placed:
Nested Groups
LiveCode supports nested groups (one group containing another). Since a group is itself a control,
it can be contained in another group.
Creating a nested group is just like creating a group: select the controls you want to group
(including the existing group), then choose Object -> Group Selected. The existing group is
now a member of the new group.
Selecting and Editing Groups
To select a group, simply click on one of the objects that is contained within it. This will select the
group.
If you want to select an object within the group, instead of the group itself, there are two ways to
do so. You can turn on the Select Grouped option on the toolbar or in Edit -> Select
Grouped Controls. This causes groups to be ignored when selecting objects, allowing you to
select objects inside a group as if the group didnt exist. You can enter this mode by script by
toggling the selectGroupedControls global property.
Alternatively you can go into edit group mode, a special mode that only displays the objects within
that group. Select the group, then press Edit Group on the toolbar or choose Object -> Edit
126
Group. When you have nished, choose Object -> Stop Editing Group. You can toggle this
mode programmatically by using the commands start editing and stop editing.
Tip: If a group's border has been set, an outline appears at the group's edges.
However, clicking within or on the border does not select the group. To select the
group, you must click one of its controls.
Placing and Removing Backgrounds
Once you create a group, you can display it on any or all cards in the stack. First, ensure that the
groups Behave as Background option has been set in the Inspector. Then navigate to the card
you want to place the group on and choose Object -> Place Group to place an instance of a
particular group on the current card. You can control these features from script by using the
backgroundBehavior property and place command.
Note: When you create a new card, if there are any groups on the current card
whose Behave as Background has been set, they are automatically placed on the
new card. To make it easy for all the cards in a stack to share a single group, create
the group on the rst card and set this property to true, before you create any other
cards.
To remove a group from the current card without deleting it from the stack select the group and
choose Object -> Remove Group. The group disappears from the current card, but it's still
placed on any other cards that share the group. You can remove a group by script using the
remove command.
Tip: You can use the start editing command from the Message Box to edit a group
that has not been placed on any card. Since the group is not on any card, you must
refer to it using the term "background" instead of the term "group".
You can completely delete a group in the same way as you delete any other object, by selecting
the group and choose Edit -> Clear or pressing backspace.
Important: Deleting a background group removes it from all the cards it appears
on, and from the stack itself.
To dissolve a group back into its component controls, select the group and choose Object ->
Ungroup. You can ungroup a group by script using the ungroup command. Ungrouping deletes
the group object and its properties (including its script) from the stack, but does not delete the
controls in it. Instead, they become card controls of the current card. The controls disappear from
all other cards the group is on.
Note: If you ungroup a group, then select the controls and regroup them before
leaving the current card, the group is restored as it was. However, leaving the current
card makes the ungrouping permanent and deletes the group from all other cards it
was on.
Groups and the Message Path
For details on how groups and backgrounds t into the Message Path, see the section on Groups,
Backgrounds & The Message Path, below.
Graphics, Images, Players, Audio & Video Clip Objects for multimedia
LiveCode supports a wide range of media formats, allowing you to produce rich media
127
applications. The image object allows you to import or reference images, manipulate images by
script or interactively with the paint tools, and save them out in dierent formats with variable
compression options. Support extends to alpha channeled PNG images and animated GIF
images. Images can be imported and reused within a stack to create custom or interactive
interface elements. To learn how to work with these objects in a script, see the section on Working
with Media.
Image formats supported include GIF, JPEG, PNG, BMP, XWD, XBM, XPM, or PBM, PGM, or PPM
les. On Mac OS systems, PICT les can also be imported (but they cannot be displayed on Unix
or Windows systems). For full details on each of these formats, see the section on Working with
Media.
You can import images using File -> Import as Control -> Image File. You can reference an
image using File -> New Referenced Control -> Image le.
Paint tools can only be used on images that have been imported as a control. See the section on
Using the Paint Tools for details on how to use the paint tools.
129
130
Figure 43 Scrollbars
131
This option allows you to preview your menu bar in the main menu bar. It only
applies on Mac OS systems where the option Set as Menu Bar on Mac OS has
been turned on.
Preview
> Important: To bring back the LiveCode development menu bar when working
with a stack that has this option turned on, click on a LiveCode IDE window such
as the Tool bar.
Menu
bar
settings
This area species the main settings for your menu bar. Use the New button to
create a new menu bar in the current top most editable stack. Enter the name
for your menu bar in the text area. Delete will permanently delete your menu bar.
Use the Edit button to load an existing menu bar from the top most editable
stack to edit in the area below.
Menu
edit
area
Select a menu to work on from the scrolling list. At a minimum your application
should have a File, Edit and Help menu. These menus are created for you
automatically when you create a new menu bar. To create a new menu, move the
orange divider bar to the position in the menu bar you want to create the new
menu, and press New Menu. Disable the currently selected menu by checking
Disabled. Choose the keyboard shortcut (the portion of the name that is
underlined), using the Mnemonic popup menu (Windows, Linux & Unix only). To
move a menu in the list, select it then press the up or down arrows (to the right
of the name area).
Menu
content
area
Select a menu item to work on from the scrolling list. To create a new menu item,
move the orange divider bar to the position in the menu bar you want to create
the new menu, and press New Item . Disable the currently selected item checking
Disabled. Choose the keyboard shortcut (the portion of the name that is
underlined, for use when the menu is open), using the Mnemonic popup menu
(Windows, Linux & Unix only). To move a menu item up or down the list, select it
then click the up or down arrows (to the right of the name area). To move items
into a submenu, click the Right arrow, or click the Left arrow to move a submenu
item back into the main menu bar. To insert a divider, position the orange divider
bar where you want the divider, the click the blue divider button (top right). To
make the menu item a Checkbox or Diamond option, choose the appropriate
option from the Mark popup menu. To create a control key shortcut for the item,
click the Shortcut check box and enter the letter you want to use for the shortcut.
To understand the symbols that are created next to the menu items, see the
section on Menu Bars within the chapter on Programming a User Interface.
Scripting
Edit Script opens the Code Editor for the currently selected menu. Auto Script
places a blank script within the currently selected button with spaces to insert
actions for each of the menu items within that item. We recommend you press
Auto Script before pressing Edit Script when you create a menu.
132
Scale or
Position
Selector
Choose whether you want the control to be scaled or positioned when the stack is
resized. Scaling will change the dimensions of the control as the stack resizes.
Positioning will move the control, it does not change its dimensions. Note that it is
possible to scale an object in the horizontal plane and have it position in the
vertical. Select Scale then set the options for one axis in the Linking area. Then
select Position and set the options for the other axis. If you set options in both the
Scale and Position modes for both axis, the Scaling options will be ignored.
Use the linking area to specify the relationship between the control and the
window, or other controls as the stack is resized. In Scaling mode you can link
each edge of the object to the window or another object. In positioning mode, you
can only link the X and Y axis of an object. Click the gray bars to create a link. A
single click results in an absolute link, a second click will create a relative link. An
absolute link will keep the object the current number of pixels away from what it is
being linked to. For example, if you link the right edge to the edge of the window
and the edge is currently 10 pixels away from the edge of the window, whenever
the stack is resized the edge will remain exactly 10 pixels away. However if you use
a relative link the distance will be calculated as a percentage of the total width of
the card. The object will remain the same percentage away from the edge of the
card, the exact number of pixels will vary.
Linking
area
When linking to another control, be sure to link to a control that is moved relative
to the window, or by a script (e.g. in a resizeStack handler).
When using the Geometry Manager with an existing resizeStack handler, be
sure to pass the resizeStack message, otherwise the Geometry Manager will
not be able to take eect.
To force the Geometry to manually update, call revUpdateGeometry.
> Tip: You can use the Geometry Manager to scale objects with a "divider" bar.
Create and script the bar to move, then link the edges of the controls to it, then
call revUpdateGeometry each time it moves to have the objects scale
automatically.
Clipping
settings
Turn on Prevent Object Clipping Text to prevent the control getting too small to
display its label when the window is resized. If the control is a eld, you can also
turn on the option to display scroll bars if the text within the eld does not t.
Limit
settings
Allows you to set the minimum and maximum possible widths and heights for the
object.
Remove
All
Removes all Geometry settings from the control. Use this option if the settings
you have applied do not give the desired eect and you want to start over.
The Geometry Card Settings options can be accessed from within the Card Property Inspector.
Use these options to determine how Geometry is applied to the controls within the current card.
134
Add to
cards
virtual
width
or
height
Use this option to implement a layout that allows a section of optional controls to
be folded out. The Geometry manager will ignore the extra height or width pixels
specied in this area, resizing objects as if that area of the card has not been
"expanded". Normally these values are set by script as the window is resized to
fold out additional controls. To set these properties by script, set the
cREVGeneral["virtualWidth"] or cREVGeneral["virtualHeight"] card
properties.
Update
before
opening
card
Causes the objects to be resized when navigating to the card if the window has
been resized while on another card. This option is not needed if the controls are
contained within a background that has already been correctly resized to the
current window dimensions.
135
136
The icons from left to right allow you to duplicate, delete orcreate a new prole
for the currently selected object. The Set all button allows you to set all the
objects on the current card or stack to the prole currently selected in Prole
selector area.
When creating a new prole, ensure you choose a name that is valid as a
variable and not a reserved LiveCode word. Use consistent names to allow you
to create a theme or language and set all the objects in your card or stack to
the same prole.
When you create a new prole, LiveCode automatically switches the object to
use that prole. There are two ways to include new property settings in a prole:
by using the property inspector to specify the properties you want to include,
and by changing the properties directly while the prole is active.
Create,
delete or
set
Proles
If you make changes to the properties of the object, the prole editor will track
the changes and save those into the current Prole. Any properties that have
not been set for the current prole will be inherited from the Master prole. The
proles system supports all common object properties including styled text and
Geometry information. However it does not store properties that duplicate each
other (e.g. only the rect value will be stored, not the objects left, right or other
location properties). Scripts and custom properties are also not stored by the
prole editor. You can however write scripts that rst check what prole is in use
on the object before taking an action by checking the revProfile property of
the object.
You can set proles by script by setting the revProfile property. To set the
entire card, stack or stack le, use revSetcardProfile , revSetStackProle or
revSetStackFileProfile commands respectively. To turn on the storage of
new properties in the current prole and thus change proles more rapidly,
toggle the g revProfile ReadOnly global.
Prole
selector
Select a prole to change all the objects properties to the values contained in
that prole. Click the currently selected prole to update the list of properties
stored for it.
Proles
properties
Displays a list of all properties that have been changed in the currently selected
prole, and thus have a value unique to this prole. Select a property to see its
contents. Press the plus icon to manually add a new property to the current
prole. Delete the property from the current prole using the delete icon.
137
View and edit the contents of the currently selected property associated with
the currently selected prole.
The Add Property dialog box lists all applicable properties, but the Property
Proles pane automatically eliminates redundant properties and property
Property
contents
For more details on working with Property Proles, see the section on Property Proles in the
Programming a User Interface guide.
138
Consider what screen resolution you are designing for and whether or not you want your interface
to be resizable early on. This decision will have a big impact on your design.
Consider the program ow
If you program performs a complex task with many options, consider creating a wizard style
interface which guides the user step by step through the task. That way they are never faced with
a screen covered with dozens of options and no idea what to do next.
Test it on real users
Bring in a group of people and watch them use the program. Don't interfere or help them out, just
get them going and take notes. If you don't have a budget for expensive user testing labs, this
process can be as simple as gathering a group of students and oering them free pizza. You'll get
a ton of useful feedback that will really help make your program easy to use.
Don't use square wheels
The various types of widget and control type available have built up a meaning for users over
years of use. Don't use something that has a well understood function to perform a dierent sort
of task. If you need a widget that does something new, build something new.
Skinning
If you're producing a custom skin for your application, a good rule of thumb is either make it
entirely custom or use standard OS widgets. An OS native button can look very out of place in the
middle of a carefully designed custom skin.
HCI guidelines for the three main platforms
Each of the platforms that LiveCode supports has its own set of User Interface Guidelines. We
recommend you take time to familiarize yourself with them.
Apple Human Interface Guidelines:
http://developer.apple.com/documentation/UserExperience/Conceptual/
OSXHIGuidelines/XHIGIntro/chapter_1_section_1.html
Windows Vista User Experience Guidelines:
http://msdn2.microsoft.com/en-us/library/aa511258.aspx
GNOME Human Interface Guidelines 2.0:
http://library.gnome.org/devel/hig-book/stable/
KDE Human Interface Guidelines:
http://wiki.openusability.org/guidelines/index.php/Main_Page
Coding in LiveCode
Writing code is how you give your application functionality. Writing the right code means your
application will do what you want it to do. Fortunately, LiveCodes built in high level language,
makes this task easy. The English-like syntax is easy to read and write. This chapter walks you
through writing LiveCode.
139
Message Handlers
Each message handler begins with the on control structure followed by the name of the message
that this handler responds to. The handler ends with the end control structure and the name of
the message. Message handlers look like this:
on mouseUp
beep
end mouseUp
A message handler is executed when the object whose script contains the handler receives the
message. This example handler responds to the mouseUp message (see Messages).
Function Handlers
Each function handler begins with the function control structure followed by the name of the
function that this handler computes. The handler ends with the end control structure and the
name of the function. Function handlers are typically called by another handler and return a value
using the return control structure. Function handlers look like this:
function currentDay
return item 1 of the long date
end currentDay
A function handler is executed when a handler in the same script (or one in an object lower in the
message hierarchy) calls the function. This example handler returns today's name.
GetProp Handlers
140
Each getProp handler begins with the getProp control structure followed by the name of the
custom property that this handler corresponds to. The handler ends with the end control
structure and the name of the property. getProp handlers look like this:
getProp myCustomProperty
return the scroll of me + 20
end myCustomProperty
A getProp handler is executed whenever the value of the corresponding custom property is
requested by a LiveCode statement. You can write a getProp handler for any custom property of
the object or another object lower in the message hierarchy. For more information, see the
section on Custom Properties.
SetProp Handlers
Each setProp handler begins with the setProp control structure followed by the name of the
custom property that this handler corresponds to. The handler ends with the end control
structure and the name of the property. setProp handlers look like this:
A setProp handler is executed whenever the value of the corresponding custom property is
changed by the set command. You can write a setProp handler for any custom property of the
object or another object lower in the object hierarchy. For more information, see the section on
Custom Properties.
Comments
Comments are remarks that are intended for a human to read and are not executed. For some
recommendations on what sort of comments to include and when, see the section on Good
Design Recommendations.Comments can be placed either in a handler, or outside any handler.
Any line (or portion of a line) that starts with two dashes (--) or a hash mark (#) is a comment.
Placing these characters at the beginning of a line is called "commenting out" the line.
You can temporarily remove a statement, or even an entire handler, by commenting it out. To
comment out several lines at once, select them and choose Script -> Comment.
Since comments are not executed, you can place them anywhere in a script--inside a handler or
141
on openCard
/* This is a multiple-line comment that might
contain extensive information about this handler,
such as the author's name, a description, or the
date the handler was last changed. */
show image "My Image"
pass openCard /* You can also make one-line comments */
end openCard
Block comments are handy when you want to temporarily remove a section of code while
debugging a handler. You can place the characters "/*" at the start of the section, and "*/" at the
end, to prevent the section from being executed.
Compiling a Script
A script is compiled when you change the script either by clicking Apply in the Code Editor (or, if
altering a script from another script, using the set command). During compilation, the entire
script is analyzed.
If a compile error is found when a script is being compiled, the entire script is unavailable for
execution until the error is corrected and the script is re-compiled. This applies only to compile
errors. If an execution error occurs during the execution of a handler, it does not aect the ability
to use other handlers in the same script. For more information on dealing with errors, see the
section on Debugging.
You cannot change a script while a handler in it is executing, because what is executed is the
compiled version, not the text in the script property.
Summary
Each object has a script, which can be empty or can contain one or more LiveCode handlers. You
change a script using the Code Editor, or by setting the object's script property.
A script can contain four kinds of handlers: commands, function handlers, setProp handlers, and
getProp handlers.
A comment is a part of the script that is not executed. Comments start with -- or #.
If a script contains a compile error, none of its handlers can be used until the error is xed.
Events
LiveCode is based upon events. Every action a script takes is triggered by an event, which is sent
in the form of a message.
142
Responding to Events
To respond to a message, you write a message handler with the same name as the message. For
example, to respond to a keyDown message sent to a eld (which is sent when the user presses
a key while the insertion point is in the eld), place a keyDown handler in the eld's script:
143
message handler that can respond to it. This makes it possible to group similar functionality
together at dierent levels within your application. This behavior applies both to event messages
sent as a result of a user action, and custom messages sent by script. It is therefore possible to
write libraries of common functions.
The object hierarchy is closely related to the path that a message travels on. In most cases, when
an object passes a message on, the message goes to the object's owner in the object hierarchy.
The Message Path is detailed in the gure below.
144
145
one is executed when the object receives the corresponding message. Other
handlers in the same object's script with the same name are never executed.
Trapping Messages
When an object receives a message and a handler for that message is found, the handler is
executed. Normally, a message that's been handled does not go any further along the message
path. Its purpose having been served, it disappears. Such a message is said to have been
trapped by the handler.
If you want to prevent a message from being passed further along the message path, but don't
want to do anything with it, an empty handler for the message will block it from being passed on.
This example prevents the mouseDown message from being acted on by the object the empty
handler is in, as well as any objects below it in the object hierarchy:
on mouseDown
end mouseDown
You can use the same technique to block custom function calls, setProp triggers, and getProp
calls.
on openCard
doSpecialSetupForThisCard
pass openCard -- let stack get the message too
end openCard
Some built-in messages, such as keyDown, trigger an action, so trapping the message prevents
the action from being performed at all. The following example passes the keyDown message
only if the character typed is a number:
on keyDown theKey
if theKey is a number then pass keyDown
end keyDown
If you place this handler in a eld's script, it allows the user to enter numbers, but any other
keystrokes are trapped by the keyDown handler and not allowed to pass.
A similar principle applies to setProp triggers. If a setProp handler does not pass the setProp
trigger, the custom property is not set.
Commands
A command is an instruction to LiveCode to do something. A command is placed at the start of a
statement (either the start of a line or after a control structure such as "then"). The command is
followed by any parameters that specify the details of what the command is to do.
Here are some examples of how built-in commands are used in statements:
Functions
A function call is a request to LiveCode for information. A function is stated using the name of the
function, followed by opening and closing brackets that may contain any parameters that specify
the details of what the function is to act on.
When you use a function in a statement, LiveCode calls the function to compute the specied
information, then substitutes that information in the script as if the script had originally written
that information in place of the function call. The information returned can therefore be put into a
variable or other container by using the put command in front of a function.
Here's an example of how a function is used:
When this statement is executed, LiveCode calls the round function. When you round o 22.3,
the resulting number is 22, so the statement puts the number 22 into the eld.
The number you're rounding o is placed in parentheses after the round function's name. This
number is called the function's parameter. A function can have one parameter, or none, or
several. The parameters are enclosed in parentheses and, if there's more than one, they're
separated with commas. Here are some examples:
Important: A function call, by itself, is not a complete statement. You need to use a
function call in conjunction with a command or control structure. (In the rst example
above, the round function is used with the put command.)
Writing function calls with the "the" form
If a built-in function has no parameters or one parameter, it can be written in a dierent form, with
no parentheses:
149
If the function has no parameters, this form is written as the functionName. If it has one
parameter, this form is written as the functionName of parameter.
The "the" form works the same way as the "()" form shown above, and you can use the two forms
interchangeably for built-in functions with fewer than two parameters. The LiveCode Dictionary
entry for each built-in function shows how to write both forms.
You can use the "the" form for built-in functions, but not for custom functions that you write.
Writing custom functions is discussed later.
myCommand
You respond to a custom command's message in the same way, by writing a message handler
with the name of the command:
If you don't specify an object, the message is sent to the object whose script is being executed,
and then passes up the message hierarchy as normal.
Like a built-in command, a custom command is an instruction to LiveCode to do something. You
can include parameters with a custom command by passing them after the name:
checkForConnection "ftp://ftp.example.org"
makePrefsFile fileLoc,field "Preferences"
However, the syntax of custom commands is more limited. A custom command can have several
parameters, and if there is more than one, they are separated by commas:
libURLDownloadToFile myFile,newPath,"downloadComplete"
revExecuteSQL myDatabaseID,field "Query","\*b" & "myvar"
But custom commands cannot use words like "and" and "to" to join parts of the command
together, the way built-in commands can. Because of this, custom commands cannot be as
English-like as built-in commands can be.
Using custom functions
When you use the custom function "leHeader" in a statement, the function handler is executed,
and the function call is replaced by the value in the return statement. This example shows how
the function can be used:
Like a built-in function or library function, a custom function call is a request for information. Here
are a few examples showing the use of made-up custom functions:
get formattedPath("/Disk/Folder/File.txt")
put summaryText(field "Input") into field "Summary"
if handlerNames(myScript, "getProp") is empty then beep
Custom functions don't have a "the" form, and are always written with parentheses following the
function name. If the function has parameters, they are placed inside the parentheses, separated
151
by commas. If the function doesn't have parameters, the parentheses are empty.
Passing Parameters
A value that you pass from one handler to another is called a parameter.
In the example below, the following statement sends the "alertUser" message with a parameter:
The parameter "You clicked a button!" is passed to the "alertUser" handler, which accepts the
parameter and places it in a parameter variable called "theMessage". The "alertUser" handler can
then use the parameter in its statements:
on alertUser theMessage
beep
answer theMessage -- uses the parameter "theMessage"
end alertUser
on seriouslyBugUser theMessage,numberOfBeeps
beep numberOfBeeps
answer theMessage
end seriouslyBugUser
seriouslyBugUser "Hello",5
When the "seriouslyBugUser" handler is executed with the statement above, the theMessage
parameter is "Hello", and the numberOfBeeps parameter is 5.
Parameter Variables
In the example above, "theMessage" and "numberOfBeeps" are the parameter variables. You
declare parameter variables in the rst line of a handler. When the handler begins executing, the
values you passed are placed in the parameter variables. You can use parameter variables the
same way as ordinary variables: you can put data into them, use them in expressions, and so on.
Parameter variables are local variables, so they go out of existence as soon as the handler stops
executing.
152
on processOrder itemName,itemSize,numberOfItems
put itemName into field "Name"
put itemSize into field "Size"
if numberOfItems is empty then put 1 into field "Number"
else put numberOfItems into field "Number"
end processOrder
processOrder "sweater","large"
The statement only passes two parameters, while the "processOrder" handler has three
parameter variables, so the third parameter variable, "numberOfItems", is empty. Because the
handler provides for the possibility that "numberOfItems" is empty, you can pass either two or
three parameters to this handler.
Setting a default value for a parameter
To use a default value for a parameter, you check whether the parameter is empty. If it is, then no
value has been passed, and you can simply put the desired default into the parameter, as in the
following example:
logData theData,theFilePath
if theFilePath is empty then
put "logfile" into theFilePath
end if
put theData into URL ("file:" & theFilePath)
end logData
The "logData" handler puts data into a le, whose name and location you specify in the second
153
parameter. If you only provide one parameter, the handler uses the lename "logle" as the
default value, and logs the data to that le:
The rst statement above species the second parameter, so it doesn't use the default value. The
second statement only species one parameter, so the data will be placed in "logle" by default.
Implicit Parameters
If a statement passes more parameters than the receiving handler has parameter variables to
hold them, the receiving handler can access the extra parameters with the param function:
The function above assumes that two parameters will be passed to be multiplied, but can multiply
more numbers by using the param function to access parameters beyond the rst two. The
following statement uses the "product" custom function above to multiply four numbers together:
answer product(22,10,3,7)
When the "product" handler executes, the rst two parameters 22 and 10 are placed in the
parameter variables "rstFactor" and "secondFactor". The third parameter, 3, is accessed with the
expression param(3) , and the fourth parameter, 7, is accessed with the expression param(4) .
parameters is called "passing by reference", because you pass a reference to the variable itself
instead of just its value.
For example, the following handler takes a parameter and adds 1 to it:
on setVariable @incomingVar
add 1 to incomingVar
end setVariable
on mouseUp
put 8 into someVariable
setVariable someVariable*-- call by reference*
answer "someVariable is now:" && someVariable
end mouseUp
Executing this mouseUp handler displays a dialog box that says "someVariable is now: 9". This is
because, since "someVariable" was passed by reference to the "setVariable" handler, its value was
changed when "setVariable" added 1 to the corresponding parameter variable.
You can pass parameters by reference to any custom function or custom command, simply by
preceding the parameter name with the @ character in the rst line of the handler, as in the
"setVariable" example handler above. Do not use the @ character when referring to the
parameter elsewhere in the handler.
Note: If a parameter is passed by reference, you can pass only variable names for
that parameter. You cannot pass string literals or expressions using other containers
such as elds. Trying to use the "setVariable" command described above using the
following parameters will cause an execution error:
Empty parameters
If a handler denes a parameter as being passed by reference, you must include that parameter
when calling the handler. Omitting it will cause an execution error.
Returning Values
Once a function handler has calculated a value, it needs a way to send the result back to the
handler that called the function. And if an error occurs during a message handler, it needs a way
to send an error message back to the calling handler.
The return control structure is used within a function handler to pass the resulting value back to
the calling handler. The returned value is substituted for the function call in the calling statement,
just like the value of a built-in function. Take another look at the example from above:
155
In the custom function example above, thereturn control structure sends the spaced-out string
back to the mouseUp handler that called the "expanded" function.
Note: The return control structure stops the handler, so it's usually the last line in
the handler.
on echoAMessage
ask "What do you want to show?"
if it is empty then return "No message!"
else answer it
end echoAMessage
This handler asks the user to enter a message, then displays that message in a dialog box. If the
user doesn't enter anything (or clicks Cancel), the handler sends an error message back to the
calling handler. A handler that uses the "echoAMessage" custom command can check the result
function to see whether the command successfully displayed a message:
on mouseUp
echoAMessage
if the result is empty then beep
end mouseUp
The result function is also set by many built-in commands in case of an error. If you check the
result in a handler, the value belongs to whatever command built-in or custom that set it last,
so if you're going to check the result, be sure to do so right after the command whose success
you want to check.
Summary
156
Variables
A variable is a place to store data that you create, which has no on-screen representation.
Variables can hold any data you want to put into them. One way to think of a variable is as a box
with a name on it. You can put anything you want into the box, and take it out later, by simply
providing the variable's name:
But unlike some other types of containers, variables are non-permanent and aren't saved with the
stack. Instead, variables are automatically deleted either when their handler is nished running or
when you quit the application (depending on the variable's scope). You can also use the delete
variable command to delete a variable. When a variable is deleted, not only the content of the
variable disappears, but also the variable itself--the "box".
Tip: To save a variable's value, set a custom property of the stack to the value of the
variable in your applications closeStackRequest or shutDown handler. To restore
the variable, put the custom property into a variable in the application's startUp or
openStack handler.
Variable Scope
The scope of a variable is the part of the application where the variable can be used. If you refer to
a variable in a handler that's outside the variable's scope, you'll get either an execution error or
an unexpected result.
There are three levels of variable scope: local, scriptlocal, and global. Every variable is one of
these three types. The dierence between these scopes is in where they can be used and how
long their value lasts.
Local Variables
A local variable can be used only in the handler that creates it. Once the handler nishes
157
executing, the variable is deleted. The next time you execute the handler, the variable starts from
scratch: it does not retain what you put into it the last time the handler was executed.
To create a local variable, you simply put something into it. If you use the put command with a
variable name that does not yet exist, the variable is automatically created as a local variable:
Tip: While you can use almost any word that isnt a LiveCode language word also
known as a reserved word for a variable name, it will help you greatly if you get into
the habit of naming variables logically and consistently. For details of what names are
allowed for variables, see the section on Variable Names below. For some
recommendations on naming variables, see the section on Tips for Writing Good
Code, below.
Alternatively, you can create a local variable explicitly by declaring it using the local command
inside a handler:
Important: If you use a local variable in one handler, and that handler calls another
handler, you can't use the local variable in the second handler. If you use a variable
with the same name, LiveCode creates a second variable that is local to the second
handler. But the two local variables don't aect each other, because they're in
dierent handlers.
One common source of bugs involves misspelling a local variable name. Normally, doing so
doesn't produce an execution error, because if you use a variable that doesn't exist, LiveCode
creates it automatically. This means that if you misspell a variable name, LiveCode creates a new
variable with the mispelled name. Such a bug may be dicult to track down because it can result
in a variable having the wrong value without causing an error message.
To prevent this problem, you can require all local variables to be declared with the local
command. You do this by turning on Script -> Variable Checking in the Code Editor menu bar.
If this option is on, trying to use a local variable that doesn't exist will cause an execution error,
instead of automatically creating it. Any misspelled variable names will therefore cause an
obvious execution error when their handler is executed, making them easy to nd.
Local variables are deleted when the handler that they're used in nishes executing. You can also
use the delete variable command to delete a local variable.
local mySharedVariable
on mouseDown
put 2 into mySharedVariable
end mouseDown
on mouseUp
answer mySharedVariable *-- displays "2"*
end mouseUp
Note: If you put the local command in a handler, instead of outside any handler, it
creates a local variable instead. The command creates a script local variable only if
you put it in the script but not within a handler.
You can also use the delete variable command to delete a script local variable.
Global Variables
A global variable can be used in any handler, anywhere in the application. Unlike a local variable, a
global variable retains its value even after the handler that created it nishes executing. Unlike a
script local variable, a global variable can be used by any handler in any object's script.
The same global variable can be used by any stack during a session. You can declare a global
variable in one stack, and use it in others.
To create a global variable, you must declare it using the global command:
global someGlobalSetting
You must also use the global command at the start of a handler to make an existing global
variable available to a handler. While a global variable can be used by any handler, you must do
this in any handler you are going to use it in. If you don't declare a global variable before using it,
the handler will not take the global variable's existence into account, and will simply create a local
variable with the same name.
You can use the global command either inside a handler, or outside any handler at the top of a
script (like a script local). If you use the command in a handler, the global variable can be used by
any statement in that handler. If you use the command in a script but outside any handler, the
global variable is available to every handler in that script.
The following example shows the use of a global variable in a button script. In this example, the
variable is declared outside any handler, so the individual handlers don't need to declare it again:
159
To use the same global variable in a handler where the variable isn't declared in the script, you
must place the global declaration in the handler:
If you click the rst button, then the secoond, the second button displays the number 8.
As with script local variables, we recommend you place all global declarations in scripts at the
top of the script, making the declarations easy for you to nd later.
Tip: You can get a list of existing global variables with the globalNames function.
You can also choose Development > Variable Watcher to see a list of global
variables and change their values. Or you can get the value using the Message Box.
Global variables are automatically deleted when you quit the application. You can also use the
delete variable command to delete a global variable.
Variable Names
The names of variables must consist of a single word and may contain any combination of letters,
digits, and underscores (_). The rst character must be either a letter or an underscore. You
cannot use any LiveCode language word as a name of a variable.
Here are some examples of legal variable names:
someVariable
picture3
my\_new\_file
_output
160
Avoid giving a variable the same name as a custom property. If you refer to a custom property,
and there is a variable by the same name, LiveCode uses the contents of the variable as the
name of the custom property. Generally this will produce unexpected results.
Global variables whose names begin with "gRev" are reserved by the LiveCode development
environment.
See the section on Tips for Writing Good Code below for advice on choosing variable names.
on myHandler thisThing,thatThing
add thisThing to thatThing
subtract thatThing from field 2
end myHandler
When you use the custom command or custom function, you can pass values to it using the
parameters:
myHandler 15,4+1
-- puts "15" into the parameter "thisThing",
-- and puts "5" into the parameter "thatThing"
When named parameters are used in a handler, they are called parameter variables. Within the
handler, the parameters can be used in the same way as local variables: you can get their value,
use them in expressions, and put data into them.
Like local variables, parameter variables persist only as long as the handler is executing.
Environment variables
161
Most operating systems that LiveCode supports provide information about the operating
environment in environment variables.
You can access environment variables by prepending the $ character to the variable's name. For
example, the following statement gets the contents of the LOGNAME environment variable, which
holds the current user's login name:
get $LOGNAME
See your operating system's technical documentation to nd out what environment variables are
available.
You can also create your own environment variables by prepending the $ character to the new
environment variable's name:
Note: Environment variables behave like global variables and can be used in any
handler. However, you do not need to use the global command to declare them
before using them.
The environment variables that you create this way are available to the application, and are also
exported to processes started up by the shell function or the open process command.
Command-line argument variables
If you start up the application from a command line, the command name is stored in the variable
$0 and any arguments passed on the command line are stored in numbered variables starting
with the $ character.
For example, if you start the application by typing the following shell command:
myrevapp -h name
then the variable $0 contains "myrevapp" (the name of the application), $1 contains "-h", and $2
contains "name".
Note: Command-line argument variables behave like global variables and can be
used in any handler. However, you do not need to use the global command to
declare them before using them.
The special variable "it"
The it variable is a special local variable used by LiveCode to store certain results.
Certain commands--such as get, convert, read from le, ask, and answer--put their results
in this special variable. For a complete list of commands that use the it variable, see the entry for
it in the LiveCode Dictionary. The following example shows how the answer command uses the it
162
variable:
on mouseUp
answer "Go where?" with "Backward" or "Forward"
-- the answer command puts the button the user clicked
-- into the it variable:
if it is "Backward" then
go back
else
go next
end if
end mouseUp
You can use the it variable in the same way as any other local variable, using the put command
to put things into it and using the variable in expressions to work with the contents.
Array Variables
A variable can hold more than a single value. A variable that holds more than one value is called
an array, and each of the values it holds is called an element. Each element has its own name
(called the element's key).
If you think of a variable as a box with a name, you can think of an array as a box with
compartments inside it. Each compartment is an element, and each compartment has a name,
or key, of its own.
You specify an element of an array variable by using the variable name along with the element's
key. You enclose the key in square brackets. The key may be a name, number or variable. Here's
an example that shows how to put data into one element of an array:
Note: If you use a key that's not a number or variable, you should enclose the key's
name in double quotes whenever you refer to it. This prevents problems in case there
is a variable or reserved word with the same name.
You can use any element of an array variable in the same way you use the whole variable: put
data into the element (or before or after it) and nd out what data it contains. In this way, any
element of a variable is like a variable in and of itself.
Array elements may contain nested or sub-elements, making them multi-dimensional. This type
of array is ideal for processing hierarchical data structures such as trees or XML. To access a subelement, simply declare it using an additional set of square brackets.
163
This statement removes the element named "myElement" from the variable "myVar", but does
not delete the other elements in the array.
Listing the Elements in an Array
Tip: To delete the contents of an element without deleting the element itself, put
empty into the element:
You use the keys function to list the elements in an array variable. The keys function returns a
list of elements, one per line:
164
KEY
VALUE
apple
bottle
cradle
For more details, see the split command in the LiveCode Dictionary.
Combining the Elements of an Array into a List
The combine command combines the elements of the array into a single variable. After the
command is nished executing, the variable specied by array is no longer an array.
For example:
Will combine the contents of the each element of the original array so that they appear on a
separate line.
For more information, see the combine command in the LiveCode Dictionary.
Nesting an Array
You may place an entire array as a child of an element by putting an array variable into an
element of another array. For example:
Will result in the entire array being placed as a child of node50 within tBigArray.
More Information
For more information about using array variables, see the guide on Processing Text and Data.
Constants
A constant is a value that has a name. Like a variable, a constant is set in your script. Unlike
variables, constants cannot be changed.
When you use a constant, LiveCode substitutes the value of the constant for its name. The
following example uses a constant named "slash":
Built-in constants
The LiveCode language denes several constants, such as return, space, and comma, for
characters that have special meaning in scripts and therefore can't be entered literally into an
expression.
Tip: To see a list of all built-in constants, open the Documentation window, click
LiveCode Dictionary, and choose "Constants" from the menu at the top of the
window.
User-dened constants
You can also dene your own constants using the constant command:
Like variables, constants can have dierent scope depending on how they are created. A constant
can be dened as either a local constant or a script local constant:
If you place the constant command in a handler, the constant can be used only in that handler.
If you place the constant command in a script, but outside any handler, the constant can be
used in any handler in the script.
Quoting strings
Literal strings that consist of more than one word or are reserved words in the LiveCode language
must be enclosed in double quotes:
put
put
put
put
In some contexts, you can use an unquoted one-word literal string without causing a script error.
However, you should make a practice of always quoting literal strings (other than numbers),
because it ensures that the statement will continue to work properly even if the string becomes a
reserved LiveCode word in the future.
If the Script -> Variable Checking option is set to true, compiling a script that contains an
unquoted literal string causes a script error.
Numeric Operators
Numeric operators produce a number as their result. Numeric operators include the arithmetic
167
operators (+, -, *, /, mod, div, and ^) and the bitwise operators (bitAnd, bitOr, bitXOr, and
bitNot). For individual usage instructions, look up the operator you wish to use in the LiveCode
Dictionary.
For example:
put "1+2 =" && 1+2 into field "Eq" -- displays "1+2 = 3"
String operators
String operators produce a string of characters as their result. String operators are the
concatenation operators (&, &&, and ,).
put "1+2 =" && 1+2 into field "Eq" -- displays "1+2 = 3"
Logical Operators
Logical operators produce either "true" or "false" as their result.
Logical operators include the comparison operators (=, \<>, \<, >, \<=, >=), existence
operators (there is a, there is no, is in, is not in, is among, is not among, contains), data
type operators (is a, is not a), geometry operators (is within, is not within), and basic logical
operators (and, or, not).
if the platform is "MacOS" and field "Time" < zero then ...
The bitNot, there is a, there is no, is a, is not a, and not operators are unary operators. All
other operators are binary operators.
Conversion of Values
LiveCode converts values in expressions to whatever type of data is needed for the operation.
This conversion happens automatically, so you don't need to know what type of data you are
dealing with in advance (something that in other languages is called "type casting").
For example, suppose you have the following statement:
168
Character 2 of the literal string "123" is the single-character string "2", and character 3 of the
literal string "456" is the single-character string "6". When LiveCode uses the + operator, it
automatically converts these strings to numbers so that they can be added together. Then it
converts the resulting number back to a string so that it can be placed in a eld as text.
Operator Precedence
When you combine sources of value using operators, LiveCode evaluates each source of value in
the expression. Next, it applies any operators to arrive at a nal value for the expression.
LiveCode does not necessarily apply all the operators in right-to-left order.
Instead, it uses the operator precedence order to determine how to compute expressions that
include more than one operator. Precedence determines the order in which LiveCode carries out
calculations in expressions. If an expression contains more than one operator, the operators with
higher precedence are calculated before operators with lower precedence.
Figure 49 Operator Precedence
Grouping
()
Unary
not
bitNot
there is
a
there is
no
Next, unary operations (that act on only one operand) are done.
This includes unary minus (which makes a number negative).
Exponentiation ^
Multiplication
*
/
div
mod
Addition
+
-
Concatenation
&
&&
,
Operations that join two strings are done next. These are string
operators and result in a string.
169
Comparison
\<
\<=
>
>=
contains
is
among
is not
among
is in
is not in
is within
is not
within
is a
is not a
Operations that compare two values are done next. These are
logical operators and result in either true or false.
Equality
=, is
\<>, !=,
?, is not
Operations that compare two values for equality are done next.
These are logical operators and result in either true or false.
bitAnd
bitAnd
bitXOr
bitXOr
bitOr
bitOr
and
and
or
or
function calls
If you want the sine of 1/4, you need to change the order of evaluation so that the division is done
rst. You do this by surrounding the part you want evaluated rst with parentheses:
If parentheses are nested, the expression within the innermost set of parentheses is evaluated
170
rst.
Dening Factors
A factor is the rst fully resolvable portion of an expression. (All factors are expressions, but not all
expressions are factors.) A factor can be either a source of value, or an expression that combines
sources of value but doesn't include any binary operators outside parentheses. Enclosing an
expression in parentheses turns it into a factor.
These examples show some expressions, along with the rst factor in each expression, to help
you see the distinction:
Expression
First factor
3+4
(3 + 4)
(3 + 4)
(3 + 4)/eld 4
(3 + 4)
eld 6 * pi
eld 6
sin of pi/4
sin of pi
sin(pi/4)
sin(pi/4)
whole
"whole world"
"whole world"
When it matters
The distinction between factors and expressions matters when you're using the the form of builtin functions, when you use URL, and when you refer to objects.
If you use the the form of a built-in function that has a parameter, the parameter must be a
factor, not an expression:
In the rst example above, although we intended to get the square root of 9, we actually ended up
with the square root of 4. This is because the expression 4 + 5 is not a factor (because it
contains a binary operator that's not inside parentheses). The rst factor in the expression 4 + 5
is 4, so the rst example gets the square root of 4 (which is 2), then adds 5 to that result.
The second example avoids this problem because it doesn't use the "the" form of the function.
Since the parameter is enclosed in parentheses, you can use either a factor or an expression,
171
In the rst example, the URL specied is a factor because it is a simple string with no operators.
The URL in the second example is not a factor, because it includes the binary operator &, so the
get command tries to get the URL "le:" which is nonexistent--and concatenate the content of
that URL with the string "myle.txt".
In the third example, we turn the URL into a factor by surrounding it with parentheses, providing
the expected result.
When referring to cards or backgrounds, the name, number or ID of the object is an
expression:
However, when referring to controls (including groups) or stacks, the name, number, or ID of the
object is a factor:
answer
answer
select
select
Making Decisions
You make decisions using the if then else control structure or, if you want to choose from a
list of options, use the switch control structure.
If then else
Use the if control structure to execute a statement or list of statements under certain
circumstances. For example, you may want your application to respond dierently depending on a
user action.
172
The if control structure always begins with the word if. There are four forms of the if control
structure:
This form may have a line break before the words then or else or both.
if condition then
statementList
[else
elseStatementList]
end if
if condition
then statement
[else
elseStatementList
end if]
if condition then
statementList
else elseStatement
The condition is any expression that evaluates to true or false. The statementList or
elseStatementList consists of one or more LiveCode statements, and can also include if, switch,
try, or repeat control structures. The statement or elseStatement consists of a single LiveCode
statement.
If the condition evaluates to true, the statement or statementList is executed; if the condition
evaluates to false, the statement or statementList is skipped. If the if control structure contains
an else clause, the elseStatement or elseStatementList is executed if the condition is false.
If one if control structure is nested inside another, use of the second form described above is
recommended, since the other forms may cause ambiguities in interpreting which else clause
belongs with which if statement.
The if control structure is most suitable when you want to check a single condition. If you need to
check for multiple possibilities, doing something dierent for each one, use a switch control
structure instead.
Switch
Use the switch control structure when you want to choose among several possible values for an
expression and then execute a set of statements that depends on the value.
173
switch [switchExpression]
case {caseValue | caseCondition}
[statementList]
[default defaultStatementList]
end switch
The switch control structure begins with the word switch on a single line, with an optional
switchExpression. The switch line is followed by one or more case sections. Each case section
begins with the case keyword, followed by either a caseValue (if a switchExpression was included
on the switch line) or a caseCondition (if no switchExpression was included). If the caseValue is
equal to the switchExpression, or the caseCondition evaluates to true, LiveCode begins executing
the following statements.
The case sections may be followed by an optional default section. If no break statement has
been encountered yet in the switch control structure, the statements in the default section are
executed. The switch structure ends with an end switch statement.
The switchExpression is any expression. The caseValue is any expression. If the caseValue
evaluates to the same value as the switchExpression, the condition is matched for that case
section. The caseCondition is any expression that evaluates to true or false. (If the caseCondition
evaluates to true, the condition is matched for that case section. Each statementList consists of
one or more LiveCode statements, and can also include if, switch, try, or repeat control
structures. The defaultStatementList consists of one or more LiveCode statements.
Flow of control in a switch structure is less complicated than it looks. In general, when LiveCode
enters a switch control structure, it looks for the rst case section whose caseValue is equal to
the switchExpression, or whose caseCondition is true. When a matching condition is found, all
statements following it are executed--even statements in another case section--until either a
break statement is encountered or the switch control structure ends.
This means that if you do not end a case section's statementList with a break statement, the
statements in all the following case sections (and the default section) are executed even if those
case sections don't have a matching caseValue or a true caseCondition. Occasionally, this
behavior is useful. However, in most cases, you should place a break statement at the end of
each statementList. This ensures that only one statementList is executed, and the rest are
skipped.
This also means that you can attach more than one caseValue or caseCondition to the same
statementList, simply by placing one case line above the next. The following example beeps if the
current card is either the last or rst card, and goes to the next card otherwise:
174
There is no limit to the number of case sections you can include in a switch control structure,
although the more case sections there are, the more expressions LiveCode must evaluate and
the more slowly the switch structure executes.
Using backScripts
To make the script of an object available to any other handler in LiveCode:
The script of an object that's been inserted into the back, as in the above example, is called a
backScript. Such an object is placed last in the message path of all objects. It receives
175
messages after any other object, and just before the engine receives the message. The
backScript object remains in the message path until the end of the session (or until you remove
it with the remove script command.)
Because a backScript receives messages after all other objects in the message path, if you
place a handler in the backScript, it eventually gets all the corresponding messages, no matter
what object sent them, unless another object handles them rst.
Using frontScripts
You can also extend the message path by placing objects into the front of the message path,
before any other object. The script of such an object is called a frontscript, and you use the insert
script command to place the object in the front:
Because the object is in the front of the message path, it receives messages even before the
target of the message. For example, if you click a button, any objects in the front of the message
path receive the mouseUp message rst, before the button. If you place a handler in a
frontscript, it receives all the corresponding messages before any other object can handle them.
Use a frontscript when you want to be able to handle a message even if the target object has a
handler for it. For example, the LiveCode development environment displays a contextual menu
when you Control-Shift-right-click an object. It does this with a mouseDown handler in a
frontscript. Whenever you click an object, the frontscript receives the mouseDown message rst,
and checks whether the needed keys are being pressed. If they are, the handler displays the
contextual menu; the mouseDown message is trapped and goes no further. Otherwise, the
handler passes the message to the next object in the message path, which is the object you
clicked.
176
on mouseUp
-- in button script
send "mouseUp" to this stack
end mouseUp
For example, suppose you have a handler for a custom command called myCommand in the
script of a button, and you want to execute that handler from a card script. Since the button is not
in the card's message path, you can't simply use the command in the script, because if the
myCommand message goes through the card's message path, it won't nd the handler. The
following statement sends the message directly to the button whose script includes the handler:
Important: When you send a message to an object, the message path for that
message starts with the target object. For example, if a stack script contains a send
command that sends a message to a button, the message moves through the
button's message path, not the stack's.
If you want to use a custom function whose function handler is not in the message path, you can
use the value function to specify the object. The value function can be thought of as an
equivalent of the send command for function calls.
For example, if card 1 of a stack contains a function handler called "myFunction" you can use the
function from within the script of card 3 with the following statement:
get value("myFunction(1,2,3)",card 1)
on showCard
answer the number of this card
end showCard
If a handler in the script of card 3 uses the send command to send a "showCard" message to
card 1, the dialog box displays "1", the number of the card the handler is on. However, if the same
177
handler uses the call command instead, the dialog box displays "3", the number of the card that
used the call command. In other words, handlers that are triggered by the send command use
the context of the object the handler is in, while handlers that are triggered by the call command
use the context of the object that triggered the handler.
178
on mouseUp
updateAnimation
end mouseUp
on updateAnimation
-- insert code to update animation here
send updateAnimation to me in 33 milliseconds
end updateAnimation
The result will be that the updateAnimation message is sent, it will update the screen then send
itself to itself in a 33 milliseconds. The message will continue to be delivered indenitely. Therefore
it is important that you ensure there is an condition in the message handler that will exit when the
task is done, without sending the message again. Alternatively you can directly cancel any
message to stop the loop (see the section Canceling a Timer Message below for more details).
To create a smooth script driven animation, you should allow for the time it takes to redraw the
display and for any interruptions (e.g. another intensive process causing your message to be
delivered late). Thus it is best to send the message a little more frequently than you need to
redraw the screen, and to check each time the message is activated what frame you should
currently be on.
179
180
local LTimerID
on mouseEnter
send "displayDialog" to me in 20 seconds
put the result into lTimerID
end mouseEnter
on mouseLeave
cancel lTimerID
end mouseLeave
on displayDialog
answer "The mouse was over this button for 20 seconds."
end displayDialog
Important: Ensure you have a way to cancel any pending timer messages. Typically
you may want to ensure that a timer is cancelled when the card is closed. For
example a timer message that draws an animation on the current card will generate
a script error if the card is changed and the message is still sent, as the script will no
longer be able to nd the objects.
tMessagesList will now contain a list of messages, one per line. Each line consists of four items,
separated by commas:the message ID, the time the message is scheduled for, the message
name, the long ID property of the object that the message will be sent to
Tip: You can see a list of all pending messages using the Message Box pending
messages tab the fth icon along. For more details, see the section on the
Message Box.
For more details, see the pendingMessages entry in the LiveCode Dictionary.
Tip: To cancel all currently pending messages indiscriminately, use the following
repeat loop:
repeat for each line l in the pendingMessages
cancel (item 1 of l)`
end repeat
benets to making your coding practices consistent. Consistently named variables are easier to
debug during development because you will always know the scope of a particular variable
(whether it's a global, or applies only to the current handler, etc.). It makes it easier to understand
the code you have written when you come to read it 6 months later. By making appropriate use of
functions and libraries, you make your program more modular and therefore easier to modify and
add features to in the future. A comprehensive guide to writing good code is beyond the scope of
this manual. But we thought it would be helpful to give you some hints and tips
Variable naming
Use consistent variable names to make your code easier to understand. It may not seem
important now, but when you have forgotten how it works 6 months later it will help to make it
readable. It also makes it easier to exchange you code with other members of the LiveCode
community, when you need to get help with something.
Character
Example
Usage
gVar
Global variables
tVar
Handler-local variables
sVar
Script-local variables
pVar
Parameters
kVar
Constants
cVar
Custom properties
Variable scope
As a general rule of thumb, use a variable with just enough scope and no more for the task at
hand. In other words, if a handler local variable is all you need for a calculation, don't use a script
local. If a script local would do, don't use a global. This makes it less likely that you will introduce
unexpected errors into your code by using the same variable name for dierent purposes. A
handler local variable only has meaning within that handler so you can safely use the same
variable name in other handlers.
Use of comments
Comment your code as you go. Don't write comments where the meaning is obvious. But even a
sentence next to a complex routine will help you or others to quickly understand it later.
Use of functions
If you're writing a lot of code, consider whether it can be written as a series of functions instead of
as a single monolithic handler. This makes it much easier to understand the function of each
discrete section of code. The more you can make these functions "black boxes", that take input
and produce output without dependences, the easier it will be if you later want to change how that
aspect of the code works.
Explicit Variables
If you're working on a larger code base you may want to turn on the Variable Checking option in
the Script menu of the Code Editor. This makes LiveCode require that you declare all variables
(even script locals) before you can compile your script. It also requires you to place all literal
strings in quotes. This method of coding can help you to quickly track down errors as you go by
making you think a little about what variables you are going to use at an early stage, and pointing
182
183
Referring to Objects
In general, you can refer to any object by its name, number, or ID property.
To change an object's name, enter a name in the object's property inspector, or use the set
command to change the object's name property:
set the name of field "Old Name" to "New Name"
select after text of field "New Name"
184
To change the number of a card or control, change the Layer box in the Size & Position pane of
the object's property inspector, or use the set command to change the object's layer property:
set the layer of field "Backmost" to 1
Tip: New objects are always created at the top layer. To refer to an object you've just
created, use the ordinal last:
create button
set the name of last button to "My New Button"
Referring to objects by ID
Each object in LiveCode has an ID number. The ID property never changes (except for stack IDs),
and is guaranteed unique within the stack: no two objects in the same stack can have the same
ID property.
You can refer to an object using its object type, then keyword ID , followed by its ID number. For
example, to refer to a card whose ID property is 1154, use the phrase card ID 1154:
go to card ID 1154
Control references
A control is any object that can appear on a card. Fields, buttons, scrollbars, images, graphics,
players, widgets, and groups are all controls. Stacks, cards, audio clips, and video clips are not
controls.
You can refer to an object of any of these object types using the word "control", followed by an ID,
name, or number:
hide control ID 2566
send mouseDown to control "My Button"
set the hilite of control 20 to false
If you use a name, as in the expression control "Thing" , the reference is to the rst control
(with the lowest layer) that has that name.
When you refer to a control by number using its object type, the reference is to the Nth control of
that type. For example, the phrase eld 1 refers to the lowest eld on the card. This may not be
the lowest control, because there may be controls of other types underneath eld 1. However,
when you refer to a control by number using the word control, the reference is to the Nth control
of any type. The phrase control 1 refers to the lowest control on the card, which may be of any
type.
Tip: To refer to the object underneath the mouse pointer, use the mouseControl
function.
You can mix names, numbers, ordinal references, and IDs in a nested object reference, and you
can nest references to whatever depth is required to specify the object. The only requirement is
that the order of references be the same as the order of the object hierarchy, going from an
object to the object that owns it. Here are some examples:
field ID 34 of card "Holder"
player 2 of group "Main" of card ID 20 of stack "Demo"
first card of this stack
stack "Dialog" of stack "Main" -- "Dialog" is a substack
If you don't specify a card in referring to an object that is contained by a card, LiveCode assumes
the object is on the current card. If you don't specify a stack, LiveCode assumes the object is in
186
the current stack. You can reference a control in another stack by either of the following methods:
Use a nested reference that includes the name of the stack:
field 1 of stack "My Stack"
graphic "Outline" `of` card "Tools" `of` stack "Some Stack"
Set the defaultStack property to the stack you want to refer to rst. The defaultStack
species the current stack, so you can refer to any object in the defaultStack without including a
stack name. This example sets a checkbox in the current stack to have the same setting as a
checkbox in another stack called "Other Stack":
put the defaultStack into savedDefault -- so you can set it back later
set the defaultStack to "Other Stack"
put the hilite of button "Me" into meSettin -- this button is in "Other
Stack"
set the defaultStack to savedDefault
set the hilite of button "Me Too" to meSetting -- this button is in the
original stack
If an object is in a group, you can include or omit a reference to the group in a nested reference to
the object. For example, suppose the current card contains a button called "Guido", which is part
of a group called "Stereotypes". You can refer to the button with any of the following expressions:
button
button
button
button
"Guido"
"Guido" of card 5
"Guido" of group "Stereotypes"
"Guido" of group "Stereotypes" of card 5
If there is no other button named "Guido" on the card, these examples are equivalent. If there is
another button with the same name in another group (or on the card, but not in any group), you
must either specify the group (as in the second and third examples) or refer to the button by its
ID property, to be sure you're referring to the correct button.
Properties
A property is an attribute of a LiveCode object. Each type of object has many built-in properties,
which aect the object's appearance or behavior. You can also dene custom properties for any
object, and use them to store any kind of data.
This topic discusses how to use properties, how properties are inherited between objects, and how
to create and switch between collections of property settings.
To fully understand this topic, you should know how to create objects, how to use an object's
property inspector, and how to write short scripts.
187
Referring to properties
Property references consist of the word the , the property name, the word of, and a reference
to the object:
Properties are sources of value, so you can get the value of a property by using it in an
expression:
put the height of field "Text" into myVar
put the width of image "My Image" + 17 after field "Values"
if item 1 of the location of me \> zero then beep
For example, to use the width property of a button as part of an arithmetic expression, use a
statement like the following:
add the width of button "Cancel" to totalWidths
The value of the property in this case, the width of the button in pixels is substituted for the
property reference when the statement is executed.
To see a list of all the language words (including properties) applicable to a particular object type,
open the Dictionary and navigate to the entry for the object type. You can lter the entries to only
show object types by clicking on the object in the type lter section.
188
Changing properties
To change the value of a property, you use the set command:
set the borderColor of group "My Group" to "red"
set the top of image ID 3461 to zero
You can also see and change many of an object's properties by selecting the object and choosing
Object Inspector. See the chapter Building a User Interface for more details.
Most built-in properties aect the appearance or behavior of the object. For example, a button's
height, width, and location are properties of the button. Changing these properties in a
handler causes the button's appearance to change. Conversely, dragging or resizing the button
changes the related properties.
Read-only properties
Some properties can be read, but not set. These are called read-only properties. Trying to set a
read-only property causes an execution error.
To nd out whether a property is read-only, check its entry in the LiveCode Dictionary.
Changing a part of a property
Properties are not containers, so you cannot use a chunk expression to change a part of the
property. However, you can use a chunk expression to examine part of a property. For example,
you cannot set line 1 of a property to a new value: you must set the whole property. For more
details see the section Chunk Expressions in the chapter on Processing Text and Data.
To change one part of a property, rst put the property value into a variable, change the required
part of the variable, then set the property back to the new variable contents:
put the rect of me into tempRect
put "10" into item 2 of tempRect
set the rect of me to tempRect
Custom properties and virtual properties are covered in their respective sections later in this
chapter.
Property Inheritance
Most properties are specic to the object they are part of, and aect only that object.
189
However, some properties of an object, such as its color and text font, take on the settings of the
object above it in the object hierarchy. For example, if a eld's background color property is not
specied (that is, if its backgroundColor property is empty), the eld takes on the background
color of the card that owns it. If no background color is specied for the card either, the stack's
background color is used, and so on. This means you can set a background color for a stack, and
every object in it will automatically use that background color, without your having to set it for
each object.
This process of rst checking the object, then the object's owner, then the object that owns that
object, and so on, is called inheritance of properties. Each object inherits the background color of
the object above it in the hierarchy. Similar inheritance rules apply to the foregroundColor,
topColor, bottomColor, borderColor, shadowColor, and focusColor properties, to their
corresponding pattern properties, and to the textFont, textSize, and textStyle properties.
Overriding inheritance
Inheritance is used to determine an object's appearance only if the object itself has no setting for
the property. If an inheritable property of an object is not empty, that setting overrides any setting
the object might inherit from an object above it in the object hierarchy.
For example, if a button's backgroundColor property is set to a color reference instead of being
empty, the button uses that background color, regardless of the button's owners. If the object has
a color of its own, that color is always used.
The eective keyword
If an inheritable property of an object is empty, you can't simply check the property to nd out
what color or font settings the object displays. In this case, use the eective keyword to obtain
the inherited setting of the property. The eective keyword searches the object's owners, if
necessary, to nd out what setting is actually used.
For example, suppose you have a eld whose textFont property is empty. The textFont of the
card that the eld is on is set to "Helvetica", so the eld inherits this setting and displays its text in
the Helvetica font. To nd out what font the eld is using, use the expression
the effective textFont :
You can use the eective keyword with any inherited property.
Global Properties
LiveCode also has global properties, which aect the overall behavior of the application. Global
properties are accessed and changed the same way as object properties. They do not belong to
any particular object, but otherwise they behave like object properties.
Tip: To see a list of all global properties, open the Message Box, and choose the
Global Properties icon the third icon from the left at the top of the window. To see a
list of all properties in the language, including both global and object properties, use
the propertyNames global property.
190
A few properties are both global and object properties. For example, the paintCompression is a
global property, and also a property of images. For these properties, the global setting is separate
from the setting for an individual object.
Some other global properties are aected by system settings. For example, the default value of
the playLoudness property is set by the operating system's sound volume setting.
Since global properties apply to the whole application, you don't include an object reference when
referring to them.
Global properties are sources of value, so you can get the value of a global property by using it in
an expression:
get the stacksInUse
put the recentNames into field "Recent Cards"
if the ftpProxy is empty then exit setMyProxy
Some global properties can be changed by other commands. For example, the lockScreen
property can either be set directly, or changed using the lock screen and unlock screen
commands. The following two statements are equivalent:
set the lockScreen to false *-- does the same thing as...*
unlock screen
If you want to use the same setting of a global property during a dierent session of your
application, you must save the setting in a Preferences le, in a custom property, or elsewhere
in a saved le and restore it when your application starts up.
The following eld properties can be applied to either an entire eld or to a chunk of the eld:
textFont, textStyle, and textSize
textShift
backgroundColor and foregroundColor
backgroundPattern and foregroundPattern (Unix systems)
Each chunk of a eld inherits these properties from the eld, in the same way that elds inherit
from their owners. For example, if a word's textFont property is empty, the word is displayed in
the eld's font. But if you set the word's textFont to another font name, that word and only that
word is displayed in its own font.
To nd the text style of a chunk in a eld, whether that chunk uses its own styles or inherits them
from the eld, use the eective keyword:
get the effective textFont of word 3 of field ID 2355
answer the effective backgroundColor of char 2 to 7 of field "My Field"
Tip: If a chunk expression includes more than one style, the corresponding property
for that chunk reports "mixed". For example, if the rst line of a eld has a textSize
of "12", and the second line has a textSize of "24", an expression like the textSize of
line 1 to 2 of eld "My Field" reports "mixed".
The linkText property of a chunk lets you associate hidden text with part of a eld's text. You can
use the linkText in a linkClicked handler to specify the destination of a hyperlink, or for any
other purpose.
The visited property species whether you have clicked on a text group during the current
session. You can get the visited property for any chunk in a eld, but it is meaningless unless the
chunk's textStyle includes "link".
The imageSource, linkText, and visited properties are the only properties that can be set to a
chunk of a eld, but not to the entire eld or any other object. Because they are applied to text in
elds, they are listed as eld properties in the LiveCode Dictionary.
The group is any group that's on the current card. If you specify a group, the new object is a
member of the group, and exists on each card that has the group. If you don't specify a group,
the object is created on the current card and appears only on that card.
create button "Click Me"
create invisible field in first group
You can also create widgets of a given kind on a card, using the create widget command.
create [invisible] widget [*name*] as *kind* [in *group*]
The kind is the kind of any currently installed widget.
For more details, see the create command in the LiveCode Dictionary. For details on how to
specify the properties of an object before creating it, see the section on Creating Objects Oscreen Using Template Objects, below.
194
When you have used the templateObject to create a new object, you should reset it before using
it again. Resetting the templateObject sets all o its properties back to defaults.
reset the template[Objecttype]
For example, to reset the templateButton :
The properties of an object is an array containing that object's signicant built-in properties.
put the properties of button 1 into myArray
set the properties of last player to the properties of player "Example"
Tip: This example handler shows you how to write the properties of an object to a
text le.
on mouseUp
put the properties of button 1 into tPropertiesArray
combine tPropertiesArray using return and "|"
ask file "Save properties as:"
if it is not empty then put tPropertiesArray into URL ("file:" & it)
end mouseUp
In this example, each property name will be written followed by the "|" character and the property
value and then a return character.
For more details, see the properties property in the LiveCode Dictionary.
195
Custom Properties
A custom property is a property that you create for an object, in addition to its built-in properties.
You can dene custom properties for any object, and use them to store any kind of data.
This topic discusses how to create and use custom properties, and how to organize custom
properties into sets (or arrays). The following section covers how to create virtual properties and
use getProp and setProp handlers to handle custom property requests.
You can create custom properties for any object. However, you cannot create global custom
properties, or custom properties for a chunk of text in a eld. Unlike some built-in properties, a
custom property applies only to an object.
Important: Each object can have its own custom properties, and custom properties
are not shared between objects. Creating a custom property for one object does not
create it for other objects.
You can see and change all of an object's custom properties in the Custom Properties pane of the
object's property inspector: click the custom property you want to change, then enter the new
value.
196
Like built-in properties, custom properties are sources of value, so you can get the value of a
custom property by using it in an expression. The property's value is substituted for the property
reference when the statement is executed. For example, if the card's "lastCall" custom property is
"Today", the example statement above puts the string "Today" into the "Date" eld.
197
Note: Referring to a nonexistent custom property does not cause a script error. This
means that if you misspell a custom property name in a handler, you won't get an
error message, so you might not notice the problem right away.
To nd out whether a custom property for an object exists, you check whether it's listed in the
object's customKeys. The following statement checks whether a player has a custom property
called "doTellAll":
if "doTellAll" is among the lines of the customKeys of player "My Player"
then*...*
You can also look in the Custom Properties pane of the object's property inspector, which lists the
custom properties. See the chapter on Building a User Interface for more details.
198
Instead of storing the custom property as text, store it as HTML, using the HTMLText property of
elds:
set the myProp of this card to the HTMLText of field 1
Because the HTMLText property encodes special characters as entities, it ensures that the
custom property does not contain any special characters--only the platform-independent
encodings for them. You can then set a eld's HTMLText to the contents of the custom property
to display it:
set the HTMLText of field "Display" to the myProp of this card
You restore the le by putting the custom property's value into a URL:
put the myStoredFile of stack "My Stack" into URL "binfile:mypicture.jpg"
Because a custom property can hold any kind of data, you can store either text les or binary les
in a custom property. You can use this capability to bundle media les or other les in your stack.
Many Mac OS Classic les have a resource fork. To store and restore such a le, you can use the
resle URL scheme to store the content of the resource fork separately.
Tip: To save space, compress the le before storing it:
set the myStoredFile of stack "My Stack" to compress(URL
"binfile:mypicture.jpg")
properties. You can set the customKeys of an object to control which custom properties it has.
In LiveCode, there is no command to delete a custom property. Instead, you place all the custom
property names in a variable, delete the one you don't want from that variable, and set the
object's customKeys back to the modied contents of the variable. This removes the custom
property whose name you deleted.
For example, the following statements delete a custom property called "propertyToRemove" from
the button "My Button":
get the customKeys of button "My Button"
set the wholeMatches to true
delete line lineOffset("propertyToRemove",it) of it
set the customKeys of button "My Button" to it
You can also delete a custom property in the Custom Properties pane of the object's Property
Inspector. Select the property's name and click the Delete button to remove it.
You can list all the custom property sets of an object using its customPropertySets property.
As with custom properties, you can create custom property sets for any object. But you can't
create global custom property sets, or custom property sets for a chunk of a eld.
Any references to custom property refer to the current custom property set. For example,
suppose you have two custom property sets named "Spanish" and "French", and the French set
includes a custom property called "Paris" while the Spanish set does not. If you switch to the
Spanish set, the customKeys of the object does not include "Paris", because the current custom
property set doesn't include that property.
If you refer to a custom property that isn't in the current set, the reference evaluates to empty. If
you set a custom property that isn't in the current set, the custom property is created in the set.
You can have two custom properties with the same name in dierent custom property sets, and
they don't aect each other: changing one does not change the other.
The customProperties property of an object includes only the custom properties that are in the
current custom property set. To specify the customProperties of a particular custom property
set, you include the set's name in square brackets:
put the customProperties[mySet] of this card into myArray
To nd out whether a custom property set for an object exists, you check whether it's listed in the
201
object's customPropertySets. The following statement checks whether an image has a custom
property set called "Spanish":
if "Spanish" is among the lines of the customPropertySets of image ID 23945
then*...*
You can also look in the Custom Properties pane of the object's property inspector, which lists the
custom property sets in the "Set" menu halfway down the pane.
202
provides either the English or French, depending on which custom property set is active:
"myEnglishStrings" or "myFrenchStrings".
You can also use the customProperties property (which was discussed earlier in this topic) to
copy custom properties between sets. For example, suppose you have created a full set of
custom properties in a custom property set called "myEnglishStrings", and you want to copy them
to a new custom property set, "frenchStrings", so you can translate them easily. The following
statements create the new custom property set, then copy all the properties from the old set to
the new one:
-- create the new set:
set the customPropertySet of this stack to "frenchStrings"
-- copy the properties in the English set to the new set:
set the customProperties["frenchStrings "] of this stack to the
customProperties["frenchStrings "] of this stack
203
But you can also use array notation to refer to the "myProp" property, even if "mySet" is not the
current set. To refer to this custom property regardless of which custom property set is active, use
statements like the following:
get the mySet["myProp"] of button 1
set the mySet["myProp"] of the target to 20
Note: Because the default custom property set has no name, you cannot use array
notation to refer to a custom property in the default set.
Storing an array in a custom property set
If you store a set of custom properties in a custom property set, the set can be used just like an
array. You can think of the custom property set as though it were a single custom property, and
the properties in the set as the individual elements of the array.
To store an array variable as a custom property set, use a statement like the following:
set the customProperties["myProperty"] of me to theArray
The statement above creates a custom property set called "myProperty", and stores each
element in "theArray" as a custom property in the new set. To retrieve a single element of the
array, use a statement like this:
get the myProperty["myElement"] of field "Example"
You can also delete a custom property set in the Custom Properties pane of the object's property
inspector. Select the set's name from the Set menu, then click the Delete button to remove it.
204
205
When you set the "percentUsed" custom property, the "percentUsed" handler is executed:
set the percentUsed of scrollbar "Progress" to 90
When this statement is executed, LiveCode sends a setProp trigger to the scrollbar. The new
value of 90 is placed in the newAmount parameter. The handler makes sure that the new value is
in the range 0100; if not, it beeps and exits the handler, preventing the property from being set.
For more details about the setProp control structure, see setProp in the LiveCode Dictionary.
Passing the setProp trigger
When the setProp trigger reaches the engine - the last stop in the message path - the custom
property is set. If the trigger is trapped and doesn't reach the engine, the custom property is not
set.
To let a trigger pass further along the message path, use the pass control structure. The pass
control structure stops the current handler and sends the trigger on to the next object in the
message path, just as though the object didn't have a handler for the custom property.
In the "percentUsed" handler above, if the newAmount is out of range, the handler uses the exit
control structure to halt; otherwise, it executes the pass control structure. If the newAmount is in
the right range, the pass control structure lets the property be set. Otherwise, since the trigger is
not passed, it never reaches the engine, so the property is not changed.
You can use this capability to check the value of any custom property before allowing it to be set.
For example, if a custom property is supposed to be boolean (true or false), a setProp handler
can trap the trigger if the value is anything but true or false:
setProp myBoolean newValue
if newValue is true or newValue is false
then pass myBoolean
exit myBoolean
the message path to implement the same setProp behavior for objects that all have the same
custom property.
If a setProp handler sets its custom property, for an object that has that setProp handler in its
message path, a runaway recursion will result. To avoid this problem, set the lockMessages
property to true before setting the custom property.
Note: To refer to the object whose property is being set, use the target function.
The target refers to the object that rst received the setProp trigger
the object whose custom property is being set - even if the handler being
executed is in the script of another object.
Setting properties within a setProp handler
In the "lastChanged" example in the box above, the handler sets the custom property directly,
instead of simply passing the setProp trigger. You must use this method if the handler makes a
change to the property's value, because the pass control structure simply passes on the original
value of the property.
If you use the set command within a setProp handler to set the same custom property for the
current object, no setProp trigger is sent to the target object (this is to avoid runaway recursion,
where the setProp handler triggers itself). Setting a dierent custom property sends a setProp
trigger. So does setting the handler's custom property for an object other than the one whose
script contains the setProp handler.
Using this method, you can not only check the value of a property, and allow it to be set only if it's
in range, you can also change the value so that it is in the correct range, has the correct format,
and so on.
The following example is similar to the "percentUsed" handler above, but instead of beeping if the
newAmount is out of range, it forces the new value into the range 0100:
setProp percentUsed newAmount
set the percentUsed of the target to max(zero,min(100,newAmount))
end percentUsed
Nonexistent properties
If the custom property specied by a setProp handler doesn't exist, the setProp handler is still
executed when a handler sets the property. If the handler passes the setProp trigger, the
custom property is created.
Custom property sets and setProp handlers
A setProp handler for a custom property set behaves dierently from a setProp handler for a
custom property that's in the default set.
When you set a custom property in a custom property set, the setProp trigger is named for the
set, not the property. The property name is passed in a parameter using a special notation. This
means that, for custom properties in a set, you write a single setProp handler for the set, rather
than one for each individual property.
The following example handles setProp triggers for all custom properties in a custom property
207
As you can see from the exit, pass, and end control structures, the name of this setProp
handler is the same as the name of the custom property set that it controls
"myFrenchStrings". Because there is only one handler for all the custom properties in this
set, the handler uses the switch control structure to perform a dierent action for each
property that it deals with.
Suppose you change the "standardErrorPrompt" custom property:
set the customPropertySet of this stack to "myFrenchStrings"
set the standardErrorPrompt of this stack to field 1
LiveCode sends a setProp trigger to the stack, which causes the above handler to execute. The
property you set "standardErrorPrompt" is placed in the "myPropertyName" parameter, and
the new value--the contents of eld 1 is placed in the "newValue" parameter. The handler
executes the case for "standardErrorPrompt", putting a return character before and after the
property before setting it.
If you set a custom property other than "standardErrorPrompt" or "lePrompt" in the
"myFrenchStrings" set, the default case is executed. In this case, the pass control structure lets
the setProp trigger proceed along the message path, and when it reaches the engine, LiveCode
sets the custom property.
Note: As mentioned above, you can address a custom property in a set either by
rst switching to that set, or using array notation to specify both set and property.
The following example:
208
is equivalent to:
set the mySet["myProperty"] of me to true
Regardless of how you set the custom property, if it is a member of a custom property set, the
setProp trigger has the name of the set - not the custom property itself - and you must use a
setProp handler in the form described above to trap the setProp trigger.
When you use the "percentUsed" custom property in an expression, the handler is executed:
put the percentUsed of card 1 into myVariable
When this statement is executed, LiveCode sends a getProp call to the card to retrieve the value
of the "percentUsed" property. This executes the getProp handler for the property. The example
handler stores the current date and time in a global variable before the property is evaluated. For
209
The return control structure, when used in a getProp handler, reports a property value to the
handler that requested it. In the above example, the converted date not the raw property is
what is reported. As you can see from the example, you're not limited to returning the actual,
stored value of the custom property. In fact, you can return any value at all from a getProp
handler.
Important: If you use a custom property's value within the property's getProp
handler, no getProp call is sent to the target object. This is to avoid runaway
recursion, where the getProp handler calls itself.
A handler can either use the return control structure to return a value, or use the pass control
structure to let LiveCode get the custom property from the object.
If the getProp call is trapped before it reaches the engine and no value is returned in the getProp
handler, the custom property reports a value of empty. In other words, a getProp handler must
include either a return control structure or a pass control structure, or its custom property will
always be reported as empty.
Using the message path with a getProp call
Because getProp calls use the message path, a single object can receive the getProp calls for all
the objects it owns. For example, getProp calls for all controls on a card are sent to the card, if the
control's script has no handler for that property. You can take advantage of the message path to
implement the same getProp behavior for objects that all have the same custom property.
If a getProp handler is not attached to the object that has the custom property and it uses the
value of the custom property, a runaway recursion will result. To avoid this problem, set the
lockMessages property to true before getting the custom property's value.
Nonexistent properties
210
If the custom property specied by a getProp handler doesn't exist, the getProp handler is still
executed if the property is used in an expression. Nonexistent properties report empty; getting
the value of a custom property that doesn't exist does not cause a script error.
Custom property sets and getProp handlers
A getProp handler for a custom property set behaves dierently from a getProp handler for a
custom property that's in the default set.
When you use the value of a custom property in a custom property set, the getProp call is named
for the set, not the property. The property name is passed in a parameter using array notation.
This means that, for custom properties in a set, you write a single getProp handler for the set,
rather than one for each individual property.
The following example handles getProp calls for all custom properties in a custom property set
called expertSettings, which contains custom properties named leMenuContents,
editMenuContents, and perhaps other custom properties:
getProp expertSettings[thePropertyName]
-- The thePropertyName parameter contains the name of
-- the property that's being set
switch thePropertyName
case "fileMenuContents"
if the expertSettings[fileMenuContents] of the target is empty then
return "(No items"
else pass expertSettings
break
case "editMenuContents"
if the expertSettings[editMenuContents] of the target is empty then
return the noviceSettings[editMenuContents] of the target
else pass expertSettings
break
default
pass expertSettings
end switch
end expertSettings
As you can see from the pass and end control structures, the name of this getProp handler is
the same as the name of the custom property set that it controls "expertSettings". Because
there is only one handler for all the custom properties in this set, the handler uses the switch
control structure to perform a dierent action for each property that it deals with.
Suppose you get the "leMenuContents" custom property:
set the customPropertySet of button 1 to "expertSettings"
put the fileMenuContents of button 1 into me
LiveCode sends a getProp call to the button, which causes the above handler to execute. The
property you queried "leMenuContents" is placed in the "thePropertyName" parameter. The
handler executes the case for "leMenuContents": if the property is empty, it returns "(No items".
211
Otherwise, the pass control structure lets the getProp call proceed along the message path, and
when it reaches the engine, LiveCode gets the custom property.
Virtual Properties
A virtual property is a custom property that exists only in a setProp and/or getProp handler,
and is never actually set. Virtual properties are never attached to the object. Instead, they act to
trigger setProp or getProp handlers that do the actual work.
When you use the set command with a virtual property, its setProp handler is executed, but the
setProp trigger is not passed to the engine, so the property is not attached to the object. When
you use a virtual property in an expression, its getProp handler returns a value without referring to
the object. In both cases, using the property simply executes a handler.
You can use virtual properties to:
Give an object a set of behaviors
Compute a value for an object
Implement a new property that acts like a built-in property
The "asPercentage" custom property depends on the scrollbar's thumbPosition, which can be
changed at any time (either by the user or by a handler). Because of this, if we set a custom
property for the object, it would have to be re-computed every time the scrollbar is updated in
order to stay current. By using a virtual property, you can ensure that the value of the property is
never out of date, because the getProp handler re-computes it every time you call for the
"asPercentage" of the scrollbar.
Virtual properties are also useful solutions when a property's value is large. Because the virtual
property isn't stored with the object, it doesn't take up disk space, and only takes up memory
when it's computed.
Another reason to use a virtual property is to avoid redundancy. The following handler sets the
width of an object, not in pixels, but as a percentage of the object's owner's width:
212
Suppose this handler is placed in the script of a card button in a 320-pixel-wide stack. If you set
the button's "percentWidth" to 25, the button's width is set to 80, which is 25% of the card's 320pixel width. It doesn't make much sense to store an object's percentWidth, however, because it's
based on the object's width and its owner's width.
Consider using virtual properties whenever you want to dene an attribute of an object, but it
doesn't make sense to store the attribute with the object because it would be redundant,
because possible changes to the object mean it would have to be re-computed anyway, or
because the property is too large to be easily stored.
Because setProp triggers use the message path, if you set the "percentWidth" of any object in
the stack, the stack receives the setProp trigger (unless it's trapped by another object rst). This
means that if the handler is in the stack's script, you can set the "percentWidth" property of any
object in the stack.
If you place the handler in a backscript, you can set the "percentWidth" of any object, anywhere in
the application.
To refer to the object whose property is being set, use the target function. The target refers to
the object that rst received the setProp trigger--the object whose custom property is being set-even if the handler being executed is in the script of another object.
Getting the "percentWidth" property
The matching getProp handler, which lets you retrieve the "percentWidth" of an object, looks like
this:
getProp percentWidth
return 100 \* (the width of the target div the width of the owner of the
target)
end percentWidth
If you place the handler above in a card button's script, the following statement reports the
button's width as a percentage:
put the percentWidth of button "My Button" into field 12
For example, if the stack is 320 pixels wide and the button is 50 pixels wide, the button's width is
15% of the card width, and the statement puts "15" into the eld.
Like the setProp handler for this property, the getProp handler should be placed far along the
message path. Putting it in a stack script makes the property available to all objects in the stack;
putting it in a backscript makes the property available to all objects in the application.
Limiting the "percentWidth" property
Most built-in properties don't apply to all object types, and you might also want to create a virtual
property that only applies to certain types of objects. For example, it's not very useful to get the
214
width of a substack as a percentage of its main stack, or the width of a card as a percentage of
the stack's width.
You can limit the property to certain object types by checking the target object's name:
setProp percentWidth newPercentage
if word 1 of the name of the target is "stack" or word 1 of the name of
the target is "card" then exit setProp
set the width of the target to the width of the owner of the target *
newPercentage div 100
end percentWidth
The rst word of an object's name is the object type, so the above revised handler ignores setting
the "percentWidth" if the object is a card or stack.
Property Proles
A property prole is a collection of object property settings, which is stored as a set. A prole for
an object can contain settings for almost any properties of the object.
You can include values for most built-in properties in a prole, and create as many dierent
property proles as you need for any object. Once you've created a prole, you can switch the
object to the prole to change all the property values that are dened in the prole.
For example, suppose you create a property prole for a eld that includes settings for the eld's
color properties. When you switch to that prole, the eld's colors change, while all other
properties (not included in the prole) remain the same.
Use property proles when you want to:
Create "skins" for your application
Display your application in dierent languages
Present dierent levels--"novice","expert", and so on
Use dierent user-interface standards for dierent platforms
For details on how to create property proles using the IDE, see the section on Property Proles in
the chapter Building a User Interface.
Prole names
Prole names follow the same rules as variable names. A prole name must be a single word,
consisting of letters, digits, and underscores, and must start with either a letter or an underscore.
Tip: If you want to use a single command to switch several objects to a particular
prole, give the prole the same name for each of the objects it applies to.
215
If you don't specify a property setting in a prole, the master prole's setting is used, so you don't
have to specify all properties of an object when you create a prole, only the ones you want to
change.
By default, the master prole is named "Master". You can change the master prole's name in the
Property Proles pane of the Preferences window.
The statement above sets the prole of all objects on the current card of the stack named "My
Stack". (Although the revSetCardProle command changes a card, you specify a stack name,
not a card name.)
If an object on the card does not have a prole with the specied name, the object is left
untouched.
Switching all the objects in a stack
To switch the proles of all the objects in a stack, use the revSetStackProle command:
revSetStackProfile "MyProfile","My Stack"
The statement above sets the prole of all objects in the stack named "My Stack".
If an object in the stack does not have a prole with the specied name, the object is left
untouched.
Switching all the objects in a stack le
To switch the proles of all the objects in every stack in a stack le, use the
revSetStackFileProle command:
revSetStackFileProfile "MyProfile","My Stack"
The statement above sets the prole of all objects in the stack named "My Stack", along with any
other stacks in the same stack le.
216
If an object in any of the stacks does not have a prole with the specied name, the object is left
untouched.
The handler above creates a prole called "myNewProle" for all the cards in the current stack.
In order for this handler to work, the "Create proles automatically" option in the "Property
Proles" pane of the Preferences window must be turned on.
You can control this behavior either in Preferences window or using the gRevProleReadOnly
keyword. If you don't want to save property changes when switching proles, do one of the
following:
Set the gRevProleReadOnly variable to true:
global gRevProfileReadOnly
put true into gRevProfileReadOnly
In the "Property Proles" pane of the Preferences window, uncheck the box labeled "Don't save
changes in prole".
The two methods of changing this setting are equivalent: changing the gRevProleReadOnly
variable also changes the preference setting, and vice versa.
For more details, see gRevProleReadOnly in the LiveCode Dictionary.
217
By default, if you change a property and then switch proles, the property you changed and its
current setting is saved with the prole.
Moving a window
Usually, you use either the location or rectangle property of a stack to move the stack window.
Thelocation property species the center of the stack's window, relative to the top left corner of
the main screen. Unlike the location of controls, the location of a stack is specied in absolute
coordinates. The following statement moves a stack to the center of the main screen:
set the location of stack "Wave" to the screenLoc
The rectangle property of a stack species the position of all four edges, and can be used to
resize the window as well as move it:
set the rectangle of this stack to "100,100,600,200"
Tip: To open a window at a particular place without ickering, set the stack's location
or rectangle property to the desired value either before going to it, or in the stacks
preOpenStack handler.
You can also use associated properties to move a window. Changing a stack's bottom or top
property moves the window up or down on the screen. Changing the left or right property moves
the window from side to side.
If the stack is already open, the go command brings it to the front, without changing its mode.
To nd out the layer order of open stack windows, use the openStacks function. This function
lists all open stack windows in order from front to back.
218
Creating a backdrop
For some applications, you may want to create a solid or patterned backdrop behind your
application's windows. This backdrop prevents other applications' windows from being seen
although it does not close those windows so it's appropriate for applications like a game or
kiosk, where the user doesn't need to see other applications and where you want to keep
distractions to a minimum.
Note: In LiveCode Media edition, you cannot turn o the backdrop property.
To create a backdrop, you set the backdrop property to either a valid color reference, or the ID
of an image you want to use as a tiled pattern:
set the backdrop to "\#99FF66" *-- a color*
set the backdrop to 1943 *-- an image ID*
In the LiveCode development environment, you can create a backdrop by choosing View ->
Backdrop. Use the Preferences dialog box to specify a backdrop color to use.
220
A handler in another stack referred to a property of the closed stack. This automatically loads the
referenced stack into memory.
The stack is in the same stack le as another stack that is open.
The stack was opened and then closed, and its destroyStack property is set to false. If the
destroyStack property is false, the stack is closed, but not unloaded, when its window is closed.
Tip: To list all stacks in memory, whether they're open or closed, use the
revLoadedStacks function.
For complete information about the possible values of the mode property, see its entry in the
LiveCode Dictionary.
Window Appearance
Details of a window's appearance, such as the height of its title bar and the background color or
pattern in the window itself, are mainly determined by the stack's mode. There are a few
221
additional elements of window appearance that you can control with specic properties.
The metal property
On OS X systems, you use a stack's metal property to give the stack window a textured metal
appearance. This metal appearance applies to the stack's title bar and its background.
Tip: The metal appearance, in general, should be used only for the main window of
an application, and only for windows that represent a physical media device such as a
CD player. See Apple's Aqua user-interface guidelines for more information.
Window background color
The background color or pattern of a window's content area--the part that isn't part of the title
bar--is determined by the window type and operating system, by default. For example, on Mac OS
X systems, a striped background appears in palettes and modeless dialog boxes.
If you want a window to have a specic color or pattern, you can set the stack's
backgroundColor or backgroundPattern property:
set the backgroundColor of stack "Alpha" to "aliceblue"
set the backgroundPattern of stack "Beta" to 2452 *-- img ID*
The statement above sets the stack'sminimizeBox property to true, as well as showing its title
bar, and sets other stack properties (maximizeBox, closeBox, metal) to false. Conversely, if
you set a stack's minimizeBox property to true, its decorations property is changed to include
"minimize" as one of its items. In this way, the decorations property of a stack interacts with its
closeBox, minimizeBox, zoomBox, metal, shadow, and systemWindow properties.
The decorations property and menu bars in a window
On Linux and Windows systems, the menu bar appears at the top of the window. On these
systems, whether a window displays its menu bar is determined by whether the stack's
decorations property includes "menu":
set the decorations of this stack to "title,menu"
On Mac OS X systems, the menu bar appears at the top of the screen, outside any window. On
these systems, the "menu" decoration has no eect.
222
Title bar
The user drags the title bar of a window to move the window around the screen. In general, if the
title bar is not displayed, the user cannot move the window. You use the decorations property
(discussed below) to hide and show a window's title bar.
When the user drags the window, LiveCode sends a moveStack message to the current card.
The decorations property aects only whether the window can be moved by dragging it. Even if a
stack's decorations property does not include the title bar decoration, you can still set a stack's
location, rectangle, and related properties to move or resize the window.
Window title
The title that appears in the title bar of a window is determined by the stack's label property. If
you change a stack's label in a script, the window's title is immediately updated.
If the label is empty, the title bar displays the stack's name property. (If the stack is in an
editable window whose cantModify is false, an asterisk appears after the window title to indicate
this, and if the stack has more than one card, the card number also appears in the window title.
These indicators do not appear if the stack has a label.)
Because the window title is determined by the stack's label property instead of its name
property, you have a great deal of exibility in changing window title. Your scripts refer to the stack
by its name--which doesn't need to change--not its label, so you can change the window title
without changing any scripts that refer to the stack.
The close box
The close box allows the user to close the window by clicking it. To hide or show the close box, you
set the stack's closeBox property:
set the closeBox of stack "Bravo" to false
When the user clicks the close box, LiveCode sends a closeStackRequest message, followed by
a closeStack message, to the current card.
The closeBox property aects only whether the window can be closed by clicking. Even if a
stack's closeBox property is false, you can still use the close command in a handler or the
message box to close the window.
The minimize box or collapse box
The terminology and behavior of this part of the title bar varies depending on platform. The
minimize box shrinks the window to a desktop icon.
To hide or show the minimize box or collapse box, you set the stack's minimizeBox property:
set the minimizeBox of this stack to true
Tip: On OS X and Linux systems, you can set a stack's icon property to specify the
icon that appears when the stack is minimized.
223
When the user clicks the minimize box or collapse box, LiveCode sends an iconifyStack
message to the current card.
The maximize box or zoom box
The terminology and behavior of this part of the title bar varies depending on platform. On Mac
OS X systems, the zoom box switches the window between its current size and maximum size.
The maximize box (Linux and Windows systems) expands the window to its maximum size.
To hide or show the zoom box or maximize box, you set the stack's zoomBox property:
set the zoomBox of stack "Hello" to false
When the user clicks the zoom box or maximize box, LiveCode sends a resizeStack message to
the current card.
224
and submenus, and how to use a stack window as a menu for total control over menu
appearance.
To easily create menu bars that work cross-platform, choose Tools -> Menu Builder. See the
section on the Menu Builder in the chapter on Building a User interface for more details. The
details about menu bars in this topic are needed only if you want edit menu bars by script, for
example if you want to include specic features not supported by the Menu Builder.
Menu Types
LiveCode supports several menu types: pulldown menus, option menus (usually called popup
menus on Mac OS X), popup menus (usually called contextual menus on Mac OS X), and combo
boxes.
Each of these menu types is implemented by creating a button. If the button's style property is
set to "menu", clicking it causes a menu to appear. The button's menuMode property
determines what kind of menu is displayed.
Even menu bars are created by making a pulldown-menu button for each menu, then grouping
the buttons to create a single menu bar. The menu bar can be moved to the top of the stack
window (on Unix and Windows systems). To display the menu bar in the standard location at the
top of the screen on Mac OS X systems, you set the stack's menubar property to the group's
name. The name of each button is displayed in the menu bar as a menu, and pulling down a
menu displays the contents of the button as a list of menu items.
Button Menus
You can create a button menu by dragging out one of the menu controls from the tools palette.
However, if you want to create one by script, the easiest is to create a button and set the style of
the button to "menu". Next, you can set the menuMode of the button to the appropriate menu
type. You can either set the menuMode in a handler, or use the Type menu in the button's
property inspector to set the menu type.
To create the individual menu items that will appear in the menu, set the button's text property to
the menu's contents, one menu item per line. You can either set this property in a handler, or ll
in the box labeled "Menu items" on the Basic Properties pane of the property inspector.
When you click the button, the specied menu type appears, with the text you entered displayed
as the individual menu items in the menu.
Tip: To dynamically change the menu's contents at the time it's displayed, put a
mouseDown handler in the button's script that puts the desired menu items into
the button. When the menu appears, it displays the new menu items.
For menus that retain a state (such as option menus and combo boxes), the button's label
property holds the text of the currently chosen menu item.
Handling the menuPick message
When the user chooses an item from the menu, LiveCode sends the menuPick message to the
button. The message parameter is the name of the menu item chosen. If you want to perform an
action when the user chooses a menu item, place a menuPick handler like this one into the
button's script:
225
on menuPick theMenuItem
switch theMenuItem
case "Name of First Item"
-- do stuff here for first item
break
case "Name of Second Item"
-- do stuff here for second item
break
case "Name of Third Item"
-- do stuff here for third item
break
end switch
end menuPick
226
These commands simply add or remove the ( special character at the start of the designated line
of the button's contents.
228
Because menus are also buttons, you can use a button reference to get the same information.
But you may need to specify the group and stack the button is in, to avoid ambiguity. (For
example, if there is a standard button named "Edit" on the current card, the expression
button "Edit" refers to that button, not to the one in the menu bar.) An unambiguous button
reference to a menu might look like this:
get line 2 of button "Edit" of group "Menu" of stack "Main"
The above statement produces the same information as the form using "menu ", but you need to
know the group name and possibly which stack it's in, so the menuName form is a little more
convenient.
The layer of menu buttons
For a menu bar to work properly on Mac OS X systems, the menus must be in layer order within
the group. That is, the button for the File menu must be numbered 1, the button for the Edit
menu must be 2, and so on. The Menu Builder takes care of this automatically; you only need to
worry about layering if you're creating the menu bar by hand.
Changing menus dynamically
If you want to dynamically change a menu's contents with a mouseDown handler at the time the
menu is displayed, you must place the mouseDown handler in the group's script. When a menu
button is being displayed in the Mac OS menu bar, it does not receive mouseDown messages,
but its group does.
The editMenus property
When you set the menubar property of a stack to the name of a group, the stack is resized and
scrolled up so the part of the window that holds the menus is not visible. To reverse this action so
you can see, select and edit the buttons that make up your menu bar, set the editMenus
property to true. This resizes the stack window so the button menus are again visible, and you can
use the tools in the LiveCode development environment to make changes to them.
229
To scroll the stack window again so that the menus are hidden, set the editMenus property back
to false.
Special menu items
A few menu items on Mac OS X are handled directly by the operating system. To accommodate
these special menu items while allowing you to create a fully cross-platform menu bar, LiveCode
treats the last two menu items of the Help menu, the File menu, and the Edit menu dierently.
By following these guidelines, you can make sure your menus will appear properly on all operating
systems without having to write special code or create platform-specic menu bars.
The Help menu and the "About This Application" menu item
When LiveCode sets up the Mac OS X menu bar, it automatically makes the last button the Help
menu (regardless of the button's name). The standard Help menu items, such as the "Search"
bar are included for you automatically; you don't need to include them in your Help menu button,
and you can't eliminate them from the Help menu.
LiveCode moves the last menu item in the Help menu to the "About This Application" position. On
Mac OS X systems, it's the rst menu item in the Application menu. Therefore, the last menu item
in your Help menu button should be an appropriate "About" item. The menu item above it must
be a divider line (a dash), and above that must be at least one menu item to be placed in the
Help menu.
The File menu and the "Quit" menu item
On Mac OS X systems, the "Quit" menu item is normally placed in the Application menu (which is
maintained by the operating system) rather than in the File menu, as is standard on other
platforms. To accommodate this user-interface standard, LiveCode removes the last two menu
items of the File menu when a standalone application is running on an OS X system. Therefore,
the last menu item in your File menu button should be "Quit". The menu item above it should be a
divider line (a dash).
The Edit menu and the "Preferences" menu item
On OS X systems, the "Preferences" menu item is also normally placed in the Application menu.
To accommodate this user-interface standard, LiveCode removes the last two menu items of the
Edit menu when a standalone application is running on an OS X system. Therefore, the last menu
item in your Edit menu button should be "Preferences". The menu item above it should be a
divider line (a dash).
Note: The Preferences menu item is treated in this special way only if its name starts
with the string "Preferences".
Tip: If your application's user interface is presented in a language other than English,
set the name of the Edit menu button to "Edit", and set its label to the correct
translation. This ensures that the engine can nd the Edit menu, while making sure
that the menu is shown in the correct language.
Choosing the special menu items
When the user chooses any of these special menu items, a menuPick message is sent to the
button that the menu item is contained in. This ensures that your button scripts will work on all
platforms, even if LiveCode displays a menu item in a dierent menu to comply with userinterface guidelines.
230
Stack Menus
Button menus can be used for most kinds of standard menus. However, if you want to create a
menu with a feature that is not supported by button menus--for example, if you want a popup
menu that provides pictures, rather than text, as the choices--you can create a menu from a
stack.
Creating a stack menu
To create a stack menu, you create a stack with a control for each menu item. Since the stack
menu is a stack and each menu item is an object, the menu items receive mouse messages
such as mouseEnter,mouseLeave, and mouseUp.
When the user chooses an item from the stack menu, a mouseUp message is sent to that
control. To respond to a menu item choice, instead of handling the menuPick message, you can
place a mouseUp handler in the script of the object.
To create a stack menu that looks like a standard menu, create a button in the stack for each
menu item. The button's autoArm and armBorder properties should be set to true. Or you can
choose "Menu Item" item in the "New Control" submenu of the Object menu to create a button
with its properties set to the appropriate values.
Be sure to set the rectangle of the stack to the appropriate size for the menu. Remember, when
you open the menu, the stack will be displayed exactly as it looks in an editable window.
Finally, either set the menuName property of a button to a reference to the stack, or place a
mouseDown handler containing a pulldown, popup, or option command in the script of an
object. When you click the button or object, the stack menu appears.
Displaying a stack menu
Stack menus can be associated with a button, just like button menus. But when you click the
button, instead of displaying a menu with the button's contents, LiveCode displays a stack with
the behavior of a menu.
You can also display a stack menu without associating it with a button, by using the pulldown,
popup, or option command. Normally, you use these commands in a mouseDown handler, so
that the menu appears under the mouse pointer:
on mouseDown -- in card script
popup stack "My Menu Panel"
end mouseDown
231
Note: If you set a button's menuName property to the name of a stack, the stack
menu is displayed automatically when the user clicks the button. You need the
popup, pulldown, and option commands only if you want to display a stack menu
in some way other than when a button is clicked.
normal
characters or character (or chars or char)
words or word
string
whole
If no form is specied, the nd normal form is used.
The textToFind is any expression that evaluates to a string.
The eld is any expression that evaluates to a eld reference. If the eld is not specied, the nd
command searches all the elds in the current stack (except elds whose dontSearch property is
set to true).
find "heart"
find string "beat must go on" in field "Quotes"
When the nd command nds a match, it highlights the match on the screen if necessary
navigating to the card that contains the match and scrolling the eld so the text is in view.
The nd command can also be used to return the location of the text that was found.
To reset the nd command so that it starts searching at the beginning again:
find empty
For more details on the nd command and associated options, see the nd command in the
LiveCode Dictionary.
LiveCode allows you complete control over drag and drop both within LiveCode windows and
between LiveCode and other applications.
You can set the dragData to contain any of the following types of data:
text
HTML
The styled text being dragged, in the same format as the htmlText
RTF
The styled text being dragged, in the same format as the RTFText
Unicode
image
les
The name and location of the le or les being dragged, one per line
Note: LiveCode automatically handles the mechanics of dragging and dropping text
between and within unlocked elds. To support this type of drag and drop operation,
you don't need to do any scripting.
For more details, see the entries for dragStart and dragData in the LiveCode Dictionary.
You can use the dragMove message to update the screen whenever the cursor moves during a
drag and drop operation.
233
You can use the dragLeave message to remove any outline around an object or change the
cursor when the mouse moves out of an object during a drag operation.
on dragLeave
-- remove any outline around the drop no-longer-target
set the borderColor of the target to empty
end dragLeave
For more details, see the entries for dragEnter, dragMove and dragLeave in the LiveCode
Dictionary.
You must set the acceptDrop property to true before a drop will be allowed. Usually, you set this
property to true in a dragEnter handler.
You can use the dragDestination function to retrieve the long id of the object that the dragged
data was dropped on. You can use the dragSource function to retrieve the long id of the object
that was the source of the drag.
When a drag drop has been completed, a dragEnd message is sent to the object the drag and
drop started from.
on dragEnd -- remove data being dragged
d
elete the dragSource
end dragEnd
You can use the dropChunk function to retrieve the location of the text that was dropped in a
eld. For example, you could select the text that was dropped by doing the following:
234
If you want to prevent dragging text within a eld, intercept the dragStart message:
on dragStart
-- do nothing
end dragStart
For more details, see the entries for acceptDrop, dragDrop and dragEnter in the LiveCode
Dictionary.
235
236
237
Because LiveCode compiles all the scripts within a stack when it loads them, a Script Error dialog
can be generated when you load a stack from disk for the rst time if you saved a stack that
contained a script that could not compile.
Important: Do not confuse the Execution Error and Script Error dialogs. The
Execution Error dialog occurs when a script is running and cannot continue due to an
error. The error dialog will start with the words "executing at [time]". The Script Error
dialog appears when you attempt to compile a script that contains a syntax error.
The error dialog will start with the words "executing at [time]".
Tip: If you turn on the Variable Checking option in the Code Editor, LiveCode will
require that you declare all variables and enclose all literal strings in quotes. It will
report a script compile error if you attempt to use an unquoted literal or do not
declare a variable. This can be useful in catching mistakes before you run a script.
Note that if you turn this option on and attempt to compile an existing script that has
not been written in this way, it will typically generate a large number of errors that
need to be corrected before you can compile it.
display the information. Using a put command without specifying a destination outputs to the
Message Box:
put tVar
In the example above, substitute tVar with the name of the variable in your script that you want to
see the contents of. You can also output information only if a certain condition is met:
if tVar is true then put tData
Whenever you display something in the message box, a special global variable called message
(often abbreviated to msg) is updated. This allows you to check the contents of the message box
easily, as well as add or append information rather than replacing it.
-- puts tInformation and a return after the data
-- already in the message box
put tInformation & return after msg
For more information, see the section on the Message Box, above.
Output to Standard Out (stdout or the Console on Mac)
Standard Output (stdout) is a useful place to log messages. Unlike the Message Box, it is easy to
log a sequence of events which you can then scroll back to review later on. It also has the
advantage of being external to LiveCode so using it does not interfere with your application
window layering or focus in any way. On Mac, it can be accessed by opening the Console
application, located in the Utilities folder within Applications.
The syntax to write something to stdout or the Console is:
write tMessage & return to stdout
Tip: If you are writing a lot of data out to the console, it can be useful to append the
time to each one to make it easier to debug.
write tMessage && the long time & return to stdOut . If you need more
granularity than seconds, use the milliseconds instead of the long time.
If you are inserting debugging output statements into your code, consider making them
conditional on a global variable. This allows you to turn on debugging by setting the variable
without making changes to code. Even better it prevents forgotten debugging code in your
application inadvertently lling the console with messages on an end user's system.
if gDebugging then write tMessage & return to stdOut
Output to a eld
239
You can create a stack that contains elds used for debugging:
put tVar & return after field "debugging info" of stack "my debug stack"
Tip: You may want to create a set of tools that makes it easy to debug a specic
application you are working on. Create this stack then save it into your plug-ins folder
so it is available from the Development menu in the IDE.
Output to a dialog
To display a dialog with the contents of a statement, use the answer command. This method is
suitable if you want to output something quickly, but is usually unsuitable for larger debugging
tasks as it pauses execution to display a dialog each time.
if tVar is true then answer tVar
Output to a text le
If you want to log information more permanently, you can use a text le. You may want to store
the le path in a global variable so you can change it easily. See the Transferring Information guide
for more information.
put tVar & return after URL "file:debug.txt"
Interrupting Execution
If you need to interrupt a script while it is running, press control-period (or command-period on
Mac OS). Note that interrupting a script will only work if the global allowInterrupts property is set
to true.
Tip: On Mac OS X systems, if your application has got into an unstable state and you
are unable to interrupt it with command-period you may be able to interrupt it and
regain control by sending it a signal. Open the Terminal utility and then use top -o cpu
or ps ax to retrieve the process ID for LiveCode. Then run kill -sighup [processID]
where [processID] is the ID of the LiveCode process.
The Debugger
Typically when you want to track down a problem with your script, you will want to use the
debugger. The debugger provides a simple interface that allows you to step through your script
line by line as it executes. You can see the results of each statement as it happens. If you load the
Variable Watcher from within the debugger, it will show you the contents of all of the variables
used in a particular handler. These values will be updated as you step through. You can even edit
these values while your script is running. This can be useful if you spot a problem in a given area
or want to test a section of code with a dierent set of data as it runs.
To activate the debugger, rst ensure that Script Debug Mode is turned on in the Development
menu. Then open up the script you want to debug and click in the gray bar to the left of the line
240
where you want to open the debugger. Alternatively you can write the command breakPoint into
the script. Using the breakPoint command allows you to break conditionally
if tVar is true then breakPoint .
Next run your script as normal. When LiveCode reaches a breakpoint it will pause execution and
load up the debugger.
Important: To see the contents of variables while your script is running, wait for the
debugger to open then open the Variables pane (or select Variables from the Debug
menu).
Tip: The data returned to the error routine is returned in the internal format that
LiveCode uses to display execution errors. To look up the human friendly string
associated with a particular error, look at the rst item returned against the list of
execution errors stored in the LiveCode IDE.
put line (item 1 of someError) of the cErrorsList of \
card 1 of stack "revErrorDisplay"
In the example above, if the le cannot be opened and the result is set, the value of the result will
be passed to the catch statement in the someError variable.
Writing a custom errorDialog routine
When an execution error occurs, an errorDialog message is sent. The IDE uses this message to
display the execution error dialog. However you can write and include your own custom
errorDialog routine. This is useful if you are planning to distribute your application. For example,
you could create a stack that transmits the error information directly to your technical support
department or displays a custom message on screen. A basic errorDialog routine is shown
below:
on errorDialog pError
answer "There was an error" && pError
end errorDialog
This routine will also be activated if you use the throw keyword to throw an error (outside of a
try/catch control structure).
243
Lists messages as they happen. The format is the name of the message, the
time the message was sent and the number of milliseconds since the last
message. Click to select a message, double click to open it in the Code Editor. In
the example above we can see that the user was inactive for 4.7 seconds before
Message moving the mouse over an object that triggered a mouseEnter message. 599
list area
milliseconds later they clicked the mouse triggering a mouseUp message. The
mouseUp handler called calculateResult 0 milliseconds later, then formatData
was called 147 milliseconds later. Because there were no user-generated
messages in the sequence, we know that the calculateResult handler took 147
milliseconds to run.
Object
Shows the object that the message was sent to. Click on a line in the Message
eld
List to update this eld.
Message Shows the type for the selected message command, function, getProp or
type
setProp
Check this box to activate the Message Watcher. Deactivate the Message
Active
Watcher when you have captured information about the sequence of events you
are interested in and want to stop the logging of additional messages.
Clear
Clears the message list eld.
Allows you to set what messages you want displayed and which ones you want to
suppress. Use this option to narrow down the messages that are logged so you
Suppress
can see information about the sequence you are interested in. See below for
more information.
244
Action
Handled
Don't log any message that causes a handler to run when it is sent.
Action
Not
Handled
Don't log any message that does not cause a handler to run when it is sent. This
is the default option and prevents the log from lling up with messages that do
not cause any scripts to run.
245
IDE
Messages
Do not log LiveCode IDE messages. The LiveCode IDE generates lots of
messages as it is written in LiveCode. This is the default option but you may
wish to display these messages if you are customizing the LiveCode IDE.
Handler
Type
Do not log the selected type of handler. For example, to prevent displaying all
function calls, check the function box.
Message
list
Add
Delete
246
The table style of a data grid allows you to display your data in a modern looking table complete
with headers, sorting, column alignment and more. By default a data grid table will use a LiveCode
eld to each column of each row. If you need to customize a column with graphics you can dene
your own templates for each column. A custom template can be any LiveCode control such as a
graphic or group.
A Data Grid Form
247
The form style of a data grid (1) is similar to a list eld (2) in LiveCode in that it allows you to
display records from a data source (text le, database, XML, etc.) that the user can select.
The dierence is that the data grid uses a group as a template for each record. This means that
for each record you display you can create rich user interfaces using menus, images, etc.
The data grid form is also very fast as it only draws the records that are currently visible on the
screen. This means you can display large records sets without slow performance.
Because the data grid form is so easy to use it is not only limited to displaying lots of records. Any
list where you want a rich UI and complete control over layout and processing of engine events
can benet from being displayed using a data grid form.
248
249
250
251
252
253
254
255
256
257
258
259
The tab delimited text you entered in the eld will appear as columns in the data grid (1). The
Property Inspector automatically creates a column in the Data Grid for each column in the text
you provide (2).
261
Customizing Columns
Now that you've populated a Data Grid Table with some data let's look at the columns in the Data
Grid.
262
Normally when you work with a Data Grid Table you will create columns in the Property
Inspector in advance using the "+" button (1). Seeing as the columns needed already exist you
can go through and rename Col 1 to state and Col 2 to code (2).
Note that a label for the columns (3) has also been assigned . Labels are useful for customizing
the column labels in the Data Grid Table.
Populate Data Grid Using dgText Property
Now that you have dened your columns let's look at how to populate a Data Grid Table by setting
the dgText property. Here is an example handler (with comments) that you can place in a button.
Note: Verify that the name of your data grid matches the name used in the code
below otherwise an error will occur when you try to run it.
263
on mouseUp
### Create tab delimited data.
### Note that first line has name of columns.
### Providing names tells Data Grid how to map
### data to appropriate columns.
put "state" & tab & "code" & cr & \
"ALABAMA" & tab & "AL" & cr & \
"ALASKA" & tab & "AK" into theText
### Let Data Grid know that first line has column names
put true into firstLineContainsColumnNames
set the dgText [ firstLineContainsColumnNames ] of group "DataGrid" to
theText
end mouseUp
Executing the above code would give you the following result in the Data Grid table.
Here is an example of populating the Data Grid Table by setting the dgData property to an array.
The end result is the same as the previous step.
Note: Verify that the name of your data grid matches the name used in the code
below otherwise an error will occur when you try to run it.
on mouseup
### Create a nested array.
### Array key names in the 2nd dimension
### dictate values for individual columns
put "ALABAMA" into theDataA[1]["state"]
put "AL" into theDataA[1]["code"]
put "ALASKA" into theDataA[2]["state"]
put "AK" into theDataA[2]["code"]
set the dgData of group "DataGrid" to theDataA
end mouseUp
265
266
267
268
269
270
271
272
You should note that while you can assign line delimited text to a data grid form, the data grid
really works with multi-dimensional arrays under the hood. By using arrays you can store and
display all dierent kinds of data in a data grid. Being able to assign the Contents property is
merely a convenience.
273
This is the data grid that you will create. Each row displays a name, a title and an image.
Add Data Grid to Card
274
To begin, drag a data grid from the Tools palette onto your card.
Change Data Grid Style
275
Select the data grid and from the Basic Properties pane of the Property Inspector change
the style of the data grid to Form.
The Data That Is Going to Be Displayed in Each Row
Now you are going to design the row template for the data grid form. The row template dictates
how each record in the data grid will be displayed.
Before you start editing the row template you need to know about the data that will be displayed
each row. This screenshot shows an excerpt from the code that populates the data grid using a
multi-dimensional array (look in the card script of the example stack). Each row will have access
276
to the data stored in the FirstName, LastName, Title and ImageURL keys of the array.
You are now going to add UI controls to the row template in order to display the data for each of
these keys.
Edit the Row Template
With the data grid selected, click on the Row Template button in the Property Inspector to
open the card containing row template controls.
277
1.
2.
3.
4.
278
Open the Property Inspector for this eld and from the Basic pane (2) change the name of the
eld to Name (2). Switch to the Contents pane and assign Name as the content (3).
279
280
Now drag an image object into the group using the Tools palette (1). With the image selected,
select the Position pane on the Property Inspector (2) and set the width and height of the
image to 48 pixels (3). Also check the Lock size and position checkbox (4) so that any image
is scaled to t within these bounds.
281
Finally, select the Background graphic (5) and resize it so that it frames the other controls. In
the example stack the width of the graphic is 214 and the height is 56.
Stop Editing the Row Template Group
You are now done adding the UI objects to the row template group. From the Object menu (1),
select Stop Editing Group. You can then Close and Save the row template
Edit the Row Behavior
Now that you have designed the controls for each row you need to write the script that will move
data into the controls and position them on the screen.
282
Click on the Edit Script button in the Property Inspector under Row Behavior to begin
editing the row behavior script.
The FillInData Message
In the script that opens when you click the Row Behavior button you will nd a command named
FillInData. This is where you move data from the pDataArray parameter into the controls you
created.
283
pDataArray is an array with the keys FirstName, LastName, Name and Title. The code that moves
the values from the array into the UI controls is pretty straightforward.
1. Assign the values of the FirstName and LastName keys to the Name eld.
2. Assign the value of the Title key to the Title eld.
3. Assign the value of the Image URL key to the lename property of the image control.
You don't need to worry about positioning any of your controls in the FillInData command. You
just need to write the code that assigns the data to the UI controls.
284
285
on LayoutControl pControlRect
local theFieldRect,theRect
-- This message is sent when you should layout your template's controls.
-- This is where you resize the 'Background' graphic, resize fields and
-- position objects.
-- The first thing you should do is capture 'the rect of me'.
-- For fixed height data grid forms you can use items 1 through 4 of the
rect as
-- boundaries for laying out your controls.
-- For variable height data grid forms you can use items 1 through 3 of the
rect as
-- boundaries.
-- Example:
set the right of image "image" of me to item 3 of pControlRect - 5
put the left of image "image" of me into theLeft
put the rect of field "name" of me into theRect
put theLeft - 10 into item 3 of theRect
set the rect of field "Name" of me to theRect
put the rect of field "title" of me into theRect
put theLeft - 10 into item 3 of theRect
set the rect of field "Title" of me to theRect
set the rect of graphic "Background" of me to pControlRect
end LayoutControl
286
command uiPopulatePeople
put "images/" into theImageFolder
put "Lucky" into theDataA[1]["FirstName"]
put "Day" into theDataA[1]["LastName"]
put "Three Amigo" into theDataA[1]["Title"]
put theImageFolder & "monkey.jpg" into theDataA[1]["Image
put "Dusty" into theDataA[2]["FirstName"]
put "Bottoms" into theDataA[2]["LastName"]
put "Three Amigo" into theDataA[2]["Title"]
put theImageFolder & "monkey.jpg" into theDataA[2]["Image
put "Ned" into theDataA[3]["FirstName"]
put "Nederlander" into theDataA[3]["LastName"]
put "Three Amigo" into theDataA[3]["Title"]
put theImageFolder & "monkey.jpg" into theDataA[3]["Image
put "Jane" into theDataA[4]["FirstName"]
put "Blue" into theDataA[4]["LastName"]
put "Secret Agent" into theDataA[4]["Title"]
put theImageFolder & "monkey.jpg" into theDataA[4]["Image
put "Jefferson" into theDataA[5]["FirstName"]
put "Blue" into theDataA[5]["LastName"]
put "Secret Agent" into theDataA[5]["Title"]
put theImageFolder & "monkey.jpg" into theDataA[5]["Image
lock screen
set the dgData of group "DataGrid 1" to theDataA
### Hilite first row
set the dgHilitedLines of group "DataGrid 1" to 1
unlock screen
end uiPopulatePeople
URL"]
URL"]
URL"]
URL"]
URL"]
It is called by a button placed on the card Populate Data Grid with script
on Mouseup
uiPopulatePeople
end Mouseup
The Result
After calling the uiPopulatePeople command the Data Grid should look something like this (1).
287
Once you have set the dgData property you can refresh the data grid to see any of the changes
made to the row template. You can send the ResetList message to the data grid, or press the
Refresh Data Grid button on the Basic Properties pane of the Property Inspector (2) to
redraw the data using the updated template.
Troubleshooting: Row Height
By default a data grid uses a xed height for each row. If you have not set the row height the rst
time you populate the data grid with data then the value that is current for the data grid may not
be suitable.
288
You can change the height of the row template by updating the row height in the Property
Inspector.(1)
Alternatively you could also simply uncheck the Empty row height property.(2)
289
290
This stack (1) contains a single card (2) for each data grid you add to a stack. Each card contains
the template(s) and behaviors that the data grid will use to display the data.
Data Grid Templates Card Contents
This screenshot shows some controls that might appear on a Data Grid Templates card. The Row
Template (1) is the group that contains either all of the controls for a form or the column
templates for a table. The IDE assigns the Row Template group to the dgProps ["row
template"] property of the data grid.
291
The Behavior Script button is assigned as the behavior to the Row Template group and is
used for data grid forms. This script controls how data is inserted into the Row Template
controls and how those controls are positioned.
Opening the Data Grid Templates Stack
The LiveCode IDE makes it easy to locate your templates in the Data Grid Templates stack.
Simply select the data grid control and click the Row Template... button (1) in the Data Grid
(2) pane of the inspector.
292
The card containing the template(s) for the selected data grid will open.
293
The Row Template is a Livecode group control. This group represents a single record in the data
that you are displaying in a data grid form. This group can contain any Livecode control and the
look and layout are entirely controlled by you.
How a Record Template Is Used
When the data grid form displays your data it copies the Row Template into itself. It makes just
enough copies to cover the visible area and then inserts data into these copies of the Row
Template. As the user uses the scrollbar to scroll through the data the same copies are used but
new data is inserted. This means that the data grid form is never drawing more records than the
user can actually see which means the data grid is fast.
294
When your data is drawn into a data grid table each column template is copied into the data
grid as many times as necessary in order to ll the visible area. Data is then inserted into these
templates as the user scrolls.
You can use the Contents pane of the Property Inspector to quickly assign data to a data grid.
295
This does not provide as many options as setting the properties mentioned below but it will get
you up and running quickly.
1. Switch to the Contents pane of the Property Inspector.
2. Enter some tab delimited text into the eld.
When you use the Property Inspector to assign data to the data grid the Property Inspector
sets the dgText property of the data grid.
Set the dgText Property
The data grid works with arrays behind the scenes but in the interest of making life easier there is
a dgText property. The syntax is as follows:
set the dgText [ pFirstLineContainsHeaders ] of group "Data Grid" to pText
pText is assumed to be a collection of data where each row is delimited by the return character
and each item is delimited by a tab. You can map each item of each line in pText to a particular
key in an array (and thus a table column) by passing in true for pFirstLineContainsHeaders. If
true then the data grid will extract the rst line of pText and match the values for existing internal
key/column names. The default value for pFirstLineContainsHeaders is false.
If you set the dgText of a data grid table then all data will be imported and assigned to the
appropriate column depending on the value of pFirstLineContainsHeaders. Normally you
should set this property to true and provide the header that maps each item of each line to a
specic column.
Note: that if pFirstLineContainsHeaders is true then the named columns must
already exist in your data grid table in order to be displayed. Setting
pFirstLineContainsHeaders to true does not create the headers for you.
296
If pFirstLineContainsHeaders is false then the columns property of the data grid is used for
mapping. For example, the rst item of a line of pText would be assigned to the column that
appears on the rst line in the columns property of the data grid. If line 1 of pText contains more
items than there are columns in the table then new columns are added. Any new columns are
named "Col 1", "Col 2", etc.
If you set the dgText property of a data grid form then the data will be imported but it is up to
you to modify your Row Template Behavior to display the imported data correctly. If
pFirstLineContainsHeaders is false then each item of each line in pText will be named "Label
X" (where X is the item number) in the array that is passed to FillInData.
Set the dgData Property
297
The dgData property of a data grid is a multi-dimensional array and is the actual format that the
data grid works with under the hood. The data grid expects the rst dimension of the array to be
integers. The number of keys in the rst dimension represents the number of records being
displayed in the data grid. Here is an example with ve records:
298
theDataA[1]
theDataA[2]
theDataA[3]
theDataA[4]
theDataA[5]
You then store all of your custom data in the second dimension. The following is how you would
display ve records, each with a Name property:
theDataA[1]["Name"]
theDataA[2]["Name"]
theDataA[3]["Name"]
theDataA[4]["Name"]
theDataA[5]["Name"]
In the example code above there are 5 records, each with a FirstName, LastName and Title
property. Your templates will have access to these properties when the time comes to draw the
data on the screen.
Important: if you are using a data grid table then a key in the array must match the
name of a column in the table in order for that variable (column) to be displayed. So
if you have a column named Image URL in your table you must have a corresponding
key named Image URL:
theDataA[1]["Image URL"]
299
Select the data grid (1) and open the Property Inspector (2). Click on the Row Template...
button (3) to open the card that the data grid's template is on.
The template for the data grid will open. You can now edit the controls within the Row Template
group in order to customize the look and feel according to your needs.
Example of a Customized Template
300
Here is an example of a customized template. A Name (1) and Title eld (2) have been added as
well as a control for displaying a picture of the person (3).
Edit Behavior
301
After customizing the controls in your template you need to update the behavior associated with
the template. The behavior script is where you tell the data grid what data goes in which controls
as well as how to position the controls.
Click the Edit Script... button to open the behavior script.
Edit the Behavior Script
302
The default behavior script contains comments explaining what to do in each handler. The
FillInData message is where you will move data from a record into a LiveCode control. To do this
you assign keys of pDataArray (1) to a control (2).
Note that the rst parameter passed to FillInData is an array representing the current row being
displayed. Also note how this is dierent than the rst parameter passed to FillInData for a
column template which is the value of the column.
Important: Make sure that you always refer to controls in the template using of me
(3). Since multiple copies of the template will be made you will have multiple controls
with the same names. Using of me removes any ambiguity and ensures that data is
displayed in the correct control.
An Example of a Customized Behavior
303
This is an example of a behavior that has been customized. The dgData of the data grid this
template is associated with looks like this:
304
theDataA[1]["FirstName"]
theDataA[1]["LastName"]
theDataA[1]["Title"]
theDataA[2]["FirstName"]
theDataA[2]["LastName"]
theDataA[2]["Title"]
When lling in the data the FirstName and LastName values are placed into a Name eld (1) and
the Title value into a Title eld (2).
This example also shows how to use LayoutControl to layout your row template. Notice how
the rectangle of the row template is captured at the beginning (3) and then used to position all
of the other elements (4).
305
In the Property Inspector, select the column you would like to customize (1). Click the "+"
button at the bottom of the pane to create a column template (2).
306
In order to customize the look you need to edit the contents of the template group. Select it (1)
and click Edit Group (2) in the LiveCode toolbar.
Edit Column Group
307
Now select the column group (1) and click Edit Group again (2). At this point you can customize
what controls appear in the column template.
A Column Template
In this example there are three controls for three dierent columns in the data grid table.
A eld named Time that formats data into a time format (1) (Just rename the eld
that is included in the row template by default). A group named My Rating. This group
has some widgets that display images of a star. (2) * A button named Genre* that oers dierent
Genre selections. (3)
Here is what those controls look like in the Project Browser. Notice how all of the controls are
located in the Row Template group.
Supporting Controls
308
The controls created (Time eld, Genre button and My Rating group) each have behaviors
associated with them. These were created automatically and are stored in appropriately named
309
buttons.
Behavior Example
Here is what the FillInData handler looks like for the My Rating column (as stored in the My
Rating Behaviour button). pData (1) contains the value of the My Rating column for the row
being displayed.
Note how this parameter diers than the parameter sent to FillInData for a row template. For
a row template the parameter passed in is an array.
You then use that value to determine how many stars to display (2).
Result
310
Here is what the table looks like now that the custom column templates have been dened. The
table found controls named Genre, Time and My Rating in the record template group so those
were used to render the data for those three columns.
311
You can get the selected line or lines of a data grid using the dgHilitedLines property.
Determining the Line in a Row's Behavior
If we need to determine the line number of a row's behavior script we can access the dgLine
property of the row template. The data grid automatically assigns the dgLine and the dgIndex
property when displaying the row.
312
Note: that the use of of me (1) can be used because the mouseDown handler is
in the row template group behavior script (which is as if the script were in the row
template group itself). If you were to put the mouseDown handler in the script of a
button that was located in the row template group then you would have to use of
the dgControl of me instead.
313
If you want to get the data associated with the selected row use the dgHilitedLines property.
The value of that property can be used in conjunction with the dgDataOfLine property. Here is
an example of a script that could be placed in a button. The Data Grid group script is NOT in the
message path for this example:
314
on mouseUp pBtnNum
if pBtnNum is 1 then
put the dgHilitedLines of group "DataGrid 1" into theLine
put the dgDataOfLine[theLine] of group "DataGrid 1" into theDataA
## theDataA is now an array variable.
## In the case of the Data Grid pictured above the keys of the
## array are id, FirstName, LastName and Title.
## This answer dialog will display: Dusty Bottoms
answer theDataA["FirstName"] && theDataA["LastName"]
end if
end mouseUp
Now let's assume that you only want to get the id value for the selected row without fetching the
entire array. You can use GetDataOfLine to accomplish this. You need to keep in mind that
GetDataOfLine (and GetDataOfIndex) is a function dened for a Data Grid. That means that
the Data Grid group MUST be in the message path. If the Data Grid group is not in the message
path you would need to use the call command.
To illustrate how to use GetDataOfLine let's look at how you could dene your own custom
property for a Data Grid. The following code denes a uSelectedID custom property that returns
the id of the selected row. This code would be placed in the Data Grid group script.
getProp uSelectedID
put the dgHilitedLines of me into theLine
return GetDataOfLine(theLine, "id")
end uSelectedID
You can now access this custom property from any script in your application:
put the uSelectedID of group "DataGrid" into theSelectedID
If you want to get the data in a row behavior script you can use the dgIndex or dgLine
custom properties of the row control. Here is an example that could be used in a Data Grid's
form behavior script:
316
If you wanted to move this same mouseUp code into the Data Grid script itself then you would
change the me references to target and add a check to ensure that the user clicked on a row.
This example also uses GetDataOfIndex rather than dgDataOfIndex to show an alternative.
##Data Grid Form Example: Data Grid Script
on mouseUp pMouseBtnNum
if pMouseBtnNum is 1 then
## the dgIndex is a custom property of the row.
put the dgIndex of the target into theIndexThatWasClickedOn
if theIndexThatWasClickedOn is not empty then
put GetDataOfIndex(theIndexThatWasClickedOn, "id") into theID
uiViewRecordOfID theID
end if
end if
end mouseUp
317
If you want to get the data in a column behavior script you can use the dgIndex or dgLine and
dgColumn custom properties of the column control. Here is an example that could be used in a
Data Grid column behavior script:
318
on mouseUp pMouseBtnNum
if pMouseBtnNum is 1 then
## the dgIndex is a custom property of the row.
## the dgColumn is a custom property of the column.
put GetDataOfIndex(the dgIndex of me, the dgColumn of me) into
theColumnValue
## Do something with column value..
end if
end mouseUp
If you wanted to move this same mouseUp code into the Data Grid script itself then you would
change the me references to target and add a check to ensure that the user clicked on a
column:
319
Using AddLine
320
To use AddLine you create a tab delimited string of text containing the values for the new row.
You also need to tell the Data Grid the names of the columns that the data should map to. Here is
an example of how to add a new row and have it appear as the last line in a Data Grid.
put "First Name" & tab & "Last Name" & tab & "Title" into theRowData
put "FirstName" & cr & "LastName" & cr & "Title" into theDataColumns
put the dgNumberOfLines of me + 1 into theLineNo
AddLine theRowData, theDataColumns, theLineNo
Note: This example script resides inside the Data Grid group script so AddLine is in
the message path.
321
or
322
ScrollLineIntoView theLineNo
The data grid will now refresh with the new data you assigned to the highlighted index.
Updating a Row's Data Without Refreshing the Data Grid
If you want to update the data in a row without automatically refreshing the data grid then you can
use SetDataOfIndex. You can then use the RefreshList command to redraw the data grid.
Example that sets all values at once:
323
How Do I Add a mouseDown Event to the Data Grid Without Breaking It?
This lesson will show you how you to write your own mouseDown event in a Data Grid without
breaking the default Data Grid behavior. You need to know how to do this when showing a
contextual menu or if during the mouseDown event you want to use the data in the row the user
clicked on.
When you add a mouseDown handler to a Data Grid you are intercepting a message that the
Data Grid normally handles. Doing so changes the behavior of the Data Grid and you need to take
that into account when coding your mouseDown handler.
What Doesn't Work
If you were to place the following code in your Data Grid script you would not get the result you
were expecting. The reason is that the line that was clicked on would not be selected until after
your popup menu was displayed. Why? Because the Data Grid behavior script processes
mouseDown AFTER the mouseDown handler you have dened in the Data Grid script itself.
324
on mouseDown pMouseBtnNum
if pMouseBtnNum is 3 then
## Oops! Line that user clicked on has not been selected since
## Data Grid has not processed mouseDown yet. Contextual
## menu won't target proper line.
popup button "MyContextualMenu"
end if
pass mouseDown
end mouseDown
325
How Can I Store an Option Menu Value When the User Makes a Selection?
This lesson will demonstrate how to update the data associated with a row in a data grid when the
user makes a selection from an option menu.
Example Data Grid
Here is the data grid we will be working with. Col 2 has been given the name Rating and has been
customized with an option menu. What we are going to do is update the data associated with a
row to reect the selection the user makes in the option menu.
Edit Column Behavior
326
We need to customize the column behavior. From the Columns pane (1) in the Property
Inspector select the Rating column (2) and then click the Column Behavior button (3).
FillInData
In the FillInData handler we are setting the menuhistory based on the value of pData that is
passed in. As there is only a single button in the Rating column template, it can be referreed to as
button 1 of me.
menuPick
327
A menuPick handler needs to be added to the column behavior script in order to accomplish the
goal. When the user makes a selection from the option menu the menuPick message is sent by
the engine. The SetDataOfIndex command to can then update the value for the column. The
parameters for SetDataOfIndex are the index, the column name and the new value. Since
the above script is in a column behavior we can use the dgIndex of me (1) for the index and
the dgColumn of me (2) for the column name.
The Behavior in Action
Here is what the data grid's internal array looks like before making a menu selection.
328
329
After making a selection for row 2 (1) the internal value was updated (2).
330
331
How Do I Refresh a Data Grid After Making Changes to a Template Through Script?
The command ResetList redraws a data grid after having copied in fresh copies of any
templates. Here is an example of how you might use it.
## Get reference to group that serves as row template for data grid
put the dgProps["row template"] of group "DataGrid" into theRowTemplate
## For tables get reference to custom template for column
put the long id of group "My Column" of theRowTemplate into theColTemplate
## Make any updates to template
set the text of button 1 of theColTemplate to "New Option1" & cr & "New
Option 2"
## Refresh the data grid
dispatch "ResetList" to group "DataGrid"
332
The rst step is to create your rst data grid and customize the template (1). The data grid
property that determines the Row Template that is used to draw the data grid is
dgProps["row template"]. The message box shows a query for this property in order to get a
reference to the data grids row template (2).
Create Other Data Grids
Now you can add other data grids to your project. Here the second data grid is added to the
same stack as the rst. After adding the data grid you can set the dgProps["row template"]
property to the long id of the rst data grid's row template.
333
You can also see that the Row Behavior for datagrid 2 is listed as coming from the
same template card as for the original DataGrid 1 which was obtained in the previous
step.
Alternatively you could also do the following: (here we are setting the properties of a data grid in a
second stack)
set the dgProps["row template"] of group "DataGrid 1" of stack "Untitled 1"\
to the dgProps["row template"] of group "DataGrid 1" of stack "my program"
Note: The LiveCode IDE creates a card in the Data Grid Template XXX stack with
a row template every time you drag a data grid on to a card. You may want to
delete this card if you aren't going to be using that template.
Result
334
See how the Row Behavior script (1) correctly identies the template from the rst stack (Data
Grid Sampler) and how this indeed does contain the Row Template (2) being used in the
second stack.
335
How Can I See What the Data Grid's Internal Array Currently Looks Like?
Using PrintKeys
336
337
338
A data grid has a helper command that will print o the rst line of each key in the internal data
array. If you need to quickly see what the internal array looks like just send PrintKeys to the data
grid. This will print the array in the message box.
Note: You should not rely on PrintKeys for anything other than taking a quick peek
at the array. It only prints the rst line of each key so it is not a 100% accurate view of
the data.
The simplest way to calculate aggregate values is to add a getProp handler to your data grid
script. In this example a custom property called uSumOfColumn (1) has been dened. Passing it
a column name (2) returns the sum of all rows of that column (3).
Using the Custom Property
339
Here is an example of using the custom property. When clicking on the button (1) the text of
another eld (in this case "sum") is set to the uSumOfColumn custom property (2).
The Result
340
Here the result has been put into the Sum eld.
341
342
The data will be exported from a data grid that looks like this.
The Handler for Populating Data Grid
343
command uiPopulatePeople
put "images/" into theImageFolder
put
put
put
put
put
put
put
put
put
put
put
put
put
put
put
put
put
put
put
put
lock screen
set the dgData of group "DataGrid 1" to theData
## Hilite first row
set the dgHilitedLines of group "DataGrid 1" to 1
unlock screen
end uiPopulatePeople
This is the code that was used to populate the data grid. This shows you the keys that each record
has (FirstName, LastName, Title and Image URL).
Export Handler
344
command uiExportData
## Export data to XML
## Get Data Grid Array
put the dgData of group "DataGrid 1" into theDataA
## Get indexes in proper order
put the dgIndexes of group "DataGrid 1" into theIndexes
## Prefix XML
put "<people>" & cr into theXML
## Loop through data, putting into XML format
repeat for each item theIndex in theIndexes
put "<person>" & cr after theXML
put "<first_name>" & theDataA[theIndex]["FirstName"] & "</first_name>"
& cr after theXML
put "<last_name>" & theDataA[theIndex]["LastName"] & "</last_name>" &
cr after theXML
put "<title>" & theDataA[theIndex]["Title"] & "</title>" & cr after
theXML
put "</person>" & cr after theXML
end repeat
## Close root XML tag
put "</people>" after theXML
put theXML
end uiExportData
This is an example of how to get data out of a data grid. Begin by getting the dgData array and
the dgIndexes. The indexes are a comma delimited list of the keys of the dgData in the proper
order.
After you have the array and the ordered list of indexes you can loop through each record in the
array. In this example the data is just wrapped in XML tags.
Example Output
This is what the output for this example looks like in the message box.
345
346
Attached Files
Checkbox_Example.livecode
Adding a Checkbox to a Form
Before you begin, drag a data grid onto a stack and set the style to Form using the Property
Inspector.
347
Click the Row Template button to open the template for the data grid.
Edit Row Template Group
Now that the card with the data grid row template is visible, open the Project Browser selecting
the Tools > Project Browser menu option.
Select the card with your template (it should be the second card under the Data Grid Templates
stack) (1). Next, double-click the Row Template group on the card (2). Doing so will select the
group on the card (3).
Now select the Object > Edit Group menu option. This will put the group in edit mode which will
allow you to drag controls from the tools palette into the group.
348
Add a Checkbox
From the tools palette, drag a checkbox onto the card and place it in the upper-left corner. The
button will appear in the list of controls in the Project Browser.
349
350
You may also need to collapse the card tree in the Project Browser window and
reopen it to force the update to the Project Browser display.
In the Project Browser select the Label eld and delete it by pressing the delete key on the
keyboard.
You will be asked to conrm you wish to delete this object. Check that it is identifying the correct
object to delete, and then click OK.
351
After deleting the eld you should have only the Background graphic and the Check checkbox in
the Row Template group.
352
In the FillInData Handler you need to remove references to the Label eld and add code for the
Check button. The code will set the label of the checkbox to the label property of the data grid
row. It will set the hilited property to the checked property of the row.
353
Update Data Grid Row Value When User Changes Checkbox State
When the user clicks on the checkbox the hilited state will change. You need to update the row
354
data in the data grid when this happens so that the dgData array properly represents what is
being seen in the interface. You can do this in the mouseUp handler of the behavior script.
During mouseUp the hilited state of the checkbox has been changed and so it is safe to save the
value. You just need to call SetDataOfLine and pass in the hilite of the target (the target
being the checkbox button).
Add the following to the behavior script. Make sure and compile the script afterwards.
355
With the Edit tool active, right-click on the button and select Edit Script.
Add a simple script that will populate the data grid with two rows. Each has the label and
checked properties that were referenced in the behavior script earlier.
356
Test
After compiling the script, click on the Populate Grid button. The card should now look similar to
this.
357
Try it out. If you click on a checkbox in line 1 it should uncheck. Click on it again to check it.
Checking/Unchecking All Checkboxes in a Data Grid
When working with lists that have checkboxes it is nice to include the option to check or uncheck
all of the items in the list. Let's look at how to do that.
Add a button to the card and name it Check/Uncheck.
358
The code for checking/unchecking all items in the list isn't too complicated. Here is how the logic is
broken up:
1. Use the checked value of row 1 to decide what to set all of the other rows to. Get the
current value of row 1 and toggle it.
2. Loop through all lines of the data grid, setting the value of the checked property of each
row to the new value. Use SetDataOfLine as this command will not redraw the data grid
each time it is called.
359
3. Finally refresh the data grid so that the new row values are used to display each row.
Test
Click the Check/Uncheck button to test. You should see the checkboxes toggle between the
checked and unchecked state.
If you get the dgData or dgText property of the data grid then you will see the proper values for
the checked state of each row.
360
361
Using Script
You can change the alignment by setting the dgColumnAlignment for a column.
set the dgColumnAlignment["Name"] of group "DataGrid" to "left"
362
Using Script
You can sort by column setting the dgProp["sort by column"] property of the data grid to the
name of the column you want to sort by.
set the dgProps["sort by column"] of group "DataGrid" to "Name"
363
Similarly you can change other properties related to the sort by script too.
364
Select the data grid and open the Property Inspector. Navigate to the Columns pane (1),
select the column you want to modify (2), and set the width of the column using the Width text
entry eld (3).
Using Script
You can set the size of a column by setting the dgColumnWidth property for the column to an
integer.
set the dgColumnWidth["Name"] of group "DataGrid" to 150
365
Create a Button
The default column behavior property can be set to a button. The script of the button will be
used to ll in each cell in the table.
Drag a button onto the card and name it My Default Column Behavior.
366
When creating your own default column behavior it is a good idea to start with the script that
the data grid itself uses as the default. You can copy the data grid default script easily enough by
selecting the button (1) and executing the following statement in the Message Box (2):
Careful of continuation character " \"
set the script of selobj() to the script of button "Default Column" \
of stack "revDataGridLibrary"
Customize Behavior
367
Now this behavior can be customized. Here is what the default behavior looks like.
Important: If you decide to write a default behaviour script from scratch make sure
to include the dgDataControl getProp handler. This is required in order for the data
grid to work properly.
getprop dgDataControl
-- Required by library so that it can locate the control.
return the long ID of me
end dgDataControl
368
Now you can set the default column behavior property of the data grid. Select the button (1)
and execute the following in the Message Box (2):
Note: Careful of continuation character " \"
set the dgProps["default column behavior"] of group "DataGrid 1" \
to the long id of selobj()
369
The following example will show you how to truncate the tail end of every cell whose content is too
wide to t. The data grid provides a helper command named TruncateTail that takes the short
id of a eld and a string that signies the text is being truncated. A call to TruncateTail has been
added to the FillInData and LayoutControl handlers so that cell contents are truncated when
drawn or when a column is resized.
Note: TruncateTail works fairly well for most cases but can cause visual lag if there
are lots of cells being displayed that use TruncateTail. You should test your data and
table to make sure it performs adequately for your needs.
Quick Tip: You can determine the name of the column that is being rendered by
checking the dgColumn property. You could use this property if you only wanted to
truncate the text in certain columns:
370
Refresh
To see the results, click the Refresh Data Grid button in the Property Inspector (1). Notice how
cell contents are no truncated as needed (2).
371
This example will dim any cell that is empty. Since the default cell consists of a single eld object
this can be accomplished by setting the eld's opaque to true, setting the backgroundcolor
and changing the blendlevel.
Result
Deleting some entries in the data and click on the Refresh Data Grid button to see the result
372
A Data Grid table has a header where the column names are displayed (1). When a user clicks in
the header with the mouse the dgHeader of the target returns the long id of the group control
that contains all of the header controls.
When the user clicks on a column header (2) the dgHeaderControl of the target returns the
long id of the group control that contains all of the column header controls.
Example
373
Here is some sample code that prints o the dgHeaderControl and dgHeader properties
when the user clicks on a Data Grid. Place this script in the Data Grid script.
After adding the script to the Data Grid the value of the dgHeaderControl and dgHeader
properties are displayed in the Message box. In this example both properties return the long id
of a control (1) because the click was on a column header (2) (State in this case.)
In the following example only the dgHeader property returns the long id of a control (1)
because even though the click was in the table header it was not on a column header (2).
374
How Do I Display a Contextual Menu When the User Clicks on a Column Header?
Overview
This lesson will show you how to display a contextual menu (1) when the user clicks on a column
header in a Data Grid table (2).
The Code
375
Here is some LiveScript code that will display a contextual menu. The code is located in the Data
Grid's script.
A contextual menu is displayed when during the mouseDown message when the user clicks with
the right mouse button (1).
To determine if the user clicked on a column header you can check whether or not the
dgHeaderControl property of the control that was clicked on (the target) is empty (2). If the
property is not empty then you know that the user clicked on a column header.
Once you know that the user clicked on a column header you can display the contextual menu. In
this example the name of the column that was clicked on (3) is appended to "Popup" in order to
get the name (State Popup) of the popup button to display (4).
376
on mouseDown pBtnNum
## Let Data Grid process mouseDown
dgMouseDown pBtnNum
if pBtnNum is 3 then
if the dgHeaderControl of the target is not empty then
## the user clicked on a column header
## Get column name
put the dgColumn of the target into theColumn
## Get name of contextual button to use
put theColumn && "Popup" into theContextualButtonName
## Display contextual if exists
if there is a button theContextualButtonName then
popup button theContextualButtonName
end if
end if
end if
end mouseDown
The Result
Now when a right-click occurs on the State column the State Popup popup button is displayed
as a contextual menu.
377
set the dgProp["default column behavior"] of group "DataGrid" to the long id\
of button "My Custom Column Behavior" of stack "MyStack"
Here is an example of a FillInData command that takes a column value encoded as UTF-8 and
sets the unicodetext of the column eld.
Important: If you decide to write your own default behaviour script make sure to
include the dgDataControl getProp handler. This is required in order for the data
grid to work properly.
getprop dgDataControl
-- Required by library so that it can locate the control.
return the long ID of me
end dgDataControl
To see the default column script the data grid uses enter the following in the Message box:
edit script of button "Default Column" of stack "revDataGridLibrary"
378
Select the data grid and open its Property Inspector. Select the Columns pane (1) and add a
column using the "+" button (2). Rename the column Line Number (3).
379
Use the up arrow (1) to move the Line Number column to the top of the list.
Create a template for this column by clicking on the "+" button at the bottom of the Property
Inspector (2).
Edit Line Number Group
380
After creating the column template the card with the template group will open. As you can see a
group called Line Number, corresponding to the column's name, has been created and within
that group is a single eld object.
We do not need to actually do anything to the template so simply close and save it when
prompted.
Edit Column Behavior
Now all that is left is to dene the behavior for this column. Go back to the Columns pane of the
data grid's Property Inspector and click the Column Behavior... button (1) to open its script
editor.
381
382
The dgLine is a property of a row template and this will display the line number for the current
line. In LayoutControl you just need to ensure the rect of the eld lls the entire cell (2).
Refresh Data Grid
383
384
385
The goal is to customize when happens when this table is sorted by the Line Number column.
The Data Grid Group Script
A Data Grid calls a built in handler SortDataGridColumn whenever the dgProps ["sort by
column"] property is set. This includes when the user clicks on a column header to sort that
column. By placing a modied version of the SortDataGridColumn in the data grid's script this
message can be captured and the behavior modied.
Place the following in the script for the data grid.
386
on SortDataGridColumn pColumn
switch pColumn
case "Line Number"
## ReverseSort is a helper provided by the Data Grid.
## It merely reverses the current sort.
ReverseSort pColumn ## pass in column so header is hilited
break
case "State Code"
## Just provided as an example of how to prevent the user
## sorting on a column. In this case the "State Code" column.
## We accomplish this by NOT passing the message.
break
default
## For all other cases, pass the message so that the data grid
## will be sorted based on column settings.
pass sortDataGridColumn
end switch
end SortDataGridColumn
The way the custom SortDataGridColumn handler works is simple. Passing the message will
cause the data grid to use its default column sorting routines. (1) Set this as the Default case.
Not passing the message prevents the data grid from performing it own sorting (2) and (3).
In this example, clicking on the Line Number column will just reverse whatever current sort
exists. This is done by calling ReverseSort, a built-in data grid helper that reverses whatever the
current sort order is. (2)
The Result
387
Clicking on the Line Number column (1) now reverses the sort.
388
##
##
##
on
389
To begin, set the sort by column property to empty. This will remove any column sorting that
might be active.
set the dgProp["sort by column"] of group "DataGrid 1" to empty
Just copy and paste the above into the Message box to execute it.
Your table headers should now appear the same, with no highlights or sorting arrow.
390
When the user clicks on a table column header the SortDataGridColumn message is sent to
the Data Grid. Intercepting this message and not passing it eectively disables sorting. For more
information about how SortDataGridColumn works see How Do I Customize Column Sorting?.
Add the following code to your Data Grid group script and compile.
Now when you click on the table header the data will not be sorted.
391
Note: Once you add the SortDataGridColumn handler to a Data Grid setting the
dgProp["sort by column"] property will no longer do anything. If you need to set
the sort by column property later on you would need to remove the
SortDataGridColumn handler from the script, or at least pass the message.
This lesson will show you how to create a custom column template that provides decimal
alignment. You can download the stack used to create this lesson.
Create a Data Grid Table
Here a couple of rows of decimal numbers have been added to experiment with.
393
394
Here you see the Project Browser with the template for the Data Grid expanded showing the
group for this column (Col 1) with a eld _ColumnData_ to hold the column's data.
Edit Column Template Group
Double-click on the column group in the Project Browser (1). This will select it on the template
card (2) and then click the Edit Group button (3) to edit the contents of the column group.
395
Be sure to double-click on the group icon and not the group's name. Double-clicking on the
object's name will simply allow you to edit the name, which is not what is wanted.
Create 3 Fields
A column that aligns decimals in the center of the column, and is editable if the user double-clicks
on the cell, is achieved by creating three elds.
396
Since the column template group already had a eld named _ColumnData_ double-click this
name (in the Project Browser) and rename it to Leftvalue (1). Open the Property Inspector
for this eld and set its textalign to right. Duplicate the Leftvalue eld and name it Rightvalue
(2). Set the its textalign to right too. Finally Duplicate this eld and rename the duplicate to
ForEditing (3). The text of this eld should be empty. Make sure that the ForEditing eld has a
higher layer than Leftvalue or Rightvalue.
Don't worry too much about positioning as the elds will be resized and repositioned when drawn
in the data grid.
Click on the card background of the editing template and then the Stop Editing button and
close and save the window.
Edit Column Behavior
Now that the objects we need to display the column data have been created its time to tell the
column what to do when it is drawn. Return to the Property Inspector for the data grid and from
the Columns pane (1) click the Column Behavior button (2). This will open the behavior script
for the column.
Update FillInData
397
The decimal number is going to be displayed by assigning the left side of the decimal to the
Leftvalue eld and the right side of the decimal to the Rightvalue eld.
set the itemdelimiter to "."
set the text of field "Leftvalue" of me to max(0, item 1 of pData)&"."
set the text of field "Rightvalue" of me to max(0, item 2 of pData)
Update LayoutControl
The left and right elds are now resized so that each takes up half of the available width to align
the decimal in the center of the cell(1). Finally we resize the ForEditing eld to take up the entire
cell width(2). This is the eld that the user can double-click on to edit the cell contents.
398
Update EditValue
EditValue is the handler that is called by the data grid to edit a cell value. Usually this is because
the user double-clicked on the cell or tabbed into the cell.
EditFieldText displays, by default, the htmltext of the eld you are editing. This default can be
overriden by setting the dgTemplateFieldEditor[text
|htmltext|rtftext|unicodetext|utf8text] of the data grid. Here the
dgTemplateFieldEditor["text"] of the data grid is set to text(1). Of course the ForEditing eld has
no text in it by default and the "left" and "right" eld values need to be combined as documented
in the handler.
Also, if the user double-clicks on this cell they actually double-click on the ForEditing eld (as it
has the higher layer) and it is thus the target (2)
399
command EditValue
## Assign text the the editor will have when it opens
## We combine the left and right field values.
Set the dgTemplateFieldEditor["text"] of the dgControl of me to \
the text of field "Leftvalue" of me & the text of field "Rightvalue" of
me
## The "ForEditing" field is what the user actually clicked on.
## This is the "target"
EditFieldText the long ID of field 1 of the target, the \
dgIndex of me, the dgColumn of me
end EditValue
Now that the necessary changes have been made refresh the data grid so that it redraws with the
new template controls. From the Basic Properties pane of the inspector palette click the
Refresh Data Grid button. Alternatively you can send ResetList to the data grid.
send "resetList" to group "datagrid 1"
Test
400
The decimals all appear in the center of the cell. Double-clicking brings up an editing eld as
shown here. Finally the decimal remains in the center of the cell if the column is resized.
In this example we are going to modify the basic example created in the lesson mentioned above
so that it colors a row red if the row's line has error property is true.
401
By clicking on the Toggle Line 3 Color button the color of line 3 turns red. The code in the
button extracts the data for line 3 from the data grid, toggles the line has error property and
reassigns the new data to line 3.
on mouseUp pMouseBtnNo
put the dgDataOfLine[3] of group "DataGrid 1" into theDataA
put not theDataA["line has error"] into theDataA["line has error"]
set the dgDataOfLine[3] of group "DataGrid 1" to theDataA
end mouseUp
Now let's look at what the default custom column behavior looks like for this data grid.
The Default Custom Column Behavior
Here is the relevant code from the default custom column behavior for this data grid. The key
addition to the code is the SetForeGroundColor handler. This handler checks the value of the
line has error column for this row (using GetDataOfIndex) and if it is true then changes the
cell to red. Since each cell in this row has the same value for line has error the entire row
appears red.
402
on FillInData pData
-- This message is sent when the Data Grid needs to populate
-- this template with the column data. pData is the value to be displayed.
set the text of me to pData
SetForeGroundColor
end FillInData
on LayoutControl pControlRect
-- A default column is just a field.
end LayoutControl
setprop dgHilite pBoolean
-- This custom property is set when the highlight of your column template
has
-- changed. You only add script here if you want to customize the
highlight.
if pBoolean then
set the foregroundcolor of me to the dgProp["hilited text color"] of the
dgControl of me
else
SetForeGroundColor
end if
end dgHilite
private command SetForeGroundColor
if GetDataOfIndex(the dgIndex of me, "line has error") then
set the textcolor of me to red
else
set the textcolor of me to black
end if
end SetForeGroundColor
403
To begin, turn o Empty row height for your data grid form in the Property Inspector.
Edit Row Template
404
Open the card that has the row template group by clicking the Row Template button.
Turn O dontWrap Property
405
The default row template for a data grid has a single eld that displays data. With Select
Grouped turned on (1) select the eld (2). Using the Property Inspector turn o dontWrap
(3). You can now close the stack.
Edit Row Behavior
406
Return to the Property Inspector for your data grid. Edit the Row Behavior by clicking on Edit
Script button.
Script Field to Resize to Fit Height
Only a few modications are needed to make to the default LayoutControl handler resize the
eld to t the height.
407
The default LayoutControl handler resizes the eld to ll the available width (1). After that is
done you then need to resize the eld to ll the formattedHeight (2). Finally, adjust the rect of
the Background graphic to take into account the new eld height (3).
on LayoutControl pControlRect
local theFieldRect
## Expand the field to fill the available width
put the rect of field "Label" of me into theFieldRect
put item 3 of pControlRect - 5 into item 3 of theFieldRect
set the rect of field "Label" of me to theFieldRect
## Now resize the field to fit its content
put item 2 of theFieldRect \
+ the formattedheight of field "Label" of me - \
the bottommargin of field "Label" of me \
into item 4 of theFieldRect
set the rect of field "Label" of me to theFieldRect
## Now update the bounding rect to match total the height
## you want this row to have (note there is an additional 4
## pixels added to the bottom
put item 4 of theFieldRect + 4 into item 4 of pControlRect
set the rect of graphic "Background" of me to pControlRect
end LayoutControl
408
409
This card has a data grid and an option menu. The option menu contains three values that you
can sort by: First Name, Last Name and Title.
Option Menu Code
The code to perform the sort is pretty straight forward.
410
1. Determine which array key of the data grid form to sort by. This will be one the keys created
when the data was assigned to the dgData. If you used the dgText property then the key
will be "Label 1" or "Label 2", etc.
2. Determine the sort type, direction and whether or not the sort is case sensitive.
3. Call the SortDataByKey command.
411
on menuPick pItemName
switch pItemName
case "First Name"
put "FirstName" into theKey
break
case "Last Name"
put "LastName" into theKey
break
case "Title"
put "Title" into theKey
break
end switch
put "international" into theSortType
put "ascending" into theDirection
put "false" into isCaseSensitive
dispatch "SortDataByKey" to group "Datagrid 1" with \
theKey, theSortType, theDirection, isCaseSensitive
end menuPick
The Result
Here is what the sort looks like after selecting First Name and after selecting Last Name.
Attached Files
ExpandingRow.rev
Expanding and Contracting Rows
This is what the example stack looks like. By default all of the rows are contracted and only show
names.
Clicking on the arrow next to a name expands the row to show the description of the person.
Setting the Data Grid Properties
To create a Data Grid form with rows that expand/contact you need to turn o xed control
height in the data grid's Property Inspector.
413
Note: To turn o the property using script you set the dgProp["xed row
height"] property to false.
Updating the Row Behavior Script
In order to get expanding rows working a couple of things need to be taken into account in the
Row Behavior Script.
The FillInData handler should show or hide controls as necessary. The example stack stores the
expanded state of each row in the expanded key.
414
In the LayoutControl handler the position of the controls and background graphic based on
whether or not the row is expanded or contracted are adjusted . Since the xed row height
property is set to false the Data Grid computes the total height of the data based on the height
of each row after calling LayoutControl.
When the user clicks on the arrow the example stack updates the expanded key in the row's
data and then redraws the row. Using SetDataOfIndex in conjunction with RefreshIndex is the
most ecient way to do this.
pDataArray["expanded"] is a boolean which determines the state of the row.
the short name of the target is "ArrowContracted"
is an expression that evaluates to true or false depending on the target. If the ArrowContracted
graphic is visible and thus clicked on, the expression evaluates to true which in turn sets the row
to be in its expanded state as per the FillnData handler.
Thus this little snippet eectively toggles the state of the row.
When you set the dgProp["xed row height"] property of a Data Grid to false the Data Grid
must draw all records in order to determine the total height. That means that FillInData and
LayoutControl are called for every record in the Data Grid. This can be time intensive depending
on the amount of data.
This lesson will show you a technique that can speed up the calculation of the total height of the
data in situations where the rows can only have heights of known values.
CalculateFormattedHeight
When the Data Grid loops through the data to calculate the height the message
CalculateFormattedHeight will be sent to the Row Template. If your Row Behavior handles
this message then the Data Grid will use the integer value that you return rather than calling
FillInData and LayoutControl.
Here is an example that uses CalculateFormattedHeight to return the height of a row based
on whether or not the row is expanded. Just place the CalculateFormattedHeight handler in
your Row Behavior script.
on CalculateFormattedHeight pDataArray
if pDataArray["expanded"] then
return 74
else
return 20
end if
end CalculateFormattedHeight
on FillInData pDataArray
...
end FillInData
The
The
The
The
EditFieldText command
EditValue message
EditKey and EditKeyOfIndex commands
CloseFieldEditor command which can be sent as a result of calling EditFieldText.
416
CloseFieldEditor
If the user changes any content in the eld editor this message will be sent to the eld targeted in
the rst parameter sent to EditFieldText. Read the API docs for EditFieldText which discusses
this message.
Example of storing value in dgData in CloseFieldEditor. This would be required if you only
passed in one parameter to EditFieldText.
417
on CloseFieldEditor pFieldEditor
put the dgIndex of me into theIndex
put the dgDataOfIndex[theIndex] of the dgControl of me into theDataA
put the text of pFieldEditor into theDataA[the dgColumn of me]
set the dgDataOfIndex[theIndex] of the dgControl of me to theDataA
end CloseFieldEditor
How Can the User Edit Field Content in a Data Grid Form?
The data grid commands for creating an editor for a particular eld in a row template. This lesson
will show you how to use them.
What You Need to Know
In order to edit eld contents in a data grid form you need to know about the following:
1. The EditFieldText command
2. The EditValue message
3. The EditKey and EditKeyOfIndex commands
Read up on the entries for EditFieldText, EditValue and EditKey/EditKeyOfIndex in the API
documentation.
EditFieldText
The EditFieldText command will create an editor for a eld that you specify. You can use this
command to create a eld editor for a eld in your row template.
EditValue
EditValue is the message that is sent to a row when a request to edit a elds contents has been
made. You can call EditFieldText from within a handler for this message to begin an editing
operation.
EditKey and EditKeyOfIndex
EditKey and EditKeyOfIndex will trigger the EditValue message in a row. Each takes the name
of the key you want to edit and the line or index you want to edit. Here are two example scripts
showing how you could use these commands in the script of a data grid.
Placed in script of row template behavior
418
on mouseDown pBtnNum
if pBtnNum is 1 then
## Did the user click on the FirstName field?
if the short name of the target is "FirstName" then
put "FirstName" into theKey
put the dgHilitedLine of me into theLineNo
EditKey theKey, theLineNo
end if
end if
end mouseDown
on mouseDown pBtnNum
if pBtnNum is 1 then
## Did the user click on the FirstName field?
if the short name of the target is "FirstName" then
put "FirstName" into theKey
put the dgHilitedIndex of me into theIndex
EditKeyOfIndex theKey, theIndex
end if
end if
end mouseDown
Either of the above calls will trigger the EditValue message. The EditValue can be thought of as
a central message where you can open a eld for editing text. A handler for this message is where
you will call EditFieldText.
on EditValue pKey
## Example of opening a field editor for the field displaying
## the value for pKey
## Since we are passing in parameters 2 and 3 any changes
## will automatically be saved to the dgData.
## 'me' is the Data Grid in this case.
EditFieldText the long id of field pKey of me, the \
dgHilitedIndex of me, pKey
end EditValue
CloseFieldEditor
If the user changes any content in the eld editor this message will be sent to the eld targeted in
the rst parameter sent to EditFieldText. Read the API docs for EditFieldText which discusses
this message.
Here is an example of storing the new value in the dgData of the Data Grid in the
CloseFieldEditor handler. Manually storing the value would be required if you only passed in one
parameter to EditFieldText.
This example script would be in the Row Behavior script as it uses the dgIndex of me
property.
419
on CloseFieldEditor pFieldEditor
## 'me' is the row control
put the dgIndex of me into theIndex
put the dgDataOfIndex[theIndex] of the dgControl of me into theDataA
put the text of pFieldEditor into theDataA[the dgColumn] of me
set the dgDataOfIndex[theIndex] of the dgControl of me to theDataA
end CloseFieldEditor
We can accomplish this by using the formatting information contained in the data.
However, when you edit the content of the cell the formatting is lost. This is because the Data
Grid edits the text property of the eld by default.
420
Other properties you can set include rtftext, text, unicodetext and utf8text.
The Result
421
Here is the result of using the example code above in the custom column behavior. Notice how
the text being edited is bold.
How Can I Select the Text in the Edit Field When It Opens?
The default Data Grid behavior when editing cell contents is to put the cursor at the end of the
eld. This lesson will show how to tell the Data Grid that all of the cell text should be selected.
The technique described requires a custom column behavior as outlined in the lesson How Do I
Override the Default Behavior For Rendering Data to a Cell .
The Default Behavior
By default the Data Grid will place the insertion point at the end of the text of a cell when you start
editing a value.
Selecting The Text
422
You can tell the Data Grid to select all of the text by setting a special custom property called
dgTemplateFieldEditor. If you set the dgTemplateFieldEditor["select text"] of the Data
Grid to true then the data Grid will select the cell text.
An Example Script
Add this line of text to the EditValue handler in a custom column behavior. Just place the code
right before the call to EditFieldText.
How Do I Save Changes the User Makes in an Editor Field to an External Data Source?
When Calling EditFieldText With 3 Parameters (Simpler)
When calling EditFieldText with all three parameters (which is what a data grid column does by
default) the data grid will automatically save the text that the user enters in the dgData array.
That means that all you need to do is save the text of the editor eld to your external data source
in the CloseFieldEditor handler. Note that if you save anything other than the text of
pFieldEditor then your data source will not match the dgData value.
Here is an example script that goes in the Data Grid group script.
423
A CloseFieldEditor message would still be sent when the user changes the contents of the eld
but would need to contain code for saving the changes to the dgData array.
Here is an example script that goes in the Data Grid group script.
## CloseFieldEditor placed in data grid script
on CloseFieldEditor pFieldEditor
put the dgColumn of the target into theColumnBeingEdited
## Store UTF8 text
put unidecode(the unicodetext of pFieldEditor, "UTF8") into theNewText
## Save data to database using command I defined
put "Person" into theTable
## Get the unique id of the row in the database we want to edit
put GetDataOfIndex(the dgIndex of the target, "id") into theRowID
SaveDataToDatabase theTable, theRowID, theColumnBeingEdited, theNewText
## Update dgData.
## Setting dgDataOfIndex will refresh the data grid display as well as
update dgData
put the dgDataOfIndex[ the dgIndex of the target] of me into theDataA
put theNewText into theDataA[theColumnBeingEdited]
set the dgDataOfIndex[the dgIndex of the target] of me to theDataA
end CloseFieldEditor
By default the Data Grid eld editor allows users to enter data and save it back to the Data Grid. If
you need data entry to behave dierently you can assign your own behavior script to the eld
editor before it opens. This lesson will show you how.
Create Your Behavior Script
1. Create a button (1) to hold the behavior script you want to use with the Data Grid eld
editor. Here it is placed on the same card as the data grid.
2. Set the script of the button (2) to the script of button "Field Editor" of stack
"revDataGridLibrary". This is the behavior script that Data Grid uses by default and is a good
place to start when customizing the behavior.
Customize Your Script
Open the button's script...
425
426
Templates".
When you build a standalone application LiveCode uses the settings you have set for your
application. These are on the General tab of the Standalone Applications Settings. By
default LiveCode will look for a substack whose name begins with "Data Grid Templates". If it nds
one then the revDataGridLibrary stack is added to your standalone application.
the Standalone Settings dialog. You can now force the inclusion of the DataGrid library, to
ensure that any stack loaded by the standalone can use Data Grids.
Open the General tab of the Standalone Applications Settings (1) and select Select
inclusions for the standalone application (2)
Now open the Inclusions tab (1), locate the DataGrid library, and then click the checkbox (2) to
include it.
428
Example B
## Script that deletes hilited index on mouseUp.
## Place in the data grid script.
on mouseUp pMouseBtnNum
if pMouseBtnNum is 1 then
put the dgHilitedIndex of me into theIndex
DeleteIndex theIndex
end if
end mouseUp
the correct value will not be returned/set. A Data Grid relies on getProp/setProp handlers to
429
Advanced Options
Displaying Large Amounts of Data
Setting the dgText property or creating an array and setting the dgData property of a data grid
is the easiest way to display your data. But what about situations where creating an array is too
time intensive and you already have the data in another format? A data grid can handle these
situations for you as well using a feature called callbacks.
Download the attached sample stack and database that shows how to use the techniques
described in this lesson to display data from a SQLite database.
Attached Files
datagrid_databases.zip
The dgNumberOfRecords Property
Normally a data grid reports the number of records based on the number of numeric indexes in
the rst dimension of the dgData array. If you set the dgNumberOfRecords property,
however, the data grid stops using an internal array and issues a callback message whenever it
needs to display data in a line.
Important: When using this technique properties like dgData, dgText,
dgDataOfIndex, etc. will no longer return values. The data grid is just displaying
records from your data source. It does not store any of that data internally.
GetDataForLine Callback
430
This diagram demonstrates how this works. If you were to set the dgNumberOfRecords to
10000 then the data grid would start sending the GetDataForLine message whenever it needed
to display a row. Your responsibility is to ll in the data that the data grid needs by handling the
GetDataForLine message. To do that you dene GetDataForLine as follows:
command GetDataForLine pLine, @pDataA
end GetDataForLine
You can dene this handler in the data grid script or anywhere else in the message path. Just ll in
pDataA with the appropriate data and the data grid will display it.
431
You should probably create this ahead of time using the IDE. For example, you could create a data
grid and then delete it while leaving the row template behind (it will exist on a card in "Data Grid
Templates xxx" stack).
432
433
Everything together
To test out the example scripts, simply copy the following mouseUp handler into a button of an
empty stack, and click on it with the browse tool.
on mouseUp
answer file "tab delimited" with type "any file" or \
type "tab file|tab|TEXT" or type "txt file|txt|TEXT"
--in case the user cancels the file dialogue, the script does not proceed
if it = "" then
exit mouseUp
end if
put url ("file:" & it) into theData
lock screen --when doing visual stuff, this helps to speed things up
--make sure the group does not exist already
if there is a group "my Datagrid" then
delete group "my Datagrid"
end if
--copy the template group
copy group "DataGrid" of group "Templates" of stack "revDataGridLibrary" \
to this card
set the name of it to "my Datagrid"
set the dgProp["style"] of group "my Datagrid" to "table"
--position it nicely
set the rectangle of group "my Datagrid" to 0,the bottom \
of me + 16,the width of this card, the height of this card
--create row template
put the name of this stack into theMainstack
put "Data Grid Templates" && the seconds into theName
create invisible stack theName
set the mainStack of stack theName to theMainstack
go stack theName
create card
create field "label"
create graphic "Background"
group field 1 and graphic 1
set the name of last group to "Row Template"
go stack theMainstack
--point datagrid to template
set the dgProp["Row Template"] of group "my Datagrid" to the \
long id of group "Row Template" of stack theName
--create columns
put line 1 of theData into theColumns
--no empty column names are allowed, so insert a space when \
that happens
replace tab & tab with tab & " " & tab in theColumns
replace tab with return in theColumns
set the dgProp["columns"] of group "my DataGrid" to theColumns
434
Here is selected row in a data grid (1). The goal is to scroll that row to the top of the data grid (2).
How To Do It
Here is the code that will scroll the selected line to the top of the data grid.
435
The Result
After executing the code the row will have been moved to the top of the data grid.
436
command
local
local
local
The Handler rst checks that no errors have been returned. If there are any, the error data is
returned.
The handler then steps through the database cursor restructuring the data into an indexed
multidimensional array that can be used by the data grid.
How to use
You can call this command as follows.
In this example theCursor is a database cursor that you have opened using revQueryDatabase.
local theDataA
ConvertSQLCursorToArray theCursor, theDataA
put the result into theError
If theError is empty then dimension 1 of theDataA will contain integers from 1 to the number of
records in the cursor (revNumberOfRecords). Each 1st dimension, in turn, has a key for each
column in the cursor (revDatabaseColumnNames).
Example
437
Here is what the array might look like if your cursor had 2 columns (id and name) and 3 rows.
theDataA [1] ["id"]
theDataA [1] ["name"]
theDataA [2] ["id"]
theDataA [2] ["name"]
theDataA [3]["id"]
theDataA [3] ["name"]
You can use this array to set the dgData property of a data grid.
set the dgData of group "DataGrid 1" to theDataA
438
Printing In LiveCode
Introduction
Printing is a vital aspect of many applications. LiveCode provides a comprehensive set of printing
capabilities. Whether you want a simple print out of your stack, want to print labels or produce
complex reports, LiveCode has the features you need.
LiveCode supports a number of methods of printing. You can use the print card command and
have LiveCode manage the layout of cards on the paper. Alternatively you can use the print into
rectangle commands which allow you to take full control over the layout of your print out. The
former method is most suited to implementing simple print functionality, while the latter is better
suited for more complex layout printing or printing reports. Finally, you can use the built-in eld
printing script library to print the contents of any text eld using a simple command.
LiveCode also includes a full set of features to access and set printer device options, including
options such as margins, page range and number of copies. This feature is invaluable if you want
to produce a high resolution PDF le from your stack.
Choosing a Printer
Use the availablePrinters to list the printers available on the user's system. Printers can include
fax modems and networked devices. If the availablePrinters is empty, no printer is assigned.
For example, to place a list of the available printers into a list eld:
put the availablePrinters into field "list of printers"
Set the printerName to the printer you want to use to print. You can use any printer listed in the
availablePrinters. This property is useful when producing an in-house utility that needs to print to a
specic printer on the corporate network, or for automatically restoring the user's previous printer
choice stored in a preferences le.
set the printerName to the cSavedPrinter of stack "My Preferences"
The printerFeatures provides a list of the features supported by the currently selected printer.
Features will vary widely from device to device, but typical features may include things such as
"collate", "color" and "duplex". Use this property to enable and disable output options in any
custom printer settings dialog.
property is set to device it will output to the physical printer. Alternatively, you can set it to a le
path to print to a le. On Mac you can set this to preview to create a preview.
For example, to save the current card to a le:
ask file "Save as:
set the printerOutput to ("file:" & it )
print this card
answer printer
If the user does not press the cancel button then any changes to the printer settings will be
reected in the global printing properties, discussed below.
To bring up the standard OS page setup dialog, use the answer page setup command.
answer page setup
440
441
Do not confuse the printMarginsand other card layout printing properties with paper properties
such as the printRectangle. The printMarginsonly applies to printing cards using LiveCode's
automatic card layout capabilities (discussed below). Thus the printMarginshas no eect on
printRectangle.
Use the printPaperOrientation to get and set the orientation of your print out. This property
may be set to one of the following values:
Use the printPaperScale property to apply a scale factor to your print out after all other
settings have been taking into account.
The printPaperScale is applied after all other layout and scaling options. For example, if you
have used the layout printing features to print a series of cards at 50% scale, then set the
printPaperScale, this factor will be applied to the entire layout after the card layout scaling has
been calculated.
To print a range between 1 and 100% set the printPaperScale to a number between 0 and 1. To
print at 200% set the printPaperScale to 2.
set the printPaperScale to 0.5 -- 50%
Use the printDuplex property to tell the printer to print double sided. This property may be set
to any of the following values:
442
short edge: double-sided printing with tumble (ip the non-facing page)
long edge: double-sided printing without tumble.
set the printDuplex to "short edge"
Use the printCollate property to specify whether to interleave multiple copies of a print job. If a
print job has three pages, P1, P2 and P3, with printCollate set to true and printCopiesset to 2
the output order will be P1, P2, P3, P1, P2, P3. With printCollate set to false the output will be P1,
P1, P2, P2, P3, P3.
set the printCollate to true
Use the printColors property to specify whether to print in color or not. If "color" is not among
the lines of the printerFeatures then this property will have no eect and all print jobs will be
printed in monochrome. This property may be set to either true or false.
For example, to check if color printing is supported on the current printer and use it if it is:
if "color" is among the lines of the printerFeatures then
set the printColors to true
end if
Use the printTitle property to specify the name of the next print job in the system printer queue.
Setting this property to match the name of the user's document will ensure that the user is able
to recognize it in the system printer queue utility. If the printTitleis empty at the start of a
printing loop, the title of the defaultStack will be used.
set the printTitle to "My Report 1"
Use the printRectangle property to determine the printable region of the physical page as
returned by the printer. This rectangle will always be contained within the printPaperRectangle.
Thus you should use the printRectangle and not the printPaperRectangle when calculating a
print layout. The printPaperRectangle is useful if you are generating a print preview and want
to show the entire area of the paper including any margin areas that cannot be printed on. This
property is read only and cannot be set directly.
443
Create a stack o screen (with formatForPrinting set to true) with your print layout
template and copy text into it prior to printing.
Set the formatForPrintingbefore doing any print layout related calculations on the stack.
Set the formatForPrintingto true on any print preview stack being displayed to the user.
Don't:
Allow the user to directly edit text in elds whose formatForPrinting is set to true.
Attempting to do this may cause display anomalies. Set this property to false and reload
the stack rst.
Generally use stacks with formatForPrintingset to true for display on screen, as this will
show text that has been optimized for print display (instead of screen display), which is
harder to read on screen.
Use this property on other platforms Windows is the only platform that uses dierent fonts
on screen vs. in a print out.
Use the windowBoundingRect property to constrain display of a stack who's
formatForPrintinghas been set to true this property will be ignored when the stack is
opened or maximized.
Printing a Card
Once you have set your printer, paper and job options (above) you are now ready to use one of
the print commands to start printing. At its simplest, the print card command allows you to print
a card. Later we will discuss ways of printing more complex layouts, elds and text.
print this card -- prints the current card
print card 12 -- prints card 12
For more details on how to specify which cards to print, see the print command in the LiveCode
Dictionary.
To print a scale between 1 and 100% set the printScale to a number between 0 and 1. To print at
200% set the printScale to 2.
The printScale applies to each card that you print. It is not related to the printPaperScale which
is applied to the entire print job after all other scaling calculations have been applied. Thus you
may set the printPaperScale to 0.5 to print at 50%, then print individual cards at dierent
printScale values. With a printPaperScale of 0.5, a printScale of 2 would result in that card being
printed at 100%.
When printing a card, use the printMargins to specify the margins around the border of the card
on the page.
Note: When calculating placement on the printed page, all calculations assume that
there are 72 dots per inch regardless of platform or printer device. LiveCode will
automatically adjust the print out for resolution of the actual device. This makes it
simple to calculate your printed layout.
-- a one-inch margin on each side
set the printMargins is set to 72,72,72,72
444
The printMargins only applies when using print card directly. It does not have any eect on
printing cards into a layout (described below).
The printCardBorders property species whether or not the bevel border around the edge of a
card should appear in the print out.
Now we will implement the printing commands. If this was a real application you would probably
want to put these in a Print command in the File menu. In this instance you may execute the
following in the multi-line message box (open the Message Box then press the second icon to get
the multi-line pane).
-- allow the user to choose printer output options
answer printer
print 9 cards
If we modify the print commands to include an additional line to turn o the printRowsFirst:
445
answer printer
set the printRowsFirst to false
print 9 cards
The resulting print out will look like the gure below.
Use the printGutters property to specify the margin between each card. By default the
printGutters are set to 36,36 or one half inch horizontally and vertically.
In the following example, we print the same label stack but reduce the space between each label
to 1/10th of an inch. To make it easy to see the dierente we also turn on printing of card borders
using the printCardBorders property.
answer printer
set the printGutters to 7,7
set the printCardBorders to true
print 9 cards
The resulting print out will look like the gure below.
revPrintField is implemented as a script library located in the LiveCode IDE. The script library
creates an invisible stack, sets the rectangle of that stack to the current paper size, sets the
formatForPrintingto true, creates a eld, then copies the contents of the eld you specify into
this invisible stack. It then prints the eld one page at a time, scrolling the text after each page.
Advanced users can locate this library script by going to the Back Scripts tab in the Message Box,
turning on the checkbox for Show LiveCode UI Back Scripts, then editing the script of stack
"revPrintLibrary". The revPrintField handler is near the top of the script.
Use the revShowPrintDialog command to control whether the system printer and page setups
dialogs should be shown by revPrintField or revPrintText.
446
Use the revPrintText command to print plain or styled text together with an optional header and
footer.
revPrintText textToPrint [,headerText [,footerText [,fieldTemplate]]]
The textToPrint is anything which evaluates to a string. If you want to printed styled text, pass
HTML instead of plain text. (To convert a eld containing styled text to a HTML use the htmlText
property.)
The headerText and footerText contains the text to use as a header and footer. You may include
an expression that is computed for each page. For more details on using expressions, see the
LiveCode Dictionary entry for revPrintText.
The eldTemplate parameter allows you to specify a eld reference to use. Fonts in the print out
will be inherited from this eld.
Printing a Layout
If you need to print a more complex layout than allowed with the basic print card command or text
printing commands (described above), you can use the print card into rect syntax to create
any sort of layout you choose.
print card from topLeft to rightBottom into pageRect
The topLeft is the top left coordinate of the current card to start printing at.
The rightBottom is the bottom right coordinate of the current card to stop printing at.
The pageRect is therectangular area on the paper to print into.
printMargins only applies when using print card directly. It does not have any eect on printing
cards into a layout. Use the printRectangle to get the printable area when working with layout
printing.
For example, lets say that we want to print the text eld from the middle of the stack in the gure
below. (You can load the stack shown in the picture by going to your LiveCode installation folder
then opening Resources-> Examples-> SQLite Sampler.rev.) We want the output to scale to take
up the entire width of the paper and half the height.
447
local tRect
put 0,0,item 3 of the printRectangle, \
round(item 4 of the printRectangle / 2) into tRect
print this card from the topleft of field "theText" \
to the bottomRight of field "theText" \
into tRect
You can construct a complex layout taking components from multiple stacks by printing a
sequence of rectangles onto the same page. For example, you may have a stack that contains a
standard header and footer, another that contains a logo, and a layout that contains text. Use
the open printing command to start a print job, then print each element into the appropriate
rectangle on the paper. The use then close printing command to send the print job to the
printer. The example in the gure below shows two stacks with printable regions that we want to
combine onto a single sheet of paper.
To print a more complicated layout, create a stack and set its rectangle to the current
printRectangle. Add rectangular areas for each component you will be printing. Then set
Geometry properties (see the section on the Geometry Manager, in the LiveCode Script guide
for more information) on each of these rectangles so they resize correctly when the stack is
scaled. Set up your print routine so that you open this stack invisibly then resize it to the
printRectangle. This will trigger the geometry routines and scale the rectangular areas correctly.
Then run your sequence of print commands to print into each rectangle.
In the gure below, we have set the size of the stack to the printRectangle then added 4
rectangle graphics. We have named each graphic and turned on the Show Name property for
each so you can see the name.
Next, we set Geometry properties for each of the rectangle graphics. The header graphic is set to
scale relative to the right and bottom, with a minimum size limit of 100 pixels (see the gure
below). The body graphic is set to link the top edge to the header graphic, the right and bottom to
the stack (see the gure below). The footer 1 graphic is set to scale the right edge and position
the bottom edge. And footer 2 is set to position both the right and bottom.
To make the printing template stack take on the size of the paper, we can add the following
handler to the stack script:
on preOpenStack
set the width of this stack to (item 3 of the printRectangle - item 1 of
the printRectangle)
set the height of this stack to (item 4 of the printRectangle - item 2 of
the printRectangle)
end preOpenStack
We now have a working print template stack. All that remains is to write the script that prints into
the rectangles:
-- prepare to load this stack off screen
hide stack "print layout"
-- this will trigger the stack to resize, which run the geometry
-- routines, giving us the correct values for each rectangle
go stack "print layout"
-- now we store
put the rect of
put the rect of
put the rect of
put the rect of
450
For more information on how to print multiple pages of a complex layout, see the section on
Printing Multiple Pages, below. For information on printing scrolling text elds into an area within a
layout, see the section on Working with Scrolling Fields when Layout Printing, below.
Examples:
-- prints the current card
print this card
-- prints all cards in the current stack
print all cards
-- prints the next 10 cards, starting with the current card
print 10 cards
-- prints card 3 to 7 of the current stack
print card 3 to 7 print marked cards
-- prints all cards where the mark property is true
print marked cards
451
Important: Set the Lock Location (lockLoc) property of the eld to true before
setting the height in the loop above to avoid the eld drifting each time you alter
the height.
Tip: Turn o the scroll bar properties (hScrollbar and vScrollbar) of the eld before
printing and set the border width to 0 if you want to avoid printing a border or scroll
bar.
You can incorporate scrolling elds into a template print layout stack (see the section Printing a
Complex Layout above) to make it easier to manage printing a complex layout. Create a eld in
your template print stack instead of a graphic, turn o the scroll bar, set the border width to 0, the
lock location to true and then the geometry properties as per the section above. At the start of
each print job, copy the text font and size by using the textFont and textSize properties, then
the contents of the text eld you want to print using the htmlText property.
printing loop.
453
Types of Chunks
The common types of chunks are the character, word, line, or item. An item can be delimited
by any character you specify. In addition, the token chunk is useful when parsing script data.
Here is an example of a chunk expression using the word chunk:
put word 1 to 3 of field "text" into myVariable
You can also use chunk expressions to replace (using the put command) or remove (using the
deletecommand) any portion of a container.
454
script property:
put the script of me into tempScript
put "-- Last changed by Jane" into line 3 of tempScript
set the script of me to tempScript
Other chunks
There are also some chunks which are useful for more advanced text processing. These are:
paragraph
sentence
trueWord
codepoint
455
codeunit
byte
A token is a string of characters delimited by certain punctuation marks. The token chunk is
useful in parsing LiveCode statements, and is generally used only for analyzing scripts.
The sentence and trueWord chunk expressions facilitate the processing of text, taking into
account the dierent character sets and conventions used by various languages. They use the
ICU library, which uses a large database of rules for its boundary analysis, to determine sentence
and word breaks.
The paragraph chunk is currently identical to the existing line chunk, however in the future
paragraph chunks will also be delimited by the Unicode paragraph separator.
The codepoint chunk type allows access to the sequence of Unicode codepoints which make up
the string. The codeunit chunk type allows direct access to the UTF-16 code-units which
notionally make up the internal storage of strings. The codeunit and codepoint chunk are the
same if a string only contains unicode codepoints from the Basic Multilingual Plane.
The byte chunk is an 8-bit unit and should be used when processing binary data.
For more information on the above chunk types, please consult the LiveCode Dictionary.
Specifying a Chunk
The simplest chunk expression species a single chunk of any type. The following statements all
include valid chunk expressions:
get
get
get
put
You can also use the ordinal numbers rst, last, middle, second, third, fourth, fth, sixth,
seventh, eighth, ninth, and tenth to designate single chunks. The special ordinal any species
a random chunk.
put "7" into last char of "1085" -- yields "1087"
456
The desired result is "y", the second item in the third segment. But the statement above causes
an execution error, because it asks for an item of a segment, and segments can't contain items.
You can obtain the desired result by using parentheses to change the order of evaluation:
put item 2 of (segment 3 of "a,b,c i,j,k x,y,z") -- good
In the example above, LiveCode gets the third segment rst, then gets the second item in that
457
segment. By adding parentheses around (segment 3 of "a,b,c i,j,k x,y,z"), you force LiveCode to
evaluate that part of the chunk expression rst. The value of the expression in parentheses is
"x,y,z", and item 2 of "x,y,z" is "y".
As with arithmetic expressions, the parts of a chunk expression that are in parentheses are
evaluated rst. If parentheses are nested, the chunk expression within the innermost set of
parentheses is evaluated rst. The part that is enclosed in parentheses must be a valid chunk
expression, as well as being part of a larger chunk expression:
put
put
put
put
line
line
line
line
2
2
2
2
of
of
of
of
The rst of the above examples doesn't work for much the same reason as the previous example:
segments can't contain lines. The second and third examples don't work because neither "1 to 15
of myValue" nor "of myValue" is a valid chunk expression. However, "segment 1 to 15 of myValue"
is a valid chunk expression, so the last example works.
Nonexistent Chunks
If you request a chunk number that doesn't exist, the chunk expression evaluates to empty. For
example, the expression char 7 of "AB" yields empty.
If you attempt to change a chunk that doesn't exist, what happens depends on what kind of chunk
you specify:
Nonexistent character or segment:
Putting text into a character or segment that doesn't exist appends the text to the end of the
container, without inserting any extra spaces.
Nonexistent item:
Putting text into an item that doesn't exist adds enough itemDelimiter characters to bring the
specied item into existence.
Nonexistent line:
Putting text into a line that doesn't exist adds enough return characters to bring the specied
line number into existence.
Specifying a Range
To specify a portion larger than a single chunk, you specify the beginning and end of the range.
These are all valid chunk expressions:
get char 1 to 3 of "ABCD" -- yields "ABC"
get segment 2 to -1 of myValue -- second segment to last segment
put it into line 7 to 21 of myValue -- replaces
458
The start and end of the range must be specied as the same chunk type, and the beginning of
the range must occur earlier in the value than the end. The following are not valid chunk
expressions:
char 3 to 1 of myValue -- won't work
-- end cannot be greater than start
char -1 to -4 of myValue -- won't work
-- 4th from last comes before last
You can also nest chunk expressions to nd the number of chunks in a single chunk of a larger
chunk type:
the number of chars of item 10 of myVariable
You can also use the is in operator to check whether some text or data is within a specied chunk
of another container.
459
Case Sensitivity
Comparisons in LiveCode are case insensitive by default (except for Regular Expressions, which
have their own syntax for specifying whether or not a match should be case sensitive). To make a
comparison case sensitive, set the caseSensitive property to true. For more details, see the
caseSensitive property in the LiveCode Dictionary.
The is a operator is the logical inverse of the is not a operator. When one is true, the other is
false.
"1/16/98" is a date -- evaluates to true
1 is a boolean -- evaluates to false
45.4 is an integer -- evaluates to false
"red" is a color -- evaluates to true
Tip: To restrict a user to typing numbers in a eld, use the following script
460
on keyDown pKey
if pKey is a number then pass keyDown
end keyDown
The keyDown message will only be passed if the key the user pressed is a number. If you trap a
keyDown message and dont pass it, the key will not be entered into the eld. For more details,
see the keyDown message in the LiveCode Dictionary.
The second example evaluates to false because, although the string "free" is found in the value,
it's a portion of a larger segment, not an entire segment.
Replacing Text
To replace one string with another, use the replace command. (If you want the search string to
contain a regular expression, see the section on the replaceText command below instead.)
replace "A" with "N" in thisVariable -- changes A to N
To delete text using replace, replace a string with the empty constant.
replace return with empty in field 1 -- runs lines together
To preserve styling when replacing one string with another in a eld, use the preserving styles
clause. replace "foo" with "bar" in eld "myStyledField" preserving styles -- replaces instances of
"foo" with "bar" in the given eld, -- "bar" will retain the styling of instances of "foo"
461
For more details, see the replace command and the replace in eld command in the LiveCode
Dictionary.
Chunks Summary
A chunk expression describes the location of a piece of text in a longer string.
Chunk expressions can describe characters, items, tokens, trueWords, segments, lines,
sentences and paragraphs of text.
To count backward from the end of a string, use negative numbers. For example,
segment -2
You can combine chunk expressions to specify one chunk that is contained in another chunk, as in
segment 2 of line 3 of myVariable
For a range of chunks, specify the start and end points of the range, as in line 2 to 5 of myVariable
To check if a chunk is within another, use the is in operator. To check if a chunk is a specied type
of data, use the is a operator. To check if a chunk starts or ends with another uses the begins
with or ends with operators.
To check if a chunk is contained exactly within a string use the is among operator. To get an
index specifying where a chunk can be found in a container, use the \Oset functions described
above. To match only a complete chunk within a string, set the wholeMatches to true before using
the oset functions.
Regular Expressions
Regular expressions allow you to check if a pattern is contained within a string. Use regular
expressions when one of the search or comparison chunk expressions does not do what you need
(see the section on Comparing and Searching above).
LiveCode supports searching for a pattern, replacing a pattern, or ltering the lines in a container
462
depending on whether or not each line contains the pattern. Regular expressions use PERL
compatible or "PCRE" syntax. Figure 52, below, shows the supported syntax. For more details on
the supported syntax, see the PCRE manual
463
Regex
[chars]
[^chars]
Rule
Example
A[BCD]E
matches "ACE",
but not "AFE" or
"AB"
[^ABC]D
matches "FD" or
"ZD", but not
"AD" or "CD"
A[B-D] matches
"AB" or "AC",
but not "AG"
[charchar]
A.C matches
"ABC" or "AGC",
but not "AC" or
"ABDC"
^A matches
"ABC" but not
"CAB"
B$ matches
"CAB" but not
"BBC"
[A-Z0-9]
matches any
alphanumeric
character
ZA*B matches
"ZB" or "ZAB" or
"ZAAB", but not
"ZXA" or "AB"
[A-D]*G
matches "AG"
or "G" or "CAG",
but not "AB"
ZA+B matches
"ZAB" or
"ZAAB", but not
"ZB"
[A-D]+G
matches "AG"
or "CAG", but
not "G" or "AB"
464
Regex
**\
Rule
Example
ZA?B matches
"ZB" or "ZAB",
but not "ZAAB"
[A-D]?G
matches "AG"
or "CAGZ", but
not "G" or "AB"
matches either
the pattern
before or the
pattern after
the \
**
any other
matches itself
character
B
matches
"A" or
. A\
"B"
[ABC]\
[XYZ]
matches
"AY" or
"CX", but
not "AA"
or "ZB".
A\.C matches
"A.C", but not
"A\.C" or "ABC"\\
matches "\"
ABC matches
"ABC"
Fundamentally computers use numbers to store information, converting those numbers to text to
be displayed on the screen. A text encoding describes which number converts to a given
character. There are many dierent encoding systems for dierent languages. Below is a table
containing examples of some common encodings.
Encoding
ASCII
ISO8859
Windows1252
MacRoman
UTF-16
UTF-8
Representation
Description
Single byte
English
Single byte
Single byte
English
Single byte
English
Double byte
Any
Multi-byte - Any
Scripts can be grouped together into four approximate classes. The "small" script class contains a
small alphabet with a small set of glyphs to represent each single character. The "large" script
class contains a large alphabet and with a larger set of glyphs. The "contextual" script class
contains characters that can change appearance depending on their context. And nally the
"complex" script class contains characters that are a complex function of the context of the
character there isnt a 1 to 1 mapping between code point and glyph.
Roman
Small
script
Chinese
Large
script
Greek
Arabic
Devanagari
Complex
script
Introduction to Unicode
Traditionally, computer systems have stored text as 8-bit bytes, with each byte representing a
single character (for example, the letter 'A' might be stored as 65). This has the advantage of
being very simple and space ecient whilst providing enough (256) dierent values to represent
all the symbols that might be provided on a typewriter. The aw in this scheme becomes obvious
fairly quickly: there are far more than 256 dierent characters in use in all the writing systems of
the world, especially when East Asian ideographic languages are considered. But, in the preinternet days, this was not a big problem.
LiveCode, as a product rst created before the rise of the internet, also adopted the 8-bit
character sets of the platforms it ran on (which also meant that each platform used a dierent
character set: MacRoman on Apple devices, CP1252 on Windows and ISO-8859-1 on Linux and
Solaris). LiveCode terms these character encodings "native" encodings.
In order to overcome the limitations of 8-bit character sets, the Unicode Consortium was formed.
This group aims to assign a unique numerical value ("codepoint") to each symbol used in every
written language in use (and in a number that are no longer used!). Unfortunately, this means
that a single byte cannot represent any possible character.
The solution to this is to use multiple bytes to encode Unicode characters and there are a number
of schemes for doing so. Some of these schemes can be quite complex, requiring a varying
number of bytes for each character, depending on its codepoint.
467
LiveCode previously added support for the UTF-16 encoding for text stored in elds but this could
be cumbersome to manipulate as the variable-length aspects of it were not handled transparently
and it could only be used in limited contexts. Unicode could not be used in control names, directly
in scripts or in many other places where it might be useful.
From LiveCode 7.0, the LiveCode engine has been able to handle Unicode text transparently
throughout. The standard text manipulation operations work on Unicode text without any
additional eort on your part; Unicode text can now be used to name controls, stacks and other
objects; menus containing Unicode selections no longer require tags to be usable - anywhere text
is used, Unicode should work.
Using Arrays
For an introduction to arrays, see the section on Array Variables in the chapter Coding in
LiveCode.
468
Global,4
Line,3
Lines,1
Multiple,2
Properties,2
Single,2
Variables,2
and,3
469
A=1
0.333333
B=2
0.666667
C=3
D=4
1.333333
E=5
1.666667
Styled Text
LiveCode supports encoding and decoding styled text as HTML and RTF. This feature is useful when
you want to adjust text styles programmatically, or import or export text with style information.
Important: At present HTML conversion support only extends to the styles that the
LiveCode eld object is capable of rendering.
To convert the contents of a eld to HTML compatible tags, use the HTMLText property. This
property is documented in detail in the LiveCode Dictionary. You can also set this property to
display styled text in a eld.
Tip: You can get and set the HTMLText property of a chunk within a eld, allowing you
to view or change text attributes on a section of the text.
For example, to set the text style of line 2 of a eld to bold:
on mouseUp
put the
replace
replace
set the
end mouseUp
While this is not as simple as directly applying the style to the text using:
set the textStyle of line 2 of field "sample" to "bold"
It does allow you to search and replace text styles or perform multiple complex changes to the
text based on pattern matching. Performing a series of changes on the HTMLText in a variable
then setting the text of a eld once can be quicker than updating the style repeatedly directly on
the eld.
Use the HTML keyword with the Drag and Drop features and the Clipboard features to perform
conversion of data to and from HTML when exchanging data with other applications. For more
information see the section on Drag and Drop in the Programming a User Interface guide.
Use the RTFText property and RTF keyword to work with the RTF format.
Use the unicodeText property and Unicode keyword to work with Unicode. For more information
see the section on International Text Support, above.
URLs
To encode and decode URLs, use the URLEncode and URLDecode functions. The URLEncode
function will make text safe to use with a URL for example it will replace space with +. These
471
functions are particularly useful if you are posting data to a web form using the POST command,
using the launch URL command or sending email using the revMail function. For more
information see the LiveCode Dictionary.
Text:
Binary Data Base64 (for MIME Email Attachments and Http Transfers)
To encode and decode data in Base64 (e.g. to create an email attachment), use the
base64Encode and base64Decode functions. These functions are useful anywhere you want
to convert binary data to text data and back. For more information see the LiveCode Dictionary.
To convert Unicode characters, set the useUnicode local property to true. For more information
see the section on International Text Support, above.
Data Compression
To compress and decompress data using GZIP, use the compress and decompress functions.
The following routine asks the user to select a le, then creates a GZip compressed version with a
".gz" extension in the same directory as the original.
on mouseUp
answer file "Select a file:"
if it is empty then exit mouseUp
put it & ".gz" into tFileCompressed
put compress(URL ("binfile:" & it)) into URL ("binfile:" &
tFileCompressed)
end mouseUp
Encryption
To encrypt or decrypt data use the encrypt and decrypt commands. These commands are
documented in the LiveCode Dictionary.
472
Generating a Checksum
Use the MD5Digest to generate a digest of some data. Use this function later to determine if
the data was changed or to check that transmission of information was complete.
Tip: In this example we save the MD5Digest of a eld when the user opens it for
editing. In the eld script place:
on openField
set the cDigest of me to md5Digest(the htmlText of me)
end openField
If the eld is modied (including if a text style is changed anywhere) then a subsequent check of
the MD5Digest will return a dierent result. In the following example we check this digest to
determine whether or not to bring up a dialog alerting the user to save changes:
on closeStackRequest
local tDigest
put md5Digest(the htmlText of field "sample text") into tDigest
if the cDigest of field "sample text" is not tDigest then
answer "Save changes before closing?" with "No" or "Yes"
if it is "Yes" then
save this stack
end if
end if
end closeStackRequest
XML
Extensible Markup Language, or XML, is a general-purpose language for exchanging structured
data between dierent applications and across the Internet. It consists of text documents
organized into a tree structure. It can generally be understood by both human and machine.
LiveCode includes comprehensive support for XML through its built-in XML library. Additionally,
standards exist to support exchange of XML over a network connection (or "web services") most
notably through the XML-RPC and SOAP protocols. LiveCode includes a library for using XML-RPC
and there are examples of using LiveCode to build SOAP applications available.
473
Root
node
Root
element,
document
element
Comment
Node
Element, tag
Attributes
Empty
node
Empty
element
Entity
reference
includeChildCount allows you to include the number of each child in square brackets next to the
name.
We can use this function on our sample XML as follows:
476
card[1]
card[2]
Retrieving the Contents of the Children in a Node
To retrieve a list of children of a node including their contents, use revXMLChildContents.
revXMLChildContents(treeID,startNode,tagDelim,nodeDelim,
includeChildCount,depth)
See above for an explanation of treeID, startNode and tagDelim .
The nodeDelim indicates the delimiter that separates the contents of the node from its name.
The depth species the number of generations of children to include. If you use 1 as the depth
then all children are return.
Using this function on our example XML le as follows:
put revXMLChildContents(1, "/stackFile/stack", space, return, true, -1) into
tContents
This results in tContents containing:
card[1]
eld[1]
text[1] Hello World!
htmlText[1] \Hello World\
card[2]
Retrieving the Number of Children in a Node
To retrieve the number of children of a node revXMLNumberOfChildren.
revXMLNumberOfChildren(treeID,startNode,childName,depth)
See above for an explanation of treeID, startNode, childName and depth.
Using this function on our example XML le as follows:
477
479
This section discusses how to edit XML trees. Before reading this section you should read the
section above on loading, displaying and unloading XML.
Adding a new Child Node
To add a new node use the revAddXMLNode command.
revAddXMLNode treeID, parentNode, nodeName, nodeContents, [location]
See above for an explanation of treeID.
The parentNode is the name of the node you want to add the child to.
The nodeName is the name of the new node to create.
483
To create another node at the same level as another node, use the revInsertXMLNode
command instead.
Appending XML to a tree
To add a new node use the revAppendXML command.
revAppendXML treeID, parentNode, newXML
See above for an explanation of treeID and parentNode.
The newXML is XML you want to append to the tree.
Moving, Copying or Deleting a Node
To move a node use the revMoveXMLNode command.
revMoveXMLNode treeID, sourceNode, destinationNode [, location] [,
relationship]
See above for an explanation of treeID.
484
Adding a DTD
To add a DTD to the tree, use the revXMLAddDTD command.
revXMLAddDTD treeID,DTDText
485
Sorting
Sorting data is a common and fundamental operation. Sorting allows you to display data in a
user-friendly fashion or code a number of algorithms. LiveCode's intuitive sort features give you
the power and exibility to perform any kind of sorting you may require.
486
Result:
F54.mov
tMinimumInteger is 3
M27.mov
tMaximumInteger is 54
M7.mov
F3.mov
Figure 57 Results of sort command using sort key
Result:
Oliver,1.54
Elanor,5.67
Elanor,5.67
Elanor,6.3
Marcus,8.99
Marcus,8.99
487
Original list:
Result:
Elanor,6.34
Oliver,1.54
Oliver,8.99
Oliver,8.99
Tim,3.44
Tim,3.44
These lines now sort the required way as if the rst eld (the name) ties, the order is determined
by the second eld due to the use of padding characters making all the elds the same size.
Sorting Cards
To sort cards, use the sort command.
sort [marked] cards [of stack] [direction] [sortType] by sortKey
The stack is a reference to any open stack. If you don't specify a stack, the cards of the current
stack are sorted.
The direction is either ascending or descending. If you don't specify a direction, the sort is
ascending.
The sortType is one of text, international, numeric, or dateTime. If you don't specify a sortType, the
sort is by text.
The sortKey is an expression that evaluates to a value for each card in the stack. Any object
references within the sortKey are treated as pertaining to each card being evaluated, so for
example, a reference to a eld is evaluated according to that eld's contents on each card.
Typically the sort command is used with background elds that have their sharedText property set
to false so that they contain a dierent value on each card.
For example to sort cards by the contents of the last name eld on each:
sort cards by field "Last Name"
488
Tip: To sort cards by a custom expression that performs a calculation, you can
create a custom function:
sort cards by myFunction() -- uses function below
function myFunction
put the number of buttons of this card into tValue
-- perform any calculation on tValue here
return tValue
-- sort will use this value
end myFunction
489
You can see that to write a le path, you start by naming the disk the le is on, then add each
enclosing folder in order until you arrive at the le.
To see the path to a le, enter the following in the message box:
answer file "Choose a file:"; put it
Folder paths
You construct the path of a folder the same way as the path to a le. A folder path always ends
with a slash character (/). This nal slash indicates that the path is to a folder rather than a le.
For example, this pathname describes a folder called "Project" inside a folder called "Forbin" on a
disk named "Doomsday":
/Doomsday/Forbin/Project/
If "Project" is a le, its pathname looks like this, without the nal slash:
/Doomsday/Forbin/Project
492
Similarly, when dealing with a bundle, use the delete folder command instead of delete le,
and the revCopyFolder command instead of revCopyFile.
Referring to les inside a bundle
When referring to a le that's inside a bundle, you can treat the bundle just as if it were a folder.
For example, if you have placed a le called "My Support.txt" inside your application's bundle, the
absolute path to the le might look like this:
/Volumes/Disk/Applications/MyApp/My Support.txt
493
Note: On Mac OS X, and Linux systems, absolute le paths always start with a slash
character. On Windows systems, absolute le paths always start with a drive letter
followed by a colon (:).
Relative le paths
Now suppose you want to tell someone how to get to the "Westwind" le, starting from the folder
containing the application.
Since the application is in "Application Folder", we don't need to include the steps to get to
"Application Folder". Instead, we can describe the location of the "Westwind" le with this relative
pathname:
Stories/Westwind
This relative pathname starts at "Application Folder"--the folder that holds the application--and
describes how to get to the "Westwind" le from there: you open the folder "Stories", then nd
"Westwind" inside it.
A relative le path starts at a particular folder, rather than at the top of the le system like an
absolute le path. The relative le path builds a le path from the starting folder to the le or
folder whose location is being specied.
Finding the current folder
By default, the current folder is set to the folder containing the application (either the LiveCode
development environment or your application, depending on whether your application is a
standalone). So in the example above, the current folder is "Application Folder", because that's
where the running application is located.
Note: To change the current folder, set the defaultFolder property.
Going up to the parent folder
The relative path ".." indicates the current folder's parent folder. If the current folder is "Stories",
the relative path
..
494
To go up more than one level, use more than one "../". To go up two levels, use "../../"; to go up
three levels, use "../../../", and so forth.
For example, suppose the current folder is "Stories", and its absolute path looks like this:
/Hard Disk/Application Folder/Stories/
To get to "My Application" in "Application Folder", you go up one level to "Application Folder", then
down one level to "My Application". The relative path looks like this:
../My Application
To get to "Top Folder" on "Hard Disk", you go up two levels--to "Application Folder", then to "Hard
Disk"--and then down one level to "Top Folder". The relative path looks like this:
../../Top Folder/
495
Special Folders
Modern operating systems each have a set of special-purpose folders designated for a variety of
purposes. If you are writing an application it is recommended that you make use of these folders
where appropriate so that you provide the best possible user experience. For example, the
contents of the desktop reside in a special folder; there is a folder set aside for fonts; there is a
folder for application preferences; and so on.
These special folders don't always have the same name and location, so you can't rely on a
stored le path to locate them. For example, if your application is installed onto an OS localized
into a dierent language, the names of the le path will be dierent, on some Windows special
folders are named or placed dierently depending on what version of Windows is running, etc.
To nd out the name and location of a special folder, regardless of any of these factors, you use
the specialFolderPath function. The function supports a number of forms for each operating
system, describing the special folders for each one. Some of the forms are the same crossplatform. The following example will get the location of the Desktop folder on Windows, Mac OS X
or Linux:
put specialFolderPath("Desktop") into myPath
496
If your application does not create les that you want the application to own, you don't need to
make any modications to the registry or specify any extensions.
Applications that own their own les
If your application creates les with its own custom extension, when you install the application, you
should make changes to the Windows registry to identify the extension as belonging to your
application.
Popular Windows installer programs will make these registry changes automatically for you. You
can also perform these registry changes using the setRegistry function.
Installing custom icons
Each Windows le can display its own icon. You can have separate icons for your application and
for les it owns. Icon les must be stored in .ico format.
Custom application icons
If you want to include a custom icon for your application, use the "Application Icon" option on the
Windows screen of the Standalone Application Settings window to specify the icon le. When you
build the application, the icon will be included in the application. For more information, see the
chapter on Deploying Your Application.
Custom le icons
To include a custom icon for your documents, use the "Document Icon" option on the Windows
screen of the Standalone Application Settings window to specify the icon le. When you build the
application, the icon will be included in the application.
Important: For the correct icon to appear on les your application creates, the le's
extension must be registered in the Windows registry.
File extensions
You can add an extension to the name of any Windows le. The extension may contain letters A-Z,
digits 0-9, ' (single quote), !, @, #, $, %, ^, &, (, ), -, _, {, }, `, or ~.
The Windows registry associates applications with the extension for the les they own.
<string>LiveCode Stack</string>
498
When your application creates les, set the leType property to the desired creator signature and
le type for the new le. (For stack les created with the save command, use the stackFileType
property instead.) When creating les, the application uses the current value of the leType or
stackFileType property to determine what creator and le type the new le should have.
It's important to understand that a le's creator signature determines which application is
launched automatically when you double-click the le, but doesn't prevent other applications from
being able to open that le. For example, if your application creates les of type "TEXT", any text
editor can open the les. If your application creates stack les, and uses the le type "RSTK", then
LiveCode will be able to open the stack les, as well as your application.
File extensions
You can add an extension to the name of any OS X le. When the user double-clicks a le with no
creator signature, the operating system uses the extension to determine which application to use
to open the le.
An application bundle's name should end with the extension ".app".
Note: Apple's recommendations for determining le type and creator on OS X
systems are currently in ux. The recommended method for the present is to set a
le type and creator signature, and also attach an extension to the end of each le's
name when it is created. Valid extensions on OS X systems are up to twelve
characters in length, and may include the letters a-z, the digits 0-9, $, %, _, or ~. For
up-to-date information on Apple's recommendations for OS X, see Apple's developer
documentation.
Repeat steps 2-3 for each dierent le type your application can create.
When your application creates les, set the leType property to the desired creator signature and
le type for the new le. For stack les created with the save command, use the stackFileType
property instead. When creating les, the application uses the current value of the leType or
stackFileType property to determine what creator and le type the new le should have.
Installing custom icons
Each Mac OS file may display any of six dierent icons, depending on context and on the
number of colors the screen can display: large (32x32 pixel) icons and small (16x16 pixel) icons,
each in black-and-white, 16 colors, and 256 colors.
Mac OS provides default icons that are used for applications and documents that don't have their
own. If you want your application or the documents it owns to display a custom icon, you must
create the icons and then attach them to the application.
Custom application icons
If you want to include a custom icon for your application, use ResEdit or a similar tool to create a
set of icon resources. There are six standard icon resource types: ICN# (black-and-white), icl4
(four-bit color), icl8 (8-bit color), ics# (black-and-white small), ics4 (4-bit small), and ics8 (8-bit
small). Each of these application icons should have the resource ID 128.
Save the icons in a single le, and use the "Include resources from le" option on the Mac OS X
screen of the Standalone Application Settings window to specify the le. When you build the
application, the icons will be included in the application's le.
An Overview of URLs
In the LiveCode language, a URL is a container for a file or other document, such as the output
of a CGI on a web server. The data in a URL may be on the same system the application is running
500
URL Schemes
A URL scheme is a type of URL. LiveCode supports ve URL schemes with the URL keyword: http,
ftp, le, binle, and (for backwards compatibility on Mac OS X) resle.
The http and ftp schemes designate documents or directories that are located on another
system that's accessible via the Internet. The le, binle, and resle schemes designate local
les.
When you use an http URL in an expression, LiveCode downloads the URL from the server and
substitutes the downloaded data for the URL.
When you put something into an http URL, LiveCode uploads the data to the web server:
Note: Because most web servers do not allow http uploads, putting something into
an http URL usually will not be successful. Check with the server's administrator to
nd out whether you can use the http protocol to upload les.
For more details about http URLs, see the entry for the http keyword in the LiveCode
Dictionary.
When you use an ftp URL in an expression, LiveCode downloads the URL from the server and
501
substitutes the downloaded data for the URL. When you put something into an ftp URL, LiveCode
uploads the data to the ftp server:
put image 10 into URL \
"ftp://user:[email protected]/picture.jpg"
FTP servers require a user name and password, which you can specify in the URL. If you don't
specify a user name and password, LiveCode adds the "anonymous" user name and a dummy
password automatically, in accordance with the convention for public FTP servers.
Note: Uploading to an FTP server usually requires a registered user name and
password.
For more details about ftp URLs, see the entry for the ftp keyword in the LiveCode Dictionary.
Directories on an FTP server
A URL that ends with a slash (/) designates a directory (rather than a le). An ftp URL to a
directory evaluates to a listing of the directory's contents.
The le scheme
A le URL designates a le on your system:
put field "Stuff" into URL "file:/Disk/Folder/testfile"
When you use a file URL in an expression, LiveCode gets the contents of the file you
designate and substitutes it for the URL. The following example puts the contents of a file into a
variable:
put URL "file:myfile.txt" into myVariable
When you put data into a file URL, LiveCode puts the data into the le:
Note: As with local variables, if the le doesn't exist, putting data into it creates the
le.
To create a URL from a le path that LiveCode provides, use the & operator:
answer file "Please choose a file to get:"
get URL ("file:" & it)
502
When you use a binle URL in an expression, LiveCode gets the contents of the le you
designate and substitutes it for the URL. The following example puts the contents of a le into a
variable:
put URL "binfile:picture.png" into pictVar
When you put data into a binle URL, LiveCode puts the data into the le:
put pictVar into URL "binfile:/Volumes/Backup/pict.png"
put image 1 into "binfile:/image.png"
As with local variables, if the le doesn't exist, putting data into it creates the le.
The binle scheme works like the le scheme, except that LiveCode does not attempt to convert
end-of-line markers. This is because return and linefeed characters can be present in a binary le
but not be intended to mark the end of the line. Changing these characters can corrupt a binary
le, so the binle scheme leaves them alone.
503
The resource fork contains dened resources such as icons, menu denitions, dialog boxes, fonts,
and so forth. A resle URL designates the resource fork of a Mac OS X le:
put myBinaryData into URL "resfile:/Disk/Resources"
When you use a resle URL in an expression, LiveCode gets the resource fork of the le you
designate and substitutes it for the URL.
When you put data into a resle URL, LiveCode puts the data into the le's resource fork.
Note: A resle URL species the entire resource fork, not just one resource. To work
with individual resources, use the getResource, setResource, deleteResource
and copyResource functions.
The most common use for this URL scheme is to copy an entire resource fork from one le to
another. To modify the data from a resle URL, you need to understand the details of Apple's
resource fork format.
Creating a resource fork
Unlike the le and binle URL schemes, the resle keyword cannot be used to create a le. If
the le doesn't yet exist, you cannot use the resle keyword to create it. To create a new
resource le, rst use a le URL to create the le with an empty data fork, then write the needed
data to its resource fork:
put empty into URL "file:myFile" -- creates an empty file
put myStoredResources into URL "resfile:myFile"
504
The URL keyword tells LiveCode that you are using the URL as a container.
Some properties (such as the lename of a player or image) let you specify a URL as the
property's value. Be careful not to include the URL keyword when specifying such properties,
because using the URLkeyword indicates that you're treating the URL as a container. If you use
the URL keyword when specifying such a property, the property is set to the contents of the URL,
not the URL itself, and this is usually not what's wanted.
Using the content of a URL
As with other containers, you use the content of a URL by using a reference to the URL in an
expression. LiveCode substitutes the URL's content for the reference.
If the URL scheme refers to a local le (le, binle, or resle URLs), LiveCode reads the content
of the le and substitutes it for the URL reference in the expression:
answer URL "file:../My File"
-- displays the file's content
put URL "binfile:flowers.jpg" into myVariable
put URL "resfile:Icons" into URL "resfile:New Icons"
If the URL scheme refers to a document on another system (http or ftp URLs), LiveCode
downloads the URL automatically, substituting the downloaded data for the URL reference:
answer URL "http://www.example.net/files/greeting.txt"
Note: If the server sends back an error message--for example, if the le you specify
in an http URL doesn't exist--then the error message replaces the URL reference in
the expression.
Important: When you use an ftp or http URL in an expression, the handler pauses
until LiveCode is nished downloading the URL. If you do not want to block LiveCode
when accessing these resources, use the load URL form of the command (see
below).
Putting data into a URL
As with other containers, you can put data into a URL. The result of doing so depends on whether
the URL scheme species a le on your system (le, binle, or resle) or on another system
(http or ftp).
If the URL scheme refers to a local le (le, binle, or resle URLs), LiveCode puts the data into
the specied le:
put field "My Text" into URL "file:storedtext.txt"
put image 1 into URL "binfile:picture.png"
If the URL scheme refers to a document on the Internet (http or ftp URLs), LiveCode uploads the
data to the URL:
505
Because most web servers do not allow HTTP uploads, this usually will not be successful with the
http scheme.
Chunk expressions and URLs
Like other containers, URLs can be used with chunk expressions to specify a portion of what's in a
URL--a line, an item, a word, or a character. In this way, any chunk of a URL is like a container
itself. For more information about Chunk Expressions, see the guide on Processing Text and Data.
You can use any chunk of a URL in an expression, in the same way you use a whole URL:
get line 2 of URL "http://www.example.net/index.html"
put word 8 of URL "file:/Disk/Folder/myfile" into field 4
if char 1 of URL "ftp://ftp.example.org/test.jpg" is "0" then ...
You can also specify ranges, and even one chunk inside another:
put char 1 to 30 of URL "binfile:/marks.dat" into myVar
answer line 1 to 3 of URL "http://www.example.com/file"
You can also put a value into a chunk of an ftp or http URL. Because it's impossible to upload
part of a le, LiveCode downloads the le, makes the change, then uploads the le back to the
server.
Tip: This method is inecient if you need to make several changes. In this case, it's
faster to rst put the URL in a variable, replace the chunk you want to change, then
put the variable into the URL:
put
put
put
put
This ensures that the le only needs to be downloaded once and re-uploaded once, no matter
506
Deleting URLs
You remove a URL with the delete URL command.
To delete a local le, you use a le or binle URL:
delete URL "file:C:/My Programs/test.exe"
delete URL"binfile:../mytext.txt"
It doesn't matter whether the le contains binary data or text; for deletion, these URL schemes
are equivalent.
Tip: You can also use the delete le command to remove a le. To delete the
resource fork of a le, you use a resle URL. The following example removes the
resource fork along with all resources, but leaves the le in place:
delete URL "resfile:/Volumes/Backup/proj.rev"
Tip: To delete a single resource instead of the entire resource fork, use the
deleteResource function.
To remove a le or directory from an FTP server, you use an ftp URL:
delete URL "ftp://root:[email protected]/deleteme.txt"
delete URL "ftp://me:[email protected]/trash/"
As with creating les, you can use an http URL to delete a le, but most HTTP servers are not
507
If you use the put command with a le or binle URL as the source, the le is uploaded:
put URL "file:newfile.txt" into URL
"ftp://user:[email protected]/newfile.txt"
When you upload data in this way, the operation is blocking: that is, the handler pauses until the
upload is nished. (See below for details on how to create a le transfer that is not blocking.) If
there is an error, the error is placed in the result function:
put field "Data" into URL myFTPDestination
if the result is not empty then beep 2
Important: Uploading or downloading a URL does not prevent other messages from
being sent during the le transfer: the current handler is blocked, but other handlers
are not. For example, the user might click a button that uploads or downloads
another URL while the rst URL is still being uploaded. In this case, the second le
transfer is not performed and the result is set to "Error Previous request has not
completed." To avoid this problem, you can set a ag while a URL is being uploaded,
and check that ag when trying to upload or download URLs to make sure that there
is not already a le transfer in progress.
Downloading using a URL
Referring to an ftp or http URL in an expression downloads the document.
put URL "ftp://ftp.example.net/myfile.jpg" into image 1
get URL "http://www.example.com/newstuff/newfile.html"
508
If you use the put command with a le or binle URL as the destination, the document is
downloaded to the le:
put URL "ftp://ftp.example.net/myfile.jpg" into URL \
"binfile:/Disk/Folder/myfile.jpg"
Non-blocking transfers
When you transfer a le using URL containers, the le transfer stops the current handler until the
transfer is done. This kind of operation is called a blocking operation, since it blocks the current
handler as long as it's going on.
If you want to transfer data using http without blocking, use the load command. if you want to
transfer large les using ftp, use the libURLftpUpload, libURLftpUploadFile, or
libURLDownloadToFile commands.
Non-blocking le transfers have several advantages:
Since contacting a server may take some time due to network lag, the pause involved in a
blocking operation may be long enough to be noticeable to the user.
If a blocking operation involving a URL is going on, no other blocking operation can start until the
previous one is nished. If a non-blocking le transfer is going on, however, you can start other
non-blocking le transfers. This means that if you use the library commands, the user can begin
multiple le transfers without errors.
During a non-blocking le transfer, you can check and display the status of the transfer. This lets
you display the transfer's progress and allow the user to cancel the le transfer.
Using the load command
The load command downloads the specied document in the background and places it in a
cache. Once a document has been cached, it can be accessed nearly instantaneously when you
use its URL, because LiveCode uses the cached copy in memory instead of downloading the URL
again.
To use a le that has been downloaded by the load command, refer to it using the URL keyword as
usual. When you request the original URL, LiveCode uses the cached le automatically.
For best performance, use the load command at a time when response speed isn't critical (such
as when your application is starting up), and only use it for documents that must be displayed
quickly, such as images from the web that will be shown when you go to the next card.
Checking status when using the load command
While a le is being transferred using the load commands, you can check the status of the
transfer using the URLStatus function. This function returns the current status of a URL that's
being downloaded or uploaded:
509
local tUrl
put "ftp://ftp.example.com/myfile.txt" into tUrl
put the URLStatus of tUrl into field "Current Status"
510
libURLftpUpload myVar,"ftp://me:[email protected]/file.txt"
put myVar into URL "ftp://me:[email protected]/file.txt"
libURLftpUploadFile "test.data","ftp://ftp.example.org/test"
put URL "binfile:test.data" into URL "ftp://ftp.example.org/test
libURLDownloadToFile "ftp://example.org/new\_beta","/HD/File"
put URL "ftp://example.org/new\_beta" into URL "binfile:/HD/File"
When you click the button, the mouseUp handler is executed. The libURLDownloadToFile
command begins the le transfer, and its last parameter species that a showStatus message will
be sent to the button whenever the URLStatus changes.
As the URLStatus changes periodically throughout the download process, the button's
showStatus handler is executed repeatedly. Each time a showStatus message is sent, the handler
places the new status in a eld. The user can check this eld at any time during the le transfer to
see whether the download has started, how much of the le has been transferred, and whether
there has been an error.
If a le transfer was started using the libURLftpUpload, libURLftpUploadFile, or
libURLDownloadToFile command, you can cancel the transfer using the unload command.
Uploading, downloading, and memory
When you use a URL as a container, LiveCode places the entire URL in memory. For example, if
you download a le from an FTP server using the put command, LiveCode downloads the whole
contents of the le into memory before putting it into the destination container. If the le is too
large to t into available memory, a le transfer using this method will fail (and may cause other
511
unexpected results).
The library commands libURLftpUpload, libURLftpUploadFile, and libURLDownloadToFile,
however, do not require the entire le to be loaded into memory. Instead, they transfer the le
one piece at a time. If a le is (or might be) too large to comfortably t into available memory, you
should always use the library commands to transfer it.
Note: For such a statement to work, the stack le must have been uploaded as
binary data, uncompressed, and not use encodings such as BinHex.
Tip: If you need to download a large stack, use the load command to complete the
download before using the go command to display the stack. This allows you to
display a progress bar during the download.
LiveCode automatically downloads the stack le. The main stack of the stack le then opens in a
window, just as though you had used the go command to open a local stack le.
You can go directly to a specic card in the stack:
local tStackUrl
put "http://www.example.org/myapp/main.rev" into tStackUrl
go card "My Card" of stack URL tStackUrl
The statement automatically downloads the le "comp.gz", uncompresses it, and opens the main
stack of the le.
Saving stacks from a server
When a stack is downloaded using the go command, it's loaded into memory, but not saved on a
local disk. Such a stack behaves like a new (unsaved) stack until you use the save command to
save it as a stack le.
Note: Saving a stack that has been downloaded with the go command does not reupload it to its server. To upload a changed stack, you must save it to a local le, then
use one of the methods described in this topic to upload the le to the server.
You can add headers, or replace the Host or User-Agent header, by setting the HTTPHeaders
property before using the URL:
set the HTTPHeaders to "User-Agent: MyApp" & return \
& "Connection: close"
put URL "http://www.example.org/myfile" into myVariable
binle schemes, putting something into the URL creates the le:
put dataToUpload into URL
"ftp://jane:[email protected]/newfile.dat"
Tip: You can create an FTP directory by uploading a le to the new (nonexistent)
directory. The directory is automatically created. You can then delete the le, if you
wish, leaving a new, empty directory on the server:
-- Create an empty file in the nonexistent directory:
put empty into URL "ftp://jane:[email protected]/newdir/dummy"
-- Delete unwanted empty file to leave new directory:
delete URL "ftp://jane:[email protected]/newdir/dummy"
Troubleshooting
The following commands and functions can be useful when debugging an application that uses the
Internet library.
resetAll : Closes all open sockets and halts all pending Internet operations.
Caution: The resetAll command closes all open sockets, which includes any other
sockets opened by your application and any sockets in use for other uploads and
downloads. Because of this, you should avoid routine use of the resetAll command.
Consider using it only during development, to clear up connection problems during
debugging.
libURLErrorData : Returns any error that was caused during a download that was started
with the load command.
libURLVersion : Returns the version of the Internet library.
libURLSetLogField : Species a eld for logging information about uploads and downloads
on screen.
libURLLastRHHeaders : Returns the headers sent by the remote host in the most recent
HTTP transaction.
libURLLastHTTPHeaders : Returns the value of the httpHeadersproperty used for the
515
To set properties on the browser, use the revBrowserSet command. The following commands
makes the border visible then sets the rectangle to be the same as an image named
"browserimage":
revBrowserSet sBrowserId, "showborder","true"
revBrowserSet sBrowserId, "rect",rect of img "browserimage"
To close a browser when you nished with it, use the revBrowserClose command. This
command takes the windowID for the stack containing the browser:
revBrowserClose sBrowserId
RevBrowser supports a number of settings and messages. You can intercept a message whenever
the user navigates to a link, prevent navigation, intercept clicks in the browser, requests to
download les or to open a new window.
For a complete list of commands that operate on RevBrowser, open the LiveCode Dictionary and
type "browser" into the lter box.
516
Tip: If you are using the encryption library on a Windows system, it is possible that
another application will have installed DLLs that use the same name as the ones
included with LiveCode to support encryption. You can force your application to load
LiveCode's SSL DLLs by setting the $PATH environment variable before loading the
library.
put
put
get
put
If there is an error, it will be placed into the result . If you need to include a user name and
password you can do so in the following form:
https://user:[email protected]/
connection to the IP address specied in the tIPAddress variable and the port specied in the
tPort variable. It species that LiveCode should send the message "chatConnected " when a
connection has been established.
open socket (tIPAddress & ":" & tPort) with message "chatConnected"
To open a secure socket, use the open secure socket variant of the command. To open a UDP
datagram socket, use the open datagram socket variant of the command. For more
information on these variants, see the LiveCode Dictionary.
Looking up a host name or IP address
You may look up an IP address from a host name with the hostNameToAddress function. For
example, to get the IP address for the livecode.com server:
put hostNameToAddress("www.livecode.com") into tIPAddress
To get the host name of the local machine, use the hostName function. To look up the name
from an IP address, use the hostAddressToName function.
Reading and writing data
Once LiveCode opens a connection, it will send a chatConnected message. To receive data, use
the read from socket command. The following message reads data from the socket and sends
a chatReceived message when reading is completed.
on chatConnected pSocket
read from socket pSocket with message chatReceived
end chatConnected
Once reading from the socket is completed the chatReceived message can be used to process
or display the data. It can then specify that it should continue to read from the socket until more
data is received, sending another chatReceived message when done.
518
Disconnecting
To disconnect, use the close socket command. You should store a variable with details of any
open sockets and close them when you have nished using them or when your stack closes.
close socket (tIDAddress & ":" & tPort)
Handling errors
If there is an error, LiveCode will send a socketError message with the address of the socket and
the error message. If a socket is closed a socketClosed message will be sent. If a socket times
out waiting for data a socketTimeout message will be sent. To get a list of sockets that are
open, use the openSockets function. You can set the default timeout interval by setting the
socketTimeOutInterval property. For more details on all of these features, see the LiveCode
Dictionary.
Tip: You can see a complete implementation of a basic client server "chat"
application by navigating to Documentation -> Getting Started -> Sample Projects > Internet Chat creating a custom protocol using sockets -> Launch. Most of the
scripts for the "server" stack are in the "start server" button. Most of the scripts for
the client are in the stack script for the "chat client" stack.
519
SQL Databases
A SQL database is a database that you access and control using SQL, a standard databaseaccess language which is widely supported. You use SQL queries (statements in the SQL
language) to specify the part of the database you want to work with, to get data, or to make
changes to the database.
LiveCode's database access is fully-featured. You can send any SQL statement to a database. You
can open multiple databases (or multiple connections to the same database), maintain multiple
record sets (database cursors) per connection, and send and receive binary data as well as text.
You can do all this using the commands and functions in the Database library.
To see a list of LiveCode terms in the Database library, open the Dictionary, and type "database"
into the search lter eld.
A database is built of records, which in turn are built out of database elds. A eld is the smallest
part of a database that can be separately addressed. Each database eld contains a particular
kind of information. This might be a name, a le path, a picture, or any other kind of information.
Each record contains one value for each of its elds. A set of records is called a database table,
and one or more tables comprise a database.
Here's an example: suppose you have a database of customers for your business. The elds of
this database might include the customer name, a unique customer ID number, and shipping
address. Each record consists of the information for a single customer, so each record has a
dierent customer name, shipping address, and so on.
Note: You may have noticed that the database structure being described resembles
a multiple-card stack that has the same elds on each card. A database eld is like a
eld in a stack, and a record is like a card. A stack set up this way can act as a
database, in fact, but lacks some of the features of an external database, such as
the ability to perform SQL queries and the ability to perform robustly when accessed
by more than one user.
You can also think of the set of customer records as a grid (like a spreadsheet). Each row is a
record, and each column is a eld, so each cell in the grid contains a dierent piece of information
about a particular customer. Here's an example:
ID
Customer Name
Address
Country
234 E. Street
U.K.
1 CanCo Blvd.
Japan
521
only US customers, you can write a SQL query that selects only records where the country eld is
"USA". This subset of records then becomes a record set. You can nd out more about the elds
and records contained in this record set, and move from record to record within this subset of the
database. You can create more than one record set to work with more than one set of records at
a time.
Note: Dierent database implementations have dierent limitations on movement
within a record set. For example, some databases won't let you move backward
within a record set: instead, you must start at the rst record and move forward in
order to examine the data.
Choosing a Database
LiveCode directly supports the following database implementations:
MySQL
SQLite
PostgreSQL
LiveCode also supports connecting to a database via ODBC. You can use ODBC to use Access,
FileMaker, MS SQL Server and many other database implementations. See below for more
information about ODBC.
LiveCode's database commands and functions use the same syntax regardless of what type of
database you are connecting to. You don't need to learn a separate database language for each
type. Instead, when you rst open a database with the revOpenDatabase function, you specify
the type as one of the parameters so LiveCode knows what type of database it's dealing with. The
Database library handles the details of each type behind the scenes for you.
Overview of ODBC
Open Database Connectivity (ODBC) is a system that allows developers to access any type of
compatible database in a standard way.
To communicate with a database, you usually have to add code that uses the database's own
proprietary protocols. Without ODBC, in order to create a program that can communicate with--for
example--FileMaker, Access, and Oracle databases, LiveCode would have to include code for three
dierent database protocols. With ODBC, LiveCode can communicate with any of these database
types using the same code.
522
ODBC Managers
To work with databases through ODBC, you need two pieces of software: an ODBC manager, plus
a database driver for the specic database type you're using.
Windows and OS X include ODBC software with the operating system. For Linux systems, you can
download an ODBC manager and a set of drivers (see the section below titled "Software for
Database Access" for more information).
MySQL
MySQL database drivers are included as part of the LiveCode installation on Linux, Mac OS X, and
Windows systems.
PostgreSQL
A PostgreSQL database driver is included as part of the LiveCode installation on Linux, Mac OS X
and Windows systems.
SQLite
Drivers for accessing this database are included with LiveCode. No additional installation is
523
necessary.
One of the advantages of setting up a DSN is that if you wish to change the location of the
database, you only have to edit the DSN settings, not your application code. You can think of a
DSN as a kind of shortcut or alias to your database.
524
Bitmap Images
LiveCode supports a wide variety of image formats, including the popular PNG and JPEG formats.
PNG images are space ecient and have full support for alpha channels. JPEG images are good
for displaying photos. For more details see the table below.
Format
Export
Mask
Comments
PNG
Yes
Yes, 1-bit or
alpha channel
JPEG
Yes
No
GIF
Yes
1-bit
BMP
No
No
Uncompressed
PBM
Yes
No
PGM
No
No
Grayscale
PPM
No
No
XBM
No
No
XPM
No
No
XWD
No
No
PICT
No
No
As you can see from the table above, a number of the supported image formats can also be
exported by LiveCode.
You can modify images using LiveCode's paint tools, or manipulate the binary data by script or
using an external.
You can create images from any of LiveCode's native objects, including buttons, elds and
graphics. These can then been exported in a number of formats. You can copy images from the
clipboard or export images to the clipboard.
LiveCode can capture a portion of the screen, or the entire screen.
525
Importing Images
To import an image, choose File -> Import As Control -> Image File. Select the image le you want
to import. This will import the image le into a new image object on the current card. This is
equivalent to executing the import paint command in the Message Box.
Note: If you want to reuse an image throughout your application, for example as part
of a custom skin for your application, create a substack and import all your images
into that. You can then reference them throughout your stack le. For more
information, see the section Creating Custom Skins, below.
This will create an image object on the current card from the rectangular area specied.
Creating Images
To create an image, drag an image object from the Tools palette to your stack. You may now paint
on the image using the paint tools, set the fileName reference to an image or manipulate the
binary data of the image.
To access the paint tools, press the fold out triangle at the bottom right of the Tools palette.
Keyboard
Modiers
Usage
Select
Shift constraints
to a square;
command /
control duplicates
selection
Bucket
Control-click to ll
with transparency
Spray
can
Control-click to
spray with
transparency
Eraser
527
Shift
constrains to
a square;
control
creates
transparency
Tool
Polygon
Line
Keyboard
Modiers
Usage
Shift constrains
lines angles to
multiples of
22.5; control
creates
transparency
Shift constrains
lines angles to
multiples of
22.5; control
creates
transparency
Alt / option
prevents drawing
line border;
control creates
transparency
Pencil
Control creates
transparency
Brush
Control creates
transparency;
command click to
magnify
Fill
(brush)
color
Line
color
Brush
shape
To magnify an image, right click it with the pointer tool and choose Magnify from the menu.
When you edit an image, it will be recompressed into the format specied by the
paintCompression global property.
528
For more information, see the entries for the templateImage, tool, brush, brushColor,
brushPattern, dragSpeed, penColor and penPattern in the LiveCode Dictionary.
You may reduce the size of an image using the crop command.
You may rotate an image using the rotate command.
To adjust the quality of the scaling algorithm used when scaling an image, set the resizeQuality
property before setting the image's rect.
To manipulate the binary data of an image using an external, use the imagePixMapID property.
When you set the imageData of an image the image will be recompressed into the format
specied by the paintCompression global property.
529
The import snapshot command creates a new image in the current defaultStack. The image is
encoded using the current paintCompression format.
To save this snapshot directly to a le instead of creating an image, use the export snapshot
command:
export snapshot from the selectedObject to file "snap.jpg" as JPEG
Exporting Images
To export an image in the current format that it is stored in, put it into a binary le using the URL
commands. The following example prompts the user to select a le then export the image into it:
ask file "Select a file:"
put image "picture" into URL ("binfile:" & it)
To recompress the image in a dierent format, use the export command to export it to a
variable then put that variable into an image.
To copy an image to the clipboard, use the copy command.
copy image 1
530
531
Simple motion can be applied using the move command. For example, to move a graphic 100
pixels to the right asynchronously:
move graphic 1 relative 100,0 without waiting
For more information, see the move command in the LiveCode Dictionary.
To program a more complex animation eect, calculate the changes to the points or rectangles
and set these values using timer based messaging. The following example scales a graphic
named "rectangle" down by 100 pixels over the course of 1 second.
local sCount
on mouseUp
put 0 into sCount
scaleGraphic
end mouseUp
on scaleGraphic
add 1 to sCount
if sCount > 100 then exit scaleGraphic
get the rect of graphic "rectangle"
add 1 to item 1 of it
add 1 to item 2 of it
subtract 1 from item 3 of it
subtract 1 from item 4 of it
set the rect of graphic "rectangle" to it
send "scaleGraphic" to me in 10 milliseconds
end scaleGraphic
See the section on Timer based messaging for more information on using timers.
Function
Example
showController
set the
showController of
player 1 to false
currentTime
duration &
timeScale
alwaysBuer
on currentTimeChanged
pInterval
currentTimeChanged
startTime
endTime
showSelection
playSelection
playRate
533
Property Name
Function
Example
looping
playLoudness
tracks
enabledTracks
callbacks
The following properties can be used to control a QTVR movie: pan, tilt, zoom, currentNode,
nodeChanged, hotspots, and hotSpotClicked.
For more information on any of these terms, see the LiveCode Dictionary.
To stop playing
play stop
534
To make changes to objects on the screen with a visual eect (e.g. hide, show or move them),
rst lock the screen, then make the changes, then unlock the screen:
lock screen
hide image 1
show image 3
unlock screen with visual effect "wipe right"
Then:
visual effect (the cEffect of this stack)
go next card
For more information on visual eects, see the visual eect command in the LiveCode
Dictionary. To try out the dierent visual eects available in an interactive format see the
Multimedia Workshop
535
"icons" of unlimited size which can be used to replace the native appearance of a button entirely.
Windows can be irregularly shaped and even contain holes and alpha mask (variable)
transparency. All of LiveCode's objects support a variety of transfer modes or inks. Stacks can
take over the entire screen or be displayed with a backdrop.
Irregular Windows
To create an irregularly shaped window, import or create an image that has a transparency mask.
Then use the Stack Inspector to choose that image as the stack's Shape. To change the shape by
script, set the windowShape property. Many modern window managers support alpha blended
windows (variable degrees of transparency). To create a window with an alpha channel, import a
PNG that contains an alpha channel and set the windowShape to this image.
For more information, see the ink entry in the LiveCode Dictionary.
To set the degree of transparency, set the object's blendLevel property. All LiveCode objects
(including stacks) support blendLevel :
536
Displaying a Backdrop
To display a backdrop set the backDrop global property. You may set the backDrop to a solid
color or to the ID of an image.
set the backDrop to "black"
537
Action
New Stack
Opens a cascading menu you can use to choose a stack type to create.
When you save the stack, LiveCode asks for a le name and location.
Default Size
Predened
Size
Script only
Stack
Creates a stack to be used for script only. You will be prompted for a stack
name, and the script editor for the new stack will launch automatically
New
Substack of
(main stack
name)
Creates a new untitled stack in the same le as the active main stack. When
you save the substack, it is saved in the main stacks le. This item is
disabled if the active window is not a main stack.
Open
Stack...
Opens the main stack whose le you select. If you select a HyperCard le, it
is automatically converted into a LiveCode main stack.
Open Recent
Stack
Opens a cascading menu containing the names of the 30 main stacks you
have most recently closed. Choose a name to open the stack. You can
change the number of items displayed using Preferences.
Close
Close and
Remove
from
Memory...
Closes the current stack and all stacks in the same stack le as the current
stack, and removes all stacks in the le from memory. This item is disabled if
the active window is not a user stack.
Import as
Control
Opens a cascading menu you can use to choose a le and place its contents
in a new control of the appropriate type. This item is disabled if the active
window is not a stack.
538
Menu Item
Action
Image File...
Imports the picture le you choose as a new image on the current card. You
can import GIF, JPEG, PNG, BMP, XWD, XBM, XPM, or PBM, PGM, or PBM les
(and PICT les on Mac OS and OS X systems). For more details see the
section on the image object.
Audio File...
Imports the sound le you choose as a new audio clip in the current stack.
You can import WAV, AIFF, or AU les. For more details, see the section on
the audioClip object.
Video File...
Imports the video le you choose as a new video clip in the current stack.
You can import AVI, or MPEG les. For more details, see the section on the
videoClip object.
Text File...
Imports the text le you choose as a new eld on the current card.
Snapshot
Displays a crosshairs cursor for you to select an area of the screen, and
imports a screen shot of that area as a new image on the current card.
All Images in
Folder...
Imports all the picture les in the folder you choose, and places them in new
images on the current card. Subfolders, and other types of les, are ignored.
For more details see the section on the image object.
All Audio
Files in
Folder...
Imports all the sound les in the folder you choose, and places them in new
audioClips in the current stack. Subfolders, and other types of les, are
ignored. For more details, see the section on the audioClip object.
All Video
Files in
Folder...
Imports all the video les in the folder you choose, and places them in new
videoClips in the current stack. Subfolders, and other types of les, are
ignored. For more details, see the section on the videoClip object.
Imports all the text les in the folder you choose, and places them in new
elds in the current stack. Subfolders, and other types of les, are ignored.
New
Referenced
Control
Opens a cascading menu you can use to select a le to reference (i.e. link)
to a new control of the appropriate type. This item is disabled if the active
window is not a stack.
Image File...
Creates a new image on the current card and links to the picture le you
select in the new image object. For more details see the section on the
image object.
Video File...
Creates a new player on the current card and links to the video le you
select in the new player object. For more details see the section on the
player object.
All Images in
Folder...
For each picture le in the folder you select, creates a new image on the
current card and links it with one of the les. Subfolders, and other types of
les, are ignored. For more details see the section on the image object.
All Videos in
Folder...
For each video le in the folder you select, creates a new player on the
current card and links it with one of the les. Subfolders, and other types of
les, are ignored. For more details see the section on the player object.
Save
Saves changes to the current stack and to any other stacks that reside in
the same stack le. If the le has not yet been saved, you specify the new
les name and location. This item is disabled if the active window is not a
stack.
Save As...
Saves the current stack, along with any other stacks that reside in the same
le, to a new le with a name and location you specify. The new le becomes
the current working copy.
539
Menu Item
Action
Move
Substack to
File...
Saves the front most substack as a main stack in a le of its own, with a
name and location you specify. The substack is removed from its previous
stack le. This item is disabled if the active window is not a substack.
Revert to
Saved...
Throws away any changes to the current stack, along with any other stacks
that reside in the same stack le. The entire stack le is then reloaded.
Standalone
Application
Settings...
Save As
Standalone
Application...
Page
Setup...
Opens the Page Setup dialog box for the currently selected printer.
Print Card...
Print Field...
Prints the currently selected eld using the revPrintField command. For more
details, see the section on Printing.
Exit
Action
Undo
Reverses the most recent text change, paint action, movement or deletion of
an object.
Cut, Copy,
Paste
Cuts, copies or pastes the selected text or object. Text and images can be
exchanged with other programs in this manner. Objects are only available
within the currently running instance of LiveCode.
Clear
Duplicate
Makes a copy of the selected object or objects. If the object is a card, the copy
is added after the current card. If the object is a control, the copy is placed on
the current card, below and to the right of the original object. This item is
disabled if no object is selected.
Select All
Selects all the text in the current eld or all the controls on the current card.
Deselect
All
Deselects any selected objects, or removes the insertion point from a eld.
Invert
Selection
Selects all the unselected objects and unselects all the selected ones. This
item does not work on text selections.
Select
Grouped
Controls
If this item is checked, clicking a control that's part of a group selects only that
control. If unchecked, clicking a control that's part of a group selects the
group.
Intersected
Selections
If this item is checked, dragging with the Pointer tool selects each object that
intersects the dragged rectangle. If unchecked, dragging with the Pointer tool
selects only objects that are entirely enclosed by the dragged rectangle.
Find and
Replace...
Searches for and optionally replaces text in elds, properties, scripts, global
variables, or button contents. For more details, see the section on Find and
Replace.
540
Action
Browse
Tool
Chooses the Browse tool for running a project. Allows you to perform user
actions such as running scripts by clicking buttons, or entering text in a eld.
Pointer
Tool
Chooses the Pointer tool for editing a project. Allows you to select, move, and
resize objects.
Tools
Palette
Shows or hides the Tools palette for choosing tools for object creation.
Paint and
Draw
Tools
Shows or hides the paint and draw tools in the Tools palette.
Project
Browser
Opens the Project Browser window, which lists all open stacks, the cards in each
stack, and the controls on each card. For more details, see the section on the
Project Browser.
Message
Box
Shows or hides the Message Box. The Message Box is a command line tool that
allows you to run scripts or perform automated editing operations. For more
details, see the section on The Message Box.
Extension Shows or hides the Extension Manager. The Extension Manager is a stack which
Manager shows what widget and library extensions are currently installed.
Shows or hides the Extension Builder. The Extension Builder is a stack which aids
Extension in the creation of widget and library extensions to LiveCode. For more
Builder
information on creating extensions using the Extension Builder, please see the
Extending LiveCode guide.
Menu
Builder
Creates or changes the menu bar in the currently active stack. For more details,
see the section on the Working with Menus.
Action
Object
Inspector
Opens the Inspector for the currently selected object, allowing you to view and
set object properties. If more than one object is selected, changes made to the
properties are applied to each of the selected objects. This item is disabled if no
object is selected. For more details, see the section on The Properties Inspector.
Card
Inspector
Opens the Inspector for the current card, allowing you to view and set card
properties.
Stack
Inspector
Opens the Inspector for the current stack, allowing you to view and set stack
properties.
Object
Script
Opens the Script Editor for the selected objects. If more than one object is
selected, a script editor window opens for each one. For more details, see the
section on The Script Editor.
541
Menu
Item
Action
Card
Script
Stack
Script
Group
Selected
Makes the selected objects into a group. This item changes to "Ungroup
Selected" if the only selected object is a group. For more details, see the
section on Groups and Backgrounds.
Ungroup
Selected
Makes the selected group into individual objects. This removes the group
permanently if you visit another card before grouping the objects again. This
item changes to "Group Selected" if more than one object is selected.
Edit
Group
Stop
Editing
Group
Leaves group-editing mode. This item changes to "Edit Group" if the stack is not
already in group-editing mode.
Remove
Group
Removes the selected group from the current card, without deleting it from the
stack.
Place
Group
Opens a cascading menu containing the names of groups that are in the stack
but not on the current card. Choose a group to add it to the current card. This
item is disabled if all the groups in the stack already appear on the current card,
or if there are no groups. Note: Only the names of top-level groups are listed;
groups that are a part of another group are not listed in this menu.
New Card
Creates a new card following the current card. Note: If there are any shared
groups on the current card when you choose this menu item, they are
automatically placed on the new card. If a group's backgroundBehavior is false,
they are not placed automatically on new cards.
Delete
Card
New
Control
Opens a cascading menu you can use to create a new control. For more details,
see the section on Control Types.
New
Widget
Opens a cascading menu you can use to create a new widget control. For more
details, see the section on Control Types.
Flip
Opens a cascading menu you can use to change the orientation of the selected
image or graphic. This item is disabled if any object other than an image or
graphic is selected.
Horizontal
Swaps the left and right edges of the selected image or graphic, ipping it
around an imaginary line drawn from top to bottom of the object.
Vertical
Swaps the top and bottom edges of the selected image or graphic, ipping it
around an imaginary line drawn from left to right of the object.
Rotate
Opens a cascading menu you can use to rotate the selected image or graphic.
By...
Rotates the selected image or graphic by the number of degrees you specify.
90 Right
90 Left
180
Menu
Item
Action
Reshape
Graphic
Align
Selected
Controls
Opens a cascading menu you can use to line up objects. This item is disabled if
no object or only one object is selected.
Left
Moves the selected controls so their left edges are lined up with the left edge of
the rst control selected.
Right
Moves the selected controls so their right edges are lined up with the right edge
of the rst control selected.
Top
Moves the selected controls so their top edges are lined up with the top edge of
the rst control selected.
Bottom
Moves the selected controls so their bottom edges are lined up with the bottom
edge of the rst control selected.
Make
Widths
Equal
Resizes the selected controls so that the width of each one is equal to the width
of the rst control selected.
Make
Heights
Equal
Resizes the selected controls so that the height of each one is equal to the
height of the rst control selected.
Send to
Back
Moves the selected objects behind all other objects on the card. This item is
disabled if no object is selected.
Move
Backward
Move
Forward
Bring to
Front
Moves the selected objects in front of all other objects on the card.
Action
Text Style
Options
Applies or removes the selected style from the selected text or the selected
object. These items are disabled if nothing is selected.
Link
Makes the selected text, or all text in the selected object into a link. Linked
text has special properties in LiveCode, for example linked text will receive a
linkClicked message when clicked on. For more details, see the section on the
Field object.
Subscript
Moves the selected text below the baseline and makes it smaller.
Superscript Moves the selected text above the baseline and makes it smaller.
Font
Opens a cascading menu you can use to change the font face used for the
selected text or objects.
543
Menu Item
Action
Use
Owner's
Font
Causes the font face of the object's owner (if an object is selected) or the
object the text is in (if text is selected) to be used, removing any font face
specic to the selected text or objects. For more information on font
inheritance, see the section on the Message Hierarchy.
Size
Opens a cascading menu you can use to change the font size used for the
selected text or objects.
Use
Owner's
Size
Causes the font size of the object's owner (if an object is selected) or the
object the text is in (if text is selected) to be used, removing any font size
specic to the selected text or objects. For more information on font
inheritance, see the section on the Message Hierarchy.
Color
Opens a cascading menu you can use to change the font color used for the
selected text or objects. (This item is disabled if nothing is selected.)
Use
Owner's
Color
Causes the font color of the object's owner (if an object is selected) or the
object the text is in (if text is selected) to be used, removing any font color
specic to the selected text or objects. For more information on font
inheritance, see the section on the Message Hierarchy.
Pen Color
Changes the selected text, or text used in any selected objects, to use the
current pen color setting (used to draw graphics from the main tool palette).
Align
Opens a cascading menu you can use to change the text alignment
(justication) used for the text in the selected objects.
Action
Plugins
Opens a cascading menu you can use to open custom tool stacks stored in
the Plugins folder.
Plugin
Settings
Customizes which messages are handled by the custom tool stacks stored
in the Plugins folder.
Test
Test Target
Opens a cascading menu you can use to select what device or simulator to
use when simulating deployment.
Script Debug
Mode
Clear All
Breakpoints
Removes all breakpoints that you've used the Script Editor to mark, in all
open stacks. Note: This menu item does not aect breakpoints set with the
breakpoint command.
Message
Watcher
Opens the Message Watcher window, used to view and track messages,
function calls, getProp calls, and setProp triggers as they are sent to
objects.
Suppress
Errors
544
Menu Item
Action
Prevents system messages (such as openCard and closeCard) from being
sent during normal navigation. This option will also cancel any currently
pending messages.
Suppress
Messages
Suspend
Hides LiveCode's menus, palettes, and other parts of the development
Development environment, so that you can preview how your application will look and
Tools
behave as a standalone, outside the development environment.
Caution: Suppressing errors will cause your scripts to fail silently instead of giving an
error message in the event LiveCode encounters an error.
Tip: To also suspend LiveCode libraries, hold down the Shift key while choosing the
Suspend Development Tools menu item.
Action
Go First
Go Prev
Go Next
Go Last
Go
Recent
Goes back to the card you were on before navigating to the current card.
Toolbar
Text
Shows or hides the text labels in the Toolbar at the top of the screen. To hide the
Toolbar completely, uncheck both this item and "Toolbar Icons".
Toolbar
Icons
Shows or hides the icons in the Toolbar at the top of the screen.
Palettes
Rulers
Shows or hides a ruler at the left and bottom edges of each open stack.
Grid
Backdrop
Show IDE
Stacks in
Lists
Show
Invisible
Objects
If this item is checked, objects whose visible property is set to false are shown. If
unchecked, objects whose visible property is set to false remain hidden.
Menu
Item
Send
Window
To Back
Action
Shues the frontmost stack window to the back and brings the second window
to the front. (This item is disabled if only one stack is open or the active window
is not a stack.)
Action
Dictionary
(API)
Opens the main LiveCode documentation window, where you can get
information about all aspects of developing in LiveCode.
Start Center
Sample
Stacks
Sample
Scripts
Opens the Resource Center, which contains many sample scripts, including
tutorials on text processing and using databases.
Beginner's
Guide
All Guides
Opens the main LiveCode documentation window, which contains all of the
user guides
Tutorials
User Guide
Forums
Technical
Questions
Discussion
List
Newsletters
Release
Notes
License
Agreement
User Guide
Support
Loads the support section of the LiveCode web site in your web browser.
Buy a
license
Check for
Updates
Re-license
LiveCode
The Property Inspector allows you to view and edit the properties for any selected object.
Properties control how an object looks and some aspects of an objects behavior. The Inspector
can be accessed by double clicking on a selected object, from the toolbar, from the Object menu
and from context sensitive menus.
Lock icon
The lock icon locks the Inspector to the object currently being inspected. Once
locked, the Inspector will not update when you change selection or switch to
Run mode by choosing the Browse tool. This allows you to used a locked
Inspector to change an objects properties while interacting with your project.
Selecting another object and choosing Inspect will create another Inspector to
inspect the new object. You can use this facility to compare the properties of
two objects.
Pane
Selector
This menu allows you to access each of the dierent panes within the inspector
for a given object.
Action
menu
Use the action menu to select another object, edit the script of the current
object or send a message to current object.
Settings
menu
Use the settings menu to congure the settings of the property inspector.
547
Property
text
Edit the contents of a property by typing into the text area within the Inspector.
Press return to set the property and leave the current option selected. Press
tab to set the property and move on to the next editable text property.
This text describes the object property. By default this text is an English-like
description of the property. However you can change this to contain the name
Property
of the LiveCode property in the Preferences or the settings menu. You may
description
prefer to view the LiveCode property names if you are writing scripts that set
object properties.
Important: For documentation on what each individual object property does, hover
the mouse over the object until you see the script property equivalent. Then look that
term up in the LiveCode Dictionary.
Header/Footer
size
Property labels
Controls whether to use the LiveCode script tokens for property labels
or not.
548
Breakpoints Area
Click next to a line of script to set or remove a breakpoint. A breakpoint species a point at which
script execution should pause and the debugger be loaded. For more details, see the section on
Debugging.
Apply Button
Compiles the script instantly. Any syntax errors will appear in the Error Display and the script will
not compile. A compiled script is not saved until the stack that contains it is saved.
Press Enter (on the numeric keypad) to activate the Compile button. Press Enter again to close
the Script Editor.
Note that none of the message handlers within the script will be available if there is a Script Error
during compilation, as none of the script will have compiled.
Errors Pane
Compile and execution errors will appear here. Double click the icon next to the error details to
549
highlight the line the error occurred on in the script (if applicable).
Handler List
The handler list displays all the functions, commands and handlers which are part of the current
script. When a handler name is clicked, the script will jump to that handler.
The currently displayed list of handlers can be ltered by typing in the lter box below it.
Documentation Pane
The Script Editor also has a built-in syntax dictionary. When this tab is active a summary of the
dictionary entry for the keyword which you are currently typing will be displayed. The full dictionary
entry can be viewed by clicking Launch Documentation. Alternatively you can choose to view the
entire entry in place by toggling the Full Document check box at the bottom of the documentation
pane.
550
551
Script Tabs
When multiple scripts are open they will appear as tabs in the Script Editor. Right clicking on the
tabs brings up a menu which allows a tab to be moved to a new window, closed, or kept while
closing all other tabs. Clicking a tab will bring up the script it represents.
The Debugger
The Debugger helps you track bugs and understand code, by allowing you to pause the execution
of your programs or step through them line by line. You cause execution to pause by setting
breakpoints. When you run your script, execution will pause at a breakpoint and you will be able to
observe or edit variable values, continue execution or set another breakpoint later in the code.
Each debugger feature is outlined below:
552
Continue
When in debug mode, the Continue button will start running the code from the current position.
The program will run until the end is reached or another breakpoint is found.
When you are not in debug mode, the continue button can be used to execute a handler. When
you press it, a dialog will appear asking which handler you would like to call and, if applicable,
which parameters you'd like to pass. On clicking OK the Script Editor will call the handler you
specied. It will also remember the handler for next time. To change the handler called later,
choose Entry Point from the Debug menu.
Stop Debugging
Will halt execution at the current point and stop debugging. You will then be able to edit the script.
553
554
Step Out
The Step Out function allows you to exit a command or function that you have previously stepped
into. When selected, the rest of the current handler will run and execution will pause on the line
after the handler call. This is useful to avoid stepping through a long command or function line by
line when you have identied that the error you are looking for is not within that command or
function.
555
Debug Context
The Debug Context shows you the path of execution up to the current statement you are paused
on in the debugger. This allows you to identify where you are in your program and which handlers
called the current handler you are in. Changing the debug context allows you to view variables
from dierent parts of the program. Use this feature to nd an erroneous command call or a call
where wrong parameters were used.
Variable Watcher
The Variable Watcher tab allows you to examine the value of variables within your program while it
is executing. As you step through your code these values will be updated. The variable name is
shown in the left column and its value adjacent on the right. If a variable's value is too large to be
displayed in the pane it will have a magnifying glass next to it. Clicking this will bring up a watch
window which allows the variable's value to be changed. Variables can also be edited by double
clicking on their value in the variable watcher.
Tip: You can see the value of a variable by moving the mouse over the variables
name in the script eld while debugging.
Breakpoint Management
Use breakpoints to specify where to pause execution in the debugger. You set breakpoints by
clicking in the gutter, or by right clicking in the Breakpoint Manager at the bottom of the Script
556
Editor and selecting New Breakpoint. Each breakpoint is associated with a line of code and
execution is paused when that line is reached. Alternatively, a condition can be assigned to the
breakpoint. In this case, execution will only pause if the condition is true when the line is reached.
Tip: To see a list of all the breakpoints within a stack, including the script they are in,
which line they are on, and whether there is a condition attached, click the
Breakpoints Manager at the bottom of the Script Editor. The check box to the left of
each breakpoint can be used to enable or disable the breakpoint. Double click a
breakpoint to go to that line in the associated object's script. To edit a breakpoint,
including adding a condition or changing the line number, click the pencil icon. This
can also be done by right-clicking on the breakpoint, either in the Breakpoints
Manager, or the Script Editor's gutter.
557
558
The Breakpoint Manager also allows you to set watches. These are associated with variables
rather than lines of code and will pause execution when the value of the variable you are watching
changes. Alternatively, if the watch has a condition attached, execution will only pause if, when the
variable's value is changed, the condition is true. To add a watch, right click in the Breakpoint
Manager and choose New Breakpoint.
559
Compile
Save
Close
Quit
Revert
Takes any changes which haven't been compiled, and removes them from the
current script.
Comment
Find and
Replace
Go
Brings up a dialog box which lets you enter a line number to jump to in the
script.
Variable
Checking
Show
Next
Step
Into
Highlights the next line of code to be executed. This is useful if you have changed
tab or scrolled your script during debbuging.
Executes the next line of the handler being debugged. If the next line is a call to
another handler, this command steps into that handler. This menu item is disabled if
the debugger is not running.
Executes the next line of the handler being debugged. If the next line is a call to
Step
another handler, this command steps over that call, skipping it and staying within the
Over
current handler.
Tip: Press F10 to step over the next line.
Run
Resumes normally executing the handler being debugged, starting from the current
line.
561
Toggle
Breakpoint
Variables
Changes the tab view at the bottom of the Script Editor to the Variable
Watcher tab.
Breakpoints
Changes the tab view at the bottom of the Script Editor to the Breakpoint
Manager.
Entry Point
Lets you dene which handler execution should begin at when debugging a
script.
Script
Debug
Mode
If this item is checked, the debugger is enabled: the execution of the program
will pause when a breakpoint is encountered during script execution, and you
can enter the debugger when an execution error occurs. If unchecked the
debugger is disabled. For more details, see the section on Debugging.
562
563
Type valid LiveCode code into this area. In Single Line mode, separate multiple
lines with ; (semi-colon) and press Return to execute. In Multiple Line mode,
press return to separate lines, and press Enter to execute.
For example, in Single Line mode, to move all controls on the current card 10
pixels to the left you would run:
repeat with i = 1 to the number of controls ;
move control i relative 10,0 ; end repeat
In Multiple Line Mode: repeat with i = 1 to the number of controls
move control i relative 10,0
end repeat
Command
area
Type control-m to focus the command area and start typing, whenever the
Message Box does not have the focus. Press control-u when typing to clear the
command area.
In Single Line mode press the Up Arrow key to cycle backwards through the
history of previously entered and executed scripts. Press the Down Arrow key
to cycle forwards. In Multiple Line mode, press alt-up arrow or alt-down
arrow to cycle forwards or backwards, respectively. Press control-u to clear the
current command area.
Typing the name of a global variable or property on its own will result in the line
being auto-completed to include put in front of the global variable or property,
thus the contents of that global will be placed into the results area. For example
typing:
time
Will be auto completed to:
put the time
The current time will be placed in the results area.
564
Displays:
The result function after running code in the command area.
Any script that uses the put command without a destination container.
Any script compile error created as a result of attempting to run code placed in
the command area.
Results
area
Any execution error created as a result of attempting to run code placed in the
command area.
The msg special global will be updated whenever anything is placed in the
results area, either by script or by directly editing the content of the results
area. You can set or retrieve the content of this variable in any script. For
example, try running the following in the command area:
put the clipBoardData; replace return with return & return in
msg
The result placed into the results area will contain the current contents of the
clipboard, with every return character replaced with a second return character.
Stack
selector
Select a stack to work on. Prior to executing any script the defaultStack will be
set to the stack displayed in this menu. By default the Message Box will choose
the front most editable stack. The menu is updated whenever you change the
front most stack or click on the Message Box. You can use this menu to choose
an alternative open stack. For example, running the following script in the
command area of the single line message box:
put the number of controls
Lock icon
Would place the number of controls in the current card of the stack displayed in
the menu, into the results area.
This option prevents the Stack selector from updating automatically when you
change stacks. Use this option if you want to run a number of commands on a
specic stack regardless of which stack is currently in front.
Settings
menu
Use the settings menu to congure the settings of the message box.
Target
action
Click the target icon to navigate to the last line of script that executed a put
command with the message box as its target.
Header/Footer
Controls how large the mode selector icons and footer action icons are.
size
565
Auto update
pending
messages
Select
intelligence
object
Global Properties
The Global Properties mode allows you to view and edit all global properties. Scroll to select a
property from the list on the left and select it to view or edit it. Typing a portion of the property
name into the Filter eld at the top will lter the list of properties. Changes to global properties
take eect immediately. If a property is read only this will be indicated when you select it and
editing it will have no eect. For more details on Global Properties, see the section on Global
Properties.
Global Variables
The Global Variables mode allows you to view and edit all global variables. Environment variables
are shown rst, followed by other variables. Scroll to nd a variable from the list on the left and
select it to view or edit it. Typing a portion of the variable name into the Filter eld at the top will
lter the list of variables. Changes to global properties take eect immediately. The Show
LiveCode UI Variables is an advanced option, discussed in the section on Editing the LiveCode
User Interface. For more details on Global Variables, see the section on Global Variables.
Pending Messages
The Pending Messages mode allows you to view all the current timer based messages that are
pending. This is the same as the global property the pendingMessages. You can select a
pending message to edit its script or cancel it.
566
Tip: You can cancel all current pending messages using the Suppress Messages
button on the toolbar.
Pressing update refreshes the list with the current list of pending messages. The Auto Update
mode refreshes the list continuously. Note that the Auto Update takes place every 200
milliseconds. If your messages re more quickly they may not be displayed. For more details on
Pending Messages, see the section on Timer Based Messaging. The Show LiveCode UI Messages
is an advanced option, discussed in the section on Editing the LiveCode User Interface.
Stacks In Use
This mode is the same as the Front and Back scripts mode, except that it displays the
stacksInUse global property. You can also add a stack directly using the Add button.
The Toolbar
The main toolbar provides easy access to commonly used functions.
567
Find eld
568
Find button
Case
Sensitive
Species that the search should be case sensitive (e.g. "a" and "A" are
treated as dierent characters)
Regular
Expression
Species that the Find Field contains a regular expression instead of plain text.
A regular expression allows you to describe a pattern of text to match. For
more details on using regular expressions, see the section on Using Regular
Expressions below.
Obey
dontSearch
properties
Species that elds, cards or groups with their dontSearch property set to
true should be excluded from the search. For more details on the dontSearch
property, see the LiveCode Dictionary.
Search
marked or
unmarked
cards only
Search in
Name
Script
Custom
Searches and objects custom properties and custom property sets. For more
details on Custom properties, see the section on Custom Properties.
Field Text
Button Text
Searches button text. This includes text in menus. For more information on
buttons and menus, see the section on Control Types.
All Other
Searches all other commonly used object properties. For more details on
exactly what is included, see the properties entry in the LiveCode Dictionary.
Results
column
header
Allows you to sort search results by clicking. Drag between the column
headers to change column widths.
Search
Results
Area
Remove
from List
Removes the currently selected search result in the Search Results area from
the list. Once removed, the object will no longer be included in any replace
operation.
Replace
With
Replace in
All
Replaces the Find Field with the Replace With eld in all objects currently listed
in the Search Results Area.
Keyboard Shortcuts
The Development Environment
Windows / Linux
Mac OS X
Control-9
Command-9
Conttrol-0
Command-0
Control-alt-tab
Command-option-tab
Control-tab
Command-control-tab
Command-control-shift-click
Control-alt-s
Command-option-s
Return
Return
Control-1st
Navigation
Command-1st letter of
button
letter of
button
Windows / Linux
Mac OS X
Control-1
Command-1
Control-2
Command-2
Control-3
Command-3
Control-4
Command-4
Control-5
Command-5
Windows / Linux
Mac OS X
Select all
Control-a
Command-a
Duplicate
Control-d
Command-d
570
Objects
Windows / Linux
Mac OS X
Create card
Control-n
Command-n
Nudge control
Arrow keys
Arrow keys
Shift-arrow-keys
Shift-arrow-keys
Return
Return
Control-K
Command-K
Control-;
Command-;
Control-shift-=
Command-shift-=
Control-=
Command-=
Control-right-click
Command-click
Control-click
Control-click
Shift
Shift
Shift
Shift
Windows / Linux
Mac OS X
Control-e
Command-e
Control-shift-c
Command-shift-c
Control-shift-s
Command-shift-s
Control-alt-click
Command-option-click
Apply changes
Enter
Enter
Enter twice
Enter twice
Control-s
Command-s
Control-hyphen
Command-hyphen
Remove comments
Control-shift-hyphen Command-shift-hyphen
Switch to nd mode
Control-f
Command-f
Find next
Control-g
Command-g
Control-Option-f
Command-Option-f
Tab
Tab
Windows / Linux
Mac OS X
Control-m
Command-m
Control-m
Command-m
Control-u
Command-u
Up/down arrow
Up/down arrow
Option-up/down arrow
Return
Return
Enter
Control-Return
Enter
Control-Return
The Debugger
Windows / Linux
Mac OS X
Step Into
F11
F11
Step Over
F10
F10
Step Out
Shift-F11
Shift-F11
Run
F5
F5
Stop
Shift-F5
Shift-F5
Abort
Control-.
Command-.
571
Windows / Linux
Mac OS X
Up/down arrow
Up/down arrow
Right/left arrow
Right/left arrow
Open object
Return
Return
Shift-Return
Shift+Return
Shift-Alt-Return
Shift-Alt-Return
Inspect object
Control-Return
Command-Return
572
573
Mode
Selector
Standalone
Name
Set the name of your standalone application. This should be the name you
want your nished application to have. Dont include a le extension (.exe on
Windows or .app on Mac OS X) as the standalone builder can create
standalones for multiple platforms and will add the appropriate extension
automatically.
Inclusions
Selector
Choose the components you want to include in a standalone. You may either
choose to search for required inclusions automatically, or manually select the
components you want to include.
Proles
Settings
Choose between the Property Prole settings options. You only need to alter
settings in this area if you have used Property Proles (see the section on
Property Proles in Chapter 4, Builder a User Interface above)
Remove all
proles
Removes all proles and builds the standalone using the currently active
prole on each object. Select this option if you don't need to change prole in
the standalone and want to save disk space by removing extraneous prole
information.
Set all
objects to
prole
Set all objects to a specic prole then remove the prole data from objects.
Include
proles and
the prole
library
Include the prole library and allow switching between proles in the
standalone application. You can choose whether to include specic proles or
all proles.
575
Use this section to add additional stack les to your application. Any stacks
you add to this section will be added to the stackFiles property of the
Stack Files
main stack of your standalone. This means that any scripts within your
standalone application will be able to locate and reference these stacks by
name.
Advanced
Options
Use this section to control exactly how multiple stack les are managed in
your standalone.
Move
substacks
into
individual
les
If you select this option, each of the sub stacks in the stack les you select
will be moved into their own individual le, located in the data folder or within
the application bundle of your standalone.
Rename
stackles
generically
Renames each sub stack le using a number on disk (instead of using the
name of the sub stack). Select this option if you do not want the names you
have selected for stacks to be visible to the end user in the ling system.
Create
folder for
stackles
Creates a folder and places the stack les into that folder, instead of storing
them at the same level as the standalone executable. All references in the
stackFiles property will refer to this folder using a relative path so the
stacks can still be located by the standalone application.
Individual
stack
options
Select a stack le on the left then an individual stack from within the le to
set options on that stack.
Set
destroyStack
to true
Set this option if you want the selected stack le to be removed from
memory when it is closed. This option is useful if you are loading large stacks
into memory and want them to be removed when they are closed.
Encrypt with
password
Secures the scripts within the selected stack le with a password. This
provides a basic level of encryption that prevents someone from casually
reading the scripts in the stack by opening the le in a binary le viewer.
576
Non-stack
les in the
application
Copy
Referenced
Files
List other les to be included in the standalone. Use this feature to include
help documents, read me les and other resources that you want to include
with your standalone each time you build.
Loops over all image and player objects in stacks and copies any les
referenced in the fileName property of these objects into the standalone.
Then automatically sets the fileName property to reference these les in the
standalone using referenced le paths.
Destination
folder
Create a subfolder within your standalone to copy the image and movie les
to.
Extensions
577
Ask
Dialog
This option is required if any of your scripts use the "ask" or "ask password"
commands. The standalone builder will copy the stack "ask dialog" from the IDE
into your standalone as a sub stack. The standalone builder makes a copy of
your stack before adding resources to it as part of the build process, so your
original stack is unaltered.
Answer
Dialog
This option is required if any of your scripts use the "answer" command. Note
that this only applies to the dialog form of the command. The answer le /
printer / color / eect / folder / page setup / printer and record forms of the
command do not require this option. The standalone builder will copy the stack
"answer dialog" into your standalone.
578
Browser
Browser
(CEF)
This option is required if your application uses the embedded browser or any
revBrowser command.
This option is required if your application uses the embedded CEF browser or
any revBrowser command.
Brushes
This option is required if your application uses any of LiveCode's brush cursors.
It is not required if your application does not make use of the painting
commands. It copies the stack "brushes" into your standalone.
Cursors
Database
Magnify
PDF
Printer
This option is required if your application uses the "open printing to pdf"
command.
Print
Dialog
This option is required if your application uses LiveCode's built-in print or page
setup dialogs (e.g. for use on Linux without GTK installed). It is not required if
you only display the system printer and page setup dialogs. It copies the stack
"print dialog" and "page setup" into your standalone.
SSL &
This option is required if your application uses any SSL or encryption related
Encryption commands
Video
Grabber
This option is required if your application uses any video capture commands
XML
Animation
DataGrid
DataGrid object.
Geometry
Internet
Printing
Zip
Speech
Table
XMLRPC
579
Build a standalone that will run natively on Mac OS X Intel machines. This
standalone will not run at all under PowerPC.
Build a standalone that will run natively on Mac OS X Intel machines. This
standalone will not run at all under PowerPC.
Application Icon
Document Icon
580
PLIST enter
information and
have LiveCode
write the PLIST
Have LiveCode ll out the PLIST for your application automatically. The
PLIST is a settings le stored in XML format stored as part of every Mac
OS X application. It contains information about the application, including
its name, version number, copyright notice and document associations.
Having LiveCode create this le for you is the recommended option. For
more information about PLISTs consult Apple's developer documentation
Choose a le to
import into the
application
bundle
Short version /
long version
The visible text displayed in your application's Get Info window by the
Finder.
Copyright notice
Bundle identier
Build for
Windows
Application
icon
Document
icon
Version
information
UAC
Execution
Level
Select the user account control level that applies to your application. For
more information, consult MSDN
Build
for
Linux
Build
for
Linux
x64
582
Build
for
Linux
ARMv6HF
Include
Select built-in LiveCode dialogs to include. These dialogs are useful if your
application may be run on a system that does not include these dialogs as part of
the OS. You do not need to include these dialogs if you are running a recent
version of GTK.
Include
Error
Reporting
Dialog
Include an error reporting stack in your standalone. You should select this option
if you are testing your application and want details of any errors in your
standalone, or if you have not included your own error reporting routines in your
stacks.
htmlText
for dialog
The text to display to the user in the dialog that comes up when an error is
encountered. This text should be in LiveCode-compatible HTML format. Create
and format the text in a LiveCode eld then copy the eld's HTMLText property.
Dialog
icon
The icon to display in the error dialog. This should be stored as an image in your
stack.
Allow user
to enter
comments
Display a box for the user to give you more information. This information will be
included in the report.
583
Allow user
to save
report to
le
Allow the user to save the report to a le. Select this option if you want users to
save an error report and send it to you.
Allow user
to email
report
Allow the user to email the report. Select this option if you want the user to be
able to send you or your technical support department details of the error. This
option loads up the system default email client and populates the email with
the contents of the error report and the user's comments. The To: eld is sent
to the email address specied in the email address eld.
584
HTML5 Deployment
Introduction
Note: This is an experimental release of HTML5 deployment support and is not
recommended for production use.
Almost every Internet-connected device has a web browser. If your application can run in a
browser, your app can be used anywhere and by anyone, without any need to download or install
it.
With LiveCode 8's HTML5 deployment capability, you can now run applications written in LiveCode
in any web browser that supports JavaScript and HTML5.
Supported browsers
Only a limited range of browsers are supported for HTML5 deployment in this release of LiveCode.
Mozilla Firefox 40.0 (or newer)
Google Chrome 44 (or newer)
Safari for Mac (latest version)
We hope to broaden the range of supported browsers in the future.
This will let you access your standalone by opening your web browser and visiting
http://localhost:8080.
Reporting bugs
Please report bugs to the LiveCode Quality Centre. Make sure to select "HTML5 Standalone" when
you're creating your bug report!
586
The canvas
The engine renders into a HTML5 <canvas> element. There are three important considerations
when creating the canvas:
the canvas must have absolutely no border, or mouse coordinate calculations will be
incorrect
it will be automatically resized by the engine to match the size of your stack, so don't
attempt to set its size using HTML or CSS
it needs to be easily uniquely identiable, so that the engine can nd it.
587
The absolute minimum canvas element would look something like this:
<canvas style="border: 0px none;" id="canvas"
oncontextmenu="event.preventDefault();"></canvas>
By default, most web browsers will indicate when the canvas has focus by displaying a highlighted
outline. This helps users identify which part of the web page is capturing their key presses. You can
usually disable this outline by adding outline: none; to the canvas's CSS styles.
<script type="text/javascript">
var Module = {
canvas: document.getElementById('canvas'),
};
</script>
Engine download
The engine is quite a large JavaScript le, so it's downloaded asynchronously in order to let the
rest of the page nish loading and start being displayed.
Quite straightforwardly:
<script async type="text/javascript" src="standalone-<version>.js"></script>
588
<html>
<body>
<canvas style="border: 0px none;" id="canvas"
oncontextmenu="event.preventDefault()"></canvas>
<script type="text/javascript">
var Module = { canvas: document.getElementById('canvas') };
</script>
<script async type="text/javascript" src="standalone-community.js">
</script>
</body>
</html>
589
Mac Deployment
Introduction
LiveCode 8.0 DP15 introduced the ability to build 64-bit standalones for MacOSX after a successful
sponsorship campaign on the LiveCode Feature Exchange.
The IDE
The LiveCode IDE runs in 32-bit mode by default for maximum compatibility. If you'd like to run it in
64-bit mode, right-click on the app bundle, select "Get Info" and deselect the "Open in 32-bit
mode" option. In future, we will add a menu item in the IDE that re-launches the IDE in either 32bit or 64-bit mode, as appropriate.
Testing
If you have built a 32-bit only or 64-bit only standalone, the app will always run in that mode. If you
have a Universal standalone containing both, you can force the app to run in 32-bit mode on 64bit machines by right-clicking the app bundle, selecting "Get Info" and then enabling the "Open in
32-bit mode" option.
Reporting bugs
Please report bugs to the LiveCode Quality Centre. Make sure you select the correct engine type
590
591
Extending LiveCode
Introduction
LiveCode 8.0 is the most exciting release in the history of the technology. It provides a simple way
to extend the functionality or control set of LiveCode.
Our focus in LiveCode 8.0 is extensibility. You can now build and share widgets (custom controls)
and libraries that are treated by LiveCode as engine level elements.
LiveCode 8.0 can be thought of as a version 7.0 with a new module allowing extensions to be
plugged into the engine. As a result, 8.0 should be as functional and stable as LiveCode 7.0.
This guide will take you through the process of installing and using these new widgets and libraries
and for the adventurous among you, provide a guide to building and sharing your own extensions.
Extension Builder
Open the "Extension Builder" from the tools menu:
Tools > Widget Builder
592
1. Select the extension you wish the develop or click the "open" icon in the header back to
593
2.
3.
4.
5.
6.
7.
8.
locate an extension you've not loaded before. All LiveCode authored widgets in the
application package at: /contents/extensions/. To play with one of these extensions we
recommend copying the folder from the application package to your desktop and loading it
from there. Changing the extension id in the source code will also mean it doesn't conict
with the existing extension.
Data that the builder was able to parse from the directory such as icons, resources, API's
the user guides.
Console: Shows status, error and log messages.
Test: Creates a stack, compiles the extensions and creates an instance.
Script: Opens the lcb script in an external default editor.
Insall: Installs the extension into the IDE
Uninstall: Uninstalls the extension from the IDE
Package: Creates a .lce package which can uploaded to the extension store. It is placed in
the extension directory
Note: A great way to get started is to tweak the script of one of our widgets
examples.
This is the unique identier by which your extension will be referred to by the LiveCode Engine.
Declare Meta Data
594
Next, provide meta data to help LiveCode display your product correctly in product and in the
online portal.
widget community.livecode.beaumont.pinkCircle
metadata title is "My Pink Circle"
metadata author is "Benjamin Beaumont"
metadata version is "1.0.0"
end widget
Importing libraries
The LiveCode builder syntax is broken down into modules. There are 3 classes of module:
Type
Description
Default
These modules are part of LiveCode builder and are included by default. Their
syntax is always available to you as a LiveCode developer.
Optional
These modules are created and distributed by LiveCode Ltd and must be imported
by the extension developer in order to make use of their syntax.
Custom
These modules are created and distributed through the online portal and must be
imported by the extension developer in order to make use of their syntax.
Type
Description
com.livecode.canvas
com.livecode.widget
Optional
com.livecode.engine
Optional
com.livecode.arithmetic
Default
com.livecode.array
Default
com.livecode.binary
Default
com.livecode.bitwise
Default
com.livecode.byte
Default
com.livecode.char
Default
com.livecode.codeunit
Default
com.livecode.date
Default
com.livecode.le
Default
com.livecode.foreign
Default
com.livecode.list
Default
com.livecode.logic
Default
com.livecode.mathfoundation Default
Module
Type
Description
com.livecode.math
Default
com.livecode.sort
Default
com.livecode.stream
Default
com.livecode.string
Default
com.livecode.system
Default
com.livecode.type
Default
com.livecode.typeconvert
Default
com.livecode.unittest
Default
Core Handlers
There are three core handlers that any widget developer should implement:
Handler
Description
OnPaint
OnCreate
OnGeometryChanged
OnSave
OnLoad
The OnLoad message is sent when your widget is created and enables
the widget to retrieve data saved on the widget.
596
For the most basic example, only the OnPaint() handler is required.
widget community.livecode.beaumont.pinkCircle
metadata title is "My Pink Circle"
metadata author is "Benjamin Beaumont"
metadata version is "1.0.0"
public handler OnPaint()
// Draw widget
end handler
end widget
widget community.livecode.beaumont.pinkCircle
metadata title is "My Pink Circle"
metadata author is "Benjamin Beaumont"
metadata version is "1.0.0"
use com.livecode.canvas
public handler OnPaint()
// Create a path with a radius of half the width of the canvas
// Set the paint to a solid pink color
// Fill the path
variable tCirclePath as Path
put circle path centered at point [my width / 2, my height / 2] with
radius (my width/2) into tCirclePath
set the paint of this canvas to solid paint with color [1, 0, 1]
fill tCirclePath on this canvas
end handler
end widget
597
Click test. Your widget should be displayed on the new stack. If you can't see it, check behind the
extension stack.
Properties
In order to make a widget useful to end users it is likely that you'll want to expose properties that
allow them to specify how your widget should behave.
To specify a property you must provide a name and the method to get and set the property.
property <name> get <variable/handler> set <variable/handler>
The simplest properties to get/set are numbers or strings. So lets create a circleMargin property
that allows users to dene a margin.
property circleMargin get mMargin set setMargin
In the above example, when the circleMargin property is requested, the variable "mMargin" is
returned, when set, the handler "setMargin" is called. To have LiveCode Builder handle the
getting/setting of data, provide the variable name, to take full control over the getting/setting
process dene handlers. In our case we're taking a mixed approach.
private variable mMargin as Real
We'll dene a member variable to store the value for the margin. LiveCode Builder is typed so you
598
must also specify the type of your variable. Remember, the canvas you are drawing to has
subpixel precision so our margin can be a decimal number. As a result, we've chosen to specify
our margin as a real number. For a full list of types available in LiveCode Builder please see the
Typing section of the language specication guide below. We also suggest a naming convention for
variables in the section on variable and case sensitivity.
We also need to insatiate our circleMargin to a default value. We do this by adding an onCreate
handler which is called when the widget is rst created.
public handler setMargin(in pMargin as Real)
put pMargin into mMargin
redraw all
end handler
Implementing the "setter" ourselves provides us with a little more exibility. In this case when the
property is set we want our pink circle to immediately redraw to reect the property change. We
do this by calling "redraw all".
To test the property click "test" and from the message box set the property.
set the cicleMargin of widget 1 to 15
Full Example
599
widget community.livecode.beaumont.pinkCircle
metadata title is "My Pink Circle"
metadata author is "Benjamin Beaumont"
metadata version is "1.0.0"
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
// Properties
property circleMargin get mMargin set setMargin
// Local variables
private variable mMargin as Real
public handler onCreate()
put 0 into mMargin
end handler
public handler OnPaint()
// Create a path with a radius of half the width of the canvas
// Set the paint to a solid pink color
// Fill the path
variable tCirclePath as Path
put circle path centered at point [my width / 2, my height / 2] with
radius ((my width - mMargin)/2) into tCirclePath
set the paint of this canvas to solid paint with color [1, 0, 1]
fill tCirclePath on this canvas
end handler
public handler setMargin(in pMargin as Real)
put pMargin into mMargin
redraw all
end handler
end widget
600
This same array will be returned to you when the widget is next opened.
public handler OnLoad(in pProperties as Array)
put pProperties["margin"] into mMargin
end handler
601
1.
2.
3.
4.
Creating Libraries
A extension library is written in much the same way as the above widget. The only dierence is
that all the public handlers implemented are loaded into the engine on startup.
602
Composed Widgets
Widgets can either be 'host' widgets, as in the previous example, created when a widget is directly
embedded in a stack, or 'child' widgets which are created when a widget is used as a child widget
within another widget. The syntax for composed widgets is included in the com.livecode.widget
module.
A simple composed widget
This composed widget example composes the clock widget and the selector widget, to create a
version of the clock widget with adjustable time zone.
The label at the top of the widget reects which portion of the widget the mouse is over.
603
widget com.livecode.extensions.example.simplecomposed
use com.livecode.canvas
use com.livecode.widget
metadata title is "Simple Composed Widget"
metadata author is "LiveCode"
metadata version is "1.0.0"
private variable mInsideChild as String
private variable mInside as Boolean
private variable mSelector as Widget
private variable mClock as Widget
public handler OnCreate()
put false into mInside
put the empty string into mInsideChild
put a new widget "com.livecode.extensions.livecode.selector" into
mSelector
set property "numSelections" of mSelector to 6
set annotation "Name" of mSelector to "Selector"
put a new widget "com.livecode.extensions.livecode.clock" into mClock
set annotation "Name" of mClock to "Clock"
place mSelector
place mClock
end handler
Notice that Widget is a variable type. This widget stores references to its child widgets in private
variables. In the OnCreate handler, the widget objects are created, stored in the private variables
and 'placed'. Child widgets can be stored as variables and manipulated without actually being
drawn to a canvas if they are unplaced. Properties implemented by child widgets can be got and
set using the property <propName> of <child widget> syntax. Placing a widget ensures
that they are drawn, in placement order. Setting an annotation of a child widget assigns it a tag so
that when an unknown child widget is returned by an operator, its annotation can be used to
identify it.
604
The rectangle of each child widget is controlled using the following syntax:
the rectangle of <widget> - Enables manipulation of the rectangle property of a child
widget.
605
the width of <widget> - Enables manipulation of the width property of a child widget.
the height of <widget> - Enables manipulation of the height property of a child widget.
the location of <widget> - Enables manipulation of the location property of a child
widget.
Finally, messages posted by child widgets can be handled in the direct parent by handling the
appropriate message (prepending 'On'). For example, the selector widget posts optionChanged
when one of its numbers is selected. This is handled by this composed widget example in an
OnOptionChanged handler.
public handler OnOptionChanged(in pIndex)
set property "timeZone" of mClock to pIndex - 1
end handler
606
607
To add an entry to the API for this handler, place a formatted comment above the handler
denition:
608
/*
summary: Use this handler to do an action
pString: This parameter does x
pNumber: This parameter does y
description:
# Markdown Title
Here is a full description in markdown for how this function works. Once
again, any GitHub
flavoured markdown is accepted.
*/
public handler myHandler(in pString as String, in pNumber as Number)
# Code
end handler
The LiveCode API parser will combine the comment items with other data pulled directly from your
handler denition such as name, type and some parameter details.
For a full list of acceptable documentation elements please see the LiveCode Documentation
Format guide.
Important: Documentation is only added to the LiveCode dictionary when a full
extension package is installed. Currently, this is only possible through the extension
builder.
Adding a User Guide
Any extension can include a user guide. To do so, add a markdown le called guide.md to your
widget folder alongside the other widget les.
All GitHub avoured markdown is accepted.
Packaging Extensions
Packaging extensions is easy. Simply open the "Extension Builder" stack:
Tools > Extension Builder
Load your .lcb le and click "Build Package". A new le will appears in the same directory as your
main le with the extension .lce. This is your nal package le ready for upload to the extensions
portal.
Package requirements
A valid package can be built from a minimum set of les:
widget.lcb // Widget source file
support/icon.png // 20x40 png image
support/[email protected] // 40x80 png image
609
On Windows systems you can prevent a terminal window from being displayed by setting the
hideConsoleWindows global property to true.
You can choose a dierent shell program by setting the shellPath global property. By default this
is set to "/bin/sh" on Mac OS X and Linux and "command.com" on Windows.
Tip: The shell function blocks LiveCode until it is completed. If you want to run a shell
command in the background, write the shell script to a text le then execute it with
the launch command.
Launching other applications
Use the launch command to launch other applications, documents or URLs. To launch an
application, supply the full path to the application. The following example opens a text document
with TextEdit on OS X:
launch "/Users/someuser/Desktop/text document.rtf" with
"/Applications/TextEdit.app"
Tip: To get the path to an application, use the answer file command to select the
application then copy it into your script. Run this in the message box:
answer file "Select an application"; put it
To open a document with the application it is associated with use the launch document
command.
610
To open a URL in the default web browser, use the launch URL command.
launch URL "http://www.livecode.com/"
For more information on launching URLs and details on how to render web pages within LiveCode,
see the Transferring Information guide.
Closing another application
Use the kill process command to send a signal to another application, to close it or to force it to
exit. For more details, see the LiveCode Dictionary.
Communicating with other processes
Use the open process command to open an application or process you want to read and write
data from. You can then read from the process with the read from process command and write
to it with the write to process command. To close a process you have opened, use the close
process command. The openProcesses returns a list of processes you have opened and the
openProcessIDs returns the process IDs of each one. For more details see the LiveCode
Dictionary.
Using AppleScript and VBScript (Open Scripting Architecture or Windows Scripting Host)
To execute commands using AppleScript on Mac OS or VBScript on Windows, use the do as
command. do as also allows you to use any other Open Scripting Architecture languages on Mac
OS or languages installed into the Windows Scripting Host on Windows. To retrieve a list of the
available installed languages, use the alternateLanguages.
For example, to execute an AppleScript that brings the Finder on OS X to the front, enter the
following into a eld:
To retrieve a result from commands executed using do as , use the result function. Any error
message will also be returned in the result . The following example displays the result of an
addition performed using VBScript:
do "result = 1 + 1" as "vbscript"
answer the result
To retrive additional information passed with the appleEvent use the request appleEvent data
command. The following example shows how you could handle a request to open a stack:
on appleEvent pClass, pID, pSender
--appleEvent sent when stack is opened from the finder
if pClass & pID is " aevtodoc " then
-- get the file path(s)
request AppleEvent data
put it into tFilesList
repeat for each line l in tFilesList
go stack l
end repeat
end if
end appleEvent
For more details see the LiveCode Dictionary.
Using Local sockets
If you want to communicate between local applications a common technique that can be used
without code changes on all the platforms LiveCode supports, is to open a local socket and
communicate using that. You should choose a port number that is not used by a standard
protocol typically a high number.
This technique is commonly used when you want to create multiple programs that run
independently but communicate with each other. It is a viable technique for running background
tasks and provides a straightforward way to create an application that behaves as if threaded
i.e. with benets of multiple threads. You can design your application such that additional
instances can be launched to perform processing, data transfer or other intensive activities.
Modern OSes will allocate each application to an appropriate processor core. By using socket
messaging to communicate with each one you can keep your main application's user interface
responsive and display status information. The following example shows you how to open a socket
to the local machine:
612
A detailed discussion of how to create a protocol using sockets can be found in the Transferring
Information guide.
Tip: To simplify communication between multiple LiveCode programs, consider
writing a simple library that sends and receives a handler name together with
parameter data. To call a handler in the other LiveCode program, send the handler
name and data to the library. The library will send the data over a socket. In the
receiving program intercept the incoming data from the socket and use it to call the
appropriate message with the parameter data received.
613
Operations
Jump
jump <label>
The jump operation sets the address of the next instruction to execute to that identied by .
Jump If False
jump_if_false <register>, <label>
Jump If True
jump_if_true <register>, <label>
Assign Constant
assign_constant <register>, <constant>
The assign_constant operation copies into . Here can be the nothing literal, the true or false
literal, an integer literal, a real literal, a string literal, a list literal or array literal.
614
If is typed then it is a runtime error if the type of does not conform to that type.
Assign
assign <dst-register>, <src-register>
Return
return [ <result-reg> ]
The return operation exits the current handler, returning to the instruction after the invoke
operation which created it. If present, the value in is copied as the return value. If not present then
the return value will be 'nothing'. Additionally any values in out or inout parameters are copied
back to the caller.
If is not present, then the return value will be 'nothing'.
It is a runtime error if the type of the return value does not conform to the return type of the
current handler's signature.
It is a runtime error if any out or inout parameters are unassigned at the point of return.
Invoke
invoke <handler>, <result-reg>, <arg1-reg>, ..., <argn-reg>
The invoke operation creates a new frame copying values from the argument registers for any in
or inout parameters. It then starts executing the bytecode attached to , a denition. The return
value is placed into the register .
If is a runtime error if the number of arguments provided is dierent from the signature of
If it a runtime error if for in and inout parameters, the contents of does not conform to the type of
the parameter required by the signature.
Invoke Indirect
invoke <handler-reg>, <result-reg>, <arg1-reg>, ..., <argn-reg>
The invoke indirect operation functions identically to the invoke operation except that it calls the
handler in .
It is a runtime error if does not contain a handler value.
Fetch
615
Store
store <src-register>, <definition>
Assign List
assign_list <dst-reg>, <element1-reg>, ..., <elementn-reg>
Assign Array
assign_array <dst-reg>, <key1-reg>, <value1-reg>, ..., <keyn-reg>, <valuenreg>
The assign_array operation builds an array value from each key value pair
, up to , .
It is a runtime error if the type of does not conform to array.
Reset
reset <reg>
616
Tokens
The structure of tokens is similar to LiveCode Script, but again a little stricter. The regular
expressions describing the tokens are as follows:
Identier: [A-Za-z][A-Za-z0-9.]*
Integer: [0-9]+
Real: [0-9]+"."[0-9]+([eE][-+]?[0-9]+)?
String: "[^\n\r"]*"
Separator: Any whitespace containing at least one newline
Strings use backslash ('\') as an escape - the following are understood:
\n: LF (ASCII 10)
\r: CR (ASCII 13)
\t: TAB (ASCII 9)
\q: quote '"'
**\u{X...X}: character with unicode codepoint U+X...X - any number of nibbles may be
specied, but any values greater than 0x10FFFF will be replaced by U+FFFD.
\: backslash '\'
Note: The presence of '.' in identiers are used as a namespace scope delimiter.
Note: Source les are presumed to be in UTF-8 encoding.
Comments
617
Comments
LiveCode Builder supports single line comments, which begin with // or -- and extend to the
end of the line. There are also block comments, which begin with /* and end with */ , and can
span multiple lines.
Single-line comment: (--|//)[^\n\r]*
Block comment: /*(^*?)\/
Note: A block comment that spans multiple lines terminates the line of code that it
begins on.
Line continuation
A LiveCode builder statement or declaration can be continued onto multiple lines of code by
placing the line continuation character \ at the end each line.
Line continuation: \(\n|\r\n|\r)
Note: A line continuation cannot occur within a comment.
Case-Sensitivity
At the moment, due to the nature of the parser being used, keywords are all case-sensitive and
reserved. The result of this is that, using all lower-case identiers for names of denitions should
be avoided. However, identiers are case-insensitive - so a variable with name pFoo can also be
referenced as PFOO, PfOO, pfoO etc.
Aside: The current parser and syntax rules for LiveCode Builder are constructed at
build-time of the LiveCode Builder compiler and uses bison (a standard parser
generator tool) to build the parser. Unfortunately, this means that any keywords have
to be reserved as the parser cannot distinguish the use of an identier in context
(whether it is a keyword at a particular point, or a name of a denition).
It is highly recommended that the following naming conventions be used for identiers:
tVar - for local variables
pVar - for in parameterns
rVar - for out parameters
xVar - for inout parameters
mVar - for global variables in widgets
sVar - for global variables in libraries
kConstant - for constants
Use identiers starting with an uppercase letter for handler and type names.
By following this convention, there will not be any ambiguity between identiers and keywords. (All
keywords are all lower-case).
Note: When we have a better parsing technology we will be evaluating whether to
make keywords case-insensitive as well. At the very least, at that point, we expect to
be able to make all keywords unreserved.
618
Typing
LiveCode Builder is a typed language, although typing is completely optional in most places (the
only exception being in foreign handler declarations). If a type annotation is not specied it is
simply taken to be the most general type optional any (meaning any value, including nothing).
The range of core types is relatively small, comprising the following:
nothing: the single value nothing
Boolean: one of true or false
Integer: any integral numeric value (size limitations apply)
Real: any numeric value (size and accuracy limitations apply)
Number: any integer or real value
String: a sequence of UTF-16 code units
Data: a sequence of bytes
List: a sequence of any values
Array: a mapping from strings to values
any: a value of any type
Additionally, all types can be annotated with optional. An optional annotation means the value
may be the original type or nothing.
Note: The current compiler does not do type-checking; all type-checking happens at
runtime. However, this is being worked on so there will soon be a compiler which will
give you type errors at compile-time.
Modules
Module
: 'module' <Name: Identifier> SEPARATOR
{ ( Definition | Metadata | Import ) SEPARATOR }
'end' 'module'
The smallest compilable unit of LiveCode Builder is the module. Each module is uniquely named
using reverse DNS notation, and the names of modules are considered to live in a global
namespace.
A module is a collection of public and private denitions, including constants, variables, types and
handlers.
A module may depend on another module through import. An imported modules public
denitions become accessible to the importing module.
Note: For integration with the existing LiveCode system, there are two module
variants which may be used. Widgets (use 'widget' instead of 'module') and Libraries
(use 'library' instead of 'module'). A widget appears in LiveCode as a control, whilst a
library adds all its public handlers to the bottom of the message path.
Metadata
619
Metadata
: 'metadata' <Name: Identifier> 'is' <Value: String>
The metadata clauses allow a set of key-values to be encoded in the compiled module. These are
not used in compilation or execution, but may be used by the system loading and using the
module.
At the moment, the following keys are understood:
title: a human-readable name for the module
description: a simple description of the module's purpose
version: a string in the form X.Y.Z (with X, Y and Z integers) describing the modules version
author: the name of the author of the module
Note: The current metadata mechanism is unlikely to remain part of the language. It
is intended that it will be replaced by a package description le, which will allow
modules to be grouped together with other resources.
Imports
Import
: 'use' <Name: Identifier>
The use clauses allow a module to refer to another module by importing all the target module's
public denitions into its namespace.
The name of the module specied must be its full name, e.g. com.livecode.canvas.
A module may use any other module, as long as doing so does not cause a cycle in the
dependency graph.
Note: The current IDE and extension installation system does not yet implement
arbitrary dependencies - the only dependencies it understands are those which are
builtin to the system (e.g. com.livecode.canvas). However, you can still write and test
out modules with dependencies locally - they just cannot be uploaded to the
extensions portal.
Denitions
620
Definition
: ( 'public' | 'private'
| ( 'public' | 'private'
| ( 'public' | 'private'
| ( 'public' | 'private'
| ( 'public' | 'private'
| ( 'public' | 'private'
| PropertyDefinition
| EventDefinition
)
)
)
)
)
)
ConstantDefinition
TypeDefinition
HandlerTypeDefinition
VariableDefinition
HandlerDefinition
ForeignHandlerDefinition
Denitions are what are used to dene usable entities in the language. All denitions are named
using a unique identier (so you cannot have two denitions with the same name).
Denitions can be either public or private (the default is private
so there is no need to explicitly specify that). Public denitions are available when the
module is used by another module whereas private denitions can only be used within the
module.
Note: Properties and events are, by their nature, always public as they dene things
which only make sense to access from outside.
Note: When writing a library module, all public handlers are added to bottom of the
message path in LiveCode Script.
Constants
ConstantDefinition
: 'constant' <Name: Identifier> is <Value: Expression>
A constant denition denes a named constant. The value can be any expression which depends
on only on constant values to evaluate.
Note: Constants are not currently implemented, although the syntax is recognised.
Types
TypeDefinition
: 'type' <Name: Identifier> 'is' <TypeOf: Type>
A type denition denes an alias, it names the given type with the given Name, allowing the name
to be used instead of the type.
621
Type
: <Name: Identifier>
| 'optional' <Target: Type>
| 'any'
| 'nothing'
| 'Boolean'
| 'Integer'
| 'Real'
| 'Number'
| 'String'
| 'Data'
| 'Array'
| 'List'
| 'Pointer'
A type clause describes the kind of value which can be used in a variable or parameter.
If a type is an identier, then this is taken to be a named type dened in a type denition clause.
An optional type means the value can be either the specied type or nothing. Variables which are
of optional type are automatically initial zed to nothing.
The remaining types are as follows:
any: any value
Boolean: a boolean value, either the value true or false.
Integer: any integer number value
Real: any real number value
Number: any number value
String: a sequence of UTF-16 code units
Data: a sequence of bytes
Array: a map from string to any value (i.e. an associative array, just like in LiveCode Script)
List: a sequence of any value
nothing: a single value nothing (this is used to describe handlers with no return value - i.e.
void)
Pointer: a low-level pointer (this is used with foreign code interconnect and shouldn't be
generally used).
Note: Integer and Real are currently the same as Number.
Note: In a subsequent update you will be able to specify lists and arrays of xed
types. For example, List of String.
Note: In a subsequent update you will be able to dene record types (named
collections of values - like structs in C) and handler types (allowing dynamic handler
calls through a variable - like function pointers in C).
Handler Types
622
HandlerTypeDefinition
: [ 'foreign' ] 'handler' 'type' <Name: Identifier> '(' [ ParameterList ]
')' [ 'returns' <ReturnType: Type> ]
A handler type denition denes a type which can hold a handler. Variables of such types can hold
handlers (just like function pointers in C) which allows them to be called dynamically.
If the handler type is dened as foreign then automatic bridging to a C function pointer will occur
when the type appears as the type of a parameter in a foreign handler denition.
Note: Passing an LCB handler to a foreign function requires creation of a function
pointer. The lifetime of the function pointer is the same as the widget or module
which created it.
Variables
VariableDefinition
: 'variable' <Name: Identifier> [ 'as' <TypeOf: Type> ]
A variable denition denes a module-scope variable. In a widget module, such variables are perwidget (i.e. instance variables). In a library module, there is only a single instance (i.e. a private
global variable).
The type specication for the variable is optional, if it is not specied the type of the variable is
optional any meaning that it can hold any value, including being nothing.
Variables whose type has a default value are initialized to that value at the point of denition. The
default values for the standard types are:
optional: nothing
Boolean: false
Integer: 0
Real: 0.0
Number: 0
String: the empty string
Data: the empty data
Array: the empty array
List: the empty list
nothing: nothing
Variables whose type do not have a default value will remain unassigned and it is a checked
runtime error to fetch from such variables until they are assigned a value.
Handlers
HandlerDefinition
: [ 'unsafe' ] 'handler' <Name: Identifier> '(' [ ParameterList ] ')' [
'returns' <ReturnType: Type> ] SEPARATOR
{ Statement }
'end' 'handler'
623
Handler denitions are used to dene functions which can be called from LiveCode Builder code,
invoked as a result of events triggering in a widget module, or called from LiveCode Script if public
and inside a library module.
There is no distinction between handlers which return a value and ones which do not, apart from
the return type. Handlers can be called either in expression context, or in statement context. If a
handler which returns no value (it is specied as returns nothing) is called in expression context
then its value is nothing.
ParameterList
: { Parameter , ',' }
Parameter
: ( 'in' | 'out' | 'inout' ) <Name: Identifier> [ 'as' <ParamType: Type>
The parameter list describes the parameters which can be passed to the handler. Handlers must
be called with the correct number of parameters, using expressions which are appropriate to the
mode.
An in parameter means that the value from the caller is copied to the parameter variable in the
callee handler.
An out parameter means that no value is copied from the caller, and the value on exit of the
callee handler is copied back to the caller on return.
Note: It is a checked runtime error to return from a handler without ensuring all nonoptional 'out' parameters have been assigned a value. However, this will only occur
for typed variables whose type does not have a default value as those which do will
be default initialized at the start of the handler.
An inout parameter means that the value from the caller is copied to the parameter variable in
the callee handler on entry, and copied back out again on exit.
The type of parameter is optional, if no type is specied it is taken to be optional any meaning it
can be of any type.
Note: Only assignable expressions can be passed as arguments to inout or out
parameters. It is a checked compile-time error to pass a non-assignable expression
to such a parameter.
If 'unsafe' is specied for the handler, then the handler itself is considered to be unsafe, and may
only be called from other unsafe handlers or unsafe statement blocks.
Foreign Handlers
624
ForeignHandlerDefinition
: 'foreign' 'handler' <Name: Identifier> '(' [ ParameterList ] ')' [
'returns' <ReturnType: Type> ) ] 'binds' 'to' <Binding: String>
ForeignType
: Type
| 'CBool'
| 'CInt'
| 'CUInt'
| 'CFloat'
| 'CDouble'
625
inout mode passes a pointer to a variable of one of the above types, the variable is
initialized to a value on entry
If the return type is of a Ref type, then it must be a copy.
If an out parameter is of a Ref type, then it must be a copy (on exit)
If an inout parameter is of a Ref type, then its existing value must be released, and replaced by a
copy (on exit).
The binding string for foreign handlers has the following form:
[lang:][library>][class.]function[!calling]
Here lang species the language (must be 'c' at the moment)
Here library species the name of the library to bind to (if no library is specied a symbol from the
engine executable is assumed).
Here class is currently unused.
Here function species the name of the function symbol to bind to (on Windows, the symbol must
be unadorned, and so exported from the library by listing it in a DEF module).
Here calling species the calling convention which can be one of:
default
stdcall
thiscall
fastcall
cdecl
pascal
register
All but 'default' are Win32-only, and on Win32 'default' maps to 'cdecl'. If a Win32-only calling
convention is specied on a non-Windows platform then it is taken to be 'default'.
Foreign handler's bound symbols are resolved on rst use and an error is thrown if the symbol
cannot be found.
Foreign handlers are always considered unsafe, and thus may only be called from unsafe context
- i.e. from within an unsafe handler, or unsafe statement block.
Note: The current foreign handler denition is an initial version, mainly existing to
allow binding to implementation of the syntax present in the standard language
modules. It will be expanded and improved in a subsequent version to make it very
easy to import and use functions (and types) from other languages including
Objective-C (on Mac and iOS) and Java (on Android).
Properties
626
PropertyDefinition
: 'property' <Name: Identifier> 'get' <Getter: Identifier> [ 'set' <Setter:
Identifier> ]
Property denitions can only appear in widget modules. They dene a property which can be
accessed from LiveCode Script in the usual way (e.g. the myProperty of widget 1).
Both getter and setter clauses can use either a variable or handler identier. If a variable identier
is used, then the property value is fetched (and stored) from that variable. If a handler identier is
used then a handler is called instead.
A getter handler must take no arguments and return a value. A setter handler must take a single
argument and return no value.
The set clause is optional. If it is not present then the property is read-only.
Events
EventDefinition
: 'event' <Name: Identifier> '(' [ ParameterList ] ')' [ 'as' <ReturnType:
Type> ]
Event denitions dene a callable handler which calls back to the environment.
Note: Whilst events can be dened they currently cannot be used. To send a
message to the LiveCode Script environment use the dispatch command which
allows sending messages to arbitrary LiveCode Script objects.
Statements
Statement
: VariableStatement
| IfStatement
| RepeatStatement
| ThrowStatement
| ReturnStatement
| PutStatement
| SetStatement
| GetStatement
| CallStatement
| BytecodeStatement
| UnsafeStatement
There are a number of built-in statements which dene control ow, variables, and basic variable
transfer. The remaining syntax for statement is dened in auxiliary modules.
Variable Statements
627
VariableStatement
: 'variable' <Name: Identifier> [ 'as' <TypeOf: Type> ]
A variable statement denes a handler-scope variable. Such variables can be used after the
variable statement and up to the end of the current statement block, but not before.
Variables whose type have a default value are initialized with that value at the point of denition in
the handler. See the main Variables section for the defaults of the standard types.
Note: It is a checked runtime error to attempt to use a variable whose type has no
default before it is assigned a value.
The type specication for the variable is optional, if it is not specied the type of the variable is
optional any meaning that it can hold any value, including being nothing.
If Statements
IfStatement
: 'if' <Condition: Expression> 'then' SEPARATOR
{ Statement }
[ { 'else' 'if' <Condition: Expression> 'then' SEPARATOR
{ Statement } ]
[ 'else' SEPARATOR
{ Statement } ]
'end' 'if'
The if statement enables conditional execution based on the result of an expression which
evaluates to a boolean.
Each block of code in an if/else if/else statement denes a unique scope for handler-local variable
denitions.
Note: It is a checked runtime error to use an expression which does not evaluate to
a boolean in any condition expression.
Repeat Statements
628
RepeatStatement
: RepeatHeader SEPARATOR
{ Statement }
'end' 'repeat'
| 'next' 'repeat'
| 'exit' 'repeat'
RepeatHeader
: 'repeat' 'forever'
| 'repeat' <Count: Expression> 'times'
| 'repeat' 'while' <Condition: Expression>
| 'repeat' 'until' <Condition: Expression>
| 'repeat' 'with' <Counter: Identifier> 'from' <Start: Expression> ( 'up' |
'down' ) 'to' <Finish: Expression> [ 'by' <Step: Expression> ]
| 'repeat' 'for' 'each' <Iterator> 'in' <Container: Expression>
629
The next repeat statement terminates the current iteration of the enclosing loop and starts the
next iteration of the loop, or exits if currently on the last iteration.
The exit repeat statement terminates the current iteration of the enclosing loop, continuing
execution at the statement after the enclosing loop's end repeat.
Throw Statements
ThrowStatement
: 'throw' <Error: Expression>
The throw statement causes an error to be raised. This causes execution to terminate, and the
error is passed back to environment.
The Error expression must be an expression that evaluates to a string.
Note: There is currently no try / catch mechanism in LiveCode Builder, so throwing
an error will cause the error to be raised in LiveCode Script in the appropriate
context.
Return Statements
ReturnStatement
: 'return' [ <Value: Expression> ]
The return statement causes execution of the current handler to end, and control return to the
caller.
If a Value expression is specied, it is evaluated and returned as the result of the handler call.
Note: It is a checked runtime error for a value returned from a handler to not match
the return type of the handler it is in.
Transfer Statements
PutStatement
: 'put' <Value: Expression> into <Target: Expression>
SetStatement
: 'set' <Target: Expression> 'to' <Value: Expression>
The put and set statements evaluate the Value expression and assign the resulting value to the
Target expression.
The target expression must be assignable.
630
Note: It is a checked runtime error for the source value's type to not be compatible
with the target expression's type.
GetStatement
: 'get' <Value: Expression>
The get statement evaluates the Value expression and returns it as the result of the statement.
The value is subsequently available by using the result expression.
Call Statements
CallStatement
: <Handler: Identifier> '(' [ <Arguments: ExpressionList> ] ')'
Bytecode Statements
BytecodeStatement
: 'bytecode' SEPARATOR
{ BytecodeOperation }
'end'
BytecodeOperation
: <Label: Identifier> ':'
| 'register' <Name: Identifier> [ 'as' <Type: Type> ]
| <Opcode: Identifier> { BytecodeArgument , ',' }
BytecodeArgument
: ConstantValueExpression
| Identifier
631
The bytecode statement allows bytecode to be written directly for the LiveCode Builder Virtual
Machine.
Bytecode operation arguments can either be a constant expression, the name of a denition in
current scope, the name of a register, or the name of a label in the current bytecode block. The
exact opcodes and allowed arguments are dened in the LiveCode Builder Bytecode Reference.
Labels are local to the current bytecode block, and can be used as the target of one of the jump
instructions.
Register denitions dene a named register which is local to the current bytecode block. Registers
are the same as handler-local variables except that they do not undergo default initialization.
Bytecode statements are considered to be unsafe and can only appear inside unsafe handlers or
unsafe statement blocks.
Note: Bytecode blocks are not intended for general use and the actual available
operations are subject to change.
Unsafe Statements
UnsafeStatement
: 'unsafe' SEPARATOR
{ Statement }
'end' 'unsafe'
The unsafe statement allows a block of unsafe code to be written in a safe context.
In particular, calls to unsafe handlers (including all foreign handlers) and bytecode blocks are
allowed in unsafe statement blocks but nowhere else.
Expressions
Expression
: ConstantValueExpression
| VariableExpression
| ResultExpression
| ListExpression
| ArrayExpression
| CallExpression
There are a number of expressions which are built-in and allow constant values, access to call
results, list construction and calls. The remaining syntax for expressions is dened in auxiliary
modules.
632
ConstantValueExpression
: 'nothing'
| 'true'
| 'false'
| INTEGER
| REAL
| STRING
Variable Expressions
VariableExpression
: <Name: Identifier>
Result Expressions
ResultExpression
: 'the' 'result'
The result expression evaluates to the return value of the previous (executed) non-control
structure statement.
Result expressions are not assignable.
List Expressions
ListExpression
: '[' [ <Elements: ExpressionList> ] ']'
A list expression evaluates all the elements in the expression list from left to right and constructs
a list value with them as elements.
The elements list is optional, so the empty list can be specied as [].
633
Array Expressions
ArrayExpression
: '{' [ <Contents: ArrayDatumList> ] '}'
ArrayDatumList
: <Head: ArrayDatum> [ ',' <Tail: ArrayDatumList> ]
ArrayDatum
: <Key: Expression> ':' <Value: Expression>
An array expression evaluates all of the key and value expressions from left to right, and
constructs an Array value as appropriate. Each key expression must evaluate to a String.
The contents are optional, so the empty array can be written as {} .
Array expressions are not assignable.
Call Expressions
CallExpression
: <Handler: Identifier> '(' [ <Arguments: ExpressionList> ] ')'
634
Copyright headers
Please include a license header at the top of the .lcb le.
For the main LiveCode repository, or for any community extensions, the license is the GNU
General Public License v3 without the "any later version" clause.
Naming
Module name
The module name uses reverse DNS notation. For example, a module created by the Example
Organisation would use module names beginning with org.example .
Replace any hyphen ( - ) characters in a domain name with underscore ( _ ) characters. For
example, a module derived from the fizz-buzz.example.org domain could be
org.example.fizz_buzz .
Additionally, add an underscore ( _ ) to the start of any element in the domain name starting with
a digit. For example, a module derived from the 999.example.org domain could be
org.example._999 .
You must only use module names corresponding to domain names that you control or are allowed
to use. This restriction is enforced by the the LiveCode extension store.
If you don't have a domain name of your own, you may use module names beginning with
community.livecode.<username> , replacing <username> with the username you use to log
into the LiveCode extension store. For example, if your username is "sophie", then you can create
a module named community.livecode.sophie.mymodule .
For the main LiveCode repository, please use module names beginning with com.livecode
Always write module names in lower case.
Prex
Context
Meaning
all
constant
module
static variable
widget
static variable
handler denitions
in argument
handler denitions
out argument
handler denitions
inout argument
handler bodies
local variable
In general, please use nouns to name your variables and parameters. Make the names
descriptive; for example:
variable tOutputPath as String
variable tString as String
-- Good
-- Bad
For Boolean variables, please try to use "yes or no" names. For example:
Naming handlers
Give handlers TitleCase names.
In general, please use verbs to name your handlers. For example,
handler RotateShape(inout xShape, in pAngleInDegrees)
-- ...
end handler
Named constants
636
Often, it is useful to use constant values in your code. Please declare named constants rather
than placing the values in-line. For example, you may want to create three tabs labelled "Things",
"Stu", and "Misc":
constant kTabNames is ["Things", "Stuff", "Misc"]
handler CreateTabs()
variable tName
repeat for each element tName in kTabNames
-- Create the tab
end repeat
end handler
Whitespace
Indentation
Please indent with tab characters. Please use one tab character per level of indentation.
Please do not use a level of indentation at module level.
Comments should be indented to the same level as the code they apply to.
For example:
module org.example.indent
-- Example handler
handler Fizzbuzz(in pIsFizz)
if pIsFizz then
return "Fizz"
else
-- Maybe this should have a capital letter
return "buzz"
end if
end handler
end module
If it's necessary to mix spaces and tabs for indentation, please use 4 spaces per tab.
637
-- Good
-- Bad
In handler parameter lists, please add a space between each parameter. For example:
handler FormatAsString(in pValue, out rFormat) -- Good
handler IsEqualTo(in pLeft,in pRight)
-- Bad
638
-- Good
-- Bad
Format
Documentation for a LiveCode API or documentation entry consists of a series of elements and
their values, in the following form:
elementName : content
There are several standard types of content; which one may be used depends on the
elementName.
Element names
Elements are optional unless otherwise specied.
Name (required)
The name of the API entry. The name must be a single word.
command
function
property
message
constant
keyword
control structure
operator
statement
expression
(Glossary-level)
639
*
*
*
*
library
widget
glossary
object
The glossary-level entries have part of their content generated from the API-level entries.
For example, the syntax for the rst variant of the split command:
answer file[s] <prompt> [with <defaultPath>] [with type <types> [or type
<types> ...]] [titled <windowTitle>] [as sheet]
640
Note: For inline docs, the Syntax elements are automatically generated
Summary (required)
A summary of the API entry being documented. The summary should be a single line. Anything
more in-depth should be included in the description.
Associated
A comma-delimited list of names of other API or docs entries. Each one must be of type object,
glossary, library, or widget. It is used to generate the docs for the entries to which it is
associated.
In particular, every API entry in a library should have that library name in its Associated list.
Introduced
The LiveCode version in which the API entry was rst available.
OS
A comma-delimited list specifying which operating systems the API entry is available for. One or
more of the following:
mac
windows
linux
iOS
android
RPi
html5
Platforms
A comma-delimited list specifying which platforms the API entry is available for. One or more of
the following:
desktop
server
web
mobile
Example
Example elements should show how API entries are used in context. Each example will be
displayed in the documentation viewer as a multiline code block. Where possible, an example
should be entirely self contained, so that it is runnable as a block of code without any additions.
An API entry can have any number of Example elements.
Parameters
The parameters element itself does not do anything, but can be helpful for readability as a
641
precursor to the parameter elements themselves. Parameter elements are specied in the
following way: paramName (paramType) : paramDescription
The param type is optional, although may be helpful to include, and is required for further
formatting of parameter descriptions to take place. The three types that will instigate further
formatting are:
enum
set
array
A parameter of enum type is one that expects one of a specied list of values. Similarly, a
parameter of set type is one that expects a comma-delimited list of one or more of a specied
list of values. After the param description of the enum or set type, these values should be listed
in the following way
- value1 : description of value1
- value2 : description of value2
- ...
etc.
After the description parameter of array type, the format of the array may optionally be specied
in the following way:
{
key1 (keyType) : description of key1
value1 (valueType) : description of value1
key2 (keyType) : description of key2
value2 (valueType) : description of value2
...
}
The key type and value type are optional. If one of the values is a sub-array, and the array type is
specied, then the array specication may be nested as follows:
{
key1 (keyType) : description of key1
value1 (array) : description of value1
{
key2 (keyType) : description of key2
value2 (valueType) : description of value2
...
}
...
}
This will also link correctly to <other|other's> API entry, but display as "other's" in the
documentation viewer.
If the target name is shared by two references, then the link should be disambiguated by including
the type in brackets:
We might want to link to the <other(function)> function and the <other(command)>
command in the same entry, if the references contain "other (function)" and "other
(command)".
It is possible to do both of the above at the same time:
This sentence contains links to <other(function)|other's> and
<other(command)|other's> dictionary entries.
Inline documentation
Documentation for LiveCode script and LiveCode extensions can be done in-line. In this case, the
Name, Type, Syntax and Associated elements are auto-generated.
The code-block enclosed in / / immediately preceding the handler or syntax denition is used for
the other elements of the documentation for that entry. In LiveCode extensions, the types of
parameters are also pulled from the associated handler.
Library example
646
Module: com.livecode.sort
Type: library
Description: This library consists of the sorting operations provided by the
standard library of LiveCode Builder
Name: SortListDescendingText
Type: statement
Syntax: sort <Target> in descending [text] order
Tags: Sorting
Name: SortListAscendingText
Type: statement
Syntax: sort <Target> in ascending [text] order
Inline examples
In general, writing inline docs has fewer requirements since several of the elements are autogenerated.
647
/*
This library consists of the operations on lists included in the standard
library of LiveCode Builder.
*/
module com.livecode.list
/*
Summary:
Target:
output:
Example:
variable tVar as List
put the empty list into tVar
push "first element" onto tVar
variable tResult as Boolean
if the head of tVar is "first element" then
put "success" into tResult
end if
Description:
Returns the first element of the list <Target> without modifying <Target>.
\`\`\`
the head of tVar\`\`\`
is equivalent to using the <IndexedElementOfList> operator with index -1,
\`\`\`
tVar[1]\`\`\`
References: IndexedElementOfList(operator)
Tags: Lists
*/
syntax HeadOfList is prefix operator with precedence 1
"the" "head" "of" <Target: Expression>
begin
MCListEvalHeadOf(Target, output)
end syntax
end module
648
/*
Summary: Logs the result of a test to the <xResults> list
Parameters:
pModule: The name of the module this test comes from.
pTest: The name of the test.
pResult: The result of the test
xResults: The ongoing list of test results
Description:
Pushes either the string "SUCCESS : <pModule>_<pTest>" or the string "FAILURE
: <pModule>_<pTest>" onto the results list,
depending on the value of <pResult>
*/
public handler testLog(in pModule as String, in pTest as String, in pResult
as Boolean, inout xResults as List)
variable tStringResult as String
if pResult then
put "SUCCESS" into tStringResult
else
put "FAILURE" into tStringResult
end if
push tStringResult && ":" && pModule & "_" & pTest onto xResults
end handler
649
/*
Summary: Extracts the inline docs from a .lcb file
pFile: The path to the .lcb file to extract docs from
Returns (string): A string consisting of all the docs for the library, and
the syntax and handlers present in the .lcb file
Description:
<revDocsGenerateDocsFileFromModularFile> is used when packaging a widget to
create its API documentation.
It generates the Library and Type elements from the declaration in the
<pFile> (either widget or library), and extracts
the comment block that precedes any initial declaration for use as the
library-level Description element.
It then extracts the comment blocks that precede syntax and handler
definitions in <pFile>, and generates the
Name, Type, Syntax, and Associated elements for each entry, as well as the
parameter types.
Tags: Package building
*/
function revDocsGenerateDocsFileFromModularFile pFile
...
end revDocsGenerateDocsFileFromModularFile
650