On the importance of user focussed UI

Dual desktop metaphors on Win tablets can lead to user confusion. I’ve also been a long time opponent of features or tools that can only be discovered by rolling over an invisible area or other element that does not appear to be a widget.

http://www.useit.com/alertbox/windows-8.html

As seen on daringfireball.com

Applescript: The Marines & Chief Interrogator In 1

Applescript: Much maligned, much beloved. The language itself is considered to be based on SmallTalk or List (? I need to verify that). It’s got it’s nice features in that it seems English like and more readable than almost all other programming languages, even the other scripting ones. But that’s secondary to what it does. I would compare Applescript to the US Marines: It Gets The Job Done. If you need automation (on a Mac), Applescript can do nearly everything. And what it can’t do directly, you can even fudge it to “fake” clicking the menus and buttons of non-scriptable applications.

Chief Interrogator: Here’s where Applescript is sneaky and also makes it one of the most interesting languages. In order to have an application be scriptable, the application designers have to go to significant lengths to expose their underlying framework to Applescript commands. Specifically, they must write getters and setters for their variables in ways that Applescript can use them, and also that won’t interfere with the internal workings of their methods and circumvent other cascading actions that happen when a variable is changed.

“So what” you may say. So what is this: learning how to Applescript any application is akin to looking into it’s inner workings. No 2 applications will do things the same way. InDesign will not use the same method to add a new page to a document the way QuarkXPress does nor the same way Apple Pages or MS-Word will. No 2 FTP application will upload files using the same syntax nor the same methods. I know for a fact that Interarchy will let me simply “send” and FTP command and it will send a file directly from the application, while CyberDuck (I believe) requires that you first have an active window, and tell the window to send a file. There you can see a huge difference in the internals of the design of each application. Interarchy might always show you a window, but it’s sending of a file is not dependent on instantiating a window first. While CyberDuck clearly, internally, must first instantiate a window object, and the file transfer commands must be housed inside of either the window class, or called from the window class.

So, when I am working with an application, I must always consider that I am not just “telling” the application to do something that any application of it’s category would do. No, I have access to the application, and I must sometimes consider that how one developer would word their commands is not the same as another. And it might take great creativity to find out, from usually non-existant documentation, how to properly “talk to” an application to say the magic sequence of commands it will accept.

Applescript isn’t a once-and-done learning experience. It’s learning every OTHER application at the same time too. And then learning updated applications’ new ways to do old functions, or new methods for new features.

Adding Applescript to a Cocoa (Mac OSX) App

How to add some Applescript to your application. This is by no means a comprehensive tutorial, but only a guide I built first for myself and wanted to keep it handy for myself and share it with others. There’s not a lot of information on this topic on the web.

It’s super complex so make sure you do it exactly right. It might take a few test apps to understand it well.

Classes:

You can use a category of your Cocoa object’s base class, because that is simple to handle. Then you can tell your object to “do something” and the implementation of the script can be wildly different than the standard internal methods. But remember there can be no new ivars in the category! This means if you need to get values from the main class then you will need to have a lot of getters/setters in the main class.

@interface MYObjectClass (MYObjectCategoryName)

//method declarations…

-(id)doThisThing:(NSScriptCommand*)command;

 

First example is how to make a method do something.

The method must take a NSScriptCommand value. Don’t put any other parameters here, the NSSC will pass in a bunch of variables, as many as you want, as an NSDictionary.

In your method, do something like this:

-(void)pavsFunc:(NSScriptCommand *)command
{
NSDictionary* theArgs = [command evaluatedArguments];
NSString *inputText = [theArgs objectForKey:@"theText"];
NSLog(@”passed text = %@”, inputText);
}

1. The arguments (theArgs) is the standard way to get all the passed in arguments. Your Applescript could look like

tell myObject
doThisThing first name “Dick” last name “Jones”
end

2. In the method then you have to get each part of the parameters into an ObjC variable. They pass in as one Dictionary. So you need to call out each key from the dictionary. There will be a line for each variable you passed in. Such as:

NSString *theFirstName = [theArgs objectForKey:@"firstName"];
NSString *theLastName = [theArgs objectForKey:@"lastName"];

You can see that the KEY name does NOT have to match any particular variable name in your code. You can pass about variable names as you normally would in ObjC. But you will need to match up the key name in the SDEF file later.

3. The SDEF file is the Rube Goldberg-esque construct that will link Applescript to Cocoa. Use SDEF Editor if possible, but it’s also handy to edit the XML directly. Add a Suite for your application, and give it a code. Adding the Suite is pretty basic. There’s no direct link from the suite to any particular class files.

