Archive for the 'Extensibility' category

STProjectMaker – Sublime Text 2 Plugin for creating new projects

May 20 2012 Published by under Extensibility, General, Technology

Note: I changed the name of the plugin from “SublimeProjectMaker” to “STProjectMaker”. The github address is also different now because of that change.

I love Sublime Text 2. But one thing I’ve always felt was missing was the ability to easily create a new project. I understand the difficulties involved. Sublime handles many different languages and projects of all different types. Each type of project in each language could have a completely different setup. There is no one single project type that could possibly work for everything.

Unfortunately, that means that to create, say, a simple HTML project, you need to open Sublime, close whatever project is currently open, then do a “save project”, saving the non-project as a new project, creating a directory and also naming a project file. Then you have to add that folder to the project. Finally, you have to create the actual project files – .html, .js, .css, etc. and hook them all up to each other. I’m not even talking a complex project, you have to do all that for a simple hello world type program.

Luckily, its creators made Sublime Text 2 incredibly extendable with a plugin architecture allowing you to write your own plugins that tie into the core UI of the editor. For quite a while I’ve had the idea of creating a plugin that would simplify the creation of a project. My first stab at it can be found here. That, of course, wasn’t a plugin, but an Ant build file that copied files over to a new directory and created the project file. It worked, but required Ant to be installed, and you still had to create a directory and copy a bunch of files into it and then open a command line and run the build file. And creating a new project type would have been a major pain. Even I stopped using it after a while.

Finally, at the end of last week and over the weekend I got around to working on my plugin idea. Sublime’s extensibility layer is based on Python. I broke out my old Python books and got to work. A major challenge beyond that was the fact that large portions of the plugin API are not at all documented. Throughout the documentation you will see suggestions to look at existing plugins and commands to see what low level commands are available and how to use them. That made it quite a bit of a struggle at times, but it was a fun challenge, seeing bits and pieces of functionality come together.

And so I present STProjectMaker. It is a full fledged plugin that lives within Sublime Text 2. When you call it up, you are presented with a list of templates. You choose one and then choose a location for your project. The template is scanned for any replaceable tokens and if any are found, you are prompted to provide values for them. Finally, the folder containing your new project is opened with the system file explorer application.

Templates are merely folders of files. At the moment there is only a bare bones HTML/Canvas template, but you can create your own very easily. I’ll be creating more and it’s my hope that others will contribute some as well.

There you have it. Hoping it’s useful.

8 responses so far

Making Tools Presentation at Flash and the City

Dec 01 2011 Published by under Conferences, Extensibility, Technology

In case you didn’t get to see my Making Tools presentation this year (or if you tried to see it at RIA Unleashed and suffered through my technical difficulties), you can now see it on line:

http://techchannel.att.com/play-video.cfm/2011/12/1/Conference-TV-Flash-and-the-City-Making-Tools

You can hear the guy who corrected me by pointing out that apparently crows use tools to make tools at 4:00. 🙂

One response so far

iPhone App Launch Sequence

May 22 2009 Published by under Brevity, Extensibility, iPhone, Objective C

I was going over the stuff I’m going to cover next week in my “From Flash to iPhone” workshop at Flash on Tap, and I started getting into how an iPhone app launches when you tap its icon. It might be a bit heavy to go into detail on it at the workshop, but I thought it was pretty interesting and writing about it might shed some light for developers moving past the newbie phase.

Coming from the Flash/Flex world – app start up is pretty simple. You specify a main class. When the SWF is launched, that class is instantiated, calling its constructor. Whatever is in the constructor of that main class is what happens.

But in your typical iPhone apps, you have C files, Objective-C classes, xibs, pchs, frameworks, and plists. Which is the chicken, which is the egg, and which comes first?

First of all, realized that Objective-C is an extension of C to add object oriented capabilities. If you’ve ever taken a C course, or cracked open a book on C, you’re going to see a file like this:

[c]#include

int main(int argc, char *argv[]) {
printf(“Hello World”);
return 0;
}[/c]

When you run the program, it looks for a function called “main” and runs it. It passes in the number of command line arguments (int argc) and an array of strings that are the arguments. It executes whatever code is in that function and then exits, returning an int – usually 0 means it exited as usual, anything else means some kind of error.

