Menu Close

Hello World !

These chapters are designed to give you a basic overview of what LiveCode-Perl programming is about. After having read these chapters you will have a good understanding of the powerful things one can do by using the two languages together. But, please, don’t forget that you need a little knowledge of Perl and LiveCode before reading the next.

I also provide a Demonstration LiveCode stack, called: a Quick Tour of SunnYperl.

There you will get almost the same information; the main difference is that the stack is fully functional: you can execute in live every code mentioned here.

I wanted to keep it as simple as possible, so that you can focus on the interaction, on the way how Perl and LiveCode relate, and, and as the Zen saying goes : “Don’t Mistake the Finger Pointing at the Moon for the Moon!”. And a last advice, before you dig into all this stuff: please keep in mind that this is not meant to be a reference guide.

Well, no ways to escape this first academic question: how to print “hello World!”… The Perl script is in the text field named “PerlScript” :

# print to the standard output
print "Hello World !" ;

Then, the Script in LiveCode:

-- Run the Perl script typed in the "PerlScript" text field
get Perl.Run( "PerlScript" )

In our Quick Tour Stack, you could see this :

3 ways to pass some text

The next Perl script will print some text to the Standard Output, then to the Standard Error, and at last return a text string. You probably ask yourself how the two standard Filehandles are bound to textFields in LiveCode. This is done at the init time, and we will talk about that later.

print STDOUT "Hello World of LiveCoders..." ;

print STDERR "Hello Buggy World..." ;

return "Hi LiveCoder" ;

returning an Array

Perl provides an Array variable to store a series of values; each value is uniquely identified by an integer known as its index.
LiveCode provides a list of items, each item also identified by an index.

@Array = qw( aaaa bbbbbbbbb ccccc dd ) ;
# stringify our array
return join( ",", @Array ) ;
-- get the return value of perl
put Perl.Run() into field "PerlStdout"

and we can see in our text field:

returning a Hash

A Hash in Perl is what we called an associative array in LiveCode. In the early days, we were also talking of associative arrays in Perl.
Our Perl script will initialize a Hash, print on the standard error the value of the perl entry of our Hash, transform it to a stringified list and return it to LiveCode which will split the result to build it as an associative array.

%hash = qw( LiveCode 4.5.6 perl 5.10.0 ) ;

print STDERR  "Perl version:  $hash{perl}" ;

@x = map { "$_,$hash{$_}"} keys %hash ;

return "@x" ;
put Perl.Run() into x
split x by space and comma
put "LiveCode version: " & x["LiveCode"] into r1
put "Perl version: " & x["perl"] into r2
put r1 & return & r2 into field "PerlStdout"

and we can see in our text field:

LiveCode version: 4.5.6
Perl version: 5.10.0

evaluate a Perl String

Now, we declare a function “MyFunction” in Perl. We ask the interpreter to run this script, which, from LiveCode’s side can be seen as equivalent to: “Start using this perl script”. Then, the “do it” button will call our perl function and print the result.

sub MyFunction {  return "Perl: @_" ;  }

return "Ok" ;
-- script of button "run perl"
get Perl.Run()
if it is not "Ok" then answer "Sorry, buggy here !" -- script of button named "do it"
put Perl.Do( "MyFunction" && q(the long time) ) into field "PerlStdout"

and we can see in our text field:

rotation of a graphic

Our perl script will do a rotation of a list of “x,y” points; which, actually is the description of our nice blue graphic ( list of points ). In our “do it” button, we are calling a number of times our perl Rotate() function via the Perl.Call() interface, and then update the points of the graphic.

my @points ;
my $N = 0 ;
my ( $x0, $y0, $cos, $sin ) ;

sub Rotate {
    my @p = @points ;
    my @r ;
    my ( $x, $y, $x1, $y1 ) ;
    for ( 1..$N ) {
      $x = (shift @p) - $x0 ;
      $y = (shift @p) - $y0 ;

      $x1 = $x*$cos - $y*$sin + $x0 ;
      $y1 = $x*$sin + $y*$cos + $y0 ;

      push( @r, $x1 );
      push( @r, $y1) ;
      }
    @points = @r ;
    return join( ',' , map { int( $_ + 0.5) } @r ) ;
}

