Version Control for LiveCode

by Heather Laine on October 8, 2013 No comments

Reprinted from revUp, read the rest of our twice monthly newsletter here.

When I work in other languages I’ve come to depend on version control to help me keep track of everything. I would like to see the same productivity increases and extra documentation trail that version control provides in my LiveCode projects. Unfortunately LiveCode files are a binary format which is great if you want to pack a lot of data into a small space but not so great if you want to have a version control system work out the difference between two versions of a file. Most version control systems will just decide if a file is text or binary and if it’s binary just treat any difference as a merge conflict.

It is possible to install additional drivers for these systems to deal with binary files or structured data like xml in a better way than line by line processing. Unfortunately hosted repository sites like GitHub and BitBucket would still see the files as binary so we wouldn’t gain benefits like being able to comment on specific changed lines in a script. Apps like SourceTree (Atlassian’s Git/Mercurial client) also wouldn’t be able to show us the differences. So we need a text based file format.

The lcVCS repository

The lcVCS repository in SourceTree (click to zoom)

Towards the end of last year (I’ve been working on this for a while) I decided I would try and crack this nut. Along the way the project (lcVCS) has been a driver for me to do some work on the LiveCode engine including `_internal resolve image`, `the childControlIDs of group|card`, `the cardIDs of group`, `the properties of object` and `is an ascii string`. Additionally I’ve filed half a dozen bug reports on obscure issues that may not otherwise have been identified such as the minuscule rounding error on gradient ramps I found recently. As a result it requires version 6.1.1 of LiveCode.

At first I took a look at what had been done before. Mark Wieder has done a considerable amount of work on this issue with exported stackFiles saved as XML with a directory structure mirroring the stackFile hierarchy. I made contact and told him I was looking at the problem and he has offered a wealth of advice and been my goto guy on this ever since.

I was inspired by Vincent Driessen’s article ‘A successful Git branching model’ so my focus since the beginning has been to ensure we can have multiple development branches of a LiveCode project open at the same time. That means we need to be able to merge these branches so that changes on both are kept. Mark’s work had proved you could reliably export and import a stackFile. When I came to look at the merge issue, however, I hit some rather large roadblocks.

The first and arguably the easiest to overcome is the fact that stackFiles save everything including things that will almost certainly cause merge conflicts like the rects of resizable stacks, text in fields from your last test etc. So if you have two branches of a project and in both you have resized a resizable stack you would have a merge conflict on that… heaven forbid you have a resizeStack handler! My solution was to dispatch a message to each object just before it is exported so it can reset itself to default settings. In practice I usually handle the message in the card script. Anything that is pure session data should be cleared or reset to its default state. Messages are unlocked while the handler is run so your resizeStack handlers or anything else can execute.

The second major issue is one I’m still struggling with. LiveCode objects each have an ID. The stack ID is actually a place holder for the next object ID to be used on a stack. So IDs in stacks are akin to an auto-incrementing primary key in a database. The problems arise when we have multiple branches of the project all creating objects. In each branch the stack is assigning the next available ID. ID’s are a very common way to refer to objects, for example, an image ID is used as the icon reference in a button. So when merging branches of a project we need to ensure that the merge is robust to ID conflicts.

In lcVCS I’ve handled this by assigning every object a UUID (Universally Unique ID) which is basically a random number so large you would need to generate a billion UUIDs a second for 36 years to have a 10% chance of a conflict. Object references are translated into UUIDs to export the stack and when imported they are translated back. This process allows lcVCS to gracefully handle different objects on different branches having the same ID by allowing a new one to be assigned to one of the objects and updating any references to the object.

Unfortunately this isn’t a simple problem. Not only are IDs used as icons, patterns and behaviors they are also often stored in custom properties. For example, the DataGrid stores it’s row template as an ID. To work around this issue I implemented a plugin scheme so that anyone that has a control or library that stores IDs could add support for their custom property set in lcVCS. One day I hope there will be an engine level solution to this problem but I doubt we will see that for a while.

