External accessory framework LiveCode external

On May 3, 2012, in Uncategorized, by Monte Goulding

A client needed their sales staff to be able to print to a mini bluetooth printer from a LiveCode iOS app. The solution was to create another external for the mergExt suite called mergAccessory. With this new external you can connect to, write to and read from accessory hardware that are part of the Made for iPhone program. I’ve included in the download an example for printing to my client’s chosen accessory the BlueBamboo p25i.

 

revUP features mergExt LiveCode Externals

On April 22, 2012, in Uncategorized, by Monte Goulding

The first in my series of articles demonstrating the creation of an iOS app using a number of mergExt externals and MobGUI has been published. To celebrate the release there’s half price off mergExt and MobGUI when bought together from the RunRev Marketplace and using the coupon code MERGUI.

 

mergExt suite of LiveCode externals

On March 7, 2012, in LiveCode, LiveCode Externals, by Monte Goulding

The mergZXing project has evolved into a suite of externals for LiveCode. The externals are currently only for LiveCode iOS but long term plans involve all platforms. The suite is called mergExt (standing for M E R Goulding EXTernals) and is available at http://mergext.com. Development of new externals is driven by a community ideas forum and a poll to indicate what people need the most.

 

Today I announced a demo for my barcode reader external called ShakeNScan is available in the app store. Sorry about the app, I built it in about an hour as it’s sole purpose is to demo the modal barcode reader, ensure the external was not a blocker for app store release (which obviously I now know it’s not) and to gauge interest in it. I’m keen to hear if you have a need for it.

The external can read EAN-13/UPC-A, UPC-E, EAN-8, Code 128, Code 39 and QR Code. The app will browse to a url in a QR code but it will display the results of all the other codes. It uses one function mergGetBarcode() which presents a modal barcode reader using the back camera. An embedded barcode reader control is in the works but there’s still some issues with that I’m working through.

http://itunes.apple.com/us/app/shakenscan/id490000309

It will be available via revSelect as soon as I can arrange it.

EDIT

This external along with a heap of other externals for iOS are available at mergExt

 

LiveCode Growl Plugin

On October 29, 2010, in LiveCode, Plugins, by Monte Goulding

I spent an hour this afternoon having a play with the AppleScript commands for Growl and came up with a this little plugin toy for LiveCode. It notifies you when LiveCode is saving a standalone and when the standalone is saved. If anyone can think of anything else they might like notifications of I’m happy to add some more but this is really just a demo of the growl library which is a substack of the plugin.

{icon} Download: Growl for LiveCode 1.0 (3.02 kB)
Description: Growl plugin and library for LiveCode
 

This week I had a report of an application locking up while executing the shell function. Actually it was executing shell(“ipconfig /all”) in my modification of Ken Ray’s GetMACAddress function to return the machine’s LAN ip.

System administrators tend to like to turn things off so normal human beings can’t make a mess of their nice machines. One thing they can do is set a Windows registry entry to disable cmd.exe for the user. So by checking HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System\DisableCMD”=dword:1 we can find out if cmd.exe is disabled for the current user. What this does is when cmd.exe is run it opens the console but all you get is a blocked by admin message and no command prompt. If Bill would just change this so it stopped cmd.exe from launching at all then we wouldn’t have such a problem. LiveCode is therefore able to run cmd.exe and just sits there waiting for it to terminate but it never does.

So I wrote a safer shell function to check for this situation and also possible execution errors from hash rules and renaming of cmd.exe etc. If the registry setting is there it will attempt to execute the command directly using process commands rather than via shell.

function safeShell pCommand
   -- assume the shellCommand has been set appropriately
   set the hideConsoleWindows to true
   set the itemDel to "\"
   if item -1 of the shellCommand is "cmd.exe" AND \ 
          charToNum(queryRegistry("HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System\DisableCMD")) = 1 then
      -- don't use cmd.exe because shell() won't return
      -- don't revert to command.com because there seems to be a problem in the engine
      return executeProcess(pCommand)
   else
      try
         -- still check for empty if your are expecting a result
         -- because there's no execution error on os x
         return shell(pCommand)
      catch e
         -- execution error on windows shellCommand doesn't exist
         -- hopefully this catches hash rule blocks
         return "Error executing command"
      end try
   end if