Well, it turns out that Objective-C programs launch in exactly the same way. In fact, if you fire up XCode and create a Window Based Application named “Test”, you’ll see a file under “Other Sources” called “main.m”. It contains this:

[c]#import

int main(int argc, char *argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
[/c]

This is the first bit of code that gets executed when you launch an app. For the most part, you don’t want to mess with it, unless you really know what you are doing. So what does it do? Creates an autorelease memory pool and then calls a function called UIApplicationMain, passing in the command line arguments, and two other nil arguments. We’ll see what at least one of those is in a bit.

UIApplicationMain creates whatever UI you have created and starts the program loop. Which means it just loops and sits there waiting for events. Eventually at some point, the user quits the program. This ends the execution of the UIApplicationMain method, returning an int return value. The main function releases the memory pool it created and returns that return value to the system. That’s all.

So if UIApplicationMain is a standard function in UIKit, how does it know about your classes and interfaces and stuff? Well, one of the first things it does is to read your Info.plist file, which looks something like this, if you view it as xml:

[c]

CFBundleDevelopmentRegion
English
CFBundleDisplayName
${PRODUCT_NAME}
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIconFile
icon.png
CFBundleIdentifier
com.yourcompany.${PRODUCT_NAME:identifier}
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleSignature
????
CFBundleVersion
1.0
LSRequiresIPhoneOS
NSMainNibFile
MainWindow
[/c]

You’ll notice the last key/value pair theire is NSMainNibFile, which is set to MainWindow. You can also set this value in the Target info window:

target_info

You see the “Main Nib File:” entry way down at the bottom. Setting the value in this window, simply rights it into the plist file.

And what do you know, we happen to have a .xib (nib) file called MainWindow.xib in our project! Coincidence? I think not. Let’s take a look at that. Double click on it to open it in Interface Builder. The window itself is uninteresting, but the Document window shows us all the stuff that’s defined in here:

xibcontents

So main starts UIApplicationMain, which looks at the Info.plist file, sees this nib is the main nib, and loads it in. For most of the items in there that are linked to classes, it will create an instance of that class, deserialize any properties, styles, etc. you might have set on it, and then hook up any outlets or actions you might have set on it. So what do we have here?

First we have an entry called “File’s Owner” This is linked to the UIApplication class. So an instance of UIApplication is created. Yay!As clarified in the comments, UIApplication is actually created by the call to UIApplicationMain. The entry here merely links to that instance that gets created. It exists here mainly so we can set its delegate, as we will see soon.

Then we have “First Responder”. This is a bit of a special case, i.e. I don’t fully understand it. 😉 But my understanding is that this does not get instantiated per se, but is a fill in for another class that will be responding to events.

Next up we have “Test App Delegate” which is linked to the class TestAppDelegate. If you jump back into XCode, you’ll see that you do indeed have a class with that name. So this class is instantiated.

Finally, we have “Window”, which is of type UIWindow. So we get one of those.

So the result of this is we now have instances of UIApplication, TestAppDelegate, and UIWindow created. Now, if you click on the Window object and look at the Attributes tab in the Inspector, you’ll see there are various properties you can set on it, such as scale mode, alpha, background color, tag, opaque, hidden, etc. The size tab also has dimensional and layout properties that can be assigned. Any properties set here are then set on the newly created objects.

Finally, we go to the connections tab. This is where our outlets and actions are defined. If you look at UIApplication, you’ll see it has an outlet called delegate, which is set to Test App Delegate. This is the same as calling setDelegate on the UIApplication instance, and passing in the instance of TestAppDelegate. Also note that TestAppDelegate has an outlet called window which is set to the Window instance. We are not going to dive into UIApplication’s code, but if you look at TestAppDelegate.h, you’ll see it has a @property called window, which is indeed a UIWindow.

[c]#import

@interface TestAppDelegate : NSObject {
UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end[/c]

So now our UIApplication instance has a reference called delegate which points to our instance of TestAppDelegate, and that has a referenced called window which points to the UIWindow instance. We are done with the nib.

Now, UIApplication starts its event loop. When certain events occur, it passes them over to its assigned delegate to handle. The first, and most important event it delegates is “applicationDidFinishLaunching”. This means that all this plist and nib loading and deserializing and whatever else it needs to do, is done. So it calls the applicationDidFinishLaunching on its delegate.

And, look at that, our TestAppDelegate class just happens to have a method with that very same name.

[c]- (void)applicationDidFinishLaunching:(UIApplication *)application {

// Override point for customization after application launch
[window makeKeyAndVisible];
}[/c]

All this does by default is take that window that was set and make it the key, visible window.

And that’s where it ends. If you want to do more, you would add code in that applicationDidFinishLaunching method to create views, view controllers, or whatever else.

Now, if you had created a View Based application, a lot of this would be the same, but you’d also have a TextViewController nib. This would be loaded by the MainWindow nib. This new nib would contain a reference to the TestViewController class, and a UIView linked to the view outlet on that view controller. So an instance of this view controller and a UIView would be created. In applicationDidFinishLaunching, this view would be added to the window:

[c]- (void)applicationDidFinishLaunching:(UIApplication *)application {

// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}[/c]

OK, but say you don’t even want to use nibs. Can you just create a UIWindow by yourself and make it key and visible? And can you specify an app delegate without a nib? Yes and yes.

Back in our Test application, delete the MainWindow.xib file completely. Also go into Info.plist and remove the main nib file entry. Then open up main.m

Remember when we called UIApplicationMain and we passed in two nil args at the end? Now we see what those are for. They are string representations for two classes. The first one is the principle class name. If you pass in nil, this will use UIApplication as the principle class. Unless you know enough about UIApplication to recreate it or at least subclass it, you probably don’t ever want to mess with this. The last argument is the name of the delegate class you want to use. Again this is a string. So, now that we’ve gotten rid of our nib, we can tell UIApplication to use our TestAppDelegate directly:

[c]#import

int main(int argc, char *argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, @”TestAppDelegate”);
[pool release];
return retVal;
}[/c]

So now we have our UIApplication instance and our TestAppDelegate instance. But we need our window. We can create this in applicationDidFinishLaunching. It usually looks something like this:

[c]- (void)applicationDidFinishLaunching:(UIApplication *)application {
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setUserInteractionEnabled:YES];
[window setMultipleTouchEnabled:YES];
[window setBackgroundColor:[UIColor whiteColor]];
[window makeKeyAndVisible];
}[/c]

If you now wanted to add a view, you could do so something like this:

[c]UIView *view = [[UIView alloc] initWithFrame:window.frame];
[view setBackgroundColor:[UIColor redColor]];
[window addSubview:view];[/c]

Well, hopefully that explains a bit about what happens when you fire up your app. And gives you a little more control and a few more options on how to do things.

7 responses so far

ASExpander updates

Nov 03 2008 Published by under Extensibility, Flash

Having too much fun with this.

* Changes:
* 1.1 Started using actionsPanel.getText, setText. And setSelection for cursor position.
* 1.1.1 Fixed a typo in enterFrame
* 1.1.2 Not correctly finding end of file if no cursor specified. So specified cursor at end of each snippet. Added some snippets.
* 1.1.3 Added help function. Type &help and run command and it traces out a list of commands.

http://www.bit-101.com/extensions/ASExpander.jsfl

Background in case you’re seeing this for the first time:

http://www.bit-101.com/blog/?p=1620
http://www.bit-101.com/blog/?p=1627

14 responses so far

ASExpander 1.1

Nov 02 2008 Published by under Extensibility, Flash

In the comments of my last post, James Thompson kindly pointed out that fl.actionsPanel has getText() and setText() methods, not to mention setSelection(). Thanks James! With this, I was able to get cursor positioning in there. Just put “&cursor” anywhere in the snippet, and with any luck, that’s where the cursor will go after the text replacement is done.

Got pretty messy doing that. The string in JSFL and the string in the editor return different values for getIndexOf() – seems to vary on newline characters. So I had to assign the text with the cursor info, get the index, replace the cursor info with nothing, and reassign the text. Also it wouldn’t find the &cursor string if it was followed by a newline either, so I’m just searching for &curso, which is pretty hacky but works.

Also slapped an MIT license in there and made it available for download.

http://www.bit-101.com/extensions/ASExpander.jsfl

Again, put it in your commands folder in Flash CS3 / CS4:

Mac: /[user]/Library/Application Support/Adobe/Flash CS3/en/Configuration/Commands
Windows: \Documents and Settings\username\Local Settings\Application Data\Adobe\Flash CS3\language\Configuration\

And assign a shortcut key to that command.

Also, check it out, we have video of it already!

http://www.video-flash.de/index/asexpander-code-snippets-in-flash/

23 responses so far

ASExpander : making AS3 in CS3/4 easier

Nov 02 2008 Published by under Extensibility, Flash

[Note: I just released version 1.1 of ASExpander. http://www.bit-101.com/blog/?p=1627 . This post is still worth reading for background and usage, but check out the other one for the latest version.]

There’s been a lot of talk about AS3 being “hard“. A lot of it stems around the fact that its is more verbose than AS1 or AS2. It just takes a lot more typing to do things that were really simple in earlier versions of Actionscript.

I’ve been using Flash CS4 a LOT lately, for spiking ideas, doing quick visual experiments, etc. In fact, the vast majority of stuff on my other site, Art from Code, is created directly in Flash CS4 right on the timeline.

So of course, I find myself typing a whole lot of the same few lines of code over and over (and over). The obvious solution was to use a snippets panel. Lee Brimelow has a nice one. http://theflashblog.com/?p=336

But that didn’t quite fit my workflow – making sure the panel is open, grabbing the mouse, clicking the item you want in the list, clicking the copy to clipboard button, clicking back in your code in the right place, and pasting.

One of the comments there mentioned that functionality like in Text Expander would be nice. I thought about it for a minute and realized that wouldn’t be too hard to do. And so I bring you ASExpander.

ASExpander is a simple JSFL command script. Save the following in your commands directory as ASExpander.jsfl:

[as]map = new Object();
map[“&meta”] = “[SWF(width=800, height=800, backgroundColor=0xffffff, frameRate=31)]”;
map[“&stage”] = “stage.align = StageAlign.TOP_LEFT;\nstage.scaleMode = StageScaleMode.NO_SCALE;”;
map[“&resize”] = “stage.addEventListener(Event.RESIZE, stageResizeHandler);\nfunction stageResizeHandler(event:Event)\n{\n\ttrace(\”stage resize\”);\n}”;
map[“&bitmap”] = “var bmpd:BitmapData = new BitmapData(800, 800, false, 0xffffff);\nvar bmp:Bitmap = addChild(new Bitmap(bmpd)) as Bitmap;”;
map[“&enterFrame”] = “addEventListener(Event.ENTER_FRAME, enterFrameHandler);\nfunction enterFrameHandler(event:Event):void\n\t\n}”;
map[“&mouseDown”] = “stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);\nfunction mouseDownHandler(event:MouseEvent):void\n{\n\ttrace(\”on mouse down\”);\n}”;
map[“&mouseUp”] = “stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);\nfunction mouseUpHandler(event:MouseEvent):void\n{\n\ttrace(\”on mouse up\”);\n}”;
map[“&mouseMove”] = “stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);\nfunction mouseMoveHandler(event:MouseEvent):void\n{\n\ttrace(\”on mouse move\”);\n}”;
map[“&keyDown”] = “stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);\nfunction keyDownHandler(event:KeyboardEvent):void\n{\n\ttrace(\”on key down\”);\n}”;
map[“&keyUp”] = “stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);\nfunction keyUpHandler(event:KeyboardEvent):void\n{\n\ttrace(\”on key up\”);\n}”;
map[“&loop”] = “for(var i:int = 0; i < 10; i++)\n{\n\ttrace(i);\n}"; map["&2loop"] = "for(var i:int = 0; i < 10; i++)\n{\n\tfor(var j:int = 0; j < 10; j++)\n\t{\n\t\ttrace(i, j);\n\t}\n}"; _doc = fl.getDocumentDOM() _tl = _doc.timelines[_doc.currentTimeline]; _layer = _tl.layers[_tl.currentLayer]; _frame = _layer.frames[_tl.currentFrame]; script = _frame.actionScript; for(key in map) { script = script.split(key).join(map[key]); } _frame.actionScript = script;[/as] Then, I HIGHLY recommend assigning a shortcut key to this command. I assigned Command-E, which overrides "Edit Symbol", which I never use anyway. Now I can just type: &enterFrame hit Cmd-E, and I have an enter frame listener set up. Notice that my hands never left the keyboard! It's easy to add your own snippets. Just give it a token and text: [as]map["token"] = "text to replace token with;";[/as] If you're not a coder, get one to write some useful snippets for you and put them in string format. They'll know what to do. I've gone with an ampersand (&) prefix just to avoid possible conflicts with other code in the script. You might have a "enterFrame" in your code that means something, but probably not a "&enterFrame". But that's not built into the command at all. If you don't like the ampersands, change them to %s or *s or !s or just use straight text if you are brave. Anyway, hopefully this makes AS3 a tiny bit less painful for a couple of people. Let me know if it helps.