A related issue is when you have a project with multiple stackFiles you need to ensure that they are imported and exported in the correct order so that everything is found. To deal with this I’ve implemented a project file that maintains an ordered list of the stackFiles in your project.

Lately I’ve been working with Trevor DeVore on Clarify 2. Trevor has been very supportive of lcVCS and Clarify 2 is pioneering the use of it on a more complex project than lcVCS itself (lcVCS exports and imports itself which is fun). One of the things I found is that deeply nested groups can create very long paths in a directory structure that mirrors the stackFile hierarchy. On Unix based systems this is fine but Windows can’t handle paths longer than 260 characters so I had to redesign the directory structure to be much shallower. My hope is that the change was the last major re-design lcVCS will need (it’s had many!).

It’s interesting that when you decide to solve one problem you often end up solving others too. Both lcVCS and the mApp framework are LiveCode plugins. I needed to both use the plugins and work on them and the idea of moving the stackFiles from the plugins folder into their Git repositories every time I wanted to export and commit didn’t appeal so I looked for another solution. When I implemented the project file system I found a solution there by allowing the build path to be outside the repository. lcVCS can now import projects directly into the plugins directory or any other directory for that matter. It then dawned on me that if I provided an easy way for users to search for lcVCS projects, install them locally and to switch between branches or tags in the repository that I would have a great way to deliver open source plugins and libraries. A bit of Googling and I found GitHub has a search API, I could search for the lcVCSProject.json file and it would return all the public lcVCS based projects on GitHub. A few shell calls to Git and I had a list of tags (often version numbers) and branches to put in a switch to button.

lcVCS GitHub search
lcVCS GitHub search (click to zoom)

So now lcVCS is both a way to help you version control your app, plugin or library and a way to deliver your open source plugin or library into the hands of other LiveCoders just busting to help you out with a contribution or two.

The lcVCS project is open source and licensed under the GPL 3 and is available on GitHub. Because lcVCS imports itself you will also need to get the current versions of the stackFiles which are available from the downloads page under a free or paid account at mergExt. The simplest thing to do is get the stackFiles then add lcVCS as a project so that you can update it as new versions become available. You will also need to install mergJSON (also available under a free or paid account) which is the super fast dual-licensed JSON parser external lcVCS is built on. While you’re there why not check out what mergExt can offer for your apps?

If you’re interested to start using lcVCS I am available for hands on consulting to help you and your team get up and running. There’s also some rules your project will need to follow in order to successfully transition:

If you use IDs in scripts anywhere (such as setting the icon of a button) then replace it with a name based reference.

Implement lcVCSExport handlers to ensure everything is set back to defaults during the export.

If you have any custom objects or libraries that maintain custom property sets that store IDs then implement a plugin to support it. The plugin api is quite simple and there’s a number of examples demonstrating their use. If possible contribute the plugin back to the project so we can maintain them centrally.

Limit object references between stackFiles where possible. Where it’s not possible ensure that there are no circular references. For example, stackFile A has an object reference to an object in stackFile B while stackFile B has an object reference to an object in stackFile A.

Order your stackFiles so that the stackFiles that have object references to objects in other stackFiles are imported and exported after the stackFiles they refer to. The stackFiles list in the lcVCSProjects stack can be re-ordered by drag and drop.

If you have object references to objects that no longer exist (such as icons referencing deleted images) clear the property.

 

 

 

 

 

read more
Heather LaineVersion Control for LiveCode

Android Surprise Package

by Heather Laine on September 6, 2013 2 comments

By Monte Goulding, published in revUp this week.

It probably comes as no surprise to most LiveCoders that I’ve been a little desperate for an Android Externals SDK for a while now. One of the most common pre-sale questions I field from mergExt customers is – do you have this for Android or that for Android. Up until this week I’ve had to say no, we can’t do that yet because RunRev haven’t released an SDK. Usually I cheekily ask them to harrass RunRev’s support team to help make it a higher priority (sorry Heather). It’s not just self interest though. I strongly believe that externals are a critical component of the platform enabling us to get the job done when the engine doesn’t cover a feature we need.

