One thing you do get with lists and buttons is a tried-and-true definition of the protocol for their use. All of these objects are windows of some kind, and may have child windows themselves. Windows provide you with a pre-built set of functionality to deal with opening, re-sizing, invalidation-based redisplay, and many other features you only become aware of when you deviate from the norm.We set any Smalltalk code and method selectors in a monospace font, likeThis, so you can differentiate them from more normal text.Warning: Are you looking at this in a Help file? If so, you won’t be able to see the visual clues we supply in the margin of the printed manual. Sorry, but it is a limitation of the software we use to produce Help files. You should be able to tell from the text where we’re talking about platform-specific stuff.You will use an event model to “hook into” things that happen to GO’s. For example, when you want to know when someone double-clicks on a GO, you will simply tell the GO to let you (or any other object) know by sending a message. You need only look at the list of events that are triggered by various GO’s to be up and running (see the “Summary of Events” section). If you feel you need a quick refresher, read on, because unless you understand events, everything in GF/ST may look like it is happening by magic.In its broadest sense, GF/ST provides a framework for coordinating domain model objects, graphic objects, and user interactions. This is a familiar problem, and a generic solution for it has existed in Smalltalk for a long time in the form of Model-View-Controller programming, or MVC. MVC provides a way to couple objects loosely (i.e., loose coupling) via a dependency mechanism. These are two object-oriented buzzwords that you should know and understand regardless of what Smalltalk you use. For a more generic description of the problem and solution, you might want to check out the “Observer” pattern in Gamma et al’s book. The classic treatise on MVC is Krasner and Pope’s paper “A Cookbook for Using the Model-View-Controller Paradigm in Smalltalk-80.” The details are well beyond the scope of this manual, but it is extremely useful to understand the concepts, as they are closely related to the GF/ST event model. The general idea is this:You are an object that models some part of the problem domain (i.e., a domain model), and I am an object that depends on your state somehow. For example, I am a visual representation of your state (e.g., a view or a GO). It is a bad idea from the standpoint of reusability for you to know how I am displaying you, or even that I exist at all. On the other hand, it’s okay for me to know about you by holding onto you as one of my instance variables. We solve this problem using MVC. I tell you to add me as a dependent. You, as a good Smalltalk citizen, announce whenever your state changes in any interesting way. Through the MVC dependency mechanism, I will receive a message to update myself.You may not be aware of it, but MVC is implemented in all Smalltalk versions. Events work in much the same way -- “Hey, the mouse moved!”, “Someone resized me!”, and so on. The difference is that by using events, we can be much more specific about what has changed, what object should be notified, as well as the message and arguments that should be sent when an event occurs.There are two sides to using events: registering events as a public interface for a class, and hooking into them so you can be notified when an event occurs. When we create a class, instances of which will be triggering events, we publish a list of events that these instances will trigger in a class method called eventsTriggered. This list lets the outside world know what kind of events our object will be triggering as it changes state (e.g., #getMenu, #button1DoubleClick, and so on).When someone wants to be notified that your object triggered some event, they send it the message when:send:to: with the event name (a symbol) as the first argument, a selector (symbol) as the second argument, and the receiver object for the selector as the third argument. If the selector requires arguments, they use when:send:to:with: and include an array of arguments for the selector.Instead of using the MVC-style changed message to notify dependents that they have changed, subclasses of PsiEventModel trigger events that describe the kind of change that has occurred, using one of the following expressions:By sending the message when:send:to: or one of its variations to aModel, you are setting up the dependency relationship, just as any MVC programmer accomplishes using addDependent:.
1. Read and understand the “Introducing GF/ST“ section. Hey, if you’re reading this, you must be on the right track. In particular, be sure you are familiar with “Basic Concepts and Classes“.
3. Unless you have questions about how to use some of the examples, move directly to “GF/ST Application Design & Decisionmaking“. It uses a very simple Network Editor as a learning tool to show you how all the concepts hook together. The first three or four sections should give you a good overview.Use the “How To’s” section as a reference when you don’t know where to look, when you’re looking for advice, or when you can’t find working code in the examples or the Network Editor that solves your problem. We provide the “Class Hierarchy, Protocol and Events“ section for completeness - hopefully, you’ll be using the Smalltalk browsers for most of this material. One very useful thing you’ll find summarized in that section is the events that GF/ST objects trigger as you use them. Put off reading these sections until you need specific help.Use the Visual Inspector™ to help understand how things hook together. See Appendix A – The Visual Inspector for information about how to use the tool.If you find yourself moving very far beyond the “how to’s” that we provide, you will need to start exploring the framework classes in more detail. You need to understand the why behind GF/ST before you start making significant changes to the how. The Visual Inspector is a key tool that lets you explore the interconnections between framework components.When you look through GF/ST classes, you can consult the class method called COMMENT for a description of each class and what it is used for. When we say “see the comments in” some class, we mean “look in the class COMMENT method”. In ENVY versions of GF/ST, you should look in the class comments using your favorite ENVY browser.GF/ST is a framework, not a tool. The Visual Inspector is a tool we provide with GF/ST that was built using the framework. You do not need to understand anything about GF/ST to use the Visual Inspector. If you want to build an application like the Visual Inspector, you must understand how to use the GF/ST framework.Frameworks are meant to be extended. A good framework will minimize the amount of changes and extensions you need to make to use it in the context of your particular problem. However, don’t hesitate to add subclasses and methods within the GF/ST class hierarchy. If you need a particular capability, add it in. That’s what a framework is for. If you find you cannot implement the feature, or you had to perform massive surgery on classes and behavior we supplied, we need to know so that we can determine whether the basic GF/ST framework should be modified or extended.For example, if you are working on an interface builder application, you may want to give your users the ability to position host components (like buttons) on the screen. The Drawing Editor demo shows some examples. We do not plan to support any more host components than the ones we use in the Drawing Editor. If you need more, implement them. For us, the only important issue with respect to host components is that we not make assumptions in the framework that would prevent people from writing applications that use them. By implementing a few host components, we’ve proved to ourselves that there is no problem, and we’ve provided a simple road map showing how you can do it.
•
• You will also find that GFGraphicObject is a subclass of PsiEventModel. GF/ST uses an event model for the basis of communication and updating, and PsiEventModel class helps unify these concepts. We’ve already discussed the fundamentals of the event model (see “What You Absolutely Must Know to Use GF/ST“), but we thought you’d like to know up front here that many GF/ST classes reside under PsiEventModel, a subclass of Object.If there is a central class in an object-oriented framework like GF/ST, GFGraphicObject would be it. Often, we’ll use the shorthand “GO“ to refer to anything that is a kind of GFGraphicObject. You may also catch us calling a GO a figure for historical reasons - old habits are hard to break.You will especially want to be sure to use damageDuring: whenever you move or change the bounds of GO’s. Think of damageDuring: as being the tool that you have to say “evaluate this code, keep track of damage to GO’s, and update the display when you’re done.”Graphic objects have a rich protocol for manipulating and accessing information about them. Learning the common protocol and the events built into GF/ST will be one of your first steps. The discussion in “Designing a New Application“ is the best place to start. Use the “Class Hierarchy, Protocol and Events“ section as a reference when you need it.A GFDrawing contains all GO’s that are displayed and manipulated. GFDrawing is itself a subclass of GFGraphicObject, in the great tradition of roots being a specialization of the internal nodes. The drawing is responsible for managing the GO’s under its control. It coordinates the display of GO’s in what is known as the draw loop. The drawing collects all the damaged areas, and forwards them to the interface. Given a point or area, the drawing is able to return the GO’s containing the point or intersecting the area very quickly. It keeps track of the Z-order of figures, and coordinates their display to maintain visual Z-order. Given an area and a pen, the drawing will efficiently display only the figures intersecting the area, providing a key function in the speed of the display system. The drawing is also responsible for keeping the definition of the global coordinate system for its components.Generally, you will not be accessing a GFDrawing directly. Drawings form a very critical piece of the GF/ST framework, but they are typically not of concern to you. Instead, you will be manipulating either a GFGraphicObject held in a GFDrawing, or you will be manipulating and accessing its interface, a GFDrawingInterface.Because handles are so central to graphical applications built using GF/ST, you would expect them to be extremely flexible in the way they can be used. One way to get this flexibility is to build many specialized subclasses of a generic GFHandle class; however, if you examine the hierarchy, you will find this is not so. Instead, GFHandle is heavily parameterized. When we use a word with that many syllables, it’s a sure sign that it will be very easy to get the behavior you want out of a handle, but it will be very hard to describe how we accomplish it under the covers. Fortunately, this kind of situation is handled (pun intended) quite effectively through the use of examples. You will find many examples of different kinds of handles in subsequent sections and in the example applications.A handle’s main responsibility is to mediate mouse input, and using that input, to manipulate a GO in some fashion. Handles have a locator (see “GFLocator“), which tells them where they are located. Handles are also responsible for displaying themselves.As discussed in “What You Absolutely Must Know to Use GF/ST”, if you don’t understand events, then everything you see in GF/ST may appear to be done by magic. The event system is the wiring grid of the system. The use of events makes GF/ST incredibly flexible and powerful, but it also means that the flow of control can be hard to follow. It can be difficult to follow (just as the change-update mechanism in MVC can be) because the dependency relationship is set up long before the event is triggered and acted upon.GO’s generate many different kinds of events. See “Class Hierarchy, Protocol and Events“ for a compact summary of the events that GO’s trigger. To aid in event processing efficiency and to avoid garbage collection problems, we keep track our own event handlers. We want to re-emphasize here that understanding the event model is central to understanding how GO’s are hooked up with each other, and how constraints are maintained in GF/ST.Events also provide a wonderful way to separate a GO from the model it represents. For example, retrieving the menu for a GO is taken care of with an event. If the event isn’t handled, then a default menu is supplied. However, because the object triggers the getMenu event, you can use any appropriate object to generate and return the menu when it is needed.Constraints are GF/ST’s mechanism for defining and enforcing relationships between GO’s. Smalltalk supports the concept of constraints via dependency. In GF/ST, the event model (PsiEventModel) sets up constraints using:Constraints in GF/ST are driven by events raised by the GO’s themselves. Constraints can be attached to any event triggered by a GO. A common occurrence is to attach constraints to the damaged event that is raised by all figures. Whenever a figure is damaged, the event is triggered, causing the constraint to be evaluated. This approach is used to ensure that any dependent affected by the constraint is kept up to date when a related aspect of the GO changes.A GFLocator is a kind of Message that, when evaluated, answers a point. A GFLocator holds onto a receiver, a selector, and arguments. When it is evaluated (by sending it the message value or asPoint), the receiver is sent the selector, with the optional arguments. This receiver’s method (defined by the selector) must return a point, which is the value of the locator.Consider a case where you want to keep track of the center of a GO. You would create a locator with the receiver object set to the GO being tracked. The selector would be the symbol #center. There would be no arguments in this locator. When the locator is sent the message asPoint, it is evaluated, sending the message center to the GO. All GO’s understand the message center, answering the center point of the GO. There are many such helper methods defined on GO’s, usually at the top level in GFGraphicObject itself. For instance, topLeft, topRight, leftCenter, and rightCenter are all available.which does exactly the same as above. When you send the message value to the locator (i.e., you “evaluate“ it), it would send the message offOrigin: to aGO with the argument 10@10. The result would be a point which was 10@10 off from the origin of aGO . Refer to “Specializing Handles in the Network Editor“ for an example of using a locator.A GFPositionConstraint is a kind of Message that when evaluated, sends a setting message to an object with the point represented by a locator as the argument. For instance, if you wanted to keep the start position of aLineGO fixed to the origin of anotherGO, you would do the following:This would return an instance of a GFPositionConstraint that, when evaluated, first gets the point represented by the locator. (See the discussion in “GFLocator“ for a description of how the locator produces this point). This point is then sent to the receiver, aLineGO, as an argument to the method startPoint:.One commonly used specialization of handle is the class GFTrackHandle. This class encapsulates the handle behavior of tracking a mouse. When invoked, this class will track the mouse in steps. When the mouse changes position, a two-step process is invoked. The handle first evaluates the sense action with the delta between the last position and the current position as its argument. The result of this message is then used as an argument to the change action.The design of GFTrackHandle allows it to generate objects (which don’t have to be points) based on the mouse tracking, and to feed these generated objects into some change action that changes the GO’s state. Obviously this approach is very powerful. For instance, the handle that changes the border color of a GFAbstractPathGO uses the sense action to return just the vertical delta of the mouse position. Using this point, the handle changes the border color of the GO by evaluating the action borderDarkenBy: with the GO as the receiver and the vertical delta as its argument.Since events are so central to GF/ST, you should also rest assured that the when:send:to: style of hooking up to events will be present no matter what Smalltalk platform you deploy your application on. Similarly, you should expect the same events to be triggered at the same times regardless of Smalltalk version.GF/ST modifies no base image methods on the VA Smalltalk platform.where, GFMessage is our subclass of the base IBM class DirectedMessage, which we implement on that platform for protocol compatibility. You can see that our porting job between platforms now amounts to re-implementing the gfMessageClass method, which you’ll find in Object.Should you write code like this? It depends on whether you care as much as we do about portability. If so, go ahead. You’ll find some helper methods in Object that look like gfSomethingClass which we’ve found useful. If not, you certainly won’t hear any complaints from us!You must purchase one license per developer. Within the limitations of your Smalltalk vendor’s license agreement, you may distribute runtime applications developed using GF/ST without paying any royalties for the use of GF/ST to Instantiations. You may not distribute any source code provided with, taken from, or derived from GF/ST without express written consent from Instantiations, Inc.GF/ST is ripe ground for clever users to do new things with. You’ll be building applications with GF/ST, and we’d love to hear about them and see the finished products. Along the way, however, you may develop a new WhatsIt thing that others would love to have. Please, send it to us! We will constantly be updating our library of user-supplied goodies and supply them with GF/ST. If we choose to supply your contribution as a standard part of our release, we’ll leave your copyright notices on any code you supply, and put your name in lights for new GF/ST users to see.