Last updated at 1:08 am UTC on 17 January 2006
Related somewhat to Morphic Cleanup Project (MCP)
This is version 2 of a cleaner set of UI building blocks I call Bricks. The central idea is to separate appearance from the event handling and behavior. Most drawing in bricks is delegated to painters. Painters can be combined in different ways to produce different appearances. There are different configuration panels for choosing or configuring the painters. Down the road I would like to add something like scripting to make it easy to combine bricks into useful user interfaces.
Here are some of the Bricks I have so far.
Brick grew out of the ProtoMorph class I posted awhile ago. It dynamically steals code from Morph. It hasn't stolen any new code in awhile so I'm calling it sort of stable. Bricks can coexist with Morphs in a Morphic world, but you can't embed Morphs in Bricks.
Most interestion stuff is available on the meta menu.
Layout Control - Struts and Springs.
To try it out, open the meta menu on the white brick embedded in the red lego and select "Layout Options...". You'll see a struts and springs control that looks remarkably like the one in IB on Mac OS X. Clicking on a strut changes it to a spring or vice versa. The little X closes the control. Play with the settings and then resize the red lego brick using the halo. What could be simpler?
There are a couple incarnations of border pallettes, you can drag borders to bricks. If a Brick has a painter you like, select Grab Painter on the Brick's meta menu and you will get a copy to drag and drop on another brick. Note that you might have to enable drops on the brick's halo menu to get it to accept drops.
There is a ColorWell, the blue thing with the stainless steel frame, and a gradient fill control.
You'll also see a corner rounder pallette for dragging corner painters.
Once you've assembled a pleasing looking collection of bricks, you can save the assembly as a class method on a class. Try 'save as class method' on the meta menu (control click on the Mac).
I'm nearly at the point when I could use some help expanding on this. If you would like to volunteer, please send me an email. I have some widgets (text field, button, checkbox) done but there is much more to do.
What is your goal? an alternative "morphic for applications"?
The short answer is I want to quickly construct apps with GUIs and it should be like hypercard on steroids. The only code I want to add to UI is application specific behavior.
It started out that I simply couldn't (and still can't quite) grok how to predictably control layout of morphs.
So I set out to try to add a new layout manager - but I could never quite get it integrated and the entire UI kept freezing up on me. The api for layout in Morphs is sort of half modernized and very weird.
So I created ProtoMorph - an empty object that steals code from Morph to remain compatible, and I started hacking that.
Now if I screwed up the parallel object it didn't take down my image. This let me work out how to do the layout. About the same time I wanted to have a visual way of turning on and off the struts and springs - so I wrote the layout control as a brick.
Doing the layout control brick I started playing with different looks to make it cool and I ran into the very weird idea of BorderedMorph. Lots of Morphs derive from Morph, some derive from BorderedMorph and it turns on that Morph actually depends on BorderedMorph at some point. I thought this was crazy. Most morphs, it seems, are going to have a background, a border, corner rounding (which is implemented in a really odd way and doesn't seem to work with borders), there are highlights or washes that you put on things for menu items and such - I figured that you could throw most of the really pedestrian drawing out of Morph using a decorator kind of pattern. The Bricks that do drawing do only the essential drawing and no more. For instance, layout control brick draws struts and springs, but the rest of it is done by adding painters. The painter idea I got from hearing about Pollack in VW BTW.
It appears that you're able to do some very useful stuff, like automatically saving the description for composed Bricks, and struts and springs layout.
Yes. Right now with Morph assemblies you can turn one into a subclass - but I'm not sure how that helps you. The subclass, when instantiated, doesn't give you back what you had. You can dump the morph to a file - but we like to keep things in the image. I remember from working in VisualWorks years ago (version 2.5 it was) that the tools often saved resources as class methods that returned some bytestream. I found that really useful. So I tweaked the morph fileout to dump to a bytestream and save it as a string in the method. I'd still like to get a version that didn't put up the progress indicator but this is good for now.
Can you explain the tradeoffs this required? what in Morph did you have to give up for this to work?
Nothing much really. I totally hacked out Morph's layout protocol to do struts and springs. I don't miss it because I could never figure out how to get it to do what I wanted. For the couple of morphs that I converted to bricks, basically I just simplified the drawing code, and and I hacked out a lot of the drawing options (ie, the borderstyle, fillstyle, hilight flags or whatever - all that state is contained in the painters.
Could this work be applied to general morphs?
Absolutely yes in theory. But I've locked up more images than you can imagine so I'm not in a hurry to try it.
Instead, I'm using Morph as a parts bin and converting Morphs to bricks by changing their superclass and cleaning them up.
Could something be written that explores a Morphic SystemWindow and produces a similar window with most of the functionality in Bricks?
I don't see why not. I don't have a system window kind of thing yet - I still rely on Halos to resize morphs yet but I can see getting there. I've done some window trials that look and act kind of like Mac aqua windows. There's more to do but it just programming and more programming.
The biggest problem I'm dealing with is event delivery. Morphic's event delivery is too complicated for the programmer to use IMHO. You can't just implement a handler for an event - you also have to make sure that you set yourself as a handlerFor, then return true on handlesSomeEvent, then you'll get the event. Most event frameworks just deliver the event to the innermost element and the default handler redelivers the event to the owner. I'm doing some of that in Bricks and its working pretty well - but there is still a lot of weirdness in event delivery.
An example is button hit tracking. I spent 3 days on the checkbox brick's behavior. The usual behavior for a button is to hilight on mouse down, then track the mouse while its down unhilighting when the mouse leaves and rehilighting when it reenters. If the mouseUp happens in the element, then you deliver a click. Morph's event handling change makes this really hard to implement and I had to make some small changes to MouseClickState to make it work. There is more to do but you have to move gingerly because messing with Morph's event handling code can freeze your image.