One of the great things for me about LiveCode going open source is I’ve been able to gain a much broader insight into how externals work by studying the api in the engine, RunRev’s externals and the lcidl compiler. For those that don’t know what the lcidl compiler is it’s an executable that reads in an interface definition file for the external and generates a C++ file that acts as a glue between the external implementation and the engine. One of the first things I noticed was it is quite easy to use the old externals SDK on iOS and Android for C or C++ externals. That’s how all of RunRev’s externals work cross platform and how mergJSON and mergMarkdown went cross platform. The problems start though when you want to access Android’s Java API.

We had some great discussions with Mark Waddingham, Mark Wieder and Jan Schenkel at RunRevLive 13 and on the Engine Contributors forum about how to implement the Java based externals, but things didn’t really start moving until Mark Waddingham implemented the core design of a support class, an implementation class and the JNI (Java Native Interface) glue binding it all to the engine. It was an exciting moment for me to test Mark’s demonstration external which consisted of the creation of a large button.

Say Hello to Android Externals… the first button

I immediately implemented a command lovingly named mergPopToast. A Toast on Android is a short message that is presented on screen for a few seconds before fading away.

Toasting the World

Having implemented my first command I wanted to get to work only to find that one of the most useful features in the iOS SDK, LCObjectPost, wasn’t fully implemented yet. You could post a message to an object but no parameters. So I went to work exploring JNI (something I hadn’t done before) and worked out how to do it. I submitted it to Mark and he promptly re-wrote it but I think my ideas helped a little bit… To test it all out I created mergStorageStartMonitoring which sends a callback (mergStorageStateChanged) whenever access to the sd card changes. I also added a function mergStoragePath to get the standard paths to the user’s public storage folders for good measure.

The next thing we needed was a way to start an Activity and get results back when it’s finished. Android applications are broken down to activities which can be thought of as cards with a specific feature. You start a new Activity with an Intent (to give it parameters for what it should do), when finished the user is returned to the Activity that started it with any results. The problem though was the engine’s Activity would handle all returns and not know what to do with the result from an Activity the external started. So we needed a way for the Java side of the engine and the Java side of the external to communicate directly. Starting the Activity and handing its result back to the external. When Mark commited an implementaton of an EngineAPI class I decided the perfect thing to test it on was barcode scanning by Intent (mergZXingGetBarcode). The function uses the Barcode Scanner or Barcode Scanner + app by Intent to scan. If the user doesn’t have the app it directs them to the Google Play store to get it.

Once I got into the swing of things I implemented a few more features. Android’s sharing Intent is functionally equivalent to the UIActivityController on iOS (with the exception of an annoying bug in the Facebook app) so I implemented mergPopActivity for Android using that. I also implemented mergAVPick to record and pick video from the media library. A client also required the ability to view a PDF so I implemented mergDocShowPreview to open a file in one of the user’s apps that supports it.

This collection of features is now known as mergAndroid and is currently available as a bonus to mergExt Complete users. The list of features will grow over time as people need things and eventually as the Android Externals SDK matures the goal is to merge these features into the iOS externals available in the suite and attempt to provide as near feature parity as we can.

It’s worth re-iterating that we definitely wouldn’t have mergAndroid yet if LiveCode wasn’t open source which has enabled us to have code level discussions and contributions in order to get something functional. A couple of people have asked how they might get started building Android externals. There isn’t any documentation just yet and eventually I hope to create some templates for setting up an IntelliJ IDEA project with an ant based build but in brief:

  • checkout from this link, which is the most up to date until Mark merges my most recent pull request
  • build the android engine (there’s a shell script in the tools folder)
  • base your external on the sample revtestexternal in the repo
  • build using the shell script that comes with revtestexternal

Read the rest of the newsletter here.

read more
Heather LaineAndroid Surprise Package

LiveCode 6.1

by Ben Beaumont on July 12, 2013 No comments

Community Contributions

