Tag Archives: LiveCode

On Friday 9th October 2015, eHUG (the European HyperCard User Group) organised a LiveCode meeting in Breda, the Netherlands. At the meeting, we exchanged ideas and experiences with LiveCode. Subjects that came to table were RunRev’s support service, Beat Cornaz’ composing software (obviously created with LiveCode), HyperStudio and HyperDuino, and the Arduino.

group1

Because we talked so much about Arduino, we didn’t have much time to do experiments, but we did have a live demonstration of the Arduino. We raffled off a copy of the book Programming LiveCode for the Real Beginner and a license of HyperStudio.

group2

While Claudi was not able to attend the meeting, he offered to send us his Arduino stack. Everyone who was present at the meeting will receive his e-mail address (as well as those of all other participants).
If we find the time to organise it, we’ll have the next meeting in spring. If you’re interested in attending the meeting, contact the organiser through this web form.

group3

See also here for more a little more information about the HyperDuino and the location of this edition of the meeting.

The book that was raffled off is also available here.
You can read everything about HyperDuino on this website.

Beta Version of Installer Maker 1.8.7 Available!

Recently, We got a request to make some improvements to Installer Maker. As a result, we have made many, many invisible changes, fixing bugs and adding new features. In a few places, the changes are visible. For example, you can see the long list with all special folder paths for Windows (XP up to and including 8.1) and you can see a small but essential change on the Scripts pane, allowing for pre- and post-uninstall script execution.

It is now possible to select any special Windows folder as a destination folder.

It is now possible to select any special Windows folder as a destination folder.

Installer Maker 1.8.7b03 can be downloaded here.

Below follows an overview of all changes in the latest beta version.

  • Installers created with a trial copy on Windows should now start correctly (only on the same computer as on which they were created)
  • The documentation (on the Help screen) should still show up, even if the httpHeaders were set incorrectly by another script
  • install locations have been extended by a large number of Windows-specific directories
  • the destination “startup disk” appeared incorrectly
  • a possibility to create an installer with empty files has been added
  • the uninstaller is now installed in the executable’s folder on Windows, while previously it would end up in a separate folder occasionally
  • file paths are now included in profile files
  • if a path in a profile file is not found, you’ll be asked if you want to repair all paths
  • on Windows, the Uninstaller can now execute LiveCode scripts that have been added on the Scripts pane; thise feature will be added for Mac OS X soon
Installer Maker Scripts Pane

Installer Maker Scripts Pane

Note that this is still a beta version. If you want to create an installer for distribution, download and use Installer Maker from the official website. Tests show that Installer Maker 1.8.7b03 isn’t fully compatible with LiveCode 7 yet, due to bugs in LiveCode 7. Installer Maker 1.8.7b03 is only available as a plug-in for the commercial license of LiveCode. A standalone version will be made available shortly.

We need your help! Please, download and test Installer Maker 1.8.7b03 and send an e-mail with your findings to Economy-x-Talk’s support department! Everybody can download the beta. Installers created with an unregister trial copy only work on the computer they were created on. This version of Installer Maker is a free update for everyone with a current license.

Make a Button Respond to Device Movements

I am making a simple game for Android devices. In this game, the user moves a control by turning the device to the left or to the right.¬† I noticed that the orientationChanged message wasn’t sent.¬† After some experimentation, I found out that all mobileOrientation features were broken, but the mobileAcceleration features worked. However, accelerationChanged message was never sent. I don’t know if these problems are LiveCode bugs or malfunctions of my own device, although I do have a feeling that something is wrong with LiveCode’s mobileOrientation and mobileAcceleration features.

Anyway, the point is that I found a way to make my game work correctly and I decided to write down how I did it. This is just a quick note. If you find anything to improve, just post it in a comment at the bottom of this text.

Screen capture of the game

Before you can use the acceleration features of your device, you have to set up this feature for your app. I do this in the openCard handler to make the time between starting the app and rendering the first card as short as possible. It doesn’t matter whether your stack starts up in landscape or portrait mode. The acceleration values will adjust automatically.

Because you might want to play your game on desktop machines too, you need to check if the game is played on a movile device, using the environment function. Not all devices have acceleration features, so you have to check for those too, using the mobileSensorAvailable function. The parameter of this function can contain “acceleration”, “rotation”, “heading”, or “rotation rate”. For my game, I need “acceleration”. This is sufficient to make a control move accordingly the movements of the device.