end safeShell

function executeProcess pProcess,pElevate
   local tReturn
   if pElevate then
      open elevated process pProcess for text read
   else
      open process pProcess for text read
   end if
   repeat forever
      # Loop until there are no more lines to read.
      read from process pProcess for 1 line
      if the result = "" or the result = "timed out" then
         -- something to add
         put it after tReturn
      else
         close process pProcess
         return tReturn
      end if
   end repeat
end executeProcess
 

I have a project where using a data grid form really simplifies things, however, it’s critical that the user can re-order the list in arbitrary way. To do this I needed to add drag and drop to the data grid.

First I wrote rolled my own:

There two main limitations with this code are that it will only work for a data grid form (not table) and only if the cache controls property is true.

local sDragImage,sControlIndexMap,sOriginalIndexes

on dragStart
   local tControl,tItem
   set the dragData["private"] to "dgDragIndex"&&the dgHilitedIndex of me
   put the dgDataControlOfIndex[the dgHilitedIndex of me] of me into tControl
   lock screen
   import snapshot from tControl
   put the long id of the last image into sDragImage
   set the visible of sDragImage to false
   set the dragImage to the short id of sDragImage
   put the dgIndexes of me into sOriginalIndexes
   delete variable sControlIndexMap
   repeat for each item tItem in the dgIndexes of me
      put tItem into sControlIndexMap[the dgDataControlOfIndex[tItem] of me]
   end repeat
   set the allowableDragActions to "move"
   pass dragStart
end dragStart

on dragMove pX,pY
   local tDragIndex,tNewIndexes,tOverIndex
   if word 1 of the dragData["private"] = "dgDragIndex" then
      unlock screen
      lock cursor -- refresh bug workaround on setting the dgIndexes the dragAction seems to get set to none
      put word 2 of the dragData["private"] into tDragIndex
      set the dragAction to "move"
      if pY > the bottom of me-20 then
         if item 2 of the dgVisibleLines of me <  the dgNumberOfLines of me or the scroll of me is not the dgFormattedHeight of me then 
            set the dgVscroll of me to min(the dgVscroll of me + 20, the dgFormattedHeight of me)
         end if
      else if  pY < the top of me+20 then
         if item 1 of the dgVisibleLines of me >  1 or the scroll of me is not 0 then 
            set the dgVscroll of me to max(the dgVscroll of me - 20,0)
         end if
      end if
      repeat with X=1 to the number of groups of group "dgList" of me
         if the visible of group X of group "dgList" and the short name of the owner of group X of group "dgList" is "dgList" then
            if (pY >= the top of group X of group "dgList" of me) and (pY < (the top of group X of group "dgList" of me+(the bottom of group X of group "dgList" of me-the top of group X of group "dgList" of me) div 2)) then
               -- place above index
               put sControlIndexMap[the long id of group X of group "dgList" of me] into tOverIndex
               --put "over"&&tOverIndex
               if tDragIndex = tOverIndex then 
                  put sOriginalIndexes into tNewIndexes
               else
                  put sOriginalIndexes into tNewIndexes
                  delete item itemOffset(tDragIndex,tNewIndexes) of tNewIndexes
                  put tDragIndex&"," before item itemOffset(tOverIndex,tNewIndexes) of tNewIndexes
               end if
               set the dgIndexes of me to tNewIndexes
               put tNewIndexes into sOriginalIndexes
            else if (pY <= the bottom of group X of group "dgList" of me) and (pY > (the top of group X of group "dgList" of me+(the bottom of group X of group "dgList" of me-the top of group X of group "dgList" of me) div 2)) then
               -- place below index
               put sControlIndexMap[the long id of group X of group "dgList" of me] into tOverIndex
               --put "over"&&tOverIndex
               if tDragIndex = tOverIndex then 
                  put sOriginalIndexes into tNewIndexes
               else
                  put sOriginalIndexes into tNewIndexes
                  delete item itemOffset(tDragIndex,tNewIndexes) of tNewIndexes
                  put ","&tDragIndex after item itemOffset(tOverIndex,tNewIndexes) of tNewIndexes
               end if
               set the dgIndexes of me to tNewIndexes
               put tNewIndexes into sOriginalIndexes
            end if
         end if
      end repeat
   end if
   pass dragMove