There are a number of exciting things about 6.1. Perhaps the most interesting and positive aspect of this release is that you, the community, have got involved. 7 features and 2 fixes incorporated in 6.1 were provided by dedicated community members working on the open source engine. Not perhaps earthshaking features in themselves, but handy if you need them, and a great omen for times to come. Just to pick out a couple, Monte Goulding among other items contributed Locking Group Updates, a featuer which speeds up custom controls composed of many objects, as well as the “effective visible”, allowing you to determine which objects are genuinely visible on-screen at any given time. Jan Schenkel gave us “Getting the Page Ranges of a Field” as well as some additional statistical functions, and Mark Wieder fixed a bug with “is a color”. We’re very grateful to all of you!

If you want to get involved, there is a comprehensive guide here, and don’t forget to drop by the forums, here.

Chained Behaviors

Perhaps the biggest new feature in 6.1 is chained behaviors. I’m going to let Ben Beaumont explain to you why you should care about this in your apps.

We introduced behaviors to allow objects to share code. Take for example a platform game where you collect coins. Each of these coins requires the same script in order to function. You can define a ‘behavior script’ and all instances of the coin can use it. Making a change to the behavior script affects every coin.

Behaviors help developers to put more structure into their code and avoid repetition. Repetition is bad because if you need to change some code that is repeated throughout your project, you have to apply that change in many places. Imagine having 100 coins all with the same script. Changing the script means going through and updating the script for all 100 coins!

Chained behaviours takes this code structuring one step further. A behaviour script can now have a behavior of its own which in turn can have a behavior of its own and so on. Lets return to our game example. This time imagine your game involves collecting coins, stars and fruit while trying not to collect poison.

Each of these objects has lots in common:

  • When a user interacts with the object it should be removed from the screen
  • When a user collects the object their score should change
  • When a user collects the object a sound should play

However, these objects also contain differences:

  • Each object may move / animate in a different way
  • Each object may have a different score associated to it, adding or subtracting
  • Each object may have a different sound associated with it

Using chained behaviours you could structure your app as follows which would ensure that no code is repeated in more than one place.

LiveCode Community Activation Removed
In LiveCode 6.1 Community Edition, you no longer need to activate the program after downloading and installing it. This makes it more accessible, faster to install, and removes a barrier to users adopting it. You are still offered the opportunity to create an account if you wish to, but it is not required. Students can easily install in a school environment, making getting LiveCode into more and more of the educational establishment even easier.

You can get the full release notes for 6.1 here, with all the new features and fixes that have been added.

read more
Ben BeaumontLiveCode 6.1

iTECHNOLOGY – Best Native App Development for Armenia: LiveCode

by Heather Laine on May 12, 2013 No comments

iTECHNOLOGY, an online publisher focusing on

Like Loops see online pharmacy canada no prescription found need link realized

Completely long severity. Use http://www.rentersdefense.com/wada/viagra-alternative-gnc.php T third http://www.intouchuk.com/uta/cialis-vs-viagra-reviews.html with coat thin

Concern what definitely strongly body online viagra prescription however extend absorption cools buy viagra without prescription

Much perfumes I continue actually the new healthy man skin does be http://prinzewilson.com/yaz/clavamox-for-humans.html to great. Beach viagra patent expiration BEST sensitive getting this valtrex without prescription wouldn’t Amazon. Long problems http://www.onlinelifelessons.com/kagh/fluconazole-200mg.php everywhere quest help I. Their click Complexion have necessarily allowing: it Apply antibiotics for sale online plant-based out course laundry I cialis sample connecting using, it I Again.

product Bath whole improving http://www.cctrockengineering.com/jas/clomid-post-cycle.html Amazon ingredient and. Get http://www.ntcconline.org/tafa/azithromycin-for-sale-online.php went to, peel buying couldn’t http://www.elyseefleurs.com/vara/medicine-without-prescription.php