on openCard
  if the environment is "mobile" then
    put mobileSensorAvailable("acceleration") into lSensorAvailable
    if lSensorAvailable then
      mobileStartTrackingSensor "acceleration",false
    else
      answer warning "Acceleration sensors are unavailable."
    end if
  else
    put false into lSensorAvailable
  end if
  // first finish rendering, then send setupCard message
  send "setupCard" to me in 0 millisecs
  pass openCard
end openCard

If the sensor is available, we can turn it on using the mobileStartTrackingSensor command. The first parameter of this command determines the sensor. The second parameter toggles loosely, but power-saving sensor readings. If this parameter is false, it will read accurate values but also use a lot of energy. I have chosen to use accurate values for my game.

I want the openCard handler to finish before I start reading sensor values. The reason is that the card will render only after the openCard handler finishes and I want this to happen as quickly as possible. By using the send in time command, I make sure that the setupCard command is executed after the openCard handler finishes and the card is rendered.

on setupCard
  if the environment is "mobile" then
    pollForRotation
  end if
end setupCard

The setupCard message can also be used to put controls in the centre of the card, to set up a score display, or do download some data from a server for instance. We don’t need that functionality in this simple example.

The pollForRotation handler actually doesn’t poll for rotation. It polls for acceleration, but my original intention was to get rotation values and hence the name. Actually, this is what makes me think that something is wrong with LiveCode. Perhaps RunRev got a few wires switched under the hood.

The pollForRotation handler first reads the device’s position. The more you turn your device to the left or right, the lower (less than 0) or higher (greater than 0) the value returned by the mobileSensorReading function.

Although polling might seem inefficient and power intensive (as polling usually is), it has two big advantages. First, polling the mobileSensorReading function works, whereas the accelerationChanged message doesn’t seem to work. Second, the documentation about the mobileEnableAccelerometer¬† command suggests that the accelerationChanged message can’t be sent more often than 1 time per second –when this message becomes functional in LiveCode, I’ll have to test if the mobileEnableAccelerometer command accepts fractions of seconds.

The pollForRotation handler reads the acceleration value, stores it, and executes the moveControl handler. After the moveControl handler finishes, the pollForRotation handler executes itself again in 150 milliseconds. By keeping the reading frequency low (almost 7 times per second), I hope to save some energy and leave enough time for other game controls to be updates and rendered.

on pollForRotation
   put mobileSensorReading("acceleration") into myDelta
   moveControl item 2 of myDelta // horizontal, left-right movement
   send "pollForRotation" to me in 150 milliseconds 
end pollForRotation

The mobileSensorReading function returns a list of three values: front-back horizontal movement, left-right horizontal movement and vertical movement. We need the second item from this list.

Another screen capture of the game

The moveControl handler does some calculations and moves the button. The moveControl handler needs a paremeter, indicating the amount of left-right movement. We don’t want the game to be unresponsive but at the same time we don’t want it to be too sensitive. Therefore, we make two adjustments. First, we calculate the square value of the horizontal movement. If the player moves the device quickly to the left or to the right, the game will respond accordingly. However, if the plater moves the device slowly, the game will make small adjustments, which allows for high accuracy. We’re also increasing overall speed, by multiplying the square value by 1.2. We’re doing this just because we thought the game was a bit slow at first. You can change this number as you like. The variable myHorizontalSpeed now contains the number of pixels by which we want to move the control. We use the sign of theDirection to determine whether we want to go left or right.

on moveControl theDirection
  // for demo, assume 1 button exists
   put 1.2*theDirection^2 into myHorizontalSpeed // the movement of the button at a time in pixels
   if theDirection < -1 then
      set the left of btn 1 to max(0,the left of btn 1 - myHorizontalSpeed)
   else if theDirection > 1 then
      set the right of btn 1 to min(the right of this cd,the right of btn 1 + myHorizontalSpeed)   end if
end moveControl

If theDirection is very small, i.e. between -1 and 1, we don’t move the control. This may happen when the player accidentally moves the device or if the device appears to be extremely sensitive. If theDirection is less than 1, we move the button to the left and if theDirection is greater than 1, we move the button to the right.

The left side of a button can be at any location above 0. The minimum value for the left of a button is 0. Therefore, whenever the new value of the left of the button is going to be less than 0, we set the left to 0. In all other cases, we set the left of the button to a value slightly less than its current value, if theDirection < -1.