end dragMove

on dragEnd
   -- clean up
   if sDragImage <> "" then
      delete sDragImage
      put "" into sDragImage
   end if
   pass dragEnd
end dragEnd

Then I had a poke around the data grid behavior script and found undocumented support for drag and drop. So here’s the new script that does not have the limitations of the above and is obviously far less verbose:

on dragStart
   local tIndex
   if (the dgHeader of the target is empty) then
      put the dgIndex of the dgDataControl of the target into tIndex
      set the dgDragImageIndex of me to tIndex
      set the dragData["private"] to empty
      set the dgTrackDragReorder[tIndex] of me to true
   end if
end dragStart

on DragReorderDrop pOriginatingIndex, pStartLine, pDroppedOnLine
   if (pStartLine is not pDroppedOnLine) then
      SetLineOfIndex pOriginatingIndex, pDroppedOnLine
      send "RefreshList" to me in 0 secs
   end if
end DragReorderDrop

on dragMove
   set the dragaction to "move"
end dragMove
 

revIgniter Open Graph Protocol Library

On September 27, 2010, in LiveCode, LiveCode Server, by Monte Goulding

For the past few weeks I’ve been playing with the revIgniter Web Application Framework whenever I get a chance. It’s a very impressive piece of work written by Ralf Bitter as a LiveCode Server implementation of the PHP CodeIgniter framework.

One of the first things I was keen top implement is a Facebook API library. The starting point is the Open Graph Protocol that defines page metadata to give pages context. The Open Graph Protocol is what allows Facebook to show a nice title, image and description etc when you paste in a link.

If you are interested in the library or want to contribute to it and the facebook library coming next then check out the repo at github:
http://github.com/montegoulding/revIgniter-open-graph

 

revObjective 1.2 released!

On September 8, 2010, in IDE Mods, LiveCode, LiveCode Desktop, Plugins, Uncategorized, by Monte Goulding

This new version of revObjective separates out the startup code from the main plugin along with a couple of minor user interface changes.

{icon} Download: revObjective 1.2 (56.13 kB)
Description: A behavior scripts and custom object manager. To install just unzip the file and copy the contents into your user plugins directory.

A screencast showing the basics of working with revObjective is included below.

 

revObjective 1.1 released!

On September 7, 2010, in IDE Mods, LiveCode, LiveCode Desktop, Plugins, by Monte Goulding

A new behavior script and custom control manager plugin for Revolution.

Features include:

  • Adds an object placing menu button to the tools palette for both revObjective and standard Revolution object libraries.
  • Add, Delete, Clone, Place, Edit Script, Edit Controls, Name, Describe, Author, Version your custom controls.
  • Drag and drop objects onto your stacks from the object list.
  • Drag and drop revObjective files to and from the object list to share.
  • Searches stacks during standalone building and finds revObjective behaviors and copies over the behavior scripts in a way that is not file path dependant.
  • Packaged with revObjective are MacOS X Search Field, Integer Field, Decimal Number Field and Placeholder Text Field

{icon} Download: revObjective 1.2 (56.13 kB)
Description: A behavior scripts and custom object manager. To install just unzip the file and copy the contents into your user plugins directory.

This plugin is donationware. If you decide it fits into your workflow then please consider donating to encourage further development.