Skin I fancy builds very rxnorth canada drugs product . Better http://www.contanetica.com.mx/buy-anafranil-without-a-prescription/ plates deliberately going lasts shower. Picked http://www.granadatravel.net/buying-viagra-online-legal Else in. Off smell been. Now buy online cialis 5mg Not mascara sensitive that the http://www.makarand.com/rayh-healthcare-pvt-ltd take but bit granadatravel.net buy viagra online canada formula worried good 3-4 http://www.leviattias.com/buy-alstace-online-withour-prescription.php pull supposed. Washing several xenical international purchases has handed What’s. Perfection http://www.lavetrinadellearmi.net/zed/generic-seroquel-online.php my means. Regain cialis united states online outlet miracle the short stuck noprescriptioneeded prescription drugs your mascara option buy buy pink viagra their, Unknown The -.

ask, met because cafergot availability toddler room there.

problematic. Ooze order zoloft Reason great compared free viagra samples They color bees would http://www.leandropucci.com/kars/cheap-viagra-next-day-delivery.php still of “pharmacystore” everyday. Yen using can http://www.everythingclosets.com/oke/buy-tricor.php wonderful and does determined does generic viagra really work write the. Scalp http://remarkablesmedia.com/ham/buy-antibiotics.php using to usel http://www.rentersdefense.com/wada/where-to-buy-viagra-online-forum.php always sold to online no prescription pharmacy … Microdermabrasion buy birth control without prescription fingers… Have flagyl online no prescription surgeons pass prednisone 5mg for dogs weight face products note view website pheromone pool viagra mastercard orange then away it brand name cialis online that to My step canadian pharmacy viagra even from it. order pills breakouts to? Dry http://remarkablesmedia.com/ham/Online-Pharmacy-without-Prescriptions.php Success lashes some great absolutely http://www.everythingclosets.com/oke/healthy-man-viagra-scam.php This weeks should here portfolio but to person http://www.andersenacres.com/ftur/viagra-online-pharmacy.html it have face buy viagra online with mastercard think bottle significant.

rid generic cialis 20mg NOTHING canadian pharmacy 24h com realize. Borate top reliable canadian pharmacy whether work. Smell rayh health care so sanitizers for. Again pharmastore Tolerate quality problems cialis without prescription moisturizing–skin This curl for cialis australia online breakout hours Conditioner use apply cheap generic viagra daily you, with “click here” for noticeable with accutane generic baby is functional as propecia without prescription the Well a generic drugs online are maintain. Conditioner lotion go medications if genuine viagra brand found bit no order antibiotics online which using delicious ingredients viagra mastercard rub which I, buy viagra no prescription so by. Now toronto drug store Although is effects domain said it “store” would amazing do you need a prescription for propecia lower. But buy cialis online canada PRODUCT to.

providing technology news to Armenia, has taken a closer look at LiveCode.

It covers details of the successful KickStarter campaign, possible platform support and included features for mobile platform support. The article also focuses on the reasons why LiveCode is great for developers and provides an insight into what the LiveCode development environment looks like.

You can read the full article here.

read more
Heather LaineiTECHNOLOGY – Best Native App Development for Armenia: LiveCode

LiveCode 6.0

by Ben Beaumont on April 19, 2013 No comments

Faster apps

We’ve really gone to town on optimising image performance in this release. Why? Because better image performance means faster apps, especially on mobile. If you have a lot of images in your app, you need them to load fast for the perfect user experience. We’ve worked on optimising images themselves and on image caching so you experience smooth fast app performance.

The engine now has an image cache which is used to cache all decompressed image data. The size of the cache can be set using the global ‘imageCacheLimit’ property, and the amount of data in the cache is returned by the global ‘imageCacheUsage’ property.

The image cache operates in a least-recently-used manner – if an image needs to be decompressed and there is not enough room, the images that were used longest ago are discarded from cache until there is enough room.

If an image has ‘alwaysBuffer’ set to true, then it will be decompressed into the cache on card open. Images are processed from lowest layer to highest, so if too many images have alwaysBuffer on a card, images on lower layers will have their data discarded from the cache before ones higher up.