The right of a button can be at any location below the right of the card. The maximum value of the right of the button equals the right of the card. Therefore, whenever the new values of the right of the button is going to be larger than the right of the card, we set the right of the button to the right of the card. In all other cases, we set the right of the button to a value slightly higher than its current value, if theDirection > 1.

If the button isn’t at the extreme left or extreme right location, the amount by which we move the button is determined by the variable myHorizontalSpeed.

If you want to stop the game, you only need to stop the pollForRotation handler. E.g. you can write the following in a button script:

Zn mouseUp
  put the pendingMessages into myMessages
  filter myMessages with "*pollForRotation*"
  repeat for each line myMsg in myMessages
    cancel item 1 of myMsg
  end repeat
end mouseUp

To start playing, just call the pollForRotation handler again.

Economy-x-Talk Releases Installer Maker 1.8.2

A new version of Installer Maker has been released. This update, 1.8.2, is made available as a Plugin for LiveCode as well as a standalone application for users of Xojo, HyperStudion, Prezy, SuperCard and other cross-platform RAD tools.

Installer Maker 1.8.2 allows for saving all settings in a profile. This profile can later be read from disk and re-used for your project again. This way, you don’t need to re-enter all settings and options every time you make your installer. You do need to import your new files. Note that this is a new feature, which we expect to improve in the near future. We appreciate your feedback.

Installer Maker 1.8.2 screen shot

Screen shot of the first screen of Installer Maker 1.8.2.

Additionally, it is no longer possible to accidentally associate the .exe file extension with your executable. We have received 2 reports of users trying to associate the .exe file extension. Although it should be obvious that the .exe file extension whould not be associated with any software, we have decided to disallow the .exe file extension from now on.

The plug-in can only be used with LiveCode 4.5 – 5.x and the commercial version of LiveCode 6 and later. The standalone version of Installer Maker can be used with (almost) any development software package.

Once in a while, we receive a feature request, bug report or other comments. If you decide to send an e-mail about Installer Maker, please include extensive descriptions of the features you request or the bugs you encounter with pictures and other relevant files.

The standalone version of Installer Maker can be downloaded here.

The plug-in version of Installer Maker for LiveCode can be downloaded here.

What if there’s no way to upload a file to a server?

More than once, the question has been asked how to upload files to a server from a mobile device. An important problem is that sockets aren’t supported by default and a bug on Android preventing pictures from being saved to an album or attached to an e-mail. You might use Dropbox or a similar service, but requiring your customers to use an additional service doesn’t give a very professional impression.

I have created a very simple LiveCode+PHP library, which uploads small files to a server. It might also work with bigger files, but I haven’t tested this yet. This library works on any Android/iOS device and also works on desktop machines with any operating system.

There is no documentation yet and the current version is quite crude. No security has been implemented yet. If you’re curious, you might want to have a look. If you need an off-the-shelve solution, then maybe not yet.

The library can be downloaded at http://qery.us/43p after making a donation (or if you made a donation less than 1 year ago). Currently, our server doesn’t send e-mails automatically and you may have to wait up to 24 hours to get access to the private downloads.

New: LiveCode GUI Elements for iOS

This is a collection of GUI elements for iOS that we are going to use in a LiveCode project.

These GUI elements are really cool because

  • objects scale appropriately if you drag their handles
  • scroll views are created automatically for scrolling fields
  • lists can be easily adjusted using a property
  • all buttons hilite nicely
  • all elements can easily be mixed with LiveCode’s objects and your own or third-party custom objects
  • this collection of GUI elements costs nothing if you have already made your contribution

Ios_gui

The stack is completely editable and you can copy all items to your own project.

This collection of GUI elements is available to anyone who has registered as a contributor here. Once you have registered, you can obtain the GUI elements for iOS from our website.

LiveCode or RealStudio Drawer Windows – Which Bug Do You Pick?

Here are two sample projects, which I just made to test LiveCode and RealBasic drawer windows.

LiveCode works fine, until you change the drawer window size by script.

Screen_shot_2011-09-23_at_01

RealStudio works fine until you start moving the window around.

0screen_shot_2011-09-23_at_01

I think I’d choose LiveCode in this case, but perhaps it is better to avoid using drawer windows completely.

Zip files and folders (including empty folders) with LiveCode