For simple applications, you would add just one suite for all your commands, like “MyApp Suite”. Extremely complex applications (think InDesign, Photoshop, MS Entourage) can have multiple suites, because each one does something different. For example, InDesign has a suite just for Layout (the primary way to manipulate page elements), and also one for Color (to create and edit swatches, colors, gradients etc), and about 18 others.

Now there are several conceptual levels in the SDEF. The CLASSES will let you designate one of your ObjC class files as something scriptable. You can give it a name that is different from the actual Cocoa class name in your code/project. So you can have “rectangle” as the script object but the class it works on is “CPRectangle”.

4. Add a command to the class object. Give it a name. This name will be the same as the name used for Suite > Commands. It must be the same in order to link up. Set the Cocoa Method to what method this actually runs, like: -(void)pavsFunc:(NSScriptCommand *)command. See image below.

So far we’ve simply added information to the SDEF that says “class rectangle responds to a command “rotate” and it calls the actual Cocoa method “pavsFunc:”

5. Now we have told the class what command it can understand, we have to add a part that tells Applescript what commands are available. Under the Suite > Commands folder, add a new command. Give it THE SAME NAME as your command for the class. Give it an interesting code, and some descriptive text so you know what it does. I think there’s a limit to the amount of text that can be displayed. Since we are working on a 1 to 1 relationship with this command, don’t add anything for Cocoa name or class here. (Cocoa Name and Cocoa Class are used for verb-first scripting; what we are making here is object first scripting.)

6. A direct parameter *must* be added in order for the command to be used by a class. So for example, the command “invert selection 1″ has the direct parameter of “selection 1″, the command is “invert”. It must be the class for the command or superclass.

 

7. Parameters are the other values passed to the command. The name is what you’ll call it in the actual Applescript. The code should not conflict with other codes nor Apple’s. The type is what kind of data this is, and may include objects of the same or other classes, not only text or numbers. Description is obviously for humans to read and for your documentation. Cocoa Key (see image below) is the value that will be used to make the dictionary of data that the Cocoa method must pull out from the Argument, like this: NSString *theFirstName = [theArgs objectForKey:@"firstName"]; (and in the Name part call it “first name”, ie: doThisThing first name “Dick”)

You can add any number of parameters and some can be optional. Be sure to handle optional parameters properly in the Cocoa code.

It’s not easy to have a command without a direct parameter– that requires whole new classes (look up verb-first in the Neuberg book). Really every command is handled inside of some “tell something…” block. The TYPE of the direct parameter is the name of the class in SDEF editor. Your class “CPRectangle” may be named “rectangle” in SDEF, so pick that from the popup list.

The commands should be good now.

 

The flow of command logic is something like this, in a very abstract and non-technical way:

 

1. An Applescript command is given by a script or editor.

2. The script calls a certain function/command you defined, along with any of its indirect parameters.

3. The command name then matches itself to the class command by name, and then the parameters dictionary is passed into the Cocoa method of the class object.

4. Then the Cocoa method is called and fired. If a dictionary was passed in, then the Cocoa method has to extract each dictionary item by NAME (ie Key) only, and then can do something with it, like setting a variable to the key value it scanned.

5. Potentially the Cocoa method returns something and that gets passed back to Applescript. That’s outside of my current tutorial at this point.

Desktop Blurrifier is out and munching on wallpapers

My 2nd big app “for everybody” is available to the Mac using public now. I’ve wanted to make this little app for YEARS now. There was a guy who made a spiffy app to do “multiple image wallpapers”. But I don’t think he ever kept up with it. I have a beta version of that, but I couldn’t convince him to add blurring or that would have been nifty.

So my app does exactly what I want, and come to think of it, can also handle making a desktop drawn across multiple screens from 1 image.

Desktop Blurrifier makes any image a little blurry. It scales up, or down too, and can reposition horizontally or vertically. One really cool thing is that I made the scale slider do a non-linear scale. So 1/2 of the slider scales from 0.1 to 1.0; the other half scales up as a square of the value, from 1.0 to 4.0. It also “snaps” to the middle tick slider with a bit of code. My biggest hurdle on this app was learning how to deal with CIImage class. The examples Apple supplies, the Core Image Fun House app, is fantastic in its own right; but MF! it is so efficient and dense I could not figure out for the life of me how any of it works. Really the point of sample code is to usually show an example of 1 or 2 or maybe 3 concepts. Well this one has every CIImage filter included, plus procedural UI elements! There was another sample I looked at, ImageExample I think, and that was easier to understand but had some color management code completely woven into it that I couldn’t just cut and paste code. Which is generally all the better in the end, but of course frustrating when it doesn’t make sense. I did end up with a reasonably elegant solution for my filter objects, with cues taken from that sample code. Performance was always good on my coding machine, but my wife’s older laptop showed some noticeable lag. Well, it’s not supposed to be Photoshop so I wasn’t going to try to change it much.

