Prefab is a set of widgets for the Squeak Smalltalk system built on top of the Morphic windowing system meant to provide graphical layout of windows and easy support for conventional "boring" GUI development.
Prefab is released under the same license as Squeak itself.
(The previous version was released under the MIT license but this has changed.)
This version of Prefab was tested on Squeak 2.7. It may work on some earlier versions but I know for sure that it doesn't work with Squeak 2.4.
If you're the sort who doesn't like reading lots of documentation, then frankly, you deserve what you get. But since I'm trying to get people to actually use my software in the hope of becoming an open-source IPO millionaire, I've compiled a few simple instructions to get you started. Just read these--it'll only take you a couple of minutes.
You should only need to use those methods in the API categories to modify Prefab controls.
To edit an existing dialog, enter the following:
Calculator new buildOn: (PrefabConstruction new openInWorld)
(Substitute your creation for "Calculator").
To give a PrefabManager a title bar, use #openInSystemWindow or #openInSystemWindowNamed:.
(E.g. "Calculator new openInSystemWindowNamed: 'My Calculator'.")
One of the most frustrating things I've found with Squeak is creating user interfaces. Since Squeak is purely GUI-based, it becomes necessary during the development of any application to stop what you're doing and write yet another GUI window. After the first couple, this ceases to be fun.
Morphic provides an extremely elegant and flexible framework for GUI building. It's easy to write a completely bizarre, non-traditional GUI with relatively little work compared to what it would take in, say, Win32. Unfortunately, it takes about as much effort to write a standard, traditional GUI in Morphic. There isn't much in the way of traditional widgets in Morphic, and where they do exist, they tend to require a lot of fairly complex interaction to get them working correctly. The upshot is that I have to spend a lot of time poking through the source to figure out how to use them, and since I only write GUIs when I need to, I often have to go back and relearn it for the next design.
This is a lot more work than I want to do. Prefab is my attempt to solve this problem once and for all.
Prefab widgets are designed to make it easy for a programmer to write a simple conventional GUI without much work. To do this, I basically cloned a subset of Tk for Squeak (and added graphical drag+drop-based dialog layout). What this means is that I've adopted the following guidelines:
Note that these are just guidelines, not rules. I sometimes break them, but only when there's a good reason.
A Prefab interface consists of three entities: the clients, the manager and the resizer. The clients are the individual controls that make up the UI. The manager is the window that contains and owns the controls. (This relationship maps to the Tk slave/master relationship. However, I used different terminology. Call it a Dilbert influence.) The third part, the resizer, is stored in an instance variable of the manager. Its job is to resize clients appropriately when the manager is resized.
The manager is either an instance of PrefabManager or of one of its subclasses. In the latter case (as can be seen in PrefabCalculator and the other examples), the subclassing is done to reduce the code to one class and to cause the component to appear in the "New Morph" menu.
(When I first started this project, it seemed like a good idea. Now, I'm not too sure. Subclassing breaks the interface/application separation guideline and makes it difficult to switch to another kind of manager, should somebody add one. Consider this practice semi-deprecated.)
Managers can be embedded in system windows using a special subclass of SystemWindow, PrefabManagerWrapper. You can put a manager in a frame with the #openInSystemWindow message. For example:
PrefabManager new openInSystemWindow
also works. You can set the window title with the message #title:.
A special subclass of PrefabManager--PrefabConstruction--is used to do graphical GUI building. To use it, simply create one, adjust to the appropriate dimensions and then drag and drop clients into it. Once you've got a layout you like, select the "Display Construction Source" menu item and a workspace will pop up containing the source for a method named "buildOn:". Paste this code where appropriate.
When you want to create the window, just send "buildOn:" to the appropriate object with the manager on which the clients will be placed as an argument.
This is also useful if you want to graphically edit an existing layout. Just create and open a PrefabConstruction, then call the appropriate #buildOn: on it. Once you've finished editing the layout, simply generate a new buildOn: method from it and paste it over the original.
For example, to edit the layout of the GUI for class "Foo", you'd enter:
Foo new buildOn: (PrefabConstruction new openInWorld).
Clients are those Morphs that appear in the "Prefab" submenu of the "New Morph" menu. It's pretty easy to figure out what they're supposed to do from their names and class comments, so I'll refer you to the source code and the class comments. You should only need to look a the class comments and initial comments of any API messages (i.e. messages in categories with "API-" in the name.)
(Yes, I know, saying "The source code is the documentation" is the epitome of luserdom. However, this is the standard practice with Squeak and I've commented all of the importants stuff.)
There are three classes of Resizers:
It works by letting you anchor one or more edges of a client to a parallel edge. By default, all client edges are anchored to the top and left of their manager. However, via a number of messages of the form: fix<side>Of:, you can change that.
For example, if "cl" is a client of manager "mgr", you can make it so that cl stretches as "mgr" is resized by doing this:
mgr resizer fixBottomOf: cl; fixRightOf: cl.
What this is doing is specifying that the bottom and right edges of "cl" will always stay the same distance from the manager's bottom and right edges respectively.
The EditorFrame example uses a FixedDistanceResizer. You might want to take a look at it to see what I mean.
If you wish to use a different resizer than the default, you can do it via the manager's #resizer: method:
self resizer: FixedDistanceResizer new.This must be done before any clients are put on the Manager and may not be changed after that.
(Yes, I know this violates my guidelines, so consider this a minor bug. I don't think being able to change resizers on the fly is a useful capability and leaving it out saves me some work. If you need this functionality, the source code is right there. Add it yourself and then send me a change set.)