21 responses so far

CS4 MetaData JSFL Script

Oct 27 2008 Published by under Extensibility, Flash

It’s been a while since I’ve done much with JSFL, but I’ve been playing with CS4 a lot more than I did with CS3. One thing I love is the ability to set SWF MetaData right on the timeline. I find myself typing in a line of metadata when it would probably be easier to go to the Properties Panel and set the SWF size there. But I’m usually in the Actions Panel with my hands on the keyboard and it just comes quickly.

But I realized I could make it even quicker and wrote the following very simple JSFL script:

[as]_doc = fl.getDocumentDOM();
_tl = _doc.timelines[0];
_layer = _tl.layers[0];
_frame = _layer.frames[0];
headerText =  “[SWF(width=800, height=800, backgroundColor=0xffffff, frameRate=24)]\n”
headerText += “stage.align = StageAlign.TOP_LEFT;\nstage.scaleMode = StageScaleMode.NO_SCALE;\n\n”;

_frame.actionScript = headerText + _frame.actionScript;[/as]

This also sets some common stage properties. Just throw that in your Commands directory in Flash CS4’s Configuration directory. I set up a keyboard shortcut for it: Cmd-Opt-M (for MetaData). Now, with a quick keystroke, my movie is set up the way I want it.

I’m using a very inflexible method of finding the current frame: current document, scene 0, layer 0, frame 0, because that’s where my code always is. You can certainly mess with that to make it more robust if you need it. I started making a SWF Panel that would let you set the dimensions, frame rate and background color with some controls, and then a button to add the code to the frame, then I realized that was pretty stupid, because if you are going to go through the trouble of doing settings and pushing buttons, you might as well just use the Properties Panel. 🙂

