Tag Archives: RunRev

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.

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.

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

Installer Maker Plugin 1.5.1 for LiveCode has been released – Happy New Year!

Hello! Happy New Year to all of you! I wish you all success in business and carreer and happiness in your family!

Economy-x-Talk has released a new version of the Installer Maker Plugin. This update fixes a problem that prevented Linux users from registering and several other smaller problems. More info can be found at http://rrinstallermaker.economy-x-talk.com/ .

Screen_shot_2010-12-13_at_16

This update is free for everyone who bought a (new) license during the past 3 months. Upgrades are available at half the original price.

Installer Maker Plugin 1.5 for LiveCode is now available!

Economy-x-Talk is pleased to announce a big update of the now well-known Installer Maker Plugin for LiveCode.
The Installer Maker Plugin is the easiest way to wrap your LiveCode standalones in an installer. Just create your standalones and drag them into the Installer Maker Plugin window. Without being complicated, the Installer Maker Plugin offers you sufficient options to install your software on almost every Windows PC or Mac.

The new update contains more than a dozen bug fixes and new features. Most of the implemented new features were requested by our customers. Some important changes are: deletion of pictures from the Appearance section is now possible, more and improved language options, parenthesis are now allowed in file paths, more built-in checks and fail-safes to avoid mistakes.

Screen_shot_2010-12-13_at_16

With this new release, we are adjusting our licensing policy to make continuation of this project possible. We provide everyone who buys a (new or upgrade) license with free updates for three months. Currently, everyone can buy an upgrade, regardless of when you bought your license. Soon, you will be eligible for the upgrade price only if you bought your original license less than 1 year ago.

If you bought your license more than a year ago, you might want to buy an upgrade right now, while you can still pay the upgrade price. Upgrades cost EUR 16.95, new licenses cost EUR 39.00. (You can see when your license was created by hovering your mouse over the version number in the bottom-left of the Installer Maker window. The license creation date will appear in the tooltip.)

The new version of the plugin and forms to buy a new license or an upgrade can be found at http://rrinstallermaker.economy-x-talk.com . If you have any questions, please go to http://qurl.tk/du and fill out the web form.

MySQL Licenses: The Do’s and Don’ts of Open Source, or What’s All the Fuss About?

MySQL Licenses
The Do’s and Don’ts of Open Source, or What’s All the Fuss About?

copyright ©2010 by
Mark Schonewille and Economy-x-Talk
Nijmegen, the Netherlands
this version: 1.3 (26 Nov. 2010)

1 Introduction

In reply to a question on the LiveCode User Mailing List, I argue that MySQL is one of the best freely available (open-source) databases. A number of subscribers to that mailing list reacted quite strongly, saying that open-source doesn’t mean free. Apparently, they use the word “free” as in “free beer”, while I use it as in “free speech”. They argue that one needs to pay Oracle Corporation a lot of money if one uses MySQL, despite the fact that MySQL is open-source and freely available.

This was enough reason for me to call Oracle Corporation. After 30 minutes of searching for the right person, I was connected to a friendly Oracle Corporation employee. I asked this employee three questions: 1) do I have to pay Oracle Corporation if I use MySQL at home, 2) do I have to pay Oracle Corporation if I make commercial software that works with MySQl and 3) do my customers have to pay Oracle Corporation if they use MySQL in combination with my commercial software? His answer was a resounding and clear threefold “No!”

One doesn’t need to pay Oracle Corporation. It should be clear, though, that MySQL’s license, specifically the GNU General Public License (GPL for short) requires it to stay open-source. The GPL poses a few limitations on the use and distribution of MySQL, but creates opportunities at the same time.
In the text below, I explain the implications of the GPL for users of MySQL. In doing so, I will discuss a number of typical examples.

2 Unpaid Without Redistribution

You can freely download the MySQL software from the website . You can install it on your laptop for your own personal use, to test your website with a MySQL server. You can upload those websites to a web hosting server. You don’t need to pay Oracle Corporation anything in this situation.

A web hosting company can offer the MySQL database engine as an extra service on their servers. They can freely download the MySQL database engine from the MySQL website and they don’t need to pay for it. The customers of the web hosting company also don’t need to pay for using MySQL with their websites.

As another example, a printing company wants to manage a large customer database and has MySQL installed on an internal (local) server after downloading it from the MySQL website. The printing company is allowed to use the MySQL database for free without paying Oracle. The same company can ask me to make software for them, which will talk to their MySQL database. That company still doesn’t need to pay Oracle Corporation and I myself don’t need to pay either.

In a third example, I make commercial software, which needs to have MySQL installed. My customers can use my commercial software, for which they do need to buy a license, in combination with the MySQL database engine, for which they don’t need to pay. Because the MySQL engine is not embedded in my commercial software and I don’t redistribute MySQL together with my software, I don’t need a commercial license for MySQL and neither do my customers.

The next situation is a little tricky. I make commercial software and need a special version of MySQL to make it work. I adjust the MySQL engine and distribute it as open source software. I offer the source code for free to everyone who uses my adjusted MySQL database engine. I simultaneously distribute my commercial software accompanied by a note that it needs the adjusted version of MySQL. I make sure that the original GPL applies to my customised version of MySQL. I tell my customers to install my version of MySQL on their servers and to install my software on their client machines. I don’t need to pay Oracle Corporation because I distribute the adjusted version of MySQL under the GPL and it is not embedded in my commercial product.