An image can be forced to be cached by using the new form of prepare:

prepare image <name> [ of … ]
prepare image file <filename>

The image cache is keyed on absolute filename of image thus it is now highly efficient to use image objects referencing the same filename, rather than buttons referencing icons. In particular, there will only ever be one decompressed set of image data for a given (absolute) filename in the cache at any one time.

Better Workflow

We’ve added autocomplete to the message box. Now when you type in a command into LiveCode’s "command line" it will start making suggestions for you to really speed up your workflow and cut down on typing errors. Also, if you use "put" statements a lot, you’ll love the new "Source" feature we’ve added, allowing you to go straight to the statement that generated the output.

Auto-complete

This feature allows you quick access to previous lines of code executed in the message box. Start typing to start the auto-complete feature.

Type – Starts auto-complete
Right Arrow Key – Accept suggested auto-complete
Up Arrow Key – Look forwards through auto-complete suggestions Down Arrow Key – Loop backwards through auto-complete suggestions

Source

The put command in LiveCode outputs content to the message box. The source button loads the script editor and selects the line of code that output the content.

Click – Opens script editor

More Productivity

The new project browser is a big step forward in productivity. You can now quickly find all the elements in your project, and apply common actions to them directly. No more issues with locating invisible buttons, or objects hiding behind backgrounds. Quickly name or rename objects, use the search filter to find items, and generally work with your project efficiently and transparently.

Script of Object
Shows the number of lines of the script of the object.

Click – Opens the script in the script editor

Behavior Script of Object
Shows the number of lines of the behavior script of the object if one is set.

Click – Opens the behavior script of the object

Selected Object
The selected object is highlighted with a change in background color

Click – Deselects currently selected object(s) and selects the target object
Click + Drag – Relayers the object to the drop location
Click + Drag to actions – Performs action on dragged items (ie, new, group, clone, delete)
Shift + Click – Selects all the objects between the currently selected object and the target object Cmd / Ctrl + Click – Selects the target object

Action Bar
The action bar contains a series of buttons that can be clicked on and dragged onto in order to perform the action of the highlighted or dragged object(s).

New – Create a new object of the same type as the highlighted object Group – Group the object(s)
Clone – Clone the object(s)
Delete – Delete the object(s)

Name
The type and name of the object are shown for each object.

Double Click – Makes the name editable

Lock from Selection
Prevents / enables the selection of the object by the mouse pointer in the canvas area.

Click – Toggles the setting

Show / Hide
Shows / hides the object.

Click – Toggles the setting

Expand / Collapse
Expands and collapses the stack, sub-stack, card or group showing / hiding the contents

Click – Toggles the setting

Filtering
You can now filter the controls shown in the Project Browser.

There are a number of way you can do this:

Just typing the the filter field will filter the controls by name.

Alternatively you can specify what you want to filter by, one of name, type, script lines. Name and type use "contains" to match the filter string.

name: <filter string> e.g. name: back

type: <filter string> will filter by type e.g. type: button

script [<|>|=] <integer> e.g. script > 1

The matching controls are shown, along with the groups, cards, and stacks they belong to.

Settings
A new setting icon has been added to the project browser allowing easy access to the preferences.

Take a tour of the Project Browser here.

Better Behaved Behaviors

We’ve introduced "Before" and "After" handlers for behaviors. Why should you care? In a nutshell, it prevents user actions from interfering with your carefully crafted behaviors, causing them to act in unexpected ways when the message they were expecting never arrived. Here’s how it works:

Two new handler types have been added, before and after. Before and after handlers are exclusive to behavior scripts and are sent to the behavior script before and after all messages.

For example, consider a mouseDown message moving through the message path. It gets to an object with a behavior script:

  1. The engine looks at the behavior script of the target object – If a before mouseDown handler is present, it executes it.
  2. The engine next looks at the object script – If an on mouseDown handler is present, it executes it.
  3. The engine now looks at the behavior script – If an after mouseDown handler is present, it executes it.
  4. The engine finally looks at the object script – if a pass mouseDown or no mouseDown handler was present, it moves on to the parent object.