Comments are off for this post

flashextensibility.com relaunches!

Jul 04 2006 Published by under Extensibility

A couple of years back (wow, was it so long ago already?) while I was writing the book Extending Flash MX 2004 with Todd Yard, I registered the domain name, flashextensibility.com. I had a site up there for a while with info about the book, a forum, and a repository of extensions, not only from the book, but submitted by others as well.

As time went on though, I drifted away from the extensibility scene and the site got kind of stale. A few months back I decided to give it up and let someone else have it. Peter Elst stepped forward. He was the technical editor for the book, and knows the subject well, so I was really happy to hand it over to him.
After a short break, the site is now back on line with some nice extensions up. I plan to add a bunch myself. If you use the Flash IDE at all, you’re definitely going to find some good stuff that will speed up your workflow. Do yourself a favor and check it out:

http://www.flashextensibility.com/

2 responses so far

And the FlashExtensibility.com winner is…

Jan 28 2006 Published by under Extensibility

Peter Elst!

Peter contacted me after yesterday’s post and I transferred the domain over to him. I’m thrilled that he was the one to get it. He was the technical reviewer for Extending Flash MX 2004, and has a great knowlege of and interest in the extensibility layer of Flash. I’m sure tht he will do cool things with the site, hopefully even fullfilling the original vision I had for it.
www.flashextensibility.com

Comments are off for this post

Into JSFL? Want www.flashextensibility.com ?

Jan 27 2006 Published by under Extensibility

So a couple of years ago, Todd Yard and myself wrote the book Extending Flash MX 2004. It’s a good book on the subject. Really the only book on the subject (other than a Macromedia Press one that is just a print out of the JSFL help files).

Just before the book was published, I registered the domain www.flashextensibility.com . The idea was to put up a library of cool extensions, a forum for answering questions, and so forth. Well, life went on and I drifted away from JSFL except when I really needed it for something, and the site has pretty much died. I recently found out that the forum had been hacked, so I took that down. (damn PHPBB!)

So rather than continuing to pay monthly for a site that I, myself, haven’t visited in probably half a year or more, I’m letting it go. If anyone wants the domain, get in touch and we’ll work out transferring it to you. I’m not even trying to sell it. You can have it. I’d just like to see it go to directly someone who wants it rather than get it snatched up by someone who will try to make a profit off of selling it to someone else.

5 responses so far

Older posts »