This is about as far as you can stretch the GPL. In the situations described in the above, I don’t act as an OEM (Original Equipment Manufacturer), an ISV (Independent Software Vendor) or a VAR (Value Added Reseller) and I, my customers and my (internet) service provider can use MySQL without paying Oracle. (Note that redistributors are not limited to OEM’s, VAR’s and ISV’s only).

3 Redistributing the MySQL Software

The next step would be to adjust the MySQL engine in such a way that it can work with my commercial software product without distributing the code for the adjusted engine. This causes a dependency between the MySQL software and my commercial product and violates the GPL directly. The GPL can no longer apply and I will need to buy a commercial license from Oracle Corporation in this case.

I could download the MySQL engine and embed it into my product, e.g., by letting my installer install MySQL automatically together with my own product. I don’t want to disclose the source code of my entire product. Because I am selling my commercial software product together with the embedded MySQL engine, I have become an ISV and I need to buy a special commercial license to do so.

It should be obvious that I also need to buy a commercial license, if I want to use the MySQL source code libraries, rather than compiled binaries, in the source code of a commercial product without revealing the source code. Selling this commercial product violates the GPL and requires that I pay Oracle for a license.

However… as long as I have no desire to sell the embedded MySQL source code commercially, I can let the GPL license apply. For example, if the aforementioned printing firm asks me to create an in-house tool to manage their database, they might require that the tool includes the MySQL server (either by embedding the source code into mine or by combining the binary with the final product). If I make the tool, include MySQL in it and license it to the customer under the GPL, my customer has no obligation to reveal the source code to anyone, as long as he doesn’t redistribute my work. The customer still doesn’t need to pay Oracle Corporation for a MySQL license, nor do I.

However (again)… I have to offer my customer the source code as required by the GPL. If the customer doesn’t want the source code, I don’t need to give it to him. If the customer wants to redistribute the product, he needs to ask me for the source code, because he has to make the same offer to those who receive the redistributed software from my customer as I had to.

The interesting point here is that my customer still can (or rather has to) pay me for my services. I made the software for him and he already agreed to pay me for my efforts. When he redistributes the software under the GPL, he can offer his own customers a similar service.

4 Then What’s All the Fuss About?

It is quite obvious that Oracle Corporation doesn’t write on the MySQL website “please don’t pay us”. However, the goal of MySQL isn’t only to generate money. By supporting MySQL, Oracle Corporation makes sure that a large community of software and database developers continues to exist. This community creates new ideas that Oracle Corporation might use —reverse engineer, if you want— in their commercial products. Another reason to support MySQL is that some customers might prefer the commercial Oracle database over the non-commercial MySQL database at some point.

If you decide to pay for a MySQL license, you don’t actually pay for the software. The software is open-source after all and can’t be sold without offering the source code. If Oracle Corporation would ask loads of money for the software only, someone would decide to compile the binaries and offer them for free, together with the source code. Anyone could do so.

Also, Oracle Corporation can do exactly the same as you and me: sell a service connected to MySQL. Oracle Corporation provides support to anyone who wants to pay for it. This way, MySQL is a source of revenue for Oracle Corporation.

Finally, there are the licenses for OEM’s, VAR’s and ISV’s. Everyone who wants to sell MySQL software as part of their proprietary software or hardware product needs to buy a commercial license. This is another source of revenue for Oracle Corporation.

For most small businesses, MySQL is the least expensive (or even completely free) and often the most efficient database available, provided that they don’t need support from Oracle Corporation. For example, being a small company with all necessary skills available in-house and not having huge databases that require continuous monitoring, Economy-x-Talk doesn’t need to buy support from Oracle Corporation.

5 Conclusion: Redistribution Is Key

The conclusion of this story is twofold. First of all, as long as you don’t redistribute the MySQL software, you don’t need to worry about licenses, even if you make money by providing database-related services or products that need MySQL to be available. Second, even if you redistribute MySQL under the GPL, you can still make money with it, as long as you offer the source code of your project, which your customer might not even want to have.

To clarify the second conclusion, keep in mind that it is not obligatory to redistribute your compiled software. When you offer the source code, your customers are not obliged to accept the offer. Because you are the one who provides the service of maintaining and improving the software and your customers are actually already paying you for this service, they might not care about the source code. Only if you ever decide to stop providing this service, your customer might have an interest in the source code.

Oracle Corporation seems to stick not closely, but completely, even literally, to the GPL. All the fuss about Oracle Corporation no longer supporting MySQL and not caring about small companies who use the MySQL database engine is sheer nonsense. Oracle Corporation continues to support MySQL for now. Even if they decided to terminate their support, anyone could take the MySQL engine and continue to develop and redistribute it under the GPL.

Note:

Please, feel free to comment on this article. Keep in mind, however, that I asked Oracle Corporation for their opinion on this matter and, although not in as many words and not that specific, this was their answer. I would like to thank Björnke von Gierke and Judy Perry for their comments.

The author owns the software development company Economy-x-Talk and gladly offers his services. Need help with LiveCode, PHP or MySQL? Let me know

The author accepts no responsibility for any consequences of business decisions based on this information. It is the reader’s responsibility to read the actual license conditions on Oracle Corporation’s MySQL website and consult with Oracle Corporation if in doubt. This article represents the personal opinion of the author, is not endorsed by RunRev Ltd. and has not been authorised by Oracle Corporation.

Integral reprint in physical and electronic form is herewith granted, on the condition that the copyright notice, the version number, the date, the URL’s and this sentence are included. If you publish this text on a web site, please embed the URL’s in a sensiblel way.