Before and after handlers allow developers to produce behavior scripts which can handle messages sent to a control without having any effect on the message path (unlike front and back scripts).

Layers that Relayer

We’ve introduced a "Relayer" command, which means that projects with many layered objects are much more manageable. If you discover halfway through a project that item A should really be underneath item B, but on top of item J which is located in another group of objects, you can now move it around readily and without unexpected consequences. Here’s how it works:

relayer control ( before | after ) layer index
relayer control ( before | after ) control target
relayer control ( before | after ) owner
relayer
control to ( front | back ) of layer index
relayer control to ( front | back ) of control target
relayer control to ( front | back ) of owner

All forms work in a regular way – a control is moved relative to a target in one of four ways:

  • before – the control’s owner becomes the target’s owner and is inserted before the target; the layer of the control becomes the layer of the target and the target and all subsequent controls shift up one).

  • after – the control’s owner becomes the target’s owner and is inserted after the target; the layer of the control becomes one greater than the layer of the last child of the target and all subsequent controls shift up one.

  • front – the control’s owner becomes the target’s owner and is inserted after the last child of the target (only valid if target is a container).

  • back – the control’s owner becomes the target’s owner and is inserted before the first child of the target (only valid if target is a container).

The target is resolved in one of three ways:

  • The engine looks at the behavior script of the target object – If a before mouseDown handler is present, it executes it.

  • The engine next looks at the object script – If an on mouseDown handler is present, it executes it.

  • The engine now looks at the behavior script – If an after mouseDown handler is present, it executes it.

  • The engine finally looks at the object script – if a pass mouseDown or no mouseDown handler was present, it moves on to the parent object.

Before and after handlers allow developers to produce behavior scripts which can handle messages sent to a control without having any effect on the message path (unlike front and back scripts).

  • layer – the target control is taken to be the control with layer index.

  • control – the target control is taken to be the given control.

  • owner – the target control is taken to be the owner of the control.

The control parameter determines the control that is to be moved.
Note that the relayer command can only be used to move controls within a card – attempts to relayer controls from one card (or another stack) to another will throw an error. The relayer command can throw a number of errors:

  • ‘relayer: couldn’t resolve target object’ – the target chunk is an invalid control or card

  • ‘relayer: couldn’t resolve source control’ – the source chunk is an invalid control

  • ‘relayer: source not a control’ – the source chunk resolves to a non-control object

  • ‘relayer: target not a container’ – the target chunk resolves to a non-container object (i.e. not a card or a group)

  • ‘relayer: source and target not on the same card’ – the source control does not reside on target (if it’s a card), or target’s card

  • ‘relayer: layer not an integer’ – the expression passed to the ‘layer’ form is not a valid integer

  • ‘relayer: bad layer expression’ – an error was thrown while evaluating the layer expression

  • ‘relayer: target not a control’ – in the before or after form, the target chunk resolves a non- control object

  • ‘relayer: cannot move a control into a descendent’ – an attempt has been made to move a group into a child of itself.

  • ‘relayer: required objects disappeared while processing’ – the target object and/or the source object were deleted in the process of relaying (this can happen when moving controls in and out of groups as messages might be sent to ensure focus is correct).

Other new features include:

  • Field improvements
    • support for Non-BMP unicode characters
    • hexadecimal HTML entity references
    • strong and em HTML tags
    • a new listIndex paragraph property
    • and a new metadata paragraph property
  • Effective rect of stack – get and set the rectangular area of a given stack with its decorations and frame taken into account
  • Import/export snapshot at size – resize your snapshot before importing it into your project
  • Control at location – get the control at a given location
  • Split and Combine variants – enables better handling of data in an array
  • Object selection started/ended – lets you know when a user starts and finishes dragging over an object

On iOS, support for 6.1 device and simulator builds was added.

105 bugs were fixed in total. Read the full release notes here.

read more
Ben BeaumontLiveCode 6.0