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.
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.
| 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
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
This new version of revObjective separates out the startup code from the main plugin along with a couple of minor user interface changes.
| 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.
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
| 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.
After a correction on my greyscale formula in my last post from Mark on facebook I reviewed the results of my code and decided the disabled look wasn’t quite right. What I wanted was a a washed out looking version. This code and plugin modifies the alphaData of the image to 33% of the original and greys the imageData 15% more. You can modify the constants in the button code if you want different ratios. Here’s the code:
constant kTranslucencyRatio = 0.33
constant kGreyRatio = 0.15
on fadeImage pImageID
local tAlphaData,tOffset,tWidth,tHeight,tAlpha
lock screen
put the width of pImageID into tWidth
put the height of pImageID onto tHeight
put the alphaData of pImageID into tAlphaData
repeat with tOffset = 0 to tWidth *tHeight
put charToNum(char tOffset of tAlphaData) into tAlpha
-- handle cases of very low alpha for edge smoothing
if round(tAlpha*kTranslucencyRatio) > 0 then
put NumToChar(round(tAlpha*kTranslucencyRatio)) into char tOffset of tAlphaData
end if
end repeat
set the alphaData of pImageID to tAlphaData
end fadeImage
on greyImage pImageID
local tImageData, tRed, tGreen, tBlue, tGrey, tOffset,tWidth,tHeight
lock screen
put the width of pImageID into tWidth
put the height of pImageID onto tHeight
put the imageData of pImageID into tImageData
repeat with tOffset = 0 to tWidth *tHeight * 4 step 4
put charToNum(char tOffset + 2 of tImageData) into tRed
put charToNum(char tOffset + 3 of tImageData) into tGreen
put charToNum(char tOffset + 4 of tImageData) into tBlue
put (30*tRed+59*tGreen+11*tBlue)/100 into tGrey
put round(tGrey*kGreyRatio+tRed*(1-kGreyRatio)) into tRed
put round(tGrey*kGreyRatio+tGreen*(1-kGreyRatio)) into tGreen
put round(tGrey*kGreyRatio+tBlue*(1-kGreyRatio)) into tBlue
put NumToChar(tRed) into char tOffset + 2 of tImageData
put NumToChar(tGreen) into char tOffset + 3 of tImageData
put NumToChar(tBlue) into char tOffset + 4 of tImageData
end repeat
set the imageData of pImageID to tImageData
end greyImage
|
|
download: disableImage (1.38KB) added: 04/09/2010 description: This little plugin creates a disabled version of any selected images. Default settings are changing the translucency of the image to 33% of the original and greying it out 15% of the original. |
Now that I’ve got all my icons into the image library (see my recursive image library creation post) I wanted to limit the number of times I need to go back to an image editor to mess with the original files to create variations. One of the most common variations for button icons is the greyed out disabled icon so I wrote a little rev plugin to greyscale the selected images.
The plugin uses the following command:
on greyscale pImageID
local tImageData, tRed, tGreen, tBlue, tGrey, tOffset,tWidth,tHeight
lock screen
put the width of pImageID into tWidth
put the height of pImageID onto tHeight
put the imageData of pImageID into tImageData
repeat with tOffset = 0 to tWidth *tHeight * 4 step 4
put charToNum(char tOffset + 2 of tImageData) into tRed
put charToNum(char tOffset + 3 of tImageData) into tGreen
put charToNum(char tOffset + 4 of tImageData) into tBlue
--correction for better greyscale from Mark
--put (tRed+tGreen+tBlue) div 3 into tGrey
put (tRed*30+tGreen*59+tBlue*11) / 100 into tGrey
put NumToChar(tGrey) into char tOffset + 2 of tImageData
put NumToChar(tGrey) into char tOffset + 3 of tImageData
put NumToChar(tGrey) into char tOffset + 4 of tImageData
end repeat
set the imageData of pImageID to tImageData
end greyscale
|
|
download: greyscaleIt (1.19KB) added: 04/09/2010 description: This is a quick little plugin I wrote for converting selected images to greyscale. Handy for creating disabled icons from active ones. |
After having a play with the Image Library in Revolution I remembered seeing a cool concept in a screencast from Shao Sean where a button was added in a handy empty spot on the tools palette to pull up a menu for inserting custom objects into stacks. Here I have applied the idea to the Object Library in Revolution.
Shao Sean’s original concept is seen here
|
|
download: revTools with Object Library Button (50.69KB) added: 31/08/2010 description: A mod to the revTools stack for copying custom objects into new stacks inspired by Shao Sean. |