sub GetPointsFromRev {
    @points = split ( /,/ , shift ) ;
    $N = @points / 2 ;
}

sub SetRotationxya {
    ( $x0, $y0, $angle ) =  split ( /,/ , shift ) ;
    $cos = cos( $angle ) ;
    $sin = sin( $angle ) ;
    }

return "OK" ;
-- script of button "run perl"
get Perl.Run()
if it is not "Ok" then answer "Sorry, buggy here !"
-- script of button "do it"
constant cCircle = 180
local lc, t0
  
on DoArotation
  get Perl.Call( "Rotate" )
  put it &cr before field "PerlStdout"
  set the points of graphic "G" to it
  add 1 to lc
  if lc < cCircle then
    send "DoArotation" to me in 5 milliseconds
  end if
end DoArotation

on mouseUp  
  put the points of graphic "G" into G0
  put the topleft of graphic "G" into xya
  add random( the width of graphic "G"  ) to item 1 of xya
  add random( the height of graphic "G" ) to item 2 of xya
  put 2 * pi / cCircle into item 3 of xya
  get Perl.Do( "SetRotationxya" && q(xya) )
  put the points of graphic "G" into ListPoints
  replace cr with comma in ListPoints
  get Perl.Do( "GetPointsFromRev " & quote & ListPoints & quote )
  put 0 into lc
  DoArotation
end mouseup

You can see the graphic turning nicely. Notice that Perl receives and returns a list of points as parameters, nothing more.

Perl LC Object

SunnYperl presents to Perl a global variable called $LC. This is a Perl object which you can use to access the LiveCode’s world.

# What is $LC ?

print  $LC->WhoAreYou() ;
 -- script of the button named "run perl" get Perl.Run() -- script of the current card

function WhoAreYou
  return "LiveCode " & the version
end WhoAreYou

and selecting the “run perl” button, the result in our text field will be:

Sharing Hash from the 2 worlds

Start again with our Hash and our associative array. This time, we have a straightforward accces to our LiveCode variable. In our Perl script, we can read it, add another entry to this array, and eventually print it.

my $Hash = $LC->GetanArray( "aRevArray" ) ;
print "GetaRevArray: " .join(' ', %$Hash ) . "\n" ; # a new entry in the Perl Hash
$Hash->{"Douez"} = "Thierry" ; # put back this Hash into the Rev Array
$LC->SetanArray( "aRevArray", $Hash ) ; # Get the Rev Array again
my $Hash2  = $Rev->GetanArray( "aRevArray" ) ;
print "\nGetaRevArray: " .join(' ', %$Hash2 ) . "\n" ;

return "OK" ;
initilalize our LiveCode hash put "5.10" into aRevArray["Perl"]
put "4.5" into aRevArray["Rev"] script in the 'run perl' button

get Perl.Run()

the result will be:

GetaRevArray: Perl 5.10 Rev 4.5

GetaRevArray: Perl 5.10 Rev 4.5 Douez Thierry

Perl send Messages to LiveCode

In LiveCode, we have message Handlers beginning with the word “on”. The handler respond to a message following the word “on”.
With our Perl’s Rev object, we can send messages to LiveCode in 2 differents subtles ways.

print $LC->Send( "DoIt 3, 2, 1"  ) ;

print $LC->Send( "DoIt( a, b, c, d,e,f )" ) ;
-- Card script
on DoIt put the paramcount && "parameters, " into s return s && the params
end DoIt -- button 'run perl' script

get Perl.Run()

and the result will be:

3 parameters, DoIt "3", "2", "1"

1 parameter,  DoIt "a,b,c,d,e,f"

Perl call LiveCode’s functions

We can directly call LiveCode’s functions. In our case, Perl is calling the SumP() function defined in our card script.

my $r = $LC->SumP( 1,2,3) ;

print "1+2+3= $r\n" ;

$r = $LC->SumP( 2,20,200,2000) ;

