SlideShare une entreprise Scribd logo
1  sur  283
Télécharger pour lire hors ligne
#LiveCodeGlobal
Widget Course
Extending LiveCode with Widgets and Libraries
LiveCode
Dev Team
#LiveCodeGlobal
Hello World Library
#LiveCodeGlobal
LiveCode Builder Extensions
In this lesson we will create a minimal LiveCode Builder library
which extends the set of commands and functions available in
LiveCode.
We will
● Install and configure an appropriate text editor for developing in
LiveCode Builder.
● Create a Hello World library which extends LiveCode with a
single function, which returns the string “Hello World!”.
● Compile the library.
● Install the library into the LiveCode IDE.
● Include the library in a standalone.
#LiveCodeGlobal
Libraries and Widgets
There are two types of extensions that can be created with LiveCode Builder:
● Libraries: A library can be used to extend the set of commands and
functions available in LiveCode. The public handlers in a library are
added at the bottom of the Message Path. LCB libraries make LCB
features available to LiveCode apps directly. They can also be used as
support code for widgets.
● Widgets: A widget is a custom control that is treated as an engine level
element. Widgets appear in the Tools Palette and can be added as
controls to any LiveCode stack.
A widget and a library are identical, except that a widget draws to a canvas.
As a result, the authoring process is much the same for both extension types.
#LiveCodeGlobal
When to use LiveCode Builder
Write widgets when:
● You need unique capabilities that can't be provided by
"traditional" controls.
● You require encapsulation - widgets are 'black boxes' whose
behavior can only be changed from LiveCode apps via
predefined API.
● You want access to drawing / low-level / native APIs.
● You want improved performance, you control what
recalculations are made when a control is redrawn.
#LiveCodeGlobal
When to use LiveCode Builder
Write libraries when:
● You want to write functions that are available to both LiveCode
Builder(LBC) and LiveCode Script(LCS).
● You want to wrap platform-specific functionality and make it
usable from LiveCode Script.
● You want to use LiveCode Builder's stricter rules to implement
algorithms that can't be expressed reliably in LiveCode Script.
#LiveCodeGlobal
The Message Path
LiveCode Engine
LiveCode Builder Libraries
Stack
Card
Group
Grouped Control Control
Input Events
(mouseUp, keyDown, etc.)
Other Events
(openCard, closeStack, etc.)
Handlers
implemented in
installed libraries are
placed at the end of
the Message Path.
For more on the
Message Path see
the “Message Path”
Chapter of the
LiveCode User
Guide.
#LiveCodeGlobal
Installed widgets are shown in the widgets section of the Tools Palette.
Widgets are added to stacks by dragging and dropping from the Tools
Palette.
Tools Palette showing installed widgets
Rotated Text Widget
Pie Chart Widget
#LiveCodeGlobal
LiveCode Builder API
The API for LiveCode Builder is
available in the Dictionary
stack. You may find it useful to
have this open while you are
writing your extension.
1. Open the Dictionary from
the Menubar.
2. Ensure you are on the API
pane.
3. Select LiveCode Builder
from the drop down menu.
#LiveCodeGlobal
LiveCode Builder extensions are written in a text editor rather than
the LiveCode IDE.
We recommend using the Atom text editor. A LiveCode package is
available which provides some colorization as well as indentation.
If you are on Mac and prefer to use TextWrangler, there is a
colorizing script here. It should be placed in /Application
Support/TextWrangler/Language Modules/.
Installing a Text Editor
#LiveCodeGlobal
Installing the Atom LiveCode Language Pack
To install the LiveCode
Language Pack in Atom
● Select File -> Preferences
to open the Atom Settings
● Go to the Install tab of the
Settings pane
● Search for the
“language-livecode”
package in the Search field
● Click Install
#LiveCodeGlobal
Creating a LiveCode Builder Library
Start by creating a new directory to
develop your extension in.
When you package an extension a
number of files are created. The
Extension Builder currently relies on
there being only one .lcb file in a
given directory. Because of this it is
simplest to create a new directory
for each extension you create.
The extension files that are created
include an API file, manifest and
compiled module file.
#LiveCodeGlobal
Creating a LiveCode Builder Library
Create a new plain text file in the
directory and save it to disk with the
extension ".lcb".
It’s important to use the “.lcb”
extension so your chosen text editor
applies LiveCode Builder formatting
to your code, if available.
I am naming my file
"helloWorldLibrary.lcb" but you can
name your file anything suitable.
#LiveCodeGlobal
LCB Library Definition
The first thing we need to do is declare
the type of extension we are writing.
We are writing a library and so we need
to declare the extension as such.
The library declaration is followed by an
identifier. An extension identifier should
be in the form
community.livecode.<user name>.<library
name>
In my case my username is "elanorb" and
I have chosen to use "helloworld" as the
name part of the identifier.
library community.livecode.elanorb.helloworld
end library
#LiveCodeGlobal
LCB module naming
The module name uses reverse DNS notation. For example, a module created by the
Example Organisation would use module names beginning with ‘org.example.’.
You must only use module names corresponding to domain names that you control or
are allowed to use.
If you don't have a domain name of your own, you may use module names beginning
with ‘community.livecode.’. For example, if your username is "sophie", then you can
create a module named ‘community.livecode.sophie.mymodule’.
Always write module names in lower case.
For more detailed information check the LiveCode Builder Style Guide. The guide is
available under the ‘Guide’ tab in the Dictionary or as a PDF under the ‘Resources’ tab
for this lesson.
#LiveCodeGlobal
LCB public handler definitions
Handler definitions are used to define functions which can be called from LCB code,
invoked as a result of events triggering in a widget module, or called from LCS 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.
Definitions can be either public or private (the default is private). Private handlers can
only used within the module. Public handlers are available when the module is used by
another module, for example public handlers can be called from LCS.
Handler definitions have the form
<HandlerType> handler <HandlerName>(<ParameterList>) [ returns <ReturnType> ]
end handler
#LiveCodeGlobal
Naming Handlers
It is best practice to give handlers TitleCase names.
In general, please use verbs to name your handlers. For example,
handler RotateShape(inout xShape, in pAngleInDegrees)
...
end handler
For more on this see the LiveCode Builder Language Reference
Guide in the Dictionary or Additional Course Resources.
#LiveCodeGlobal
The Hello World Library has one handler which
returns the string "Hello World!".
Add the definition for the sayHello handler to the
library.
Let's break down the definitions
● HandlerType - public: we want to be able
to call this handler from LCS so it needs
to be public
● HandlerName - SayHello: the name of the
handler, used to call the handler from LCS
● ParameterList - empty, no parameters are
passed in.
The SayHello handler
<HandlerType> handler <HandlerName>
(<ParameterList>) [ returns <ReturnType> ]
library community.livecode.elanorb.helloworld
public handler SayHello()
end handler
end library
#LiveCodeGlobal
To return a string value we can
return the string directly.
Add a return statement to the
sayHello handler.
Returning a string
library community.livecode.elanorb.helloworld
public handler SayHello()
return "Hello World!"
end handler
end library
#LiveCodeGlobal
Testing the library
Now we have a complete library
we want to compile and test it.
To do this we use the
LiveCode Extension Builder.
1. Open LiveCode.
2. Open the Extension
Builder from the Tools
Menu.
#LiveCodeGlobal
The Extension Builder
1. Open button - allows you to select and
load the extension you wish to build.
2. Data that the builder was able to parse
from the directory such as icons,
resources, API's the user guides.
3. Log: Shows status, error and log
messages.
4. Test Button: compiles the extension and
loads it into LiveCode
5. Script Button: Opens the lcb script in an
external default editor.
6. Install Button: Installs the extension into
the IDE
7. Uninstall Button: Uninstalls the extension
from the IDE
8. Package Button: Creates a .lce package
which can be shared
#LiveCodeGlobal
Compiling the Hello World Library
Initially we will use the Test button
to compile the library and test it
without installing.
1. Click the Open button and
select the
“HelloWorldLibrary.lcb” file.
2. The Icons, Resources, Default
Script, API and User Guide
sections are automatically
populated.
3. Click the Test button to
compile and load the library in
LiveCode.
#LiveCodeGlobal
Compiling the Hello World Library
The log field will give you
show the compilation progress
and display any warnings.
The Extension Builder will
create a test stack.
#LiveCodeGlobal
LiveCode Builder Extension Files
When the Extension Builder is used to compile a LiveCode Builder file a number of files
are created.
● api.lcdoc - LiveCode doc file for the extension. This file is generated by extracting
all of the documentation information from the LCB source code, and is used to
display the API documentation for the library in the Dictionary window in the IDE
● mylibraryname.lci - LiveCode Interface file. This file provides information about
the "public" interface for the library. It's used by the compiler when compiling LCB
source code that uses the library.
● Manifest.xml - This file describes the library and its contents in a structured format.
It is used by the IDE and by other tools to discover what the library contains.
● Module.lcm - The compiled module file. This is the compiled library bytecode,
which is the output of compiling the library source code. It is the low-level code
that's run by the LCB virtual machine when the library is in use.
Each module you create will have files with the same names, for example api.lcdoc,
which is why we create each extension in a separate directory.
#LiveCodeGlobal
Now the library is loaded we can
test it in a LiveCode stack.
● Add a button to the test stack.
● Set the code of the button to
● Click the button. You should
see an answer dialog
displaying the “Hello World!”
message returned by the
library.
Testing the library in a LiveCode stack
on mouseUp
answer sayHello()
end mouseUp
#LiveCodeGlobal
In order to package any extension in LiveCode Builder we need to add some
required metadata. The metadata provides information about the extension.
The required metadata is
● title: a human-readable name for the module
● author : the name of the author of the module
● version a string in the form X.Y.Z (with X, Y and Z integers) describing
the module version
You can also include an optional description
● description: a simple description of the module's purpose
If the required metadata is not added a number of warnings will be printed
into the log field when building and packaging the extension.
LiveCode Builder extension metadata
#LiveCodeGlobal
Version numbers
We suggest using Semantic Versioning when assigning the version number of
the extension.
The uses a version format of X.Y.Z (Major.Minor.Patch).
Given this format you would increment
1. The Major version when you make incompatible API changes.
2. The Minor version when you add functionality in a backwards-compatible
manner.
3. The Patch version when you make backwards-compatible bug fixes.
Under this scheme version numbers, and the way they change, provide clear
and valuable information about the underlying code and the changes between
versions.
For a more detailed explanation of Semantic Versioning see http://semver.org/.
#LiveCodeGlobal
Library metadata
library community.livecode.elanorb.helloworld
metadata title is "Hello World Library"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
… handler definition
end library
Add the metadata after the
library definition in the LCB file
● title: a human-readable
name for the module, I
have used “Hello World
Library” but you can
choose any suitable name
● author: add your name as
the author of your library
● version: this is the first
version of the library so the
version is “1.0.0”
#LiveCodeGlobal
The finished library
library community.livecode.elanorb.helloworld
metadata title is "Hello World Library"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
public handler sayHello()
return "Hello World!"
end handler
end library
The library is now complete,
including metadata, ready to be
installed into LiveCode
#LiveCodeGlobal
Installing the library into the LiveCode IDE
The Extension Builder is also used to
install libraries. Installed libraries are
loaded each time LiveCode is started up.
Extensions are installed into your My
LiveCode folder.
1. Open the Extension Builder from
the Tools menu.
2. Click the Open button and load the
“HelloWorldLibrary.lcb” file.
3. Click the Install button to install the
library.
4. You will be asked to select an icon
and a high resolution icon, click
‘Cancel’ on these dialogs as no
icon is needed for a library.
#LiveCodeGlobal
The installed library
Go to your My LiveCode folder.
In the Extensions folder you will see
a folder with the same name as
your library identifier.
This folder contains the files that
are make up the packaged
extension.
Any extensions installed to My
LiveCode are automatically loaded
when LiveCode is started up.
#LiveCodeGlobal
To test your library is correctly installed
execute execute
put the loadedExtensions
in the Message Box. Your library will
appear in the list of extensions.
To test the library handler execute
put sayHello()
in the Message Box
Testing the installed library
#LiveCodeGlobal
Packaging a library
In order to share your library you create a
package. This package can be shared
with other LiveCode users.
1. Open the Extension Builder from
the Tools menu.
2. Click the Open button and load the
“HelloWorldLibrary.lcb” file.
3. Click the Package button.
This will create a packaged library file
with the extension .lce in the same folder
as your .lcb file. The name of the file is
the library identifier followed by the
version number.
#LiveCodeGlobal
Loading a Packaged Extension
To load a packaged extension you use
the Extension Manager.
1. Open the Extension Manager
from the Tools menu.
2. Click Open(+).
3. Select the .lce file you want to
install.
The loaded extension appears in the list.
You can also use the Extension
Manager to uninstall extensions.
#LiveCodeGlobal
Including the library in a standalone
If you have created a LiveCode app
that uses a library and want to build
it into a standalone you must
ensure the library is included in the
standalone file.
Choose File -> Standalone
Application Settings.
On the General Pane you can
choose to let LiveCode search for
inclusions (libraries, widgets and
externals) or select any inclusions
manually.
#LiveCodeGlobal
Selecting inclusions
If you choose to select the
extensions to include the
Inclusions pane will be enabled.
Go to the Inclusions pane and
select the extensions you want to
include in the standalone.
#LiveCodeGlobal
Testing the standalone
Once your Standalone Settings are
complete choose File -> Save as
Standalone Application.
Start up the standalone and check
that the library is included and
returning the message.
#LiveCodeGlobal
Congratulations
You have completed this lesson, you can now
● Create a LiveCode Builder library
● Package and install a library into LiveCode
● Include the library in a standalone
#LiveCodeGlobal
Widget Course
Extending LiveCode with Widgets and Libraries
LiveCode
Dev Team
#LiveCodeGlobal
Extending the Hello World Library
#LiveCodeGlobal
Extending the Hello World library
In this lesson we will extend the minimal LiveCode Builder library we
created in Lesson 1.
We will
● Learn about LiveCode Builder types.
● Work with LiveCode Builder lists.
● Learn about type conversion between LCB and LCS.
● Pass a parameter to the SayHello handler.
● Document the library using documentation comments.
● Browse the library documentation in the Dictionary stack.
#LiveCodeGlobal
LiveCode Builder Typing
LiveCode Builder is a strongly, dynamically typed language,
although typing is completely optional in most places.
If a type is not specified it is taken to be the most general type
optional any (meaning any value, including nothing).
#LiveCodeGlobal
If a language is defined as typed it means that the types of all
variables are known or inferred at compile time.
Strongly typed
A strongly typed language does not allow you to use one type as
another. For example you cannot add a string and a number
together.
Type conversions have to be performed explicitly when required.
Weakly typed
A weakly typed language allows types to be mixed in the same
expression, by making implicit type conversions.
What is a strongly typed language?
#LiveCodeGlobal
What is a dynamically typed language?
Dynamically typed
Dynamically typed programming languages do type checking at
run-time as opposed to compile-time.
Statically typed
Statically typed programming languages do type checking (the
process of verifying and enforcing the constraints of types) at
compile-time as opposed to run-time.
LiveCode Builder is a dynamically typed language. Any typing errors
are found at runtime, not at compile time.
#LiveCodeGlobal
LiveCode Builder Types
The range of core types is relatively small, comprising the following:
● Boolean: one of true or false
● Integer: any integral numeric value
● Real: any numeric value
● 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.
There is one additional type, nothing, meaning no value.
#LiveCodeGlobal
To demonstrate typing in LiveCode
Builder we will create a very simple
addition library.
Example 1: Adding 2 numbers together
In this example we create 2 number
variables and add them together,
resulting in another number.
● The return type of the additionTest
handler is defined as Number.
● The 2 variables tLeft and tRight
are defined as Number.
● Adding two numbers together
results in a number value which can
be successfully returned.
Addition library library community.livecode.elanorb.addition
metadata version is "1.0.0"
metadata author is "Elanor Buchanan"
metadata title is "Addition Library"
public handler AdditionTest() returns Number
variable tLeft as Number
variable tRight as Number
put 4 into tLeft
put 5 into tRight
return tLeft + tRight
end handler
end library
#LiveCodeGlobal
Test the library using the Extension
Builder.
1. Open the Extension Builder from
the Tools menu.
2. Load the addition.lcb file.
3. Click the Test button
Execute
put additionTest()
in the Message Box .
The correct value “9” is displayed in the
Message Box.
Testing the Addition library
#LiveCodeGlobal
Example 2: Adding a string and a
number
In this example we try to add a String and
a Number and return a number.
● The return type of the AdditionTest
handler is defined as Number.
● Variable tLeft is defined as a
String.
● Variable tRight is defined as a
Number.
● Attempting to add the 2 values
together will return an error.
Addition library 2 library community.livecode.elanorb.addition
metadata version is "1.0.0"
metadata author is "Elanor Buchanan"
metadata title is "Addition Library"
public handler AdditionTest() returns Number
variable tLeft as String
variable tRight as Number
put 4 into tLeft
put 5 into tRight
return tLeft + tRight
end handler
end library
#LiveCodeGlobal
Testing the Addition library
Test the library using the Extension Builder
● Open the Extension Builder from the
Tools menu.
● Load the addition.lcb file.
● Click the Test button
No errors are returned at compile time but if you
execute
put AdditionTest()
In the Message Box you will see an error.
This is because LBC is strongly typed (you can’t
add an string to a number) and dynamically
typed (the error occurs at runtime).
#LiveCodeGlobal
Addition library 3
Example 3: Adding a string and a
number using type conversion
In this example we create a String and a
Number variable, convert the String to a
Number and return a Number.
● The return type of the AdditionTest
handler is defined as Number
● Variable tLeft is defined as a
String
● Variable tRight is defined as a
Number
● The value in tLeft is converted to a
number by parsing the value as a
number
● The value of the two numbers
added together is returned
library community.livecode.elanorb.addition
metadata version is "1.0.0"
metadata author is "Elanor Buchanan"
metadata title is "Addition Library"
public handler AdditionTest() returns Number
variable tLeft as String
variable tRight as Number
put 4 into tLeft
put 5 into tRight
return tLeft parsed as number + tRight
end handler
end library
#LiveCodeGlobal
Test the library using the Extension Builder.
● Open the Extension Builder from the
Tools menu.
● Load the addition.lcb file.
● Click the Test button.
Execute
put AdditionTest()
In the Message Box .
The correct value “9” is displayed in the
Message Box. The value in the string variable
was converted to a number before the
calculation was performed, allowing a number
to be calculated and returned.
Testing the Addition library
#LiveCodeGlobal
LiveCode Builder Lists and Arrays
Two important types in LCB, which deserve some more attention
are lists and arrays.
● list - a list is a sequence of values, each element of the
sequence is assigned a numerical index, starting with 1 and
proceeding sequentially
● array - an array is a mapping from a string to any value (i.e. an
associative array, just like in LiveCode Script)
#LiveCodeGlobal
Creating Lists in LCB library community.livecode.elanorb.example
metadata title is "Example Library"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
public handler CreateList() returns nothing
variable tLetterList as List
variable tNumberList as List
variable tMixedList as List
put ["a","b","c"] into tLetterList
put [1,2,3] into tNumberList
put ["one","two","three",4,5,6] into
tMixedList
end handler
end library
Creating a list in LiveCode
Builder is very simple, you put a
comma-separated list of values
between square brackets as
shown.
Each element in a list can hold
a different type of value.
#LiveCodeGlobal
Creating Lists in LCB
public handler CreateListFromString() returns
String
variable tVar as String
variable tSplit as List
put "first,second,third,fourth,fifth" into
tVar
split tVar by "," into tSplit
end handler
You can also split a string into a
list using the split keyword.
You specify the delimiter you
want to use and the string is
split into a list of strings using
the delimiter.
#LiveCodeGlobal
List elements
You can access the individual elements
of a list using the element keyword.
You can
● Get the value of an element
● Set the value of an element
● Delete an element
To add an element to a list you push a
value onto the list, you can push a value
onto the front or end of a list.
Note: LCB lists are 1 based.
Note: An error is returned if the index is
out of range.
public handler ListElement() returns any
variable tMixedList as List
put ["one","two","three",4,5,6] into
tMixedList
delete element 2 of tMixedList
-- tMixedList = ["one","three",4,5,6]
put "five" into element 4 of tMixedList
-- tMixedList = ["one","three",4,"five",6]
push "zero" onto front of tMixedList
--tMixedList =
["zero","one","three",4,"five",6]
end handler
#LiveCodeGlobal
Creating Arrays in LCB
Arrays in LCB are created in
the same way as in LiveCode
Script, so you are likely familiar
with the syntax.
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. In LCB
array keys are always strings.
public handler CreateArray() returns nothing
variable tCapitals as Array
put "Kabul" into tCapitals["Afghanistan"]
put "Tirana" into tCapitals["Albania"]
put "Algiers" into tCapitals["Algeria"]
put "Andorra la Vella" into
tCapitals["Andorra"]
put "Luanda" into tCapitals["Angola"]
end handler
#LiveCodeGlobal
Creating Arrays in LCB
You can also create LiveCode
Builder arrays using {} notation
with the syntax:
{Key 1:Value 1,Key 2:Value
2,...,Key n:Value n}
public handler CreateBracketedArray() returns
nothing
variable tCapitals as Array
put {"Afghanistan":"Kabul",
"Albania":"Tirana", "Algeria":"Algiers",
"Andorra":"Andorra la Vella",
"Angola":"Luanda"} into tCapitals
end handler
#LiveCodeGlobal
Array elements
You can access the individual
elements on array using
square bracket notation.
You can
● Get the value of an
element
● Set the value of an element
● Delete an element
public handler CreateArray() returns nothing
… previous array code
-- Add an element to the array
put "St. John" into tCapitals["Antigua and
Barbuda"]
-- Update an existing element of the array
put "St. John's" into tCapitals["Antigua
and Barbuda"]
-- Delete the specified element of the
array
delete tCapitals["Antigua and Barbuda"]
end handler
#LiveCodeGlobal
Nested elements
Both lists and arrays can be nested. This
means an element in a list can contain another
list, or an element in an array can contain
another array.
Elements of a nested list can be accessed by
using multiple element values. For example:
return element 2 of element 2 of
tListOfLetters
-- returns “B”
Elements of a nested array can be accessed by
using multiple sets of square brackets
containing the keys. For example:
return tCapitals["Spain"]["name"]
-- returns “Madrid”
public handler CreateNested() returns nothing
-- A nested list (list of lists)
variable tListOfLetters as List
put ["a", ["b","B"]] into tListOfLetters
-- A nested array
variable tCapitals as Array
variable tSpain as Array
put "Madrid" into tSpain["name"]
put "3,165,000" into tSpain["population"]
put tSpain into tCapitals["Spain"]
end handler
#LiveCodeGlobal
You can also create nested arrays directly using the syntax
{Key 1:Value 1,Key 2:Value 2,...,Key n:Value n}
Where each value can also be an array expression
{Key 1:{Key a:Value a,Key b:{Key α:Value α,Key β:Value β}},Key 2:Value 2,...,Key n:Value n}
Example Returns
public handler CreateNested() returns nothing
variable tCapitals as Array
put {"Spain": {"Name":"Madrid",
"Population":"3,165,000"},
"UK":{"Name":"London",
"Population":"8,539,000"}} into tCapitals
end handler
Nested elements 2
#LiveCodeGlobal
Type Conversion between LCB and LCS
When a value is returned to LiveCode from a LiveCode Builder library what
type will it be?
Because LCB is strongly typed and LiveCode Script is weakly typed for most
LCB types we don’t need to worry about it.
● nothing
● Boolean
● Integer
● Real
● Number
● String
● Data
All these types can be used directly in expressions or put into a LiveCode
Script variable.
#LiveCodeGlobal
Type Conversion between LCB and LCS
The two exceptions are LiveCode Builder lists and arrays.
● list: when a LiveCode Builder handler returns a list it is converted to a numerically keyed
LiveCode array, with continuous numerical keys.
● array: when a LiveCode Builder handler returns an array it is converted to a LiveCode array
LiveCode Builder LiveCode Script
variable tLetterList
put ["a","b","c"] into tLetterList
return tLetterList
LiveCode Builder LiveCode Script
variable tSpain
put "Madrid" into tSpain["name"]
put "3,165,000" into tSpain["population"]
return tSpain
#LiveCodeGlobal
Adding explicit types to the library
In the first version of the Hello World Library we didn’t use any
explicit types. In this lesson we will update the library with:
● An explicit return type
● A typed variable that will hold the message to be returned
#LiveCodeGlobal
Adding a return type
The first change we will make is to
define the return type of the
handler.
In the initial version of the library the
return type was not specified so
was taken to be the general type
optional any, meaning any value,
including nothing, could be
returned.
We want to ensure the SayHello
handler always returns a string so
change the handler definition to
specify String as the return type.
public handler sayHello() returns String
… handler code
end handler
#LiveCodeGlobal
Adding a typed variable
To ensure we return a String from the
SayHello handler we will also update the
handler code to store the message in a
String variable and return the value of
the variable.
Update the SayHello handler with:
1. String variable declaration.
2. Command to update the value of
the variable with the “Hello World!”
message.
3. Return statement returning the
value of the String variable.
public handler sayHello() returns String
variable tMessage as String
put "Hello World!" into tMessage
return tMessage
end handler
#LiveCodeGlobal
Test that your library compiles and
behaves correctly.
1. Open the Extension Builder.
2. Load the updated LiveCode Builder
file.
3. Click the Uninstall button to
uninstall the previous version.
4. Click the Test button.
5. Execute
put sayHello()
in the Message Box.
The string returned by the library is
displayed in the Message Box.
Testing the Extended Library
#LiveCodeGlobal
Passing parameters to a library handler
In many cases you will want to use parameters in your library handlers.
Handler definitions have the form
<HandlerType> handler <HandlerName>(<ParameterList>) [ returns <ReturnType> ]
end handlerName
The parameter list is a comma separated list of parameters, each of which
has the form
( 'in' | 'out' | 'inout' ) <ParameterName> [ 'as' <ParameterType>]
The type of parameter is optional, if no type is specified it is taken to be
optional any meaning it can be of any type.
#LiveCodeGlobal
Passing parameters to a library handler
The parameter list describes the parameters which can be passed to the
handler. Handlers must be called with the correct number of parameters.
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.
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 specified it is taken to be
optional any meaning it can be of any type.
#LiveCodeGlobal
Adding a parameter to the sayHello handler
We want to update the SayHello handler to take a pName
parameter, passed in when SayHello is called from LiveCode Script.
The pName parameter will be a String value, which we will use to
construct and return a custom “Hello” string.
#LiveCodeGlobal
Adding a parameter
We will
● Update the handler definition with
an in String parameter, pName.
● Construct the string to be returned
using the pName parameter.
● Return the constructed string.
Constructing a string in LCB uses the
same syntax as LCS
● & - concatenates 2 strings
● && - concatenates 2 strings with a
space in between
public handler SayHello(in pName as String)
returns String
variable tMessage as String
put "Hello" && pName & "!" into tMessage
return tMessage
end handler
#LiveCodeGlobal
Test that your library compiles and
behaves correctly.
1. Open the Extension Builder.
2. Load the updated LCB file.
3. Click the Test button.
4. Execute
put SayHello(“Elanor”)
in the Message Box.
The returned String, containing the
passed String, is displayed in the
Message Box.
Testing the parameter passing
#LiveCodeGlobal
Using lists in the library
It will often be useful to return more that a single piece of data from
a library handler.
Next we will update the SayHello handler to take a string containing
a comma separated list of names, and return a LCB list with an
element containing a “Hello” message for each name passed in.
#LiveCodeGlobal
Updating the return type
The first step is to update the
SayHello handler definition.
We will be returning a List rather
than a String so update the return
type.
We also want to be able to pass
more than one name in so update
the parameter name to pNames.
public handler sayHello(in pNames as String)
returns List
… widget code
end handler
#LiveCodeGlobal
Defining variables
We will be using 3 variables in the
handler
● tNameList - a list variable created
from the pNames parameter
● tMessage - the list variable that will
be returned, with an element
holding a message for each name
passed in in pNames
● tElement - a string variable used to
iterate over the elements of
tNameList
Add variable definitions for these 3
variables.
public handler sayHello(in pNames as String)
returns List
variable tNameList as List
variable tMessage as List
variable tElement as String
end handler
#LiveCodeGlobal
Creating a List from a String
We want to convert the String
parameter into a List. We can do
this using the split statement, which
splits the string into a list of strings,
using the specified delimiter.
We know the pNames parameter is
a command separated list of names
so we split pNames by comma to
create a List variable.
public handler sayHello(in pNames as String)
returns List
variable tNameList as List
variable tMessage as List
variable tElement as String
split pNames by "," into tNameList
end handler
#LiveCodeGlobal
Building a List
Next we want to create a list of
messages, with an element for each
name.
● Loop over each element in
tNameList
● Construct a “Hello” message using
the current element
● Append it to the end of the list
using the push statement.
● Return the list of messages
Note: When a value is pushed onto a list
the pushed value becomes the tail of the
list, by default. Use the 'front of' variant to
push onto the front of a list instead.
public handler sayHello(in pNames as String)
returns List
variable tNameList as List
variable tMessage as List
variable tElement as String
split pNames by "," into tNameList
repeat for each element tElement in
tNameList
push ("Hello" && tElement & "!") onto
tMessage
end repeat
return tMessage
end handler
#LiveCodeGlobal
Compile the library using the Extension Builder.
● Open the Extension Builder from the
Tools menu.
● Load the helloWorldLibary.lcb file
● Click Test.
● This will load the library and create a test
stack.
● Add a button to the test stack.
● Set the code of the button to
on mouseUp
put sayHello("Adam,Brenda,Craig") into
tArray
end mouseUp
● Add a breakpoint to line 3 line so you can
view the array in the Variable Watcher
Testing the library
Note: Remember that LCB lists are converted to numerically keyed arrays in LiveCode Script.
#LiveCodeGlobal
Documenting the Library
Extensions can provide an API (Dictionary) and User Guide as part
of the installed package. They are installed and viewable through
the LiveCode Dictionary stack.
Any extension can include an API. To do so, either add a file called
api.lcdoc to your widget folder alongside the other widget files or
markup your source code inline. The api.lcdoc file must be in the
lcdoc format. For a full description of the lcdoc format see the
Contributing to LiveCode Documentation guide.
#LiveCodeGlobal
Marking up your code
In this example we will document the
library using inline code comments.
Marking up your scripts is simple and
follows a similar model to other
documentation formats.
Consider the following handler:
public handler myHandler(in pString as
String, in pNumber as Number)
end handler
To add an entry to the API for this
handler, place a formatted comment
above the handler definition:
/**
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)
end handler
#LiveCodeGlobal
Documenting SayHello
We want to markup the source code of
the Hello World library by adding inline
documentation to the SayHello handler.
● The documentation is enclosed
within /** and **/
● Add a summary
● Add a description of the pNames
parameter
● Add a description of the return
value
● Add a full description of how the
handler works.
library community.livecode.elanorb.helloWorld
metadata version is "1.0.0"
metadata author is "Elanor Buchanan"
metadata title is "Hello World Library"
/**
Summary: Constructs and returns a list of Hello
messages
pNames: String containing a comma separated list
of names
Returns: List of Hello strings
Description:
Takes a comma separated String of names, converts
the String to a List, constructs a Hello message
for each name and returns the List of Hello
messages.
**/
public handler SayHello(in pNames as String)
returns List
… handler code
end handler
end library
#LiveCodeGlobal
Browse the Documentation in the Dictionary
Now we have added documentation
to the library we can view it in the
Dictionary Stack.
Extension documentation only
shows once the extension is fully
installed.
● Open the Extension Builder.
● Load the Hello World Library.
● Click Install.
#LiveCodeGlobal
Browse the Documentation in the Dictionary
Now open the Dictionary Stack and
go to the API tab.
Open the Drop Down list, you
should see “Hello World Library”, or
the title you gave your library, in the
list.
Select the library and you will see
the documentation you added to the
source file displayed.
#LiveCodeGlobal
Congratulations
You have completed this lesson, you can now
● Use explicit typing
● Perform type conversion
● Use LCB lists and arrays
● Pass parameters to library handlers
● Add documentation to libraries
#LiveCodeGlobal
Widget Course
Extending LiveCode With Widgets and Libraries
LiveCode
Dev Team
#LiveCodeGlobal
The Rotated Text Widget
#LiveCodeGlobal
The Rotated Text Widget
The second type of extension that that be created is a widget. A widget is a custom
control that is treated as an engine level element. Widgets appear in the Tools Palette
and can be added as controls to any LiveCode stack.
The Rotated Text Widget displays text and allows the user to set the rotation property
of the widget.
We will
● Define the widget.
● Define properties for the widget.
● Draw the widget using LCB canvas operations.
● Compile and test the widget.
● Install the widget into LiveCode.
● Add the widget to a stack.
● Include the widget in a standalone.
#LiveCodeGlobal
What is a Canvas?
A canvas is a container that holds various drawing elements (lines, shapes, text, frames
containing other elements, etc.). It takes its name from the canvas used in visual arts.
The main difference between a library and an extension is that a widget draws itself to
the canvas, providing a UI element for the extension.
Advantages
Widgets have a number of advantages over traditional custom controls, created using
LiveCode groups
● Once built the widget it is an atomic control.
● Widgets are more efficient.
● Widgets are not affected by engine messages.
● Widgets can be easily updated by updating the extension without having to
replace the controls on the stacks.
#LiveCodeGlobal
Creating a LiveCode Builder Widget
Just like libraries widgets are written
in a text editor.
Start by creating a plain text file in a
new directory and save it to disk
with the extension ".lcb".
I am naming my file
"rotatedText.lcb" but you can name
your file anything suitable.
Note: The extension builder
currently relies on there being only
one .lcb file in a given directory, this
is why we create a separate folder
for each new extension.
#LiveCodeGlobal
The first thing we need to do is declare the type
of extension we are writing.
We are writing a widget so we need to declare
the extension as such.
The widget declaration is followed by an
identifier. An extension identifier should be in
the form
community.livecode.<user name>.<widget name>
In my case my username is "elanorb" and I
have chosen to use "rotatedtext" as the name
part of the identifier.
For more on module naming see the Naming
section of the LiveCode Builder Style Guide,
accessible from the Dictionary stack or the
Additional Resources section of this course.
LCB widget definition
widget community.livecode.elanorb.rotatedtext
end widget
#LiveCodeGlobal
As with an LCB library, widgets also
require metadata.
The required metadata for widgets
is the same as for libraries
● title
● author
● version
You can also include an optional
description.
Add the widget metadata to the
definition.
Widget metadata
widget community.livecode.elanorb.rotatedtext
metadata title is "Rotated Text"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
end widget
#LiveCodeGlobal
The LiveCode builder syntax is broken down into modules. Each module contains the syntax for a
particular part of LiveCode Builder.
You include the modules that provide the syntax for the features your extension requires.
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.
For a full list of modules see the Importing Libraries section of the Extending LiveCode Guide and the
API entries for the individual modules.
The guide can be found under the Guides tab of the Dictionary or in the Additional Resources
section of the course.
LCB modules
#LiveCodeGlobal
As a general rule we recommend
importing all three optional modules
and the Widget Utilities library
whenever developing widgets.
Include the 3 modules and 1 library
using the use keyword, followed by
the module or library extension.
Including modules
widget community.livecode.elanorb.rotatedtext
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.library.widgetutils
metadata title is "Rotated Text"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
end widget
#LiveCodeGlobal
Module level variables
A variable definition defines a module-scope variable. In a widget module, such variables are
per-widget (i.e. instance variables). In a library module, there is only a single instance (i.e. a
private global variable). Module-scope variables in LCB are similar to script local variables in
LiveCode Script.
The syntax for declaring variables is
variable <variableName> [as <type>]
The type specification for the variable is optional, if it is not specified 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 definition.
For a list of default values see the Variables section of the LiveCode Builder Language
Reference Guide. The guide can be found under the Guides tab of the Dictionary or in the
Additional Resources section of the course.
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.
#LiveCodeGlobal
Variable declarations
In this widget we will use one module
level variable to store the value of the
rotation property of the widget.
The value of the rotation property must
be a number so we define the type as
such.
The variable will be a module level
instance variable, so we prepend the
variable name with a lower case ‘m’ to
make it easily identifiable as such.
Add the variable definition to the widget
code.
widget community.livecode.elanorb.rotatedtext
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.library.widgetutils
metadata title is "Rotated Text"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
variable mRotation as Number
end widget
#LiveCodeGlobal
Defining widget properties
Property definitions can only appear in widget modules. They define a property which can
be accessed from LiveCode Script in the usual way (e.g. the myProperty of widget 1).
The syntax for declaring properties is
property <propertyName> get <getterIdentifier> [ set <setterIdentifier> ]
The getterIdentifier and setterIdentifier can use either a variable or handler identifier. If a
variable identifier is used, then the property value is fetched (and stored) from that variable.
If a handler identifier 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.
Note: The Extension Builder will report an error if a setter or getter handler that is used in a
property definition is not defined in the module file.
#LiveCodeGlobal
The rotation property
widget community.livecode.elanorb.rotatedtext
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.library.widgetutils
metadata title is "Rotated Text"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
private variable mRotation as Number
property "rotation" get mRotation set
setRotation
end widget
The widget will only have one property,
rotation. The value of the rotation property will
be stored in the mRotation variable.
The getter
The getter for the rotation property will return
the value of mRotation.
The setter
The setter for the rotation property will call a
handler, setRotation. Implementing the "setter"
ourselves provides us with a little more flexibility
and allows us to take multiple actions when the
property is set.
Add the property definition to the widget code.
#LiveCodeGlobal
widget community.livecode.elanorb.rotatedtext
… previous code
public handler setRotation(in pRotation as
Number) returns nothing
put pRotation into mRotation
redraw all
end handler
end widget
The setRotation handler allows us to take
multiple actions when the property is updated
● The in parameter is a number.
● The handler does not return a value.
1. Update mRotation with the new value.
2. Redraw the widget to reflect the property
change. We do this by calling "redraw
all".
Add the setRotation handler to the widget
code.
The setRotation handler
#LiveCodeGlobal
The Property Inspector
Any properties that are defined in the widget are automatically
shown in the Basic pane of the Property Inspector.
We will be looking at integrating properties into the Property
Inspector in more detail in the next lesson.
#LiveCodeGlobal
Widget Handlers
There are five core handlers that any widget developer should implement:
Handler Description
OnPaint Sent to your widget whenever LiveCode requires it to redraw.
The performance of your widget is tied primarily to this handler
and should be kept as efficient as possible.
OnCreate Sent to your widget when it is first created by LiveCode. This can
be used to initialise default data and where applicable, reduce
the burden for calculating constants etc in the OnPaint handler.
OnGeometryChanged Sent when the control is changed in size.
OnSave Sent when your widget is about to be destroyed and enables the
widget to save data set on the widget.
OnLoad Sent when your widget is created and enables the widget to
retrieve data saved on the widget.
#LiveCodeGlobal
The OnPaint handler
This widget is very simple so only
the OnPaint handler is required to
draw the widget.
The OnPaint handler will be a
public handler which takes no
parameters and does not return a
value.
Add the OnPaint definition to the
widget code.
public handler OnPaint()
end handler
#LiveCodeGlobal
The OnPaint handler
width
heightLiveCode
There are a number of steps to take
in the OnPaint handler. The first
step is to draw the unrotated text in
the widget.
1. Work out the size of the widget
by getting its width and height
2. Work out the rectangle of the
area we have to draw into
3. Draw the text at the center of
the available space
#LiveCodeGlobal
public handler OnPaint()
variable tText as String
variable tHeight as Number
variable tWidth as Number
put my width into tWidth
put my height into tHeight
put "LiveCode" into tText
variable tRectangle as Rectangle
put rectangle [0,0,tWidth,tHeight] into
tRectangle
fill text tText at center of tRectangle
on this canvas
end handler
Drawing the text
For the basic widget we will use
“LiveCode” as the text.
1. Declare variables for the text
to be displayed and the height
and width of the canvas.
2. Update the variables with the
relevant values.
3. Declare a rectangle variable.
4. Put the rectangle describing
the area of the canvas into the
rectangle variable.
5. Draw the text in the center of
the canvas.
#LiveCodeGlobal
my width: Returns the width of the widget.
my height:Returns the height of the widget.
rectangle: Specifies an area, consists of a list of 4 integers left, top, right, bottom
Example: put rectangle [0,0,tWidth,tHeight] into tRectangle
fill text at: Renders text on a canvas
Syntax: fill text mText at mAlignment of mRect on mCanvas
Example: fill text "Widget Label" at top left of rectangle [50,
100, 250, 200] on this canvas
For more on each of these keywords see the API entries in the LiveCode Dictionary.
Search for “com.livecode.canvas” in the LiveCode Builder API to see all the associated
API entries.
Drawing the text
#LiveCodeGlobal
Rotating text
To draw rotated text we
1. Rotate the canvas
2. Get the rectangle of the rotated canvas as a path
3. Rotate the path back
4. Get the rectangle of the un-rotated path
5. Draw the text within the un-rotated rectangle.
This draws the text horizontally, but relative to the position of
the canvas. Because the canvas is rotated the text also
appears rotated.
#LiveCodeGlobal
Key Concept: Rectangle Path
Syntax: rectangle path of mRect
Summary: Creates a new path.
Parameters: mRect: An expression which evaluates to a rectangle.
Example: // Create a rectangle path
variable tPath as Path
put rectangle path of rectangle [10,10,210,60]
into tPath
#LiveCodeGlobal
Key Concept: Bounding Box
Syntax: the bounding box of mPath
Summary: The bounding box of a path which is the smallest
rectangle that completely encloses mPath.
Parameters: mPath: An expression which evaluates to a path.
Example: // Create a circle path
variable tPath as Path
put circle path centered at point [100,100] with
radius 50 into tPath
// Get the bounds of the path
variable tBounds as Rectangle
put the bounding box of tPath into tBounds
#LiveCodeGlobal public handler OnPaint()
variable tText as String
variable tHeight as Real
variable tWidth as Real
put my width into tWidth
put my height into tHeight
put "LiveCode" into tText
rotate this canvas by mRotation
variable tRectangle as Rectangle
variable tPath as Path
put rectangle path of rectangle
[0,0,tWidth,tHeight] into tPath
rotate tPath by (mRotation * -1)
put the bounding box of tPath into
tRectangle
fill text tText at center of tRectangle
on this canvas
end handler
Drawing rotated text
1. Rotate the canvas by the value stored in
the mRotation variable.
2. Declare a path variable tPath.
3. Put the rectangle path of the canvas into
tPath.
4. Rotate the path by -mRotation, setting it
to a horizontal rectangle.
5. Update the line that sets tRectangle to
get the bounding box of the un-rotated
path and put it into the tRectangle
variable. This gives the rectangle that
completely encloses the un-rotated the
path in tPath.
6. Draw the text at the center of the
rectangle given by tRectangle.
The text in drawn in a horizontal rectangle, but
relative to the canvas, so appears drawn on an
angle.
#LiveCodeGlobal
Testing the widget
Now we have completed the
OnPaint handler we are ready
to test the widget.
This is the full code of the
widget, so far.
widget community.livecode.elanorb.rotatedtext
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.library.widgetutils
metadata title is "Rotated Text"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
private variable mRotation as Number
property "rotation" get mRotation set
setRotation
public handler setRotation(in pRotation as
Number) returns nothing
put pRotation into mRotation
redraw all
end handler
… continued on next slide
#LiveCodeGlobal
Testing the widget
Now we have completed the
OnPaint handler we are ready
to test the widget.
This is the full code of the
widget, so far.
public handler OnPaint()
variable tText as String
variable tHeight as Real
variable tWidth as Real
put my width into tWidth
put my height into tHeight
put "LiveCode" into tText
rotate this canvas by mRotation
variable tRectangle as Rectangle
variable tPath as Path
put rectangle path of rectangle
[0,0,tWidth,tHeight] into tPath
rotate tPath by (mRotation * -1)
put rectangle [0,0,tWidth,tHeight] into
tRectangle
put the bounding box of tPath into
tRectangle
fill text tText at center of tRectangle
on this canvas
end handler
end widget
#LiveCodeGlobal
Testing the widget
Just like a library we compile,
test, package and install
widgets using the Extension
Builder.
1. Open the Extension Builder
from the Tools menu
2. Click the Open button
3. Load the ‘rotatedtext.lcb’
file
#LiveCodeGlobal
Testing the widget
To test the widget click the Test
button.
This will create a stack in the
IDE with a Rotated Test widget
on it.
1. Go into Edit mode.
2. Select the widget.
3. Open the Property
Inspector.
4. Set the Rotation property.
#LiveCodeGlobal
Widget icons
When a widget is installed it shows in the
Tools Palette.
To provide an icon for the widget you add
image files to the folder containing the
widget definition .lcb file.
Open the folder containing the LCB file
● Create a “support” folder
● Add 2 image files
○ Icon.png (20 x 20)
○ icon@extrahigh.png (40x40)
The icon files can be found under the
Resources tab of this lesson.
#LiveCodeGlobal
Installing a widget
To install a widget we use the Extension
Builder.
1. Open the Extension Builder from
the Tools Palette.
2. Select the Open button.
3. Load the ‘rotatedtext.lcb’ file.
4. Click Install.
The widget will be installed and will
appear in the Tools Palette.
#LiveCodeGlobal
Creating a widget
You can now add the widget to
a stack by dragging it out from
the Tools Palette.
1. Create a new stack.
2. Drag on a Rotated Text
Widget.
3. Go into Edit mode.
4. Select the widget.
5. Open the Property
Inspector for the widget.
6. Set the Rotation property
on the widget.
#LiveCodeGlobal
Including the Widget in a Standalone
When building a standalone that
includes a widget you need to
ensure that the widget is included
when the standalone is built.
Open the Standalone Application
Settings from the File menu.
On the General Pane you can
choose to let LiveCode search for
inclusions (libraries and widgets) or
select any inclusions manually.
#LiveCodeGlobal
Selecting inclusions
If you choose to select the
extensions to include yourself
the Inclusions pane will be
enabled.
Go to the Inclusions pane and
check the extensions you want
to include in the standalone.
In this case we want to include
the Rotated Text widget so
check it in the list.
#LiveCodeGlobal
Saving the standalone
Choose File -> Save as
Standalone Application to
save the stack as a standalone.
Start up the standalone and
check that the widget is
included and the rotation can
be set.
#LiveCodeGlobal
Congratulations
You have completed this lesson, you can now
● Create a LiveCode Builder widget.
● Package and install a widget into LiveCode.
● Include the widget in a standalone.
#LiveCodeGlobal
Widget Course
Extending LiveCode with Widgets and Libraries
LiveCode
Dev Team
#LiveCodeGlobal
The Advanced Rotated Text Widget
#LiveCodeGlobal
The Advanced Rotated Text Widget
In this lesson we will take the Rotated Text Widget to the next level.
We will
● Fully integrate widget properties into the Property Inspector
● Add color and font properties by shadowing standard LiveCode
properties
● Handle mouse events to make the widget clickable
● Add handlers to load and save widgets
● Add read only properties to a widget
● Document the widget
#LiveCodeGlobal
Widget properties
In Lesson 3 we defined the rotation
property of the widget
property "rotation" get
mRotation set setRotation
● Properties are shown in the
Basic pane of the Property
Inspector
● The name of the property is
shown as the label in the
Property Inspector
● A standard editor is shown for
the property
#LiveCodeGlobal
You can more fully define widget properties in the LCB source file using metadata. All
property metadata is optional. Property metadata definitions have the format
metadata <property name>.<metadata name> is <value>
You can define
● Property label
● Editor type
● Editor specific metadata
● Default value
● Property Inspector Section
● Property group
● User visible
● Read only
For more on property metadata see Property Definitions Read Me.
Widget properties
#LiveCodeGlobal
Property metadata
Add the metadata for the rotation property to
the widget source file.
● label: the label to be shown in the
Property Inspector
● editor: the type of editor to be used in
the Property Inspector
● default: the default value of the property
Editor specific metadata
● step: the step value for number
properties
● min: the minimum value for a number
property
● max: the maximum value for a number
property
We want this property to appear in the Basic
section so do not specify a section.
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
private variable mRotation as Number
property "rotation" get mRotation set
setRotation
metadata rotation.label is "Rotation"
metadata rotation.editor is
"com.livecode.pi.number"
metadata rotation.default is "0"
metadata rotation.step is "1"
metadata rotation.min is "0"
metadata rotation.max is "359"
… widget handlers
end widget
#LiveCodeGlobal
Test in the Property Inspector
To see the property integrated into the
Property Inspector, using the metadata,
rebuild the widget.
● Open the Extension Builder from
the Tools menu
● Load the widget source file
● Click the Test button
● Select the widget on the test stack
● Open the Property Inspector
You should see the rotation property,
with a number property editor that will not
allow values outside the range 0-360.
#LiveCodeGlobal
The Content property
We will add a second property,
content, which allows the user to
change the text displayed in the
widget.
● Define a variable to store the
property value
● Define the property, getter and
setter
● Add metadata for the property
○ editor
○ default
○ label
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metatdata
… rotation property definition
private variable mContent as String
property "content" get mContent set setContent
metadata content.editor is "com.livecode.pi.string"
metadata content.default is "Default text"
metadata content.label is "Content"
… widget handlers
end widget
#LiveCodeGlobal
Add the content property setter
handler.
● Takes a string parameter
● Has no return value
● Update the mContent variable
with the parameter value
● Redraw the widget with the
new text
The setContent handler widget community.livecode.elanorb.rotatedtext
… widget inclusions and metatdata
… property definitions
… OnPaint handler
… SetRotation handler
public handler SetContent(in pText as String)
returns nothing
put pText into mContent
redraw all
end handler
end widget
#LiveCodeGlobal
Update OnPaint
The OnPaint() handler needs
updated to use the value of the
content property.
● Delete the declaration for the
tText variable
● Delete the line where
“LiveCode” is put into the tText
variable
● Update the “fill text” line to use
the mContent variable
public handler OnPaint()
variable tText as String
variable tHeight as Real
variable tWidth as Real
put my width into tWidth
put my height into tHeight
put "LiveCode" into tText
rotate this canvas by mRotation
variable tRectangle as Rectangle
variable tPath as Path
put rectangle path of rectangle
[0,0,tWidth,tHeight] into tPath
rotate tPath by (mRotation * -1)
put the bounding box of tPath into tRectangle
fill text tText at center of tRectangle on this
canvas
fill text mContent at center of tRectangle on
this canvas
end handler
#LiveCodeGlobal
When a widget is created the default
values for its properties should be used.
The OnCreate handler is called when the
widget is first created.
To ensure the values of the rotation and
content properties are set we add the
OnCreate handler which will call the
property setters with the default values.
● Set the default value of the
content property to “Default text”
● Set the default value of the
rotation property to 0
The OnCreate handler widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… property definitions
… OnPaint handler
public handler OnCreate()
setContent("Default text")
setRotation(0)
end handler
… Property setters
end widget
#LiveCodeGlobal
Test the widget
Now build and test your widget
using the Extension Builder.
You should see the Content
property in the Property
Inspector and be able to
change the text displayed in the
widget.
#LiveCodeGlobal
In addition to adding widget specific properties you can also link your widget to standard LiveCode
control properties, such as font, background color etc.
All controls in LiveCode, both widgets and classic controls, have a set of basic properties which are
always present and do not need to be implemented when writing a widget. Any widget you create will
always have these properties in its Property Inspector. These properties are
You can also choose to allow your widget to implement any other LiveCode control properties which
are not in the basic set.
Basic name, kind, tooltip, visible, disabled
Custom properties custom properties and custom property sets
Colors ink, blendLevel
Position lockLoc, width, height, location, left, top, right, bottom, layer
Text textFont, textSize
Advanced layerMode, behavior, traversalOn, number
Shadowing LiveCode control properties
#LiveCodeGlobal
Accessing standard properties
Although all controls, including
widgets, have all the basic
properties some work
automatically and you need to
take some into account when
you draw the widget.
For example the width property
works automatically but the text
size requires some extra
handling.
#LiveCodeGlobal
Text properties
The two basic text properties all controls
have are
● Text font
● Text size
We want to use the values of these
properties when drawing the widget. We
get the effective text properties of the
widget using my font and apply these
settings when drawing the widget.
Update the OnPaint handler to apply
these settings to the canvas before
rotating the canvas.
public handler OnPaint()
… variable declarations
… tWidth and tHeight values
set the font of this canvas to my font
rotate this canvas by mRotation
… remainder of code
end handler
#LiveCodeGlobal
Test the text properties
To test the text properties in the Property
Inspector re-compile the widget using the
Extension Builder.
● Select the widget on the test stack
● Open the Property Inspector
● Go to the Text section
● Set the Font and Text size
The text in the widget should change to
reflect the property values.
#LiveCodeGlobal
Linking to other LiveCode properties
You can also link to other standard LiveCode properties beyond the
basic, built in set.
For example we might want to set the Text fill of the Rotated Text
Widget.
Text fill, or foregroundColor to use the property name, is a
standard LiveCode property but it not part of the basic set.
To access it we have to specify that the widget has the property, but
we do not have to define the property itself.
#LiveCodeGlobal
Linking to other LiveCode properties
Below is a list of the LiveCode properties you can link to as described.
abbrevId, abbrevName, abbrevOwner, altId, backColor, backPattern,
backPixel, blendLevel, borderColor, borderPattern, borderPixel, bottom,
bottomColor, bottomLeft, bottomPattern, bottomPixel, bottomRight,
brushColor, cantSelect, colors, customKeys, customProperties,
customPropertySet, customPropertySets, disabled, enabled, focusColor,
focusPattern, focusPixel, foreColor, forePattern, forePixel, height, hiliteColor,
hilitePattern, hilitePixel, ink, invisible, kind, layer, layerMode, left, location,
lockLocation, longId, longName, longOwner, name, number, owner,
parentScript, patterns, penColor, properties, rectangle, right, script, selected,
shadowColor, shadowPattern, shadowPixel, shortId, shortName,
shortOwner, textFont, textSize, textStyle, themeControlType, toolTip, top,
topColor, topLeft, topPattern, topPixel, topRight, traversalOn,
unicodeToolTip, visible, width
#LiveCodeGlobal
Metadata for LiveCode
properties
To define a LiveCode property in a widget you
provide metadata, but do not need to define the
property within the widget.
We want to the Rotated Text Widget to have the
foregroundColor property, and for it to be
settable in the Property Inspector.
Add the metadata for the property.
● Use a color editor in the Property
Inspector
● Setting the default to empty means the
value will be inherited
● Show in the Colors section of the
Property Inspector
● Set the label to “Text Fill”
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… property definitions for rotation and
content
metadata foregroundColor.editor is
"com.livecode.pi.color"
metadata foregroundColor.default is ""
metadata foregroundColor.section is "Colors"
metadata foregroundColor.label is "Text fill"
… widget handlers
end widget
#LiveCodeGlobal
Update OnPaint
We now need to update the OnPaint
handler to use the selected
foregroundColor when drawing the text
to the canvas.
● my foreground paint - returns the
effective foreground color of the
widget. This value is either
inherited, set in code or set in the
Property Inspector
● set the paint of this canvas - sets
the color to be used when drawing
to the canvas
public handler OnPaint()
… variable declarations
set the font of this canvas to my font
set the paint of this canvas to my
foreground paint
… code continues
end handler
#LiveCodeGlobal
Test the Text Fill property
Compile and test the widget using the
Extension Builder.
● Go into Edit mode
● Select the widget in the test stack
● Open the Property Inspector
● Go to the Colors pane
● Change the Text fill
#LiveCodeGlobal
Handling mouse events
You will often want to create widgets that can respond to user actions.
LCB provides a range of messages, similar to LiveCode event messages, some
examples are
● OnMouseDown
● OnMouseUp
● OnDoubleClick
● OnKeyPress
You can choose which of these messages your widget will handle and how to handle
them. Note that the event names are all one word, e.g. OnMouseUp, unlike LCS.
You can can also post messages to the widget object in LiveCode, these can be
standard messages such as mouseUp or customised messages, such as
segmentClicked in a Pie Chart widget.
As with widget handlers we use TitleCase for event names.
#LiveCodeGlobal
Handling mouseUp
When the widget is clicked we want it to
get a mouseUp message, just like a
button or graphic control.
To do this we handle the LCB
OnMouseUp message and post a
mouseUp message to the widget object.
Add the OnMouseUp handler to the
widget code.
Note: Properties and events are, by their
nature, always public as they define
things which are external to the widget.
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… property definitions
… OnPaint and OnCreate handlers
… Property Setters
public handler OnMouseUp()
post "mouseUp"
end handler
end widget
#LiveCodeGlobal
Compile and test the widget using the
Extension Builder.
● Go into Edit mode
● Select the widget on the test stack
● Open the Code editor for the
widget
on mouseUp
answer "mouseUp received"
end mouseUp
● Go into Run mode
● Click the widget
● The widget will respond to the
mouse click
Testing mouseUp
#LiveCodeGlobal
You can post any message to the widget
object, not just LiveCode messages.
For example if you want the Rotated Text
Widget to receive a rotatedTextClicked
message instead of a mouseUp
message when it is clicked you would
post “rotatedTextClicked”.
public handler OnMouseUp()
post "rotatedTextClicked"
end handler
Custom messages
#LiveCodeGlobal
Creating, saving and loading widgets
In Lesson 3 we looked at the core handlers but so far we have only
implemented the OnPaint and OnCreate handlers. In this lesson we
will implement the OnSave and OnLoad handlers.
Handler Description
OnSave Sent when your widget is about to be destroyed
and enables the widget to save data set on the
widget.
OnLoad Sent when your widget is created and enables
the widget to retrieve data saved on the widget.
#LiveCodeGlobal
We want to be able to save and load the widget’s properties.
If the OnSave and OnLoad handlers are not included then every time you
open a saved stack that includes a widget, the widget will lose its property
data and the properties will be set to the default values.
When your widget is saved you are sent an OnSave message. It returns an
array which you can fill with whatever widget data you have. LiveCode saves
this data along with instances of the widget in the stack file.
This same array will be returned to you as a parameter to the the OnLoad
message, which is sent when the widget is next opened and can be used to
recreate the widget with its saved properties.
Saving and loading the widget state
#LiveCodeGlobal
The OnSave handler
First we write the OnSave handler, which saves
the widget’s properties when a stack containing
a widget is saved.
Add the OnSave handler to the widget code.
The rProperties array is an out parameter
meaning the value of the array is copied back
to the caller when the handler completes.
Add an element to the rProperties array for
each property
● key: property name
● value: property value
Note: LiveCode properties are automatically
saved so don’t need to be explicitly stored in the
array.
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… property definitions
… OnPaint and OnCreate handlers
… Property Setters
… Event handlers
public handler OnSave(out rProperties as Array)
put mContent into rProperties["content"]
put mRotation into rProperties["rotation"]
end handler
end widget
#LiveCodeGlobal
The OnLoad handler
Next we write the OnLoad handler, which loads
the widget’s properties when a stack containing
a widget is opened:
Add the OnLoad handler to the widget code.
The array of saved properties is passed in as a
parameter, and can be used to set the values of
the private instance variables to the stored
property values.
● Set the value of the content property to
the value of the content element in the
properties array
● Set the value of the rotation property to
the value of the rotation element in the
properties array
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… property definitions
… OnPaint and OnCreate handlers
… Property Setters
… Event handlers
… OnSave handler
public handler OnLoad(in pProperties as Array)
put pProperties["content"] into mContent
put pProperties["rotation"] into mRotation
end handler
end widget
#LiveCodeGlobal
Testing saving and loading a widget
In order to test saving and loading a widget we have
to install the widget.
● Open the Extension Builder from the Tools
Palette
● Load the lcb file
● Uninstall the previous widget, if necessary
● Click Install
● The widget will appear in the Tools Palette
● Create a new stack
● Drag on a Rotated Text Widget
● Set some properties
● Save the stack
● Close LiveCode
● Reopen the stack
The widget should appear with its properties set to
the saved state.
#LiveCodeGlobal
Read only properties
So far we have only looked at properties that can be set by the user.
In this lesson we will implement some read-only properties that depend
entirely on the widget state. These properties will be familiar to anyone
experienced with LiveCode Script.
● formattedWidth - Reports the width needed by an object to display its
full contents without scrolling. This property is read-only and cannot be
set.
● formattedHeight - Reports the height needed by an object to display its
full contents without scrolling. This property is read-only and cannot be
set.
We will implement these two properties for the Rotated Text widget by
calculating the space the text displayed in the widget requires and returning
these values.
#LiveCodeGlobal
Declare the properties
Firstly declare the properties in the
widget source code.
Add two instance variables to hold the
property values and add definitions for
the formattedWidth and
formattedHeight properties.
Because the properties are read only
they do not require setter identifiers. The
getter simply returns the value of the
variable.
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… existing property definitions
private variable mFormattedWidth as Real
private variable mFormattedHeight as Real
property "formattedWidth" get mFormattedWidth
property "formattedHeight" get mFormattedHeight
… OnPaint and OnCreate handlers
… Property Setters
… Event handlers
.... OnSave and OnLoad handlers
end widget
#LiveCodeGlobal
We want to update the values of the
formattedWidth and formattedHeight
properties whenever the state of the widget
changes. This ensures the correct value will
always be returned by the property.
Update the OnPaint handler to calculate and
store the formattedWidth and
formattedHeight of the widget whenever it is
redrawn.
● Declare a rectangle variable
● Get the bounds of the text on the
canvas. This returns the bounding box of
the text when drawn at point 0,0 as a
rectangle, taking into account the font,
style and text size of the canvas
● Update the variables holding the property
values with the width and height of the
bounding box of the text
Storing the values
public handler OnPaint()
… previous code
variable tBounds as Rectangle
put the bounds of text mContent on this
canvas into tBounds
put the width of tBounds into mFormattedWidth
put the height of tBounds into
mFormattedHeight
end handler
#LiveCodeGlobal
Testing read only properties
Compile and test the widget using the
Extension Builder.
● Go into Edit mode
● Select the widget in the test stack
● Open the Property Inspector
The formattedWidth and
formattedHeight properties will be
shown on the Basic pane, they can’t be
edited because the are read only.
You can check the width and height
properties in the Position pane and see
they are different values.
#LiveCodeGlobal
Hiding properties
There may be cases where your widget
has properties that you do not want to
show in the Property Inspector. This may
be because they are read only, internal
or undocumented.
You can set property metadata to
prevent the properties being visible to the
user.
Add user_visible metadata to the
formattedWidth and formattedHeight
properties
widget community.livecode.elanorb.rotatedtext
… widget inclusions and metadata
… existing property definitions
private variable mFormattedWidth as Real
private variable mFormattedHeight as Real
property "formattedWidth" get mFormattedWidth
metadata formattedWidth.user_visible is "false"
property "formattedHeight" get mFormattedHeight
metadata formattedHeight.user_visible is "false"
… OnPaint and OnCreate handlers
… Property Setters
… Event handlers
.... OnSave and OnLoad handlers
end widget
#LiveCodeGlobal
Testing non user-visible properties
Compile and test the widget using the
Extension Builder.
● Go into Edit mode
● Select the widget on the test stack
● Open the Property Inspector
The formattedWidth and
formattedHeight properties will not be
shown in the Property Inspector.
However you can get the property value
from code. Execute the following code in
the Message Box to test the property.
put the formattedHeight of widget 1
#LiveCodeGlobal
Documenting the widget
Extensions can provide an API (Dictionary) entry and User Guide as
part of the installed package. They are installed and viewable
through the LiveCode Dictionary stack.
In Lesson 2 we documented a library extension, which involved
documenting the handlers provided by the library.
To document the widget we will document the properties and
messages associated with the widget. As with the Hello World
library, we will use in-line documentation comments in the LCB file
to document the widget.
#LiveCodeGlobal
Documenting the widget
A description of the widget can be
included in a comment block above
the widget declaration in the LCB
file.
This description will appear in the
Dictionary stack under the API entry
for the widget identifier.
Add a comment block with a
description of the widget at the start
of the LCB file.
/**
A rotated text control. The control displays
text rotated to a given number of degrees, 0
degrees meaning unrotated.
**/
widget community.livecode.elanorb.rotatedText
… widget code
end widget
#LiveCodeGlobal
Documenting messages
Widget messages are not declared
explicitly in the LCB file, so all messages
should be documented within the
comment block that includes the widget
description at the start of the LCB file.
Each message has
● Name
● Type
● Syntax
● Description
Add the documentation for the mouseUp
message to LCB file.
You can add documentation for multiple
messages in this comment block.
/**
A rotated text control. The control displays
text rotated to a given number of degrees, 0
degrees meaning unrotated.
Name: mouseUp
Type: message
Syntax: on mouseUp
Description:
The <mouseUp> message is sent when the widget
is clicked.
**/
widget community.livecode.elanorb.rotatedText
… widget code
end widget
#LiveCodeGlobal
Documenting properties
When properties in LCB, the documentation is
included above the property definition within a
/** **/ comment block.
Include
● Syntax: the syntax for using the property.
This usually included a set and get
example
● Summary: a brief description of the
property
● Description: a more extensive description
of the property, its effects and how to use
it
Add in-line documentation for the declared
Rotated Text widget properties: rotation,
content, formattedWidth and
formattedHeight.
/**
Syntax: set the rotation of <widget> to
<pDegrees>
Syntax: get the rotation of <widget>
Summary: The number of degrees the text
displayed in the widget is rotated by.
Description:
Use the <rotation> property to set the amount
the text displayed in the widget is rotated
by. The default is 0 degrees which is
unrotated, horizontal text. The text is
rotated in a clockwise direction.
**/
property "rotation" get mRotation set
setRotation
#LiveCodeGlobal
Documenting Properties
The foregroundColor property shadows a
LiveCode property and is not declared explicitly
in the widget source code. Therefore the
documentation must be in the top-level
comment beside the message documentation.
Include
● Name: the property name
● Type: “property”
● Syntax: the syntax for using the property.
This usually included a set and get
example
● Summary: a brief description of the
property
● Description: a more extensive description
of the property, its effects and how to use
it
/**
...widget and message documentation
Name: foregroundColor
Type: property
Syntax: set the foregroundColor of <widget> to
<pColor>
Syntax: get the foregroundColor of <widget>
Summary: The text color of the widget
Description:
Use the <foregroundColor> property to control
the text color of the widget.
**/
widget community.livecode.elanorb.rotatedText
… widget code
end widget
#LiveCodeGlobal
Browsing the documentation
Use the Extension Builder to install the
widget. You can find the widget icons in
the Lesson 4 Resources.
You will see the Rotated Text widget in
the Tools Palette.
Open the Dictionary stack and select
Rotated Text from the drop down menu.
The documentation for the widget,
message and properties will be shown in
the Dictionary stack.
#LiveCodeGlobal
Congratulations
You have completed this lesson, you can now
● Fully integrate widget properties into the Property Inspector
● Shadow standard LiveCode properties
● Handle mouse events to make widgets clickable
● Save and load widget properties
● Add read only properties to a widget
● Document the widget
#LiveCodeGlobal
Widget Course
Extending LiveCode with Widgets and Libraries
LiveCode
Dev Team
#LiveCodeGlobal
The Pie Chart Widget
#LiveCodeGlobal
The Pie Chart Widget
In this lesson we will plan and implement a Pie Chart widget.
We will
● Decide how the Pie Chart should look
● Decide what properties the Pie Chart should have
● Decide what messages the Pie Chart should send
● Implement the Pie Chart widget in steps
○ Define the Properties
○ Implement OnCreate
○ Implement OnPaint
○ Implement OnGeometryChanged
○ Implement OnSave
○ Implement OnLoad
○ Respond to mouse events
● Document the widget
● Package and install the widget
#LiveCodeGlobal
Pie Chart Examples
Everyone is familiar with pie charts, but before we start
implementing the pie chart widget we’ll look at a couple of examples.
Google Docs Libre Office
#LiveCodeGlobal
The Pie Chart information
There are 2 main pieces of information
required to draw the pie chart
● List of values
● Labels associated with each value
In the examples we looked at, the values
and labels were:
Label Value
January 1
February 2
March 3
April 5
May 8
June 13
#LiveCodeGlobal
The Pie Chart layout
The usual layout for pie charts is to have
● Chart on the left
● List of labels on the right
Because the user can resize the widget there
are some considerations for us
● Ensure the labels are shown
● Make the pie chart the maximum size
while showing all the labels
● If the widget is taller than it is wide
display the labels below the chart
● Allow the user to choose whether to
show the labels or not, to provide
flexibility within apps
Aaa
Bbb
Ccc
Aaa
Bbb
Ccc
#LiveCodeGlobal
Pie Chart properties and messages
Through planning our widget we have identified 3 properties the widget needs
● List of values
● List of labels
● Boolean value specifying whether the labels should be shown or not
We also want the widgets to respond to user actions. We could simply provide a
mouseUp message but for a pie chart this is not particularly informative. Instead a
useful message would tell the user that the chart had been clicked, and which sector
was clicked on. So we will send a message with a parameter
● sectorClicked pSectorNumber
The colors used for sectors will be assigned by the widget. A possible extension of the
widget would be to make these colors settable by the user.
#LiveCodeGlobal
Creating the LiveCode Builder file
As with the Hello World Library and
Rotated Text Widget we will start a new
LiveCode Builder source file.
● Create a new directory.
● Create a new plain text file in the
directory and save it to disk with
the extension "lcb".
I am naming my file "pieChart.lcb" but
you can name your file anything suitable.
Note: The extension builder currently
relies on there being only one .lcb file in
a given directory, this is why we create a
separate folder for each new extension.
#LiveCodeGlobal
Widget definition
Begin by defining the pie chart widget in
the LCB file.
Remember
● The widget declaration is followed
by an identifier.
● An extension identifier should be in
the form
community.livecode.<user
name>.<widget name>
For more on module naming see the
Naming section of the LiveCode Builder
Style Guide, accessible from the
Dictionary stack or the Additional
Resources section of the course.
widget community.livecode.elanorb.piechart
end widget
#LiveCodeGlobal
Include the recommended modules and
libraries in the LCB file.
● com.livecode.canvas
● com.livecode.widget
● com.livecode.engine
● Com.livecode.library.widgetutils
For a full list of modules see the
Importing Libraries section of the
Extending LiveCode Guide and the API
entries for the individual modules.
Including modules
widget community.livecode.elanorb.piechart
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.library.widgetutils
end widget
#LiveCodeGlobal
Widget metadata
Add the required widget metadata to the
definition.
● Title
● Author
● Version number
You can also include an optional
metadata. We want to ensure the Pie
Chart widget is created at a reasonable
size so add
● Preferred size
widget community.livecode.elanorb.piechart
use com.livecode.canvas
use com.livecode.widget
use com.livecode.engine
use com.livecode.library.widgetutils
metadata title is "Pie Chart"
metadata author is "Elanor Buchanan"
metadata version is "1.0.0"
metadata preferredSize is "200,150"
end widget
#LiveCodeGlobal
Variable declarations
In Step 1 we identified 3 properties of the Pie
Chart widget: values, labels and whether labels
should be shown.
In addition we want an a list variable to store the
list of colors that will be used for the sectors.
As before we will use module level variables
to store the values of these properties.
Declare the 4 variables and their types.
Also add a constant, kPadding, which will be
used to layout the elements of the widget.
Note: See Lesson 3 - Step 3: Module level
variables if you need a refresher.
widget community.livecode.elanorb.piechart
… module imports
… metadata
private variable mValues as List
private variable mLabels as List
private variable mColors as List
private variable mShowLabels as Boolean
constant kPadding is 10
end widget
#LiveCodeGlobal
The values property will have both a
getter and a setter handler.
Add the definition for the property,
including:
● Property name
● Getter handler name
● Setter handler name
● Default value
● Property label
The values property
widget community.livecode.elanorb.piechart
… module imports
… metadata
… instance variable declarations
property "sectorValues" get getValues set
setValues
metadata sectorValues.default is
"1,2,3,5,8,13"
metadata sectorValues.label is "Values"
end widget
#LiveCodeGlobal
The segmentValues property has both a
getter and a setter property.
The Property Inspector allows the user to
set the segmentValues to a comma
separated list of values.
The setValues handler converts the
comma separated string to a LCB list.
The getValues handler converts the LCB
list to a string, allowing it to be displayed
in the Property Inspector.
Add the handlers to the source code.
The values property
widget community.livecode.elanorb.piechart
...previous code
public handler setValues(in pValues as String)
returns nothing
split pValues by "," into mValues
redraw all
end handler
private handler getValues() returns String
variable tValues
combine mValues with "," into tValues
return tValues
end handler
end widget
#LiveCodeGlobal
The labels property will also have both a
getter and a setter handler.
Add the definition for the property,
including:
● Property name
● Getter handler name
● Setter handler name
● Default value
● Property label
The labels property widget community.livecode.elanorb.piechart
… module imports
… metadata
… instance variable declarations
… previous property definitions
property "sectorLabels" get getLabels set
setLabels
metadata sectorLabels.default is
"Jan,Feb,Mar,Apr,May,Jun"
metadata sectorLabels.label is "Labels"
… code continues
end widget
#LiveCodeGlobal
Like the segmentValues property the
segmentLabels property has both a
getter and a setter property.
The Property Inspector allows the user to
set the segmentLabels to a comma
separated list of values.
The setLabels handler converts the
comma separated string to a LCB list.
The labels property widget community.livecode.elanorb.piechart
… previous code
public handler setLabels(in pLabels as String)
returns nothing
split pLabels by "," into mLabels
redraw all
end handler
private handler getLabels() returns String
variable tLabels
combine mLabels with "," into tLabels
return tLabels
end handler
end widget
#LiveCodeGlobal
The Show labels property is a boolean
value so only has a setter handler.
The value of the mShowLabels variable
is returned when the property value is
requested.
Add the definition for the property,
including:
● Property name
● Variable name for the get method
● Setter handler name
● Default value
● Property label
The showLabels property
widget community.livecode.elanorb.piechart
… module imports
… metadata
… instance variable declarations
… previous property definitions
property "showLabels" get mShowLabels set
setShowLabels
metadata showLabels.default is "true"
metadata showLabels.label is "Show labels"
… code continues
end widget
#LiveCodeGlobal
The setShowLabels handler sets the
value of the mShowLabels variable to the
value passed in.
Add the handler to the source code.
The showLabels property
widget community.livecode.elanorb.piechart
… previous code
public handler setShowLabels(in pShow as
Boolean) returns nothing
put pShow into mShowLabels
redraw all
end handler
end widget
#LiveCodeGlobal
The OnCreate handler
The OnCreate handler is sent to a widget when it is
first created by LiveCode.
This handler can be used to initialise default data
and, where applicable, reduce the burden for
calculating constants etc in the OnPaint handler.
Add the OnCreate handler to the LCB file
● Define a variable, tSectors, to hold the
number of sectors
● Call setValues to set the default values of
the mValues variable.
● Call setLabels to set the default values of
the mLabels variable
● Set the value of mShowLabels to true
● Update tSectors with the number of elements
in the list of values
● Call colorList to intitialise the mColors
variable
Setting the property values in the OnCreate handler
ensures the values of the properties are set when
we test from the Extension Builder.
widget community.livecode.elanorb.piechart
...previous code
public handler OnCreate()
variable tSectors
setValues("1,2,3,5,8,13")
setLabels("Jan,Feb,Mar,Apr,May,Jun")
put true into mShowLabels
put the number of elements in mValues into
tSectors
put colorList(tSectors) into mColors
end handler
end widget
#LiveCodeGlobal
LiveCode Builder Colors
LiveCode Builder colors are expressions which evaluates to a list of
3 or 4 numbers, the red, green, blue, and (optional) alpha
components of the color.
The component value denotes the intensity of that component,
expressed as a real number between 0 and 1. The alpha component
represents the opacity of the color. If the alpha component is not
specified then it is assumed to be 1 (fully opaque).
variable tColor
-- Set tColor to opaque red
put color [1.0, 0.0, 0.0] into tColor
-- Set tColor to partially transparent cyan
put color [0.0, 1.0, 1.0, 0.75] into tColor
#LiveCodeGlobal
The colorList handler Red: 1,0,0,1
Green: 0,1,0,1
Blue: 0,0,1,1
Yellow: 1,1,0,1
Purple: 1,0,1,1
Cyan: 0,1,1,1
Red 2: 0.5,0,0,1
Green 2: 0,0.5,0,1
Blue 2: 0,0,0.5,1
Yellow 2: 0.5,0.5,0,1
Purple 2: 0.5,0,0.5,1
Cyan 2: 0,0.5,0.5,1
The colorList handler returns a list of unique
colors for use when coloring the sectors of the
chart.
The number of colors to be returned is given by
the pNumber parameter.
The handler loops calculating RGB values for
colors.
● Highest intensity primary colors
● Highest intensity secondary colors
● Reduce the color intensity by half
Each iteration adds 6 colors to the list.
1. R,0,0,1
2. 0,G,0,1
3. 0,0,B,1
4. R,G,0,1
5. R,0,B,1
6. 0,G,B,1
#LiveCodeGlobal
The colorList handler
Add the colorList handler to the source
file.
● Declare the variables that will be
used.
● Assign a value to tColorLevel: the
color intensity to be used.
● Calculate the number of repeats
○ Divide pNumber by 6, 6
colors are add to the color list
on each iteration of the loop
○ Round the result
○ Add 1 to the result to ensure
we always calculate enough
colors
public handler colorList(in pNumber) returns
List
variable tColors as List
variable tColorLevel as Number
variable tRepeats as Number
put 1 into tColorLevel
put pNumber / 6 into tRepeats
round tRepeats
add 1 to tRepeats
… continues on next slide
end handler
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course
Livecode widget course

Contenu connexe

Tendances

글쓰는 개발자 모임, 글또
글쓰는 개발자 모임, 글또글쓰는 개발자 모임, 글또
글쓰는 개발자 모임, 글또Seongyun Byeon
 
Random Thoughts on Paper Implementations [KAIST 2018]
Random Thoughts on Paper Implementations [KAIST 2018]Random Thoughts on Paper Implementations [KAIST 2018]
Random Thoughts on Paper Implementations [KAIST 2018]Taehoon Kim
 
로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법Jeongsang Baek
 
결제를 구현하고 싶은 개발팀을 위한 안내서
결제를 구현하고 싶은 개발팀을 위한 안내서결제를 구현하고 싶은 개발팀을 위한 안내서
결제를 구현하고 싶은 개발팀을 위한 안내서수보 김
 
Transforming Accessibility one lunch at a tiime - CSUN 2023
Transforming Accessibility one lunch at a tiime - CSUN 2023Transforming Accessibility one lunch at a tiime - CSUN 2023
Transforming Accessibility one lunch at a tiime - CSUN 2023Ted Drake
 
Agile Transformation Governance Model
Agile Transformation Governance ModelAgile Transformation Governance Model
Agile Transformation Governance ModelACM
 
Elastic Stack & Data pipeline
Elastic Stack & Data pipelineElastic Stack & Data pipeline
Elastic Stack & Data pipelineJongho Woo
 
Elastic Search Indexing Internals
Elastic Search Indexing InternalsElastic Search Indexing Internals
Elastic Search Indexing InternalsGaurav Kukal
 
Agility boosts performance: Guide for your agile transformation journey
Agility boosts performance: Guide for your agile transformation journeyAgility boosts performance: Guide for your agile transformation journey
Agility boosts performance: Guide for your agile transformation journeySebastian Olbert
 
Cynefin sensemaking framework and usage examples
Cynefin sensemaking framework and usage examplesCynefin sensemaking framework and usage examples
Cynefin sensemaking framework and usage examplesLuxoftAgilePractice
 
Jack Ryger: Top 5 Skiing Resorts in Switzerland
Jack Ryger: Top 5 Skiing Resorts in SwitzerlandJack Ryger: Top 5 Skiing Resorts in Switzerland
Jack Ryger: Top 5 Skiing Resorts in SwitzerlandJack D. Ryger
 
Data Engineering 101
Data Engineering 101Data Engineering 101
Data Engineering 101DaeMyung Kang
 
집단지성 프로그래밍 06-의사결정트리-01
집단지성 프로그래밍 06-의사결정트리-01집단지성 프로그래밍 06-의사결정트리-01
집단지성 프로그래밍 06-의사결정트리-01Kwang Woo NAM
 
KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈
KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈
KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈Minwoo Kim
 
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축Juhong Park
 
[NEXT] Flask 로 Restful API 서버 만들기
[NEXT] Flask 로 Restful API 서버 만들기 [NEXT] Flask 로 Restful API 서버 만들기
[NEXT] Flask 로 Restful API 서버 만들기 YoungSu Son
 
Enterprise Agile Coaching - Professional Agile Coaching #3
Enterprise Agile Coaching - Professional Agile Coaching #3Enterprise Agile Coaching - Professional Agile Coaching #3
Enterprise Agile Coaching - Professional Agile Coaching #3Cprime
 

Tendances (20)

글쓰는 개발자 모임, 글또
글쓰는 개발자 모임, 글또글쓰는 개발자 모임, 글또
글쓰는 개발자 모임, 글또
 
Random Thoughts on Paper Implementations [KAIST 2018]
Random Thoughts on Paper Implementations [KAIST 2018]Random Thoughts on Paper Implementations [KAIST 2018]
Random Thoughts on Paper Implementations [KAIST 2018]
 
로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법
 
결제를 구현하고 싶은 개발팀을 위한 안내서
결제를 구현하고 싶은 개발팀을 위한 안내서결제를 구현하고 싶은 개발팀을 위한 안내서
결제를 구현하고 싶은 개발팀을 위한 안내서
 
Transforming Accessibility one lunch at a tiime - CSUN 2023
Transforming Accessibility one lunch at a tiime - CSUN 2023Transforming Accessibility one lunch at a tiime - CSUN 2023
Transforming Accessibility one lunch at a tiime - CSUN 2023
 
Agile Transformation Governance Model
Agile Transformation Governance ModelAgile Transformation Governance Model
Agile Transformation Governance Model
 
Modeling and Measuring DevOps Culture
Modeling and Measuring DevOps CultureModeling and Measuring DevOps Culture
Modeling and Measuring DevOps Culture
 
Elastic Stack & Data pipeline
Elastic Stack & Data pipelineElastic Stack & Data pipeline
Elastic Stack & Data pipeline
 
Elastic Search Indexing Internals
Elastic Search Indexing InternalsElastic Search Indexing Internals
Elastic Search Indexing Internals
 
Agility boosts performance: Guide for your agile transformation journey
Agility boosts performance: Guide for your agile transformation journeyAgility boosts performance: Guide for your agile transformation journey
Agility boosts performance: Guide for your agile transformation journey
 
Cynefin sensemaking framework and usage examples
Cynefin sensemaking framework and usage examplesCynefin sensemaking framework and usage examples
Cynefin sensemaking framework and usage examples
 
Jack Ryger: Top 5 Skiing Resorts in Switzerland
Jack Ryger: Top 5 Skiing Resorts in SwitzerlandJack Ryger: Top 5 Skiing Resorts in Switzerland
Jack Ryger: Top 5 Skiing Resorts in Switzerland
 
Data Science. Intro
Data Science. IntroData Science. Intro
Data Science. Intro
 
Data Engineering 101
Data Engineering 101Data Engineering 101
Data Engineering 101
 
집단지성 프로그래밍 06-의사결정트리-01
집단지성 프로그래밍 06-의사결정트리-01집단지성 프로그래밍 06-의사결정트리-01
집단지성 프로그래밍 06-의사결정트리-01
 
KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈
KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈
KGC 2014 가볍고 유연하게 데이터 분석하기 : 쿠키런 사례 중심 , 데브시스터즈
 
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
[NDC 2018] Spark, Flintrock, Airflow 로 구현하는 탄력적이고 유연한 데이터 분산처리 자동화 인프라 구축
 
Redis
RedisRedis
Redis
 
[NEXT] Flask 로 Restful API 서버 만들기
[NEXT] Flask 로 Restful API 서버 만들기 [NEXT] Flask 로 Restful API 서버 만들기
[NEXT] Flask 로 Restful API 서버 만들기
 
Enterprise Agile Coaching - Professional Agile Coaching #3
Enterprise Agile Coaching - Professional Agile Coaching #3Enterprise Agile Coaching - Professional Agile Coaching #3
Enterprise Agile Coaching - Professional Agile Coaching #3
 

Similaire à Livecode widget course

outgoing again
outgoing againoutgoing again
outgoing againspredslide
 
Introduction to Software Development
Introduction to Software DevelopmentIntroduction to Software Development
Introduction to Software DevelopmentZeeshan MIrza
 
Description of VivaVisualCode
Description of VivaVisualCodeDescription of VivaVisualCode
Description of VivaVisualCodePVS-Studio
 
Eclipse_Building_Blocks
Eclipse_Building_BlocksEclipse_Building_Blocks
Eclipse_Building_BlocksRahul Shukla
 
Advanced c programming in Linux
Advanced c programming in Linux Advanced c programming in Linux
Advanced c programming in Linux Mohammad Golyani
 
Basic iOS Training with SWIFT - Part 4
Basic iOS Training with SWIFT - Part 4Basic iOS Training with SWIFT - Part 4
Basic iOS Training with SWIFT - Part 4Manoj Ellappan
 
VivaCore - Quick Start
VivaCore - Quick StartVivaCore - Quick Start
VivaCore - Quick StartPVS-Studio
 
What is Java
What is JavaWhat is Java
What is Java3trg
 
The essence of the VivaCore code analysis library
The essence of the VivaCore code analysis libraryThe essence of the VivaCore code analysis library
The essence of the VivaCore code analysis libraryPVS-Studio
 
Introduction to java
Introduction to javaIntroduction to java
Introduction to javaAli Baba
 
Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...
Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...
Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...Mickael Istria
 
Purdue CS354 Operating Systems 2008
Purdue CS354 Operating Systems 2008Purdue CS354 Operating Systems 2008
Purdue CS354 Operating Systems 2008guestd9065
 
JavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript HereJavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript HereLaurence Svekis ✔
 
mblock_extension_guide.pdf
mblock_extension_guide.pdfmblock_extension_guide.pdf
mblock_extension_guide.pdfDogoMaker
 

Similaire à Livecode widget course (20)

Javascript mynotes
Javascript mynotesJavascript mynotes
Javascript mynotes
 
outgoing again
outgoing againoutgoing again
outgoing again
 
Welcome to React.pptx
Welcome to React.pptxWelcome to React.pptx
Welcome to React.pptx
 
Hibernate notes
Hibernate notesHibernate notes
Hibernate notes
 
Introduction to Software Development
Introduction to Software DevelopmentIntroduction to Software Development
Introduction to Software Development
 
Android dev tips
Android dev tipsAndroid dev tips
Android dev tips
 
Description of VivaVisualCode
Description of VivaVisualCodeDescription of VivaVisualCode
Description of VivaVisualCode
 
Eclipse_Building_Blocks
Eclipse_Building_BlocksEclipse_Building_Blocks
Eclipse_Building_Blocks
 
Advanced c programming in Linux
Advanced c programming in Linux Advanced c programming in Linux
Advanced c programming in Linux
 
Basic iOS Training with SWIFT - Part 4
Basic iOS Training with SWIFT - Part 4Basic iOS Training with SWIFT - Part 4
Basic iOS Training with SWIFT - Part 4
 
VivaCore - Quick Start
VivaCore - Quick StartVivaCore - Quick Start
VivaCore - Quick Start
 
What is Java
What is JavaWhat is Java
What is Java
 
The essence of the VivaCore code analysis library
The essence of the VivaCore code analysis libraryThe essence of the VivaCore code analysis library
The essence of the VivaCore code analysis library
 
Introduction to java
Introduction to javaIntroduction to java
Introduction to java
 
Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...
Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...
Adopting Debug Adapter Protocol in Eclipse IDE: netcoredbg (.NET debugger) ca...
 
Purdue CS354 Operating Systems 2008
Purdue CS354 Operating Systems 2008Purdue CS354 Operating Systems 2008
Purdue CS354 Operating Systems 2008
 
J introtojava1-pdf
J introtojava1-pdfJ introtojava1-pdf
J introtojava1-pdf
 
JavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript HereJavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript Here
 
Ide
IdeIde
Ide
 
mblock_extension_guide.pdf
mblock_extension_guide.pdfmblock_extension_guide.pdf
mblock_extension_guide.pdf
 

Plus de crazyaxe

Rebol brainwasher
Rebol brainwasherRebol brainwasher
Rebol brainwashercrazyaxe
 
Rebol VID STYLE CREATION AND DESIGN
Rebol VID STYLE CREATION AND DESIGNRebol VID STYLE CREATION AND DESIGN
Rebol VID STYLE CREATION AND DESIGNcrazyaxe
 
Introduzione all'open source e Linux
Introduzione all'open source e LinuxIntroduzione all'open source e Linux
Introduzione all'open source e Linuxcrazyaxe
 
Where is Carl?
Where is Carl?Where is Carl?
Where is Carl?crazyaxe
 
Rebol installation
Rebol installationRebol installation
Rebol installationcrazyaxe
 
Glance rebol
Glance rebolGlance rebol
Glance rebolcrazyaxe
 
1 A Chi Appartiene
1 A Chi Appartiene1 A Chi Appartiene
1 A Chi Appartienecrazyaxe
 
Prodotti Biologici Una Grande Truffa
Prodotti Biologici Una Grande TruffaProdotti Biologici Una Grande Truffa
Prodotti Biologici Una Grande Truffacrazyaxe
 
Introduzione all'Open Source e Linux
Introduzione all'Open Source e LinuxIntroduzione all'Open Source e Linux
Introduzione all'Open Source e Linuxcrazyaxe
 
Come Funzianano Internet Email Chat Newsgro
Come Funzianano Internet Email Chat NewsgroCome Funzianano Internet Email Chat Newsgro
Come Funzianano Internet Email Chat Newsgrocrazyaxe
 
Chromium problems
Chromium problemsChromium problems
Chromium problemscrazyaxe
 

Plus de crazyaxe (16)

Livecode
LivecodeLivecode
Livecode
 
Rebol brainwasher
Rebol brainwasherRebol brainwasher
Rebol brainwasher
 
Rebol VID STYLE CREATION AND DESIGN
Rebol VID STYLE CREATION AND DESIGNRebol VID STYLE CREATION AND DESIGN
Rebol VID STYLE CREATION AND DESIGN
 
Introduzione all'open source e Linux
Introduzione all'open source e LinuxIntroduzione all'open source e Linux
Introduzione all'open source e Linux
 
Where is Carl?
Where is Carl?Where is Carl?
Where is Carl?
 
Rebol installation
Rebol installationRebol installation
Rebol installation
 
Glance rebol
Glance rebolGlance rebol
Glance rebol
 
Neo-Sens
Neo-SensNeo-Sens
Neo-Sens
 
Neo-Sens
Neo-SensNeo-Sens
Neo-Sens
 
Rebol
RebolRebol
Rebol
 
1 A Chi Appartiene
1 A Chi Appartiene1 A Chi Appartiene
1 A Chi Appartiene
 
Rebol
RebolRebol
Rebol
 
Prodotti Biologici Una Grande Truffa
Prodotti Biologici Una Grande TruffaProdotti Biologici Una Grande Truffa
Prodotti Biologici Una Grande Truffa
 
Introduzione all'Open Source e Linux
Introduzione all'Open Source e LinuxIntroduzione all'Open Source e Linux
Introduzione all'Open Source e Linux
 
Come Funzianano Internet Email Chat Newsgro
Come Funzianano Internet Email Chat NewsgroCome Funzianano Internet Email Chat Newsgro
Come Funzianano Internet Email Chat Newsgro
 
Chromium problems
Chromium problemsChromium problems
Chromium problems
 

Dernier

%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburgmasabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...chiefasafspells
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benonimasabamasaba
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 

Dernier (20)

%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 

Livecode widget course

  • 1. #LiveCodeGlobal Widget Course Extending LiveCode with Widgets and Libraries LiveCode Dev Team
  • 3. #LiveCodeGlobal LiveCode Builder Extensions In this lesson we will create a minimal LiveCode Builder library which extends the set of commands and functions available in LiveCode. We will ● Install and configure an appropriate text editor for developing in LiveCode Builder. ● Create a Hello World library which extends LiveCode with a single function, which returns the string “Hello World!”. ● Compile the library. ● Install the library into the LiveCode IDE. ● Include the library in a standalone.
  • 4. #LiveCodeGlobal Libraries and Widgets There are two types of extensions that can be created with LiveCode Builder: ● Libraries: A library can be used to extend the set of commands and functions available in LiveCode. The public handlers in a library are added at the bottom of the Message Path. LCB libraries make LCB features available to LiveCode apps directly. They can also be used as support code for widgets. ● Widgets: A widget is a custom control that is treated as an engine level element. Widgets appear in the Tools Palette and can be added as controls to any LiveCode stack. A widget and a library are identical, except that a widget draws to a canvas. As a result, the authoring process is much the same for both extension types.
  • 5. #LiveCodeGlobal When to use LiveCode Builder Write widgets when: ● You need unique capabilities that can't be provided by "traditional" controls. ● You require encapsulation - widgets are 'black boxes' whose behavior can only be changed from LiveCode apps via predefined API. ● You want access to drawing / low-level / native APIs. ● You want improved performance, you control what recalculations are made when a control is redrawn.
  • 6. #LiveCodeGlobal When to use LiveCode Builder Write libraries when: ● You want to write functions that are available to both LiveCode Builder(LBC) and LiveCode Script(LCS). ● You want to wrap platform-specific functionality and make it usable from LiveCode Script. ● You want to use LiveCode Builder's stricter rules to implement algorithms that can't be expressed reliably in LiveCode Script.
  • 7. #LiveCodeGlobal The Message Path LiveCode Engine LiveCode Builder Libraries Stack Card Group Grouped Control Control Input Events (mouseUp, keyDown, etc.) Other Events (openCard, closeStack, etc.) Handlers implemented in installed libraries are placed at the end of the Message Path. For more on the Message Path see the “Message Path” Chapter of the LiveCode User Guide.
  • 8. #LiveCodeGlobal Installed widgets are shown in the widgets section of the Tools Palette. Widgets are added to stacks by dragging and dropping from the Tools Palette. Tools Palette showing installed widgets Rotated Text Widget Pie Chart Widget
  • 9. #LiveCodeGlobal LiveCode Builder API The API for LiveCode Builder is available in the Dictionary stack. You may find it useful to have this open while you are writing your extension. 1. Open the Dictionary from the Menubar. 2. Ensure you are on the API pane. 3. Select LiveCode Builder from the drop down menu.
  • 10. #LiveCodeGlobal LiveCode Builder extensions are written in a text editor rather than the LiveCode IDE. We recommend using the Atom text editor. A LiveCode package is available which provides some colorization as well as indentation. If you are on Mac and prefer to use TextWrangler, there is a colorizing script here. It should be placed in /Application Support/TextWrangler/Language Modules/. Installing a Text Editor
  • 11. #LiveCodeGlobal Installing the Atom LiveCode Language Pack To install the LiveCode Language Pack in Atom ● Select File -> Preferences to open the Atom Settings ● Go to the Install tab of the Settings pane ● Search for the “language-livecode” package in the Search field ● Click Install
  • 12. #LiveCodeGlobal Creating a LiveCode Builder Library Start by creating a new directory to develop your extension in. When you package an extension a number of files are created. The Extension Builder currently relies on there being only one .lcb file in a given directory. Because of this it is simplest to create a new directory for each extension you create. The extension files that are created include an API file, manifest and compiled module file.
  • 13. #LiveCodeGlobal Creating a LiveCode Builder Library Create a new plain text file in the directory and save it to disk with the extension ".lcb". It’s important to use the “.lcb” extension so your chosen text editor applies LiveCode Builder formatting to your code, if available. I am naming my file "helloWorldLibrary.lcb" but you can name your file anything suitable.
  • 14. #LiveCodeGlobal LCB Library Definition The first thing we need to do is declare the type of extension we are writing. We are writing a library and so we need to declare the extension as such. The library declaration is followed by an identifier. An extension identifier should be in the form community.livecode.<user name>.<library name> In my case my username is "elanorb" and I have chosen to use "helloworld" as the name part of the identifier. library community.livecode.elanorb.helloworld end library
  • 15. #LiveCodeGlobal LCB module naming The module name uses reverse DNS notation. For example, a module created by the Example Organisation would use module names beginning with ‘org.example.’. You must only use module names corresponding to domain names that you control or are allowed to use. If you don't have a domain name of your own, you may use module names beginning with ‘community.livecode.’. For example, if your username is "sophie", then you can create a module named ‘community.livecode.sophie.mymodule’. Always write module names in lower case. For more detailed information check the LiveCode Builder Style Guide. The guide is available under the ‘Guide’ tab in the Dictionary or as a PDF under the ‘Resources’ tab for this lesson.
  • 16. #LiveCodeGlobal LCB public handler definitions Handler definitions are used to define functions which can be called from LCB code, invoked as a result of events triggering in a widget module, or called from LCS 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. Definitions can be either public or private (the default is private). Private handlers can only used within the module. Public handlers are available when the module is used by another module, for example public handlers can be called from LCS. Handler definitions have the form <HandlerType> handler <HandlerName>(<ParameterList>) [ returns <ReturnType> ] end handler
  • 17. #LiveCodeGlobal Naming Handlers It is best practice to give handlers TitleCase names. In general, please use verbs to name your handlers. For example, handler RotateShape(inout xShape, in pAngleInDegrees) ... end handler For more on this see the LiveCode Builder Language Reference Guide in the Dictionary or Additional Course Resources.
  • 18. #LiveCodeGlobal The Hello World Library has one handler which returns the string "Hello World!". Add the definition for the sayHello handler to the library. Let's break down the definitions ● HandlerType - public: we want to be able to call this handler from LCS so it needs to be public ● HandlerName - SayHello: the name of the handler, used to call the handler from LCS ● ParameterList - empty, no parameters are passed in. The SayHello handler <HandlerType> handler <HandlerName> (<ParameterList>) [ returns <ReturnType> ] library community.livecode.elanorb.helloworld public handler SayHello() end handler end library
  • 19. #LiveCodeGlobal To return a string value we can return the string directly. Add a return statement to the sayHello handler. Returning a string library community.livecode.elanorb.helloworld public handler SayHello() return "Hello World!" end handler end library
  • 20. #LiveCodeGlobal Testing the library Now we have a complete library we want to compile and test it. To do this we use the LiveCode Extension Builder. 1. Open LiveCode. 2. Open the Extension Builder from the Tools Menu.
  • 21. #LiveCodeGlobal The Extension Builder 1. Open button - allows you to select and load the extension you wish to build. 2. Data that the builder was able to parse from the directory such as icons, resources, API's the user guides. 3. Log: Shows status, error and log messages. 4. Test Button: compiles the extension and loads it into LiveCode 5. Script Button: Opens the lcb script in an external default editor. 6. Install Button: Installs the extension into the IDE 7. Uninstall Button: Uninstalls the extension from the IDE 8. Package Button: Creates a .lce package which can be shared
  • 22. #LiveCodeGlobal Compiling the Hello World Library Initially we will use the Test button to compile the library and test it without installing. 1. Click the Open button and select the “HelloWorldLibrary.lcb” file. 2. The Icons, Resources, Default Script, API and User Guide sections are automatically populated. 3. Click the Test button to compile and load the library in LiveCode.
  • 23. #LiveCodeGlobal Compiling the Hello World Library The log field will give you show the compilation progress and display any warnings. The Extension Builder will create a test stack.
  • 24. #LiveCodeGlobal LiveCode Builder Extension Files When the Extension Builder is used to compile a LiveCode Builder file a number of files are created. ● api.lcdoc - LiveCode doc file for the extension. This file is generated by extracting all of the documentation information from the LCB source code, and is used to display the API documentation for the library in the Dictionary window in the IDE ● mylibraryname.lci - LiveCode Interface file. This file provides information about the "public" interface for the library. It's used by the compiler when compiling LCB source code that uses the library. ● Manifest.xml - This file describes the library and its contents in a structured format. It is used by the IDE and by other tools to discover what the library contains. ● Module.lcm - The compiled module file. This is the compiled library bytecode, which is the output of compiling the library source code. It is the low-level code that's run by the LCB virtual machine when the library is in use. Each module you create will have files with the same names, for example api.lcdoc, which is why we create each extension in a separate directory.
  • 25. #LiveCodeGlobal Now the library is loaded we can test it in a LiveCode stack. ● Add a button to the test stack. ● Set the code of the button to ● Click the button. You should see an answer dialog displaying the “Hello World!” message returned by the library. Testing the library in a LiveCode stack on mouseUp answer sayHello() end mouseUp
  • 26. #LiveCodeGlobal In order to package any extension in LiveCode Builder we need to add some required metadata. The metadata provides information about the extension. The required metadata is ● title: a human-readable name for the module ● author : the name of the author of the module ● version a string in the form X.Y.Z (with X, Y and Z integers) describing the module version You can also include an optional description ● description: a simple description of the module's purpose If the required metadata is not added a number of warnings will be printed into the log field when building and packaging the extension. LiveCode Builder extension metadata
  • 27. #LiveCodeGlobal Version numbers We suggest using Semantic Versioning when assigning the version number of the extension. The uses a version format of X.Y.Z (Major.Minor.Patch). Given this format you would increment 1. The Major version when you make incompatible API changes. 2. The Minor version when you add functionality in a backwards-compatible manner. 3. The Patch version when you make backwards-compatible bug fixes. Under this scheme version numbers, and the way they change, provide clear and valuable information about the underlying code and the changes between versions. For a more detailed explanation of Semantic Versioning see http://semver.org/.
  • 28. #LiveCodeGlobal Library metadata library community.livecode.elanorb.helloworld metadata title is "Hello World Library" metadata author is "Elanor Buchanan" metadata version is "1.0.0" … handler definition end library Add the metadata after the library definition in the LCB file ● title: a human-readable name for the module, I have used “Hello World Library” but you can choose any suitable name ● author: add your name as the author of your library ● version: this is the first version of the library so the version is “1.0.0”
  • 29. #LiveCodeGlobal The finished library library community.livecode.elanorb.helloworld metadata title is "Hello World Library" metadata author is "Elanor Buchanan" metadata version is "1.0.0" public handler sayHello() return "Hello World!" end handler end library The library is now complete, including metadata, ready to be installed into LiveCode
  • 30. #LiveCodeGlobal Installing the library into the LiveCode IDE The Extension Builder is also used to install libraries. Installed libraries are loaded each time LiveCode is started up. Extensions are installed into your My LiveCode folder. 1. Open the Extension Builder from the Tools menu. 2. Click the Open button and load the “HelloWorldLibrary.lcb” file. 3. Click the Install button to install the library. 4. You will be asked to select an icon and a high resolution icon, click ‘Cancel’ on these dialogs as no icon is needed for a library.
  • 31. #LiveCodeGlobal The installed library Go to your My LiveCode folder. In the Extensions folder you will see a folder with the same name as your library identifier. This folder contains the files that are make up the packaged extension. Any extensions installed to My LiveCode are automatically loaded when LiveCode is started up.
  • 32. #LiveCodeGlobal To test your library is correctly installed execute execute put the loadedExtensions in the Message Box. Your library will appear in the list of extensions. To test the library handler execute put sayHello() in the Message Box Testing the installed library
  • 33. #LiveCodeGlobal Packaging a library In order to share your library you create a package. This package can be shared with other LiveCode users. 1. Open the Extension Builder from the Tools menu. 2. Click the Open button and load the “HelloWorldLibrary.lcb” file. 3. Click the Package button. This will create a packaged library file with the extension .lce in the same folder as your .lcb file. The name of the file is the library identifier followed by the version number.
  • 34. #LiveCodeGlobal Loading a Packaged Extension To load a packaged extension you use the Extension Manager. 1. Open the Extension Manager from the Tools menu. 2. Click Open(+). 3. Select the .lce file you want to install. The loaded extension appears in the list. You can also use the Extension Manager to uninstall extensions.
  • 35. #LiveCodeGlobal Including the library in a standalone If you have created a LiveCode app that uses a library and want to build it into a standalone you must ensure the library is included in the standalone file. Choose File -> Standalone Application Settings. On the General Pane you can choose to let LiveCode search for inclusions (libraries, widgets and externals) or select any inclusions manually.
  • 36. #LiveCodeGlobal Selecting inclusions If you choose to select the extensions to include the Inclusions pane will be enabled. Go to the Inclusions pane and select the extensions you want to include in the standalone.
  • 37. #LiveCodeGlobal Testing the standalone Once your Standalone Settings are complete choose File -> Save as Standalone Application. Start up the standalone and check that the library is included and returning the message.
  • 38. #LiveCodeGlobal Congratulations You have completed this lesson, you can now ● Create a LiveCode Builder library ● Package and install a library into LiveCode ● Include the library in a standalone
  • 39. #LiveCodeGlobal Widget Course Extending LiveCode with Widgets and Libraries LiveCode Dev Team
  • 41. #LiveCodeGlobal Extending the Hello World library In this lesson we will extend the minimal LiveCode Builder library we created in Lesson 1. We will ● Learn about LiveCode Builder types. ● Work with LiveCode Builder lists. ● Learn about type conversion between LCB and LCS. ● Pass a parameter to the SayHello handler. ● Document the library using documentation comments. ● Browse the library documentation in the Dictionary stack.
  • 42. #LiveCodeGlobal LiveCode Builder Typing LiveCode Builder is a strongly, dynamically typed language, although typing is completely optional in most places. If a type is not specified it is taken to be the most general type optional any (meaning any value, including nothing).
  • 43. #LiveCodeGlobal If a language is defined as typed it means that the types of all variables are known or inferred at compile time. Strongly typed A strongly typed language does not allow you to use one type as another. For example you cannot add a string and a number together. Type conversions have to be performed explicitly when required. Weakly typed A weakly typed language allows types to be mixed in the same expression, by making implicit type conversions. What is a strongly typed language?
  • 44. #LiveCodeGlobal What is a dynamically typed language? Dynamically typed Dynamically typed programming languages do type checking at run-time as opposed to compile-time. Statically typed Statically typed programming languages do type checking (the process of verifying and enforcing the constraints of types) at compile-time as opposed to run-time. LiveCode Builder is a dynamically typed language. Any typing errors are found at runtime, not at compile time.
  • 45. #LiveCodeGlobal LiveCode Builder Types The range of core types is relatively small, comprising the following: ● Boolean: one of true or false ● Integer: any integral numeric value ● Real: any numeric value ● 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. There is one additional type, nothing, meaning no value.
  • 46. #LiveCodeGlobal To demonstrate typing in LiveCode Builder we will create a very simple addition library. Example 1: Adding 2 numbers together In this example we create 2 number variables and add them together, resulting in another number. ● The return type of the additionTest handler is defined as Number. ● The 2 variables tLeft and tRight are defined as Number. ● Adding two numbers together results in a number value which can be successfully returned. Addition library library community.livecode.elanorb.addition metadata version is "1.0.0" metadata author is "Elanor Buchanan" metadata title is "Addition Library" public handler AdditionTest() returns Number variable tLeft as Number variable tRight as Number put 4 into tLeft put 5 into tRight return tLeft + tRight end handler end library
  • 47. #LiveCodeGlobal Test the library using the Extension Builder. 1. Open the Extension Builder from the Tools menu. 2. Load the addition.lcb file. 3. Click the Test button Execute put additionTest() in the Message Box . The correct value “9” is displayed in the Message Box. Testing the Addition library
  • 48. #LiveCodeGlobal Example 2: Adding a string and a number In this example we try to add a String and a Number and return a number. ● The return type of the AdditionTest handler is defined as Number. ● Variable tLeft is defined as a String. ● Variable tRight is defined as a Number. ● Attempting to add the 2 values together will return an error. Addition library 2 library community.livecode.elanorb.addition metadata version is "1.0.0" metadata author is "Elanor Buchanan" metadata title is "Addition Library" public handler AdditionTest() returns Number variable tLeft as String variable tRight as Number put 4 into tLeft put 5 into tRight return tLeft + tRight end handler end library
  • 49. #LiveCodeGlobal Testing the Addition library Test the library using the Extension Builder ● Open the Extension Builder from the Tools menu. ● Load the addition.lcb file. ● Click the Test button No errors are returned at compile time but if you execute put AdditionTest() In the Message Box you will see an error. This is because LBC is strongly typed (you can’t add an string to a number) and dynamically typed (the error occurs at runtime).
  • 50. #LiveCodeGlobal Addition library 3 Example 3: Adding a string and a number using type conversion In this example we create a String and a Number variable, convert the String to a Number and return a Number. ● The return type of the AdditionTest handler is defined as Number ● Variable tLeft is defined as a String ● Variable tRight is defined as a Number ● The value in tLeft is converted to a number by parsing the value as a number ● The value of the two numbers added together is returned library community.livecode.elanorb.addition metadata version is "1.0.0" metadata author is "Elanor Buchanan" metadata title is "Addition Library" public handler AdditionTest() returns Number variable tLeft as String variable tRight as Number put 4 into tLeft put 5 into tRight return tLeft parsed as number + tRight end handler end library
  • 51. #LiveCodeGlobal Test the library using the Extension Builder. ● Open the Extension Builder from the Tools menu. ● Load the addition.lcb file. ● Click the Test button. Execute put AdditionTest() In the Message Box . The correct value “9” is displayed in the Message Box. The value in the string variable was converted to a number before the calculation was performed, allowing a number to be calculated and returned. Testing the Addition library
  • 52. #LiveCodeGlobal LiveCode Builder Lists and Arrays Two important types in LCB, which deserve some more attention are lists and arrays. ● list - a list is a sequence of values, each element of the sequence is assigned a numerical index, starting with 1 and proceeding sequentially ● array - an array is a mapping from a string to any value (i.e. an associative array, just like in LiveCode Script)
  • 53. #LiveCodeGlobal Creating Lists in LCB library community.livecode.elanorb.example metadata title is "Example Library" metadata author is "Elanor Buchanan" metadata version is "1.0.0" public handler CreateList() returns nothing variable tLetterList as List variable tNumberList as List variable tMixedList as List put ["a","b","c"] into tLetterList put [1,2,3] into tNumberList put ["one","two","three",4,5,6] into tMixedList end handler end library Creating a list in LiveCode Builder is very simple, you put a comma-separated list of values between square brackets as shown. Each element in a list can hold a different type of value.
  • 54. #LiveCodeGlobal Creating Lists in LCB public handler CreateListFromString() returns String variable tVar as String variable tSplit as List put "first,second,third,fourth,fifth" into tVar split tVar by "," into tSplit end handler You can also split a string into a list using the split keyword. You specify the delimiter you want to use and the string is split into a list of strings using the delimiter.
  • 55. #LiveCodeGlobal List elements You can access the individual elements of a list using the element keyword. You can ● Get the value of an element ● Set the value of an element ● Delete an element To add an element to a list you push a value onto the list, you can push a value onto the front or end of a list. Note: LCB lists are 1 based. Note: An error is returned if the index is out of range. public handler ListElement() returns any variable tMixedList as List put ["one","two","three",4,5,6] into tMixedList delete element 2 of tMixedList -- tMixedList = ["one","three",4,5,6] put "five" into element 4 of tMixedList -- tMixedList = ["one","three",4,"five",6] push "zero" onto front of tMixedList --tMixedList = ["zero","one","three",4,"five",6] end handler
  • 56. #LiveCodeGlobal Creating Arrays in LCB Arrays in LCB are created in the same way as in LiveCode Script, so you are likely familiar with the syntax. 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. In LCB array keys are always strings. public handler CreateArray() returns nothing variable tCapitals as Array put "Kabul" into tCapitals["Afghanistan"] put "Tirana" into tCapitals["Albania"] put "Algiers" into tCapitals["Algeria"] put "Andorra la Vella" into tCapitals["Andorra"] put "Luanda" into tCapitals["Angola"] end handler
  • 57. #LiveCodeGlobal Creating Arrays in LCB You can also create LiveCode Builder arrays using {} notation with the syntax: {Key 1:Value 1,Key 2:Value 2,...,Key n:Value n} public handler CreateBracketedArray() returns nothing variable tCapitals as Array put {"Afghanistan":"Kabul", "Albania":"Tirana", "Algeria":"Algiers", "Andorra":"Andorra la Vella", "Angola":"Luanda"} into tCapitals end handler
  • 58. #LiveCodeGlobal Array elements You can access the individual elements on array using square bracket notation. You can ● Get the value of an element ● Set the value of an element ● Delete an element public handler CreateArray() returns nothing … previous array code -- Add an element to the array put "St. John" into tCapitals["Antigua and Barbuda"] -- Update an existing element of the array put "St. John's" into tCapitals["Antigua and Barbuda"] -- Delete the specified element of the array delete tCapitals["Antigua and Barbuda"] end handler
  • 59. #LiveCodeGlobal Nested elements Both lists and arrays can be nested. This means an element in a list can contain another list, or an element in an array can contain another array. Elements of a nested list can be accessed by using multiple element values. For example: return element 2 of element 2 of tListOfLetters -- returns “B” Elements of a nested array can be accessed by using multiple sets of square brackets containing the keys. For example: return tCapitals["Spain"]["name"] -- returns “Madrid” public handler CreateNested() returns nothing -- A nested list (list of lists) variable tListOfLetters as List put ["a", ["b","B"]] into tListOfLetters -- A nested array variable tCapitals as Array variable tSpain as Array put "Madrid" into tSpain["name"] put "3,165,000" into tSpain["population"] put tSpain into tCapitals["Spain"] end handler
  • 60. #LiveCodeGlobal You can also create nested arrays directly using the syntax {Key 1:Value 1,Key 2:Value 2,...,Key n:Value n} Where each value can also be an array expression {Key 1:{Key a:Value a,Key b:{Key α:Value α,Key β:Value β}},Key 2:Value 2,...,Key n:Value n} Example Returns public handler CreateNested() returns nothing variable tCapitals as Array put {"Spain": {"Name":"Madrid", "Population":"3,165,000"}, "UK":{"Name":"London", "Population":"8,539,000"}} into tCapitals end handler Nested elements 2
  • 61. #LiveCodeGlobal Type Conversion between LCB and LCS When a value is returned to LiveCode from a LiveCode Builder library what type will it be? Because LCB is strongly typed and LiveCode Script is weakly typed for most LCB types we don’t need to worry about it. ● nothing ● Boolean ● Integer ● Real ● Number ● String ● Data All these types can be used directly in expressions or put into a LiveCode Script variable.
  • 62. #LiveCodeGlobal Type Conversion between LCB and LCS The two exceptions are LiveCode Builder lists and arrays. ● list: when a LiveCode Builder handler returns a list it is converted to a numerically keyed LiveCode array, with continuous numerical keys. ● array: when a LiveCode Builder handler returns an array it is converted to a LiveCode array LiveCode Builder LiveCode Script variable tLetterList put ["a","b","c"] into tLetterList return tLetterList LiveCode Builder LiveCode Script variable tSpain put "Madrid" into tSpain["name"] put "3,165,000" into tSpain["population"] return tSpain
  • 63. #LiveCodeGlobal Adding explicit types to the library In the first version of the Hello World Library we didn’t use any explicit types. In this lesson we will update the library with: ● An explicit return type ● A typed variable that will hold the message to be returned
  • 64. #LiveCodeGlobal Adding a return type The first change we will make is to define the return type of the handler. In the initial version of the library the return type was not specified so was taken to be the general type optional any, meaning any value, including nothing, could be returned. We want to ensure the SayHello handler always returns a string so change the handler definition to specify String as the return type. public handler sayHello() returns String … handler code end handler
  • 65. #LiveCodeGlobal Adding a typed variable To ensure we return a String from the SayHello handler we will also update the handler code to store the message in a String variable and return the value of the variable. Update the SayHello handler with: 1. String variable declaration. 2. Command to update the value of the variable with the “Hello World!” message. 3. Return statement returning the value of the String variable. public handler sayHello() returns String variable tMessage as String put "Hello World!" into tMessage return tMessage end handler
  • 66. #LiveCodeGlobal Test that your library compiles and behaves correctly. 1. Open the Extension Builder. 2. Load the updated LiveCode Builder file. 3. Click the Uninstall button to uninstall the previous version. 4. Click the Test button. 5. Execute put sayHello() in the Message Box. The string returned by the library is displayed in the Message Box. Testing the Extended Library
  • 67. #LiveCodeGlobal Passing parameters to a library handler In many cases you will want to use parameters in your library handlers. Handler definitions have the form <HandlerType> handler <HandlerName>(<ParameterList>) [ returns <ReturnType> ] end handlerName The parameter list is a comma separated list of parameters, each of which has the form ( 'in' | 'out' | 'inout' ) <ParameterName> [ 'as' <ParameterType>] The type of parameter is optional, if no type is specified it is taken to be optional any meaning it can be of any type.
  • 68. #LiveCodeGlobal Passing parameters to a library handler The parameter list describes the parameters which can be passed to the handler. Handlers must be called with the correct number of parameters. 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. 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 specified it is taken to be optional any meaning it can be of any type.
  • 69. #LiveCodeGlobal Adding a parameter to the sayHello handler We want to update the SayHello handler to take a pName parameter, passed in when SayHello is called from LiveCode Script. The pName parameter will be a String value, which we will use to construct and return a custom “Hello” string.
  • 70. #LiveCodeGlobal Adding a parameter We will ● Update the handler definition with an in String parameter, pName. ● Construct the string to be returned using the pName parameter. ● Return the constructed string. Constructing a string in LCB uses the same syntax as LCS ● & - concatenates 2 strings ● && - concatenates 2 strings with a space in between public handler SayHello(in pName as String) returns String variable tMessage as String put "Hello" && pName & "!" into tMessage return tMessage end handler
  • 71. #LiveCodeGlobal Test that your library compiles and behaves correctly. 1. Open the Extension Builder. 2. Load the updated LCB file. 3. Click the Test button. 4. Execute put SayHello(“Elanor”) in the Message Box. The returned String, containing the passed String, is displayed in the Message Box. Testing the parameter passing
  • 72. #LiveCodeGlobal Using lists in the library It will often be useful to return more that a single piece of data from a library handler. Next we will update the SayHello handler to take a string containing a comma separated list of names, and return a LCB list with an element containing a “Hello” message for each name passed in.
  • 73. #LiveCodeGlobal Updating the return type The first step is to update the SayHello handler definition. We will be returning a List rather than a String so update the return type. We also want to be able to pass more than one name in so update the parameter name to pNames. public handler sayHello(in pNames as String) returns List … widget code end handler
  • 74. #LiveCodeGlobal Defining variables We will be using 3 variables in the handler ● tNameList - a list variable created from the pNames parameter ● tMessage - the list variable that will be returned, with an element holding a message for each name passed in in pNames ● tElement - a string variable used to iterate over the elements of tNameList Add variable definitions for these 3 variables. public handler sayHello(in pNames as String) returns List variable tNameList as List variable tMessage as List variable tElement as String end handler
  • 75. #LiveCodeGlobal Creating a List from a String We want to convert the String parameter into a List. We can do this using the split statement, which splits the string into a list of strings, using the specified delimiter. We know the pNames parameter is a command separated list of names so we split pNames by comma to create a List variable. public handler sayHello(in pNames as String) returns List variable tNameList as List variable tMessage as List variable tElement as String split pNames by "," into tNameList end handler
  • 76. #LiveCodeGlobal Building a List Next we want to create a list of messages, with an element for each name. ● Loop over each element in tNameList ● Construct a “Hello” message using the current element ● Append it to the end of the list using the push statement. ● Return the list of messages Note: When a value is pushed onto a list the pushed value becomes the tail of the list, by default. Use the 'front of' variant to push onto the front of a list instead. public handler sayHello(in pNames as String) returns List variable tNameList as List variable tMessage as List variable tElement as String split pNames by "," into tNameList repeat for each element tElement in tNameList push ("Hello" && tElement & "!") onto tMessage end repeat return tMessage end handler
  • 77. #LiveCodeGlobal Compile the library using the Extension Builder. ● Open the Extension Builder from the Tools menu. ● Load the helloWorldLibary.lcb file ● Click Test. ● This will load the library and create a test stack. ● Add a button to the test stack. ● Set the code of the button to on mouseUp put sayHello("Adam,Brenda,Craig") into tArray end mouseUp ● Add a breakpoint to line 3 line so you can view the array in the Variable Watcher Testing the library Note: Remember that LCB lists are converted to numerically keyed arrays in LiveCode Script.
  • 78. #LiveCodeGlobal Documenting the Library Extensions can provide an API (Dictionary) and User Guide as part of the installed package. They are installed and viewable through the LiveCode Dictionary stack. Any extension can include an API. To do so, either add a file called api.lcdoc to your widget folder alongside the other widget files or markup your source code inline. The api.lcdoc file must be in the lcdoc format. For a full description of the lcdoc format see the Contributing to LiveCode Documentation guide.
  • 79. #LiveCodeGlobal Marking up your code In this example we will document the library using inline code comments. Marking up your scripts is simple and follows a similar model to other documentation formats. Consider the following handler: public handler myHandler(in pString as String, in pNumber as Number) end handler To add an entry to the API for this handler, place a formatted comment above the handler definition: /** 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) end handler
  • 80. #LiveCodeGlobal Documenting SayHello We want to markup the source code of the Hello World library by adding inline documentation to the SayHello handler. ● The documentation is enclosed within /** and **/ ● Add a summary ● Add a description of the pNames parameter ● Add a description of the return value ● Add a full description of how the handler works. library community.livecode.elanorb.helloWorld metadata version is "1.0.0" metadata author is "Elanor Buchanan" metadata title is "Hello World Library" /** Summary: Constructs and returns a list of Hello messages pNames: String containing a comma separated list of names Returns: List of Hello strings Description: Takes a comma separated String of names, converts the String to a List, constructs a Hello message for each name and returns the List of Hello messages. **/ public handler SayHello(in pNames as String) returns List … handler code end handler end library
  • 81. #LiveCodeGlobal Browse the Documentation in the Dictionary Now we have added documentation to the library we can view it in the Dictionary Stack. Extension documentation only shows once the extension is fully installed. ● Open the Extension Builder. ● Load the Hello World Library. ● Click Install.
  • 82. #LiveCodeGlobal Browse the Documentation in the Dictionary Now open the Dictionary Stack and go to the API tab. Open the Drop Down list, you should see “Hello World Library”, or the title you gave your library, in the list. Select the library and you will see the documentation you added to the source file displayed.
  • 83. #LiveCodeGlobal Congratulations You have completed this lesson, you can now ● Use explicit typing ● Perform type conversion ● Use LCB lists and arrays ● Pass parameters to library handlers ● Add documentation to libraries
  • 84. #LiveCodeGlobal Widget Course Extending LiveCode With Widgets and Libraries LiveCode Dev Team
  • 86. #LiveCodeGlobal The Rotated Text Widget The second type of extension that that be created is a widget. A widget is a custom control that is treated as an engine level element. Widgets appear in the Tools Palette and can be added as controls to any LiveCode stack. The Rotated Text Widget displays text and allows the user to set the rotation property of the widget. We will ● Define the widget. ● Define properties for the widget. ● Draw the widget using LCB canvas operations. ● Compile and test the widget. ● Install the widget into LiveCode. ● Add the widget to a stack. ● Include the widget in a standalone.
  • 87. #LiveCodeGlobal What is a Canvas? A canvas is a container that holds various drawing elements (lines, shapes, text, frames containing other elements, etc.). It takes its name from the canvas used in visual arts. The main difference between a library and an extension is that a widget draws itself to the canvas, providing a UI element for the extension. Advantages Widgets have a number of advantages over traditional custom controls, created using LiveCode groups ● Once built the widget it is an atomic control. ● Widgets are more efficient. ● Widgets are not affected by engine messages. ● Widgets can be easily updated by updating the extension without having to replace the controls on the stacks.
  • 88. #LiveCodeGlobal Creating a LiveCode Builder Widget Just like libraries widgets are written in a text editor. Start by creating a plain text file in a new directory and save it to disk with the extension ".lcb". I am naming my file "rotatedText.lcb" but you can name your file anything suitable. Note: The extension builder currently relies on there being only one .lcb file in a given directory, this is why we create a separate folder for each new extension.
  • 89. #LiveCodeGlobal The first thing we need to do is declare the type of extension we are writing. We are writing a widget so we need to declare the extension as such. The widget declaration is followed by an identifier. An extension identifier should be in the form community.livecode.<user name>.<widget name> In my case my username is "elanorb" and I have chosen to use "rotatedtext" as the name part of the identifier. For more on module naming see the Naming section of the LiveCode Builder Style Guide, accessible from the Dictionary stack or the Additional Resources section of this course. LCB widget definition widget community.livecode.elanorb.rotatedtext end widget
  • 90. #LiveCodeGlobal As with an LCB library, widgets also require metadata. The required metadata for widgets is the same as for libraries ● title ● author ● version You can also include an optional description. Add the widget metadata to the definition. Widget metadata widget community.livecode.elanorb.rotatedtext metadata title is "Rotated Text" metadata author is "Elanor Buchanan" metadata version is "1.0.0" end widget
  • 91. #LiveCodeGlobal The LiveCode builder syntax is broken down into modules. Each module contains the syntax for a particular part of LiveCode Builder. You include the modules that provide the syntax for the features your extension requires. 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. For a full list of modules see the Importing Libraries section of the Extending LiveCode Guide and the API entries for the individual modules. The guide can be found under the Guides tab of the Dictionary or in the Additional Resources section of the course. LCB modules
  • 92. #LiveCodeGlobal As a general rule we recommend importing all three optional modules and the Widget Utilities library whenever developing widgets. Include the 3 modules and 1 library using the use keyword, followed by the module or library extension. Including modules widget community.livecode.elanorb.rotatedtext use com.livecode.canvas use com.livecode.widget use com.livecode.engine use com.livecode.library.widgetutils metadata title is "Rotated Text" metadata author is "Elanor Buchanan" metadata version is "1.0.0" end widget
  • 93. #LiveCodeGlobal Module level variables A variable definition defines a module-scope variable. In a widget module, such variables are per-widget (i.e. instance variables). In a library module, there is only a single instance (i.e. a private global variable). Module-scope variables in LCB are similar to script local variables in LiveCode Script. The syntax for declaring variables is variable <variableName> [as <type>] The type specification for the variable is optional, if it is not specified 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 definition. For a list of default values see the Variables section of the LiveCode Builder Language Reference Guide. The guide can be found under the Guides tab of the Dictionary or in the Additional Resources section of the course. 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.
  • 94. #LiveCodeGlobal Variable declarations In this widget we will use one module level variable to store the value of the rotation property of the widget. The value of the rotation property must be a number so we define the type as such. The variable will be a module level instance variable, so we prepend the variable name with a lower case ‘m’ to make it easily identifiable as such. Add the variable definition to the widget code. widget community.livecode.elanorb.rotatedtext use com.livecode.canvas use com.livecode.widget use com.livecode.engine use com.livecode.library.widgetutils metadata title is "Rotated Text" metadata author is "Elanor Buchanan" metadata version is "1.0.0" variable mRotation as Number end widget
  • 95. #LiveCodeGlobal Defining widget properties Property definitions can only appear in widget modules. They define a property which can be accessed from LiveCode Script in the usual way (e.g. the myProperty of widget 1). The syntax for declaring properties is property <propertyName> get <getterIdentifier> [ set <setterIdentifier> ] The getterIdentifier and setterIdentifier can use either a variable or handler identifier. If a variable identifier is used, then the property value is fetched (and stored) from that variable. If a handler identifier 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. Note: The Extension Builder will report an error if a setter or getter handler that is used in a property definition is not defined in the module file.
  • 96. #LiveCodeGlobal The rotation property widget community.livecode.elanorb.rotatedtext use com.livecode.canvas use com.livecode.widget use com.livecode.engine use com.livecode.library.widgetutils metadata title is "Rotated Text" metadata author is "Elanor Buchanan" metadata version is "1.0.0" private variable mRotation as Number property "rotation" get mRotation set setRotation end widget The widget will only have one property, rotation. The value of the rotation property will be stored in the mRotation variable. The getter The getter for the rotation property will return the value of mRotation. The setter The setter for the rotation property will call a handler, setRotation. Implementing the "setter" ourselves provides us with a little more flexibility and allows us to take multiple actions when the property is set. Add the property definition to the widget code.
  • 97. #LiveCodeGlobal widget community.livecode.elanorb.rotatedtext … previous code public handler setRotation(in pRotation as Number) returns nothing put pRotation into mRotation redraw all end handler end widget The setRotation handler allows us to take multiple actions when the property is updated ● The in parameter is a number. ● The handler does not return a value. 1. Update mRotation with the new value. 2. Redraw the widget to reflect the property change. We do this by calling "redraw all". Add the setRotation handler to the widget code. The setRotation handler
  • 98. #LiveCodeGlobal The Property Inspector Any properties that are defined in the widget are automatically shown in the Basic pane of the Property Inspector. We will be looking at integrating properties into the Property Inspector in more detail in the next lesson.
  • 99. #LiveCodeGlobal Widget Handlers There are five core handlers that any widget developer should implement: Handler Description OnPaint Sent to your widget whenever LiveCode requires it to redraw. The performance of your widget is tied primarily to this handler and should be kept as efficient as possible. OnCreate Sent to your widget when it is first created by LiveCode. This can be used to initialise default data and where applicable, reduce the burden for calculating constants etc in the OnPaint handler. OnGeometryChanged Sent when the control is changed in size. OnSave Sent when your widget is about to be destroyed and enables the widget to save data set on the widget. OnLoad Sent when your widget is created and enables the widget to retrieve data saved on the widget.
  • 100. #LiveCodeGlobal The OnPaint handler This widget is very simple so only the OnPaint handler is required to draw the widget. The OnPaint handler will be a public handler which takes no parameters and does not return a value. Add the OnPaint definition to the widget code. public handler OnPaint() end handler
  • 101. #LiveCodeGlobal The OnPaint handler width heightLiveCode There are a number of steps to take in the OnPaint handler. The first step is to draw the unrotated text in the widget. 1. Work out the size of the widget by getting its width and height 2. Work out the rectangle of the area we have to draw into 3. Draw the text at the center of the available space
  • 102. #LiveCodeGlobal public handler OnPaint() variable tText as String variable tHeight as Number variable tWidth as Number put my width into tWidth put my height into tHeight put "LiveCode" into tText variable tRectangle as Rectangle put rectangle [0,0,tWidth,tHeight] into tRectangle fill text tText at center of tRectangle on this canvas end handler Drawing the text For the basic widget we will use “LiveCode” as the text. 1. Declare variables for the text to be displayed and the height and width of the canvas. 2. Update the variables with the relevant values. 3. Declare a rectangle variable. 4. Put the rectangle describing the area of the canvas into the rectangle variable. 5. Draw the text in the center of the canvas.
  • 103. #LiveCodeGlobal my width: Returns the width of the widget. my height:Returns the height of the widget. rectangle: Specifies an area, consists of a list of 4 integers left, top, right, bottom Example: put rectangle [0,0,tWidth,tHeight] into tRectangle fill text at: Renders text on a canvas Syntax: fill text mText at mAlignment of mRect on mCanvas Example: fill text "Widget Label" at top left of rectangle [50, 100, 250, 200] on this canvas For more on each of these keywords see the API entries in the LiveCode Dictionary. Search for “com.livecode.canvas” in the LiveCode Builder API to see all the associated API entries. Drawing the text
  • 104. #LiveCodeGlobal Rotating text To draw rotated text we 1. Rotate the canvas 2. Get the rectangle of the rotated canvas as a path 3. Rotate the path back 4. Get the rectangle of the un-rotated path 5. Draw the text within the un-rotated rectangle. This draws the text horizontally, but relative to the position of the canvas. Because the canvas is rotated the text also appears rotated.
  • 105. #LiveCodeGlobal Key Concept: Rectangle Path Syntax: rectangle path of mRect Summary: Creates a new path. Parameters: mRect: An expression which evaluates to a rectangle. Example: // Create a rectangle path variable tPath as Path put rectangle path of rectangle [10,10,210,60] into tPath
  • 106. #LiveCodeGlobal Key Concept: Bounding Box Syntax: the bounding box of mPath Summary: The bounding box of a path which is the smallest rectangle that completely encloses mPath. Parameters: mPath: An expression which evaluates to a path. Example: // Create a circle path variable tPath as Path put circle path centered at point [100,100] with radius 50 into tPath // Get the bounds of the path variable tBounds as Rectangle put the bounding box of tPath into tBounds
  • 107. #LiveCodeGlobal public handler OnPaint() variable tText as String variable tHeight as Real variable tWidth as Real put my width into tWidth put my height into tHeight put "LiveCode" into tText rotate this canvas by mRotation variable tRectangle as Rectangle variable tPath as Path put rectangle path of rectangle [0,0,tWidth,tHeight] into tPath rotate tPath by (mRotation * -1) put the bounding box of tPath into tRectangle fill text tText at center of tRectangle on this canvas end handler Drawing rotated text 1. Rotate the canvas by the value stored in the mRotation variable. 2. Declare a path variable tPath. 3. Put the rectangle path of the canvas into tPath. 4. Rotate the path by -mRotation, setting it to a horizontal rectangle. 5. Update the line that sets tRectangle to get the bounding box of the un-rotated path and put it into the tRectangle variable. This gives the rectangle that completely encloses the un-rotated the path in tPath. 6. Draw the text at the center of the rectangle given by tRectangle. The text in drawn in a horizontal rectangle, but relative to the canvas, so appears drawn on an angle.
  • 108. #LiveCodeGlobal Testing the widget Now we have completed the OnPaint handler we are ready to test the widget. This is the full code of the widget, so far. widget community.livecode.elanorb.rotatedtext use com.livecode.canvas use com.livecode.widget use com.livecode.engine use com.livecode.library.widgetutils metadata title is "Rotated Text" metadata author is "Elanor Buchanan" metadata version is "1.0.0" private variable mRotation as Number property "rotation" get mRotation set setRotation public handler setRotation(in pRotation as Number) returns nothing put pRotation into mRotation redraw all end handler … continued on next slide
  • 109. #LiveCodeGlobal Testing the widget Now we have completed the OnPaint handler we are ready to test the widget. This is the full code of the widget, so far. public handler OnPaint() variable tText as String variable tHeight as Real variable tWidth as Real put my width into tWidth put my height into tHeight put "LiveCode" into tText rotate this canvas by mRotation variable tRectangle as Rectangle variable tPath as Path put rectangle path of rectangle [0,0,tWidth,tHeight] into tPath rotate tPath by (mRotation * -1) put rectangle [0,0,tWidth,tHeight] into tRectangle put the bounding box of tPath into tRectangle fill text tText at center of tRectangle on this canvas end handler end widget
  • 110. #LiveCodeGlobal Testing the widget Just like a library we compile, test, package and install widgets using the Extension Builder. 1. Open the Extension Builder from the Tools menu 2. Click the Open button 3. Load the ‘rotatedtext.lcb’ file
  • 111. #LiveCodeGlobal Testing the widget To test the widget click the Test button. This will create a stack in the IDE with a Rotated Test widget on it. 1. Go into Edit mode. 2. Select the widget. 3. Open the Property Inspector. 4. Set the Rotation property.
  • 112. #LiveCodeGlobal Widget icons When a widget is installed it shows in the Tools Palette. To provide an icon for the widget you add image files to the folder containing the widget definition .lcb file. Open the folder containing the LCB file ● Create a “support” folder ● Add 2 image files ○ Icon.png (20 x 20) ○ icon@extrahigh.png (40x40) The icon files can be found under the Resources tab of this lesson.
  • 113. #LiveCodeGlobal Installing a widget To install a widget we use the Extension Builder. 1. Open the Extension Builder from the Tools Palette. 2. Select the Open button. 3. Load the ‘rotatedtext.lcb’ file. 4. Click Install. The widget will be installed and will appear in the Tools Palette.
  • 114. #LiveCodeGlobal Creating a widget You can now add the widget to a stack by dragging it out from the Tools Palette. 1. Create a new stack. 2. Drag on a Rotated Text Widget. 3. Go into Edit mode. 4. Select the widget. 5. Open the Property Inspector for the widget. 6. Set the Rotation property on the widget.
  • 115. #LiveCodeGlobal Including the Widget in a Standalone When building a standalone that includes a widget you need to ensure that the widget is included when the standalone is built. Open the Standalone Application Settings from the File menu. On the General Pane you can choose to let LiveCode search for inclusions (libraries and widgets) or select any inclusions manually.
  • 116. #LiveCodeGlobal Selecting inclusions If you choose to select the extensions to include yourself the Inclusions pane will be enabled. Go to the Inclusions pane and check the extensions you want to include in the standalone. In this case we want to include the Rotated Text widget so check it in the list.
  • 117. #LiveCodeGlobal Saving the standalone Choose File -> Save as Standalone Application to save the stack as a standalone. Start up the standalone and check that the widget is included and the rotation can be set.
  • 118. #LiveCodeGlobal Congratulations You have completed this lesson, you can now ● Create a LiveCode Builder widget. ● Package and install a widget into LiveCode. ● Include the widget in a standalone.
  • 119. #LiveCodeGlobal Widget Course Extending LiveCode with Widgets and Libraries LiveCode Dev Team
  • 121. #LiveCodeGlobal The Advanced Rotated Text Widget In this lesson we will take the Rotated Text Widget to the next level. We will ● Fully integrate widget properties into the Property Inspector ● Add color and font properties by shadowing standard LiveCode properties ● Handle mouse events to make the widget clickable ● Add handlers to load and save widgets ● Add read only properties to a widget ● Document the widget
  • 122. #LiveCodeGlobal Widget properties In Lesson 3 we defined the rotation property of the widget property "rotation" get mRotation set setRotation ● Properties are shown in the Basic pane of the Property Inspector ● The name of the property is shown as the label in the Property Inspector ● A standard editor is shown for the property
  • 123. #LiveCodeGlobal You can more fully define widget properties in the LCB source file using metadata. All property metadata is optional. Property metadata definitions have the format metadata <property name>.<metadata name> is <value> You can define ● Property label ● Editor type ● Editor specific metadata ● Default value ● Property Inspector Section ● Property group ● User visible ● Read only For more on property metadata see Property Definitions Read Me. Widget properties
  • 124. #LiveCodeGlobal Property metadata Add the metadata for the rotation property to the widget source file. ● label: the label to be shown in the Property Inspector ● editor: the type of editor to be used in the Property Inspector ● default: the default value of the property Editor specific metadata ● step: the step value for number properties ● min: the minimum value for a number property ● max: the maximum value for a number property We want this property to appear in the Basic section so do not specify a section. widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata private variable mRotation as Number property "rotation" get mRotation set setRotation metadata rotation.label is "Rotation" metadata rotation.editor is "com.livecode.pi.number" metadata rotation.default is "0" metadata rotation.step is "1" metadata rotation.min is "0" metadata rotation.max is "359" … widget handlers end widget
  • 125. #LiveCodeGlobal Test in the Property Inspector To see the property integrated into the Property Inspector, using the metadata, rebuild the widget. ● Open the Extension Builder from the Tools menu ● Load the widget source file ● Click the Test button ● Select the widget on the test stack ● Open the Property Inspector You should see the rotation property, with a number property editor that will not allow values outside the range 0-360.
  • 126. #LiveCodeGlobal The Content property We will add a second property, content, which allows the user to change the text displayed in the widget. ● Define a variable to store the property value ● Define the property, getter and setter ● Add metadata for the property ○ editor ○ default ○ label widget community.livecode.elanorb.rotatedtext … widget inclusions and metatdata … rotation property definition private variable mContent as String property "content" get mContent set setContent metadata content.editor is "com.livecode.pi.string" metadata content.default is "Default text" metadata content.label is "Content" … widget handlers end widget
  • 127. #LiveCodeGlobal Add the content property setter handler. ● Takes a string parameter ● Has no return value ● Update the mContent variable with the parameter value ● Redraw the widget with the new text The setContent handler widget community.livecode.elanorb.rotatedtext … widget inclusions and metatdata … property definitions … OnPaint handler … SetRotation handler public handler SetContent(in pText as String) returns nothing put pText into mContent redraw all end handler end widget
  • 128. #LiveCodeGlobal Update OnPaint The OnPaint() handler needs updated to use the value of the content property. ● Delete the declaration for the tText variable ● Delete the line where “LiveCode” is put into the tText variable ● Update the “fill text” line to use the mContent variable public handler OnPaint() variable tText as String variable tHeight as Real variable tWidth as Real put my width into tWidth put my height into tHeight put "LiveCode" into tText rotate this canvas by mRotation variable tRectangle as Rectangle variable tPath as Path put rectangle path of rectangle [0,0,tWidth,tHeight] into tPath rotate tPath by (mRotation * -1) put the bounding box of tPath into tRectangle fill text tText at center of tRectangle on this canvas fill text mContent at center of tRectangle on this canvas end handler
  • 129. #LiveCodeGlobal When a widget is created the default values for its properties should be used. The OnCreate handler is called when the widget is first created. To ensure the values of the rotation and content properties are set we add the OnCreate handler which will call the property setters with the default values. ● Set the default value of the content property to “Default text” ● Set the default value of the rotation property to 0 The OnCreate handler widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … property definitions … OnPaint handler public handler OnCreate() setContent("Default text") setRotation(0) end handler … Property setters end widget
  • 130. #LiveCodeGlobal Test the widget Now build and test your widget using the Extension Builder. You should see the Content property in the Property Inspector and be able to change the text displayed in the widget.
  • 131. #LiveCodeGlobal In addition to adding widget specific properties you can also link your widget to standard LiveCode control properties, such as font, background color etc. All controls in LiveCode, both widgets and classic controls, have a set of basic properties which are always present and do not need to be implemented when writing a widget. Any widget you create will always have these properties in its Property Inspector. These properties are You can also choose to allow your widget to implement any other LiveCode control properties which are not in the basic set. Basic name, kind, tooltip, visible, disabled Custom properties custom properties and custom property sets Colors ink, blendLevel Position lockLoc, width, height, location, left, top, right, bottom, layer Text textFont, textSize Advanced layerMode, behavior, traversalOn, number Shadowing LiveCode control properties
  • 132. #LiveCodeGlobal Accessing standard properties Although all controls, including widgets, have all the basic properties some work automatically and you need to take some into account when you draw the widget. For example the width property works automatically but the text size requires some extra handling.
  • 133. #LiveCodeGlobal Text properties The two basic text properties all controls have are ● Text font ● Text size We want to use the values of these properties when drawing the widget. We get the effective text properties of the widget using my font and apply these settings when drawing the widget. Update the OnPaint handler to apply these settings to the canvas before rotating the canvas. public handler OnPaint() … variable declarations … tWidth and tHeight values set the font of this canvas to my font rotate this canvas by mRotation … remainder of code end handler
  • 134. #LiveCodeGlobal Test the text properties To test the text properties in the Property Inspector re-compile the widget using the Extension Builder. ● Select the widget on the test stack ● Open the Property Inspector ● Go to the Text section ● Set the Font and Text size The text in the widget should change to reflect the property values.
  • 135. #LiveCodeGlobal Linking to other LiveCode properties You can also link to other standard LiveCode properties beyond the basic, built in set. For example we might want to set the Text fill of the Rotated Text Widget. Text fill, or foregroundColor to use the property name, is a standard LiveCode property but it not part of the basic set. To access it we have to specify that the widget has the property, but we do not have to define the property itself.
  • 136. #LiveCodeGlobal Linking to other LiveCode properties Below is a list of the LiveCode properties you can link to as described. abbrevId, abbrevName, abbrevOwner, altId, backColor, backPattern, backPixel, blendLevel, borderColor, borderPattern, borderPixel, bottom, bottomColor, bottomLeft, bottomPattern, bottomPixel, bottomRight, brushColor, cantSelect, colors, customKeys, customProperties, customPropertySet, customPropertySets, disabled, enabled, focusColor, focusPattern, focusPixel, foreColor, forePattern, forePixel, height, hiliteColor, hilitePattern, hilitePixel, ink, invisible, kind, layer, layerMode, left, location, lockLocation, longId, longName, longOwner, name, number, owner, parentScript, patterns, penColor, properties, rectangle, right, script, selected, shadowColor, shadowPattern, shadowPixel, shortId, shortName, shortOwner, textFont, textSize, textStyle, themeControlType, toolTip, top, topColor, topLeft, topPattern, topPixel, topRight, traversalOn, unicodeToolTip, visible, width
  • 137. #LiveCodeGlobal Metadata for LiveCode properties To define a LiveCode property in a widget you provide metadata, but do not need to define the property within the widget. We want to the Rotated Text Widget to have the foregroundColor property, and for it to be settable in the Property Inspector. Add the metadata for the property. ● Use a color editor in the Property Inspector ● Setting the default to empty means the value will be inherited ● Show in the Colors section of the Property Inspector ● Set the label to “Text Fill” widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … property definitions for rotation and content metadata foregroundColor.editor is "com.livecode.pi.color" metadata foregroundColor.default is "" metadata foregroundColor.section is "Colors" metadata foregroundColor.label is "Text fill" … widget handlers end widget
  • 138. #LiveCodeGlobal Update OnPaint We now need to update the OnPaint handler to use the selected foregroundColor when drawing the text to the canvas. ● my foreground paint - returns the effective foreground color of the widget. This value is either inherited, set in code or set in the Property Inspector ● set the paint of this canvas - sets the color to be used when drawing to the canvas public handler OnPaint() … variable declarations set the font of this canvas to my font set the paint of this canvas to my foreground paint … code continues end handler
  • 139. #LiveCodeGlobal Test the Text Fill property Compile and test the widget using the Extension Builder. ● Go into Edit mode ● Select the widget in the test stack ● Open the Property Inspector ● Go to the Colors pane ● Change the Text fill
  • 140. #LiveCodeGlobal Handling mouse events You will often want to create widgets that can respond to user actions. LCB provides a range of messages, similar to LiveCode event messages, some examples are ● OnMouseDown ● OnMouseUp ● OnDoubleClick ● OnKeyPress You can choose which of these messages your widget will handle and how to handle them. Note that the event names are all one word, e.g. OnMouseUp, unlike LCS. You can can also post messages to the widget object in LiveCode, these can be standard messages such as mouseUp or customised messages, such as segmentClicked in a Pie Chart widget. As with widget handlers we use TitleCase for event names.
  • 141. #LiveCodeGlobal Handling mouseUp When the widget is clicked we want it to get a mouseUp message, just like a button or graphic control. To do this we handle the LCB OnMouseUp message and post a mouseUp message to the widget object. Add the OnMouseUp handler to the widget code. Note: Properties and events are, by their nature, always public as they define things which are external to the widget. widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … property definitions … OnPaint and OnCreate handlers … Property Setters public handler OnMouseUp() post "mouseUp" end handler end widget
  • 142. #LiveCodeGlobal Compile and test the widget using the Extension Builder. ● Go into Edit mode ● Select the widget on the test stack ● Open the Code editor for the widget on mouseUp answer "mouseUp received" end mouseUp ● Go into Run mode ● Click the widget ● The widget will respond to the mouse click Testing mouseUp
  • 143. #LiveCodeGlobal You can post any message to the widget object, not just LiveCode messages. For example if you want the Rotated Text Widget to receive a rotatedTextClicked message instead of a mouseUp message when it is clicked you would post “rotatedTextClicked”. public handler OnMouseUp() post "rotatedTextClicked" end handler Custom messages
  • 144. #LiveCodeGlobal Creating, saving and loading widgets In Lesson 3 we looked at the core handlers but so far we have only implemented the OnPaint and OnCreate handlers. In this lesson we will implement the OnSave and OnLoad handlers. Handler Description OnSave Sent when your widget is about to be destroyed and enables the widget to save data set on the widget. OnLoad Sent when your widget is created and enables the widget to retrieve data saved on the widget.
  • 145. #LiveCodeGlobal We want to be able to save and load the widget’s properties. If the OnSave and OnLoad handlers are not included then every time you open a saved stack that includes a widget, the widget will lose its property data and the properties will be set to the default values. When your widget is saved you are sent an OnSave message. It returns an array which you can fill with whatever widget data you have. LiveCode saves this data along with instances of the widget in the stack file. This same array will be returned to you as a parameter to the the OnLoad message, which is sent when the widget is next opened and can be used to recreate the widget with its saved properties. Saving and loading the widget state
  • 146. #LiveCodeGlobal The OnSave handler First we write the OnSave handler, which saves the widget’s properties when a stack containing a widget is saved. Add the OnSave handler to the widget code. The rProperties array is an out parameter meaning the value of the array is copied back to the caller when the handler completes. Add an element to the rProperties array for each property ● key: property name ● value: property value Note: LiveCode properties are automatically saved so don’t need to be explicitly stored in the array. widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … property definitions … OnPaint and OnCreate handlers … Property Setters … Event handlers public handler OnSave(out rProperties as Array) put mContent into rProperties["content"] put mRotation into rProperties["rotation"] end handler end widget
  • 147. #LiveCodeGlobal The OnLoad handler Next we write the OnLoad handler, which loads the widget’s properties when a stack containing a widget is opened: Add the OnLoad handler to the widget code. The array of saved properties is passed in as a parameter, and can be used to set the values of the private instance variables to the stored property values. ● Set the value of the content property to the value of the content element in the properties array ● Set the value of the rotation property to the value of the rotation element in the properties array widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … property definitions … OnPaint and OnCreate handlers … Property Setters … Event handlers … OnSave handler public handler OnLoad(in pProperties as Array) put pProperties["content"] into mContent put pProperties["rotation"] into mRotation end handler end widget
  • 148. #LiveCodeGlobal Testing saving and loading a widget In order to test saving and loading a widget we have to install the widget. ● Open the Extension Builder from the Tools Palette ● Load the lcb file ● Uninstall the previous widget, if necessary ● Click Install ● The widget will appear in the Tools Palette ● Create a new stack ● Drag on a Rotated Text Widget ● Set some properties ● Save the stack ● Close LiveCode ● Reopen the stack The widget should appear with its properties set to the saved state.
  • 149. #LiveCodeGlobal Read only properties So far we have only looked at properties that can be set by the user. In this lesson we will implement some read-only properties that depend entirely on the widget state. These properties will be familiar to anyone experienced with LiveCode Script. ● formattedWidth - Reports the width needed by an object to display its full contents without scrolling. This property is read-only and cannot be set. ● formattedHeight - Reports the height needed by an object to display its full contents without scrolling. This property is read-only and cannot be set. We will implement these two properties for the Rotated Text widget by calculating the space the text displayed in the widget requires and returning these values.
  • 150. #LiveCodeGlobal Declare the properties Firstly declare the properties in the widget source code. Add two instance variables to hold the property values and add definitions for the formattedWidth and formattedHeight properties. Because the properties are read only they do not require setter identifiers. The getter simply returns the value of the variable. widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … existing property definitions private variable mFormattedWidth as Real private variable mFormattedHeight as Real property "formattedWidth" get mFormattedWidth property "formattedHeight" get mFormattedHeight … OnPaint and OnCreate handlers … Property Setters … Event handlers .... OnSave and OnLoad handlers end widget
  • 151. #LiveCodeGlobal We want to update the values of the formattedWidth and formattedHeight properties whenever the state of the widget changes. This ensures the correct value will always be returned by the property. Update the OnPaint handler to calculate and store the formattedWidth and formattedHeight of the widget whenever it is redrawn. ● Declare a rectangle variable ● Get the bounds of the text on the canvas. This returns the bounding box of the text when drawn at point 0,0 as a rectangle, taking into account the font, style and text size of the canvas ● Update the variables holding the property values with the width and height of the bounding box of the text Storing the values public handler OnPaint() … previous code variable tBounds as Rectangle put the bounds of text mContent on this canvas into tBounds put the width of tBounds into mFormattedWidth put the height of tBounds into mFormattedHeight end handler
  • 152. #LiveCodeGlobal Testing read only properties Compile and test the widget using the Extension Builder. ● Go into Edit mode ● Select the widget in the test stack ● Open the Property Inspector The formattedWidth and formattedHeight properties will be shown on the Basic pane, they can’t be edited because the are read only. You can check the width and height properties in the Position pane and see they are different values.
  • 153. #LiveCodeGlobal Hiding properties There may be cases where your widget has properties that you do not want to show in the Property Inspector. This may be because they are read only, internal or undocumented. You can set property metadata to prevent the properties being visible to the user. Add user_visible metadata to the formattedWidth and formattedHeight properties widget community.livecode.elanorb.rotatedtext … widget inclusions and metadata … existing property definitions private variable mFormattedWidth as Real private variable mFormattedHeight as Real property "formattedWidth" get mFormattedWidth metadata formattedWidth.user_visible is "false" property "formattedHeight" get mFormattedHeight metadata formattedHeight.user_visible is "false" … OnPaint and OnCreate handlers … Property Setters … Event handlers .... OnSave and OnLoad handlers end widget
  • 154. #LiveCodeGlobal Testing non user-visible properties Compile and test the widget using the Extension Builder. ● Go into Edit mode ● Select the widget on the test stack ● Open the Property Inspector The formattedWidth and formattedHeight properties will not be shown in the Property Inspector. However you can get the property value from code. Execute the following code in the Message Box to test the property. put the formattedHeight of widget 1
  • 155. #LiveCodeGlobal Documenting the widget Extensions can provide an API (Dictionary) entry and User Guide as part of the installed package. They are installed and viewable through the LiveCode Dictionary stack. In Lesson 2 we documented a library extension, which involved documenting the handlers provided by the library. To document the widget we will document the properties and messages associated with the widget. As with the Hello World library, we will use in-line documentation comments in the LCB file to document the widget.
  • 156. #LiveCodeGlobal Documenting the widget A description of the widget can be included in a comment block above the widget declaration in the LCB file. This description will appear in the Dictionary stack under the API entry for the widget identifier. Add a comment block with a description of the widget at the start of the LCB file. /** A rotated text control. The control displays text rotated to a given number of degrees, 0 degrees meaning unrotated. **/ widget community.livecode.elanorb.rotatedText … widget code end widget
  • 157. #LiveCodeGlobal Documenting messages Widget messages are not declared explicitly in the LCB file, so all messages should be documented within the comment block that includes the widget description at the start of the LCB file. Each message has ● Name ● Type ● Syntax ● Description Add the documentation for the mouseUp message to LCB file. You can add documentation for multiple messages in this comment block. /** A rotated text control. The control displays text rotated to a given number of degrees, 0 degrees meaning unrotated. Name: mouseUp Type: message Syntax: on mouseUp Description: The <mouseUp> message is sent when the widget is clicked. **/ widget community.livecode.elanorb.rotatedText … widget code end widget
  • 158. #LiveCodeGlobal Documenting properties When properties in LCB, the documentation is included above the property definition within a /** **/ comment block. Include ● Syntax: the syntax for using the property. This usually included a set and get example ● Summary: a brief description of the property ● Description: a more extensive description of the property, its effects and how to use it Add in-line documentation for the declared Rotated Text widget properties: rotation, content, formattedWidth and formattedHeight. /** Syntax: set the rotation of <widget> to <pDegrees> Syntax: get the rotation of <widget> Summary: The number of degrees the text displayed in the widget is rotated by. Description: Use the <rotation> property to set the amount the text displayed in the widget is rotated by. The default is 0 degrees which is unrotated, horizontal text. The text is rotated in a clockwise direction. **/ property "rotation" get mRotation set setRotation
  • 159. #LiveCodeGlobal Documenting Properties The foregroundColor property shadows a LiveCode property and is not declared explicitly in the widget source code. Therefore the documentation must be in the top-level comment beside the message documentation. Include ● Name: the property name ● Type: “property” ● Syntax: the syntax for using the property. This usually included a set and get example ● Summary: a brief description of the property ● Description: a more extensive description of the property, its effects and how to use it /** ...widget and message documentation Name: foregroundColor Type: property Syntax: set the foregroundColor of <widget> to <pColor> Syntax: get the foregroundColor of <widget> Summary: The text color of the widget Description: Use the <foregroundColor> property to control the text color of the widget. **/ widget community.livecode.elanorb.rotatedText … widget code end widget
  • 160. #LiveCodeGlobal Browsing the documentation Use the Extension Builder to install the widget. You can find the widget icons in the Lesson 4 Resources. You will see the Rotated Text widget in the Tools Palette. Open the Dictionary stack and select Rotated Text from the drop down menu. The documentation for the widget, message and properties will be shown in the Dictionary stack.
  • 161. #LiveCodeGlobal Congratulations You have completed this lesson, you can now ● Fully integrate widget properties into the Property Inspector ● Shadow standard LiveCode properties ● Handle mouse events to make widgets clickable ● Save and load widget properties ● Add read only properties to a widget ● Document the widget
  • 162. #LiveCodeGlobal Widget Course Extending LiveCode with Widgets and Libraries LiveCode Dev Team
  • 164. #LiveCodeGlobal The Pie Chart Widget In this lesson we will plan and implement a Pie Chart widget. We will ● Decide how the Pie Chart should look ● Decide what properties the Pie Chart should have ● Decide what messages the Pie Chart should send ● Implement the Pie Chart widget in steps ○ Define the Properties ○ Implement OnCreate ○ Implement OnPaint ○ Implement OnGeometryChanged ○ Implement OnSave ○ Implement OnLoad ○ Respond to mouse events ● Document the widget ● Package and install the widget
  • 165. #LiveCodeGlobal Pie Chart Examples Everyone is familiar with pie charts, but before we start implementing the pie chart widget we’ll look at a couple of examples. Google Docs Libre Office
  • 166. #LiveCodeGlobal The Pie Chart information There are 2 main pieces of information required to draw the pie chart ● List of values ● Labels associated with each value In the examples we looked at, the values and labels were: Label Value January 1 February 2 March 3 April 5 May 8 June 13
  • 167. #LiveCodeGlobal The Pie Chart layout The usual layout for pie charts is to have ● Chart on the left ● List of labels on the right Because the user can resize the widget there are some considerations for us ● Ensure the labels are shown ● Make the pie chart the maximum size while showing all the labels ● If the widget is taller than it is wide display the labels below the chart ● Allow the user to choose whether to show the labels or not, to provide flexibility within apps Aaa Bbb Ccc Aaa Bbb Ccc
  • 168. #LiveCodeGlobal Pie Chart properties and messages Through planning our widget we have identified 3 properties the widget needs ● List of values ● List of labels ● Boolean value specifying whether the labels should be shown or not We also want the widgets to respond to user actions. We could simply provide a mouseUp message but for a pie chart this is not particularly informative. Instead a useful message would tell the user that the chart had been clicked, and which sector was clicked on. So we will send a message with a parameter ● sectorClicked pSectorNumber The colors used for sectors will be assigned by the widget. A possible extension of the widget would be to make these colors settable by the user.
  • 169. #LiveCodeGlobal Creating the LiveCode Builder file As with the Hello World Library and Rotated Text Widget we will start a new LiveCode Builder source file. ● Create a new directory. ● Create a new plain text file in the directory and save it to disk with the extension "lcb". I am naming my file "pieChart.lcb" but you can name your file anything suitable. Note: The extension builder currently relies on there being only one .lcb file in a given directory, this is why we create a separate folder for each new extension.
  • 170. #LiveCodeGlobal Widget definition Begin by defining the pie chart widget in the LCB file. Remember ● The widget declaration is followed by an identifier. ● An extension identifier should be in the form community.livecode.<user name>.<widget name> For more on module naming see the Naming section of the LiveCode Builder Style Guide, accessible from the Dictionary stack or the Additional Resources section of the course. widget community.livecode.elanorb.piechart end widget
  • 171. #LiveCodeGlobal Include the recommended modules and libraries in the LCB file. ● com.livecode.canvas ● com.livecode.widget ● com.livecode.engine ● Com.livecode.library.widgetutils For a full list of modules see the Importing Libraries section of the Extending LiveCode Guide and the API entries for the individual modules. Including modules widget community.livecode.elanorb.piechart use com.livecode.canvas use com.livecode.widget use com.livecode.engine use com.livecode.library.widgetutils end widget
  • 172. #LiveCodeGlobal Widget metadata Add the required widget metadata to the definition. ● Title ● Author ● Version number You can also include an optional metadata. We want to ensure the Pie Chart widget is created at a reasonable size so add ● Preferred size widget community.livecode.elanorb.piechart use com.livecode.canvas use com.livecode.widget use com.livecode.engine use com.livecode.library.widgetutils metadata title is "Pie Chart" metadata author is "Elanor Buchanan" metadata version is "1.0.0" metadata preferredSize is "200,150" end widget
  • 173. #LiveCodeGlobal Variable declarations In Step 1 we identified 3 properties of the Pie Chart widget: values, labels and whether labels should be shown. In addition we want an a list variable to store the list of colors that will be used for the sectors. As before we will use module level variables to store the values of these properties. Declare the 4 variables and their types. Also add a constant, kPadding, which will be used to layout the elements of the widget. Note: See Lesson 3 - Step 3: Module level variables if you need a refresher. widget community.livecode.elanorb.piechart … module imports … metadata private variable mValues as List private variable mLabels as List private variable mColors as List private variable mShowLabels as Boolean constant kPadding is 10 end widget
  • 174. #LiveCodeGlobal The values property will have both a getter and a setter handler. Add the definition for the property, including: ● Property name ● Getter handler name ● Setter handler name ● Default value ● Property label The values property widget community.livecode.elanorb.piechart … module imports … metadata … instance variable declarations property "sectorValues" get getValues set setValues metadata sectorValues.default is "1,2,3,5,8,13" metadata sectorValues.label is "Values" end widget
  • 175. #LiveCodeGlobal The segmentValues property has both a getter and a setter property. The Property Inspector allows the user to set the segmentValues to a comma separated list of values. The setValues handler converts the comma separated string to a LCB list. The getValues handler converts the LCB list to a string, allowing it to be displayed in the Property Inspector. Add the handlers to the source code. The values property widget community.livecode.elanorb.piechart ...previous code public handler setValues(in pValues as String) returns nothing split pValues by "," into mValues redraw all end handler private handler getValues() returns String variable tValues combine mValues with "," into tValues return tValues end handler end widget
  • 176. #LiveCodeGlobal The labels property will also have both a getter and a setter handler. Add the definition for the property, including: ● Property name ● Getter handler name ● Setter handler name ● Default value ● Property label The labels property widget community.livecode.elanorb.piechart … module imports … metadata … instance variable declarations … previous property definitions property "sectorLabels" get getLabels set setLabels metadata sectorLabels.default is "Jan,Feb,Mar,Apr,May,Jun" metadata sectorLabels.label is "Labels" … code continues end widget
  • 177. #LiveCodeGlobal Like the segmentValues property the segmentLabels property has both a getter and a setter property. The Property Inspector allows the user to set the segmentLabels to a comma separated list of values. The setLabels handler converts the comma separated string to a LCB list. The labels property widget community.livecode.elanorb.piechart … previous code public handler setLabels(in pLabels as String) returns nothing split pLabels by "," into mLabels redraw all end handler private handler getLabels() returns String variable tLabels combine mLabels with "," into tLabels return tLabels end handler end widget
  • 178. #LiveCodeGlobal The Show labels property is a boolean value so only has a setter handler. The value of the mShowLabels variable is returned when the property value is requested. Add the definition for the property, including: ● Property name ● Variable name for the get method ● Setter handler name ● Default value ● Property label The showLabels property widget community.livecode.elanorb.piechart … module imports … metadata … instance variable declarations … previous property definitions property "showLabels" get mShowLabels set setShowLabels metadata showLabels.default is "true" metadata showLabels.label is "Show labels" … code continues end widget
  • 179. #LiveCodeGlobal The setShowLabels handler sets the value of the mShowLabels variable to the value passed in. Add the handler to the source code. The showLabels property widget community.livecode.elanorb.piechart … previous code public handler setShowLabels(in pShow as Boolean) returns nothing put pShow into mShowLabels redraw all end handler end widget
  • 180. #LiveCodeGlobal The OnCreate handler The OnCreate handler is sent to a widget when it is first created by LiveCode. This handler can be used to initialise default data and, where applicable, reduce the burden for calculating constants etc in the OnPaint handler. Add the OnCreate handler to the LCB file ● Define a variable, tSectors, to hold the number of sectors ● Call setValues to set the default values of the mValues variable. ● Call setLabels to set the default values of the mLabels variable ● Set the value of mShowLabels to true ● Update tSectors with the number of elements in the list of values ● Call colorList to intitialise the mColors variable Setting the property values in the OnCreate handler ensures the values of the properties are set when we test from the Extension Builder. widget community.livecode.elanorb.piechart ...previous code public handler OnCreate() variable tSectors setValues("1,2,3,5,8,13") setLabels("Jan,Feb,Mar,Apr,May,Jun") put true into mShowLabels put the number of elements in mValues into tSectors put colorList(tSectors) into mColors end handler end widget
  • 181. #LiveCodeGlobal LiveCode Builder Colors LiveCode Builder colors are expressions which evaluates to a list of 3 or 4 numbers, the red, green, blue, and (optional) alpha components of the color. The component value denotes the intensity of that component, expressed as a real number between 0 and 1. The alpha component represents the opacity of the color. If the alpha component is not specified then it is assumed to be 1 (fully opaque). variable tColor -- Set tColor to opaque red put color [1.0, 0.0, 0.0] into tColor -- Set tColor to partially transparent cyan put color [0.0, 1.0, 1.0, 0.75] into tColor
  • 182. #LiveCodeGlobal The colorList handler Red: 1,0,0,1 Green: 0,1,0,1 Blue: 0,0,1,1 Yellow: 1,1,0,1 Purple: 1,0,1,1 Cyan: 0,1,1,1 Red 2: 0.5,0,0,1 Green 2: 0,0.5,0,1 Blue 2: 0,0,0.5,1 Yellow 2: 0.5,0.5,0,1 Purple 2: 0.5,0,0.5,1 Cyan 2: 0,0.5,0.5,1 The colorList handler returns a list of unique colors for use when coloring the sectors of the chart. The number of colors to be returned is given by the pNumber parameter. The handler loops calculating RGB values for colors. ● Highest intensity primary colors ● Highest intensity secondary colors ● Reduce the color intensity by half Each iteration adds 6 colors to the list. 1. R,0,0,1 2. 0,G,0,1 3. 0,0,B,1 4. R,G,0,1 5. R,0,B,1 6. 0,G,B,1
  • 183. #LiveCodeGlobal The colorList handler Add the colorList handler to the source file. ● Declare the variables that will be used. ● Assign a value to tColorLevel: the color intensity to be used. ● Calculate the number of repeats ○ Divide pNumber by 6, 6 colors are add to the color list on each iteration of the loop ○ Round the result ○ Add 1 to the result to ensure we always calculate enough colors public handler colorList(in pNumber) returns List variable tColors as List variable tColorLevel as Number variable tRepeats as Number put 1 into tColorLevel put pNumber / 6 into tRepeats round tRepeats add 1 to tRepeats … continues on next slide end handler