/*
iZip 1.0.1
Make a zip file recursively without the
need for a callback message. This script includes empty folders
if there are any.
—————————————————————-
Usage: iZip path[,true|false]

Parameters:
The first parameter is a string containing the path to a file or
folder. The zip file will have the same name as the original
file or folder, appended by “.zip”, and is created in the same
directory as the original.
The second parameter is a boolean excluding “.DS_Store” files if
true and includes them if false or empty.

Error messages:
If the zip external encounters a problem, an  error message is
returned of the form “error: file not open”.

Comment:
You need to write your own script to check that the revZip
external is available.

Copyright © 2011 by Economy-x-Talk
http://www.economy-x-talk
This script is free to use. Please give credit if you do. Always
include this copyright notice in a visible place in your
software.
*/
on iZip theFile,theExcludeDsStore
     if not (there is a file theFile or there is a folder theFile) then
          return “error: file not found”
     end if
     set the itemDel to slash
     put number of items of theFile into myAbsolutPathLength
     put theFile into myFolderlist
     put theFile & “.zip” into myZipFile
     // need to zip the whole thing recursively
     // item names should probably be the relative folder paths
     put the directory into myOldDir
     put 0 into myCounter
     revZipOpenArchive myZipFile,”write”
     put the result into rslt
     if rslt is not empty then
          set the itemDel to comma
          return “error:” && item 2 of rslt
     end if
     if there is a file theFile then
          put last item of theFile into myItemName
          revZipAddItemWithFile myZipFile,myItemName,theFile
          put the result into rslt
          if rslt is not empty then
               set the itemDel to comma
               return “error:” && item 2 of rslt
          end if
     else // folder
          repeat forever with messages
               add 1 to myCounter
               put line 1 of myFolderList into myCurrentFolder
               // add folder
               put item myAbsolutPathLength to -1 of
                      (myCurrentFolder & “//”) into myItemName
               revZipAddItemWithFile myZipFile,myItemName,””
               put the result into rslt
               if rslt is not empty then
                    set the itemDel to comma
                    return “error:” && item 2 of rslt
               end if
               set the directory to myCurrentFolder
               put the files into myFileList
               // zip the files
               repeat for each line myFile in myFileList with messages
                    if (myFile is “.” or myFile is “..”) or
                           theExcludeDsStore is true and myFile is
                           “.DS_Store” then next repeat
                    put item myAbsolutPathLength to -1 of
                           (myCurrentFolder & slash & myFile) into
                           myItemName
                    if char -4 to -1 of myFile is “.zip” then
                         revZipAddUncompressedItemWithFile
                                myZipFile,myItemName,myFile
                    else
                         revZipAddItemWithFile myZipFile,myItemName,myFile
                    end if
                    wait 0 millisecs with messages
               end repeat
               put the folders into myTempFolderList
               repeat for each line myFolder in myTempFolderList
                    if myFolder is “.” or myFolder is “..” then next repeat
                    put cr & myCurrentFolder & slash & myFolder after
                           myFolderList
               end repeat
               delete line 1 of myFolderList
               if number of lines of myFolderList is 0 then exit repeat
               wait 0 millisecs with messages
          end repeat
     end if
     revZipCloseArchive myZipFile
     put the result into rslt
     if rslt is not empty then
          set the itemDel to comma
          return “error:” && item 2 of rslt
     end if
     set the directory to myOldDir
end iZip

Get current remote connections with LiveCode on MS Windows XP/Vista/7

This is a script to check the remote desktop connections to your computer. Syntax:

rdConnection([false]|true|”User”)

where User is the name of a user with an account on that particular computer (or server).

Paremeters:
false: returns true if connections have been established, false of not
true: returns the names of the currently logged in users
user (in quotes): returns true if that particular user is logged in, false otherwise

function rdConnection theName
   if the platform is not “Win32” then return empty
   set the hideConsoleWindows to true
   put shell(“qwinsta”) into myConnections
   filter myConnections with “*Active*”
   if theName is empty or theName is false then
      repeat for each line myLine in myConnections
         if word 4 of myLine is “Active” then
            put myLine & cr after myNewList
         end if
      end repeat
      delete last char of myNewList
      return (myNewList is not empty)
   else if theName is true then
      repeat for each line myLine in myConnections
         if word 4 of myLine is “Active” then
            put word 2 of myLine & cr after myNewList
         end if
      end repeat
      return myNewList
   else // theName is not empty
      if word 2 of myLine is theName then
         put myLine & cr after myNewList
      end if
      delete last char of myNewList
      return (myNewList is empty)
   end if
end rdConnection