I also had fun putting some drag and drop code in, which includes a big fat red stroke when a new image is dropped. One frustrating correction I had to make at the very end was dealing with multiple Space in 10.7 Lion. Lion’s spaces EACH can have different desktops AND can also have changing images as well. The changing image option was a real pain to deal with, as I never used it and it didn’t occur to me until my beta test group (thanks MacDeveloper.net) brought it up to me. I had to sort of hack in a check where if an image failed to load in 2 different ways, then I’d assume the Change Image option was on and then had to dump out to an error dialog. When the change image option is on, the current desktop isn’t actually returned as a picture, it’s returned as a FOLDER URL. And there is no option to know specifically that the option is on, you just have to see if it’s a folder or image URL. Using the set desktop method though, will simply turn this option off. So after I warn users, they can still set a picture, and BAM it’s on. But their rotating image won’t continue to rotate, that would have to be turned back on. Oh well, maybe a preference for another version eh?

One for everyone

I’ve been working on an app that every Mac user can use, not only the graphics/Prepress crowd. It’s something that I honestly wanted to make/have for myself for a long time and I finally got around to starting it. It’ll be here online in a few weeks I’m estimating, also on the App Store, but that always takes more time to massage and dumb down for Apple’s app requirements.

New App in the works

I’ve been kicking around the idea for another app and I’ve started some work on it. It involves images, but no InDesign nor Applescript. My first rev is working OK, but is far from “high performance”. I’ve got to learn some new Cocoa skills to make it work as smoothly as I’d like (and you’d expect). There’s no due date, but like usual it’s an app “I want for myself” and then build it out to be something really polished.

One of the teachers at the Big Nerd Ranch had said that the greatest gift to programming was the internet. Truly without the help of other experienced programmers and sample code, I’d never get nearly as far as I do with applications.

Font Catalog on App Store

ID Font Catalog is now available on the App Store! I had tried to submit it “as-is” but then some technical glitches showed up. I ended up rewriting the entire app in ASOC in about 2 weeks. Fastest turn around ever on that. Thankfully the core logic didn’t need any changes. I was pleasantly surprised when I could add in saving of a big array of preference items with just 3 lines of code! ASOC is pretty nice!
http://itunes.apple.com/us/app/id-font-catalog/id464149293?mt=12

XCode 3 frustration

I’m trying to build one of my older apps, ID Font Catalog, for the App Store, using XCode 3. So my signing certificate was being rejected, and XCode would not build and archive, it was greyed out. The solution, which I would not have guessed readily, was that I needed to download a package from Apple to enhance my XCode install. Look for “Application Tools” v1.1 and install that. Then my signing worked and I could build.

App Store Arrival

ID Image Catalog is now available via the App Store! It seemed like forever to get through the approval process. But thankfully there were no coding issues, only some store submission and naming issues. This is one of the few Applescript/ASOC applications on the store. I had to get it in before the Nov 1 deadline for sandboxing, since that means after that date any apps that freely “talk” to other applications on your computer will be off limits. Seriously, this outlaws any and all ASOC apps that drive other applications even though Applescript is supposed to be a first class programming citizen on the Mac. Sandboxing also outlaws Find applications that search your hard drive for file types. Not to get technical but there are certain permissions that apps must only allow in the future. I find it commendable Apple is pre-empting practically any possibility of serious viruses on OSX. But that restriction does hamper some app concepts.

Next up I am going to get to work putting ID Font Catalog on the store. That may require more work as I want it to be 10.5 compatible and not rewrite the whole thing just yet. I need to just find out how to sign the app in XCode 3.

PDF Bee 4.0 is out

After way too long a period of time with no updates, I’ve finished with the complete rewrite of PDF Bee. Version 4 includes a host of new features. All this was precipitated by moving from “plain old” Applescript to Applescript-ObjectiveC in Snow Leopard. This change took me a while to realize, since in ASOC there are a lot more things that can be accomplished, but it requires essentially starting from scratch. I reused only about 10% of my code.

I must say I think this is the cleanest and most robust implementation in ASOC I’ve done so far. I hope that the users find it a worthwhile upgrade and it keeps their workflows humming without issue. Full paid version is only $5 more than before at $95, and upgrades for previous users are $50. Email me if you didn’t get my email with the special upgrade link.