print "total= $r\n" ;
-- card script, declaration of sumP
function SumP n = 0 repeat with i = 1 to paramcount add param( i ) to n end repeat return n
end SumP -- button "run perl"
get Perl.Run()

Hope you are expecting the same result as…

Perl asks for a Dialog Window

++$n;
my $Dialog = { "Title" => "Perl and LiveCode", "Label" => "Opened by Perl $n times", "LabelColor"       => RandomColor(), "Btn1Text"       => "Perl", "Btn2Text"    => "LiveCode", } ; # pass the name of the Substack and our Hash
my $btn = $LC->ShowDialog( "aWindow", $Dialog );
print "you've clicked on: $btn !\n" ;

return "OK" ;
global gPerlDialog -- Card Script of substack "aWindow"
on preopencard set the title of this stack to gPerlDialog[title] set the foregroundcolor of control id 1003 to gPerlDialog[labelColor] set the text of control id 1003 to gPerlDialog[label] set the label of control id 1004 to gPerlDialog[Btn1Text] set the label of control id 1005 to gPerlDialog[Btn2Text] put empty into gPerlDialog
end preopencard on mouseup get word 1 of the target if it is not "Button" then exit mouseup put the label of the target into gPerlDialog close this stack
end mouseup -- Script of button "run perl"
get Perl.Run()

For instance, by selecting the “LiveCode” button, Perl will print:

you've clicked on "LiveCode" !

Perl Evaluates LiveCode’s expressions

In LiveCode, an expression is any source of value, combination of sources of value. Any of these sources of value: containers, properties, function calls, literal string and constants is a simple expression. You use operators to combine sources of value to produce more complex expressions. And now we give you a tool to access them. We have 3 forms :

        $LC->Eval( "any Rev expression" )
        
        $LC->GET_any_Rev_expression
        
        $LC->GET_any_Rev_expression( p )

the last 2 are using the first form. So, let us try with some valid expressions:

$x = $LC->Eval( "the id of this card" ) ;
$y = $LC->GET_the_short_name_of_card_id( $x ) ;
print "Card Id $x named: $y  \n" ;

$y = $LC->GET_line_8_of_field( "TOC" ) ;
print "line 8 of field TOC: $y \n" ;

$x = $LC->GET_the_number_of_controls ;
print "$x controls on this card\n" ;
get Perl.Run()

and we get:

Card Id 1087 named: Eval LiveCode's expressions
line 8 of field TOC: Eval Perl String
22 controls on this card

Export Perl functions in LiveCode

Now, we introduce our Export2Rev() function to have direct access from LiveCode to Perl exported functions.
First, we run the perl script, then in the “Do it” button , we simply call our Perl functions…

sub f1 {
              my $x = join(  ",",  @_ ) ;
              return "Perl runs f1( $x ) !\n";   }

sub f2 {  "f2 gets: @_ " ;   }

$LC->Export2Rev( "f1", "f2"  ) ;
-- "run perl" button script
get Perl.Run() -- "do it" button script
get f1( 1, 2, 3)
put it &cr into field "PerlStdout"

put f2( a, b, c) after field "PerlStdout"
Perl runs f1( 1,2,3) !
f2 gets: a, b, c

Porting a Perl/Tk application to Perl/LiveCode

As a pedagogic exercise, I do port a working Perl application using the Tk GUI library, in the shortest possible time, with the least effort. It took us less than half a day to do so; and a tutorial explains this in more details. Basically, we substitute Tk by LiveCode, and add another Perl module which acts as a wrapper between the original Perl code and our LiveCode’s script emulating the Tk behavior.

For this, we have borrowed the Perl/Tk Tetris game made by Sriram Srinivasan. If you want to understand how this Perl Tetris works, better read his book: Advanced Perl Programming, where you find a whole chapter about Perl/Tk.

use libLC "PerlModules" ;

use Tetris ;

init() ;

Where is our Perl Tetris module ? Have a look at the substack named “PerlModules” via the Application Browser. SunnYperl let you import Perl Modules stored in LiveCode’s fields.