'EngiViewBuilder' is what is called an "interface builder." This class requires ObjectWorks 4.1 or VisualWorks 1.0 because it uses 'TextView' and 'ComposedTextView' (rather than the older 'CodeView' and 'StringHolderView').
VisualWorks has a feature called the "chameleon function" which lets you emulate the look and feel of several User Interface Standars on your native window system. ObjectWorks does not have this function. If you run VisualWorks, please evaluate the following message expressions to change the look an feel of the interface.
For Motif look and feel. MotifLookPolicy installLookPreferences For Mac. MacLookPolicy installLookPreferences For Windows. Win3LookPolicy installLookPreferences For OS2. CUALookPolicy installLookPreferences For Smalltalk original. DefaultLookPolicy installLookPreferences
Furthermore VisualWorks has an interface builder, so 'EngiViewBuilder' is not necessary for VisualWorks users. However it will be worth your time to study this class to see how interface builders are constructed.
Let's take a look at Appendix 12. The inheritance tree for 'EngiViewBuilderModel ' is:
---------------------------------------------------------------------- Object() . . Model('dependents') . . . . EngiViewBuilderModel('views') ----------------------------------------------------------------------
There are only two instance variables, one is 'dependents' which stores dependent objects and the other is 'views' which stores the type and area of views which access this model. A set of 'Association' of the following types are stored in 'views'.
------------------------------------------------------ aRectangle -> #boolView aRectangle -> #listView aRectangle -> #textView ------------------------------------------------------
'aRectangle' tracks the location and size of an instance of 'LabeledBooleanView,' 'SelectionInListView,' or 'TextView' in an instance of 'CompositePart'.
'EngiViewBuilderView' is a subclass of 'CompositeView' so it can participate in MVC relationships.
---------------------------------------------------------------------- Object() . . VisualComponent() . . . . VisualPart('container') . . . . . . CompositePart('components' 'preferredBounds') . . . . . . . . DependentComposite('model') . . . . . . . . . . CompositeView('controller') . . . . . . . . . . . . EngiViewBuilderView('wrappers' 'menuSelector') ----------------------------------------------------------------------
The inheritance of 'EngiViewBuilderController' is as follows and needs no explanation.
---------------------------------------------------------------------- Object() . . Controller('model' 'view' 'sensor') . . . . ControllerWithMenu('menuHolder' 'performer') . . . . . . EngiViewBuilderController() ----------------------------------------------------------------------
Please 'file in' Appendix 12, then evaluate Program 23-1.
Program-23-01: (EngiViewBuilderModel, ValueHolder, ComposedTextView; addBoolViewIn:, addListViewIn:, addTextViewIn:) ---------------------------------------------------------------------- | viewBuilder | viewBuilder := EngiViewBuilderModel new. viewBuilder addBoolViewIn: (0.0 @ 0.0 corner: 0.4 @ 0.1). viewBuilder addListViewIn: (0.0 @ 0.1 corner: 0.4 @ 1.0). viewBuilder addTextViewIn: (0.4 @ 0.0 corner: 1.0 @ 1.0). ComposedTextView open: (ValueHolder with: viewBuilder sourceCode). ---------------------------------------------------------------------
Program 23-1 instantiates an EngiViewBuilderModel, adds a few views to it and then displays its source code in a window. The source code you see is shown in Program 23-2:
Program-23-02: (EngiViewBuilderModel, BorderedWrapper, LabeledBooleanView, PluggableAdaptor, CompositePart, LookPreferences, SelectionInListView, TextView; beToggle, beTriggerOnUp, on:aspect:change:list:menu:initialSelection:, on:aspect:change:menu:initialSelection:) ---------------------------------------------------------------------- | aModel topWindow topView | aModel := EngiViewBuilderModel new. topWindow := ScheduledWindow model: aModel label: '' minimumSize: 300@200. topView := CompositePart new. topWindow component: topView. topView addWrapper: (BorderedWrapper on: [| baseModel valueModel boolView | baseModel := (PluggableAdaptor on: aModel) getSelector: #bool putSelector: #bool:. valueModel := (PluggableAdaptor on: baseModel) selectValue: false. boolView := LabeledBooleanView model: valueModel. boolView label: ''. boolView beToggle. boolView controller beTriggerOnUp. boolView] value in: (0.0@0.0 corner: 0.4@0.1)). topView add: (LookPreferences edgeDecorator on: (SelectionInListView on: aModel aspect: #item change: #item: list: #list menu: #listMenu initialSelection: #item)) in: (0.0@0.1 corner: 0.4@1.0). topView add: (LookPreferences edgeDecorator on: (TextView on: aModel aspect: #text change: #acceptText:from: menu: #textMenu initialSelection: nil)) in: (0.4@0.0 corner: 1.0@1.0). topWindow open ----------------------------------------------------------------------
Let me explain step by step what is happening. First of all evaluate Program 23-3 and you will see a blank window.
Program-23-03: (EngiViewBuilderModel; on:menu:) --------------------------------------------------------------------- | viewBuilder topWindow subView | viewBuilder := EngiViewBuilderModel new. topWindow := ScheduledWindow model: viewBuilder label: 'View Builder' minimumSize: 300 @ 200. subView := EngiViewBuilderView on: viewBuilder menu: #menu. topWindow component: subView. topWindow open ---------------------------------------------------------------------
Now press the yellow button, and you should see a menu of 'source code', 'text view', 'list view', 'bool view', and 'remove view'. The blank window is the canvas upon which we will paint a user interface. Select 'text view' from the menu. A rectangle appears and moves with the mouse. To place it on the canvas, click once and then hold down the mouse to arrange the size of the view. 'list view' and 'bool view' behave similarly. Select 'source code' and you will see a window showing the source code necessary to programmatically generate the user interface you have just painted. To ckeck it out, just evaluate the window. Now use 'remove view' is to delete one of the views on the canvas and then do 'source code' to see that the source code is now differenct.
------------------------------------------------------------ | viewBuilder | viewBuilder := EngiViewBuilderModel new. ------------------------------------------------------------
The viewBuilder created by the above expression supports adding three kinds of views:
--------------------------------------------------------------------- viewBuilder addBoolViewIn: decide a rectangular area interactively. viewBuilder addListViewIn: decide a rectangular area interactively. viewBuilder addTextViewIn: decide a rectangular area interactively. ----------------------------------------------------------------------
Then finally it generates the source code.
---------------------------------------------------------------------- ComposedTextView open: (ValueHolder with: viewBuilder sourceCode). ----------------------------------------------------------------------
User interface construction tools on the market or public domain today do not really do much more than this.