Difference between revisions of "Classes 5"
(Window classes) |
m (1 revision) |
(No difference)
|
Latest revision as of 04:25, 1 January 2009
Contents
Windows
About this chapter
This chapter describes the Mops classes and words that manage windows for the application. Mops's window classes take away much of the burden of window management, providing the basis upon which you can build more detailed behavior. Standard Macintosh window behavior, such as dragging, growing and updating, is handled automatically by Mops's Window and Window+ classes, freeing you to solve application-level problems instead of constantly having to rewrite system-level code for window management.
Inside Macintosh | Event Manager |
Window Manager | |
QuickDraw | |
Control Manager | |
Mops | Window |
Controls | |
QuickDraw | |
Toolbox Views | |
Resources |
Window | zWindow |
WindowMod.txt | zwindowmod.txt |
Window+ | zWindow+ |
Using windows
Mops provides two classes of window objects: class Window, built into the distributed Mops.dic image, provides basic behavior necessary for all windows, but does not include any management of views (or controls, which are a view subclass). Another class, Window+, adds the behavior necessary for windows with views. Unless your application is a particularly “quick and dirty” one, which just needs an extremely simple text-only output along the style of a dumb terminal, we recommend you use the Window+ class. Lessons 18 and 19 of the Tutorial have already given an introduction to views, and how these interact with the Window+ class.
Because a Macintosh window record incorporates a QuickDraw GrafPort as the first portion of its data, class Window is a subclass of class GrafPort, inheriting both the GrafPort data and three GrafPort-related methods (see the QuickDraw section of this manual).
Windows, like controls and certain other Toolbox objects, have a dual identity in that part of the object is known only to Mops, while another part is known both to Mops and to the Toolbox. From the point of view of the Toolbox (and conventional languages like Pascal or C), a window is completely described by a window record. A Mops window object packages the window record data within the larger context of the object's private data, adding ivars to support the additional level of management that a Window object provides. The result is that the programmer is confronted with a much simpler model using objects, because all of the ‘boilerplate’ kinds of behavior, such as dragging, growing, closing, updating and activation are handled within the window object itself rather than being thrown in with the application code. That is how Mops is able to simplify the logical model of the Toolbox and elevate it to a higher level, while still giving you the freedom to change any of the default behavior that occurs in such basic classes as Window.
There are two ways to create a new window using the Toolbox: you can ask that the Toolbox allocate the window record on the heap, or you can provide the data area yourself. Because a Mops window object includes a window record as its private data, it always uses the second of these methods, passing the address of its own data to the Toolbox as the storage to use for the window record. Of course, if you have an application in which windows come and go dynamically, so that you wish to allocate them on the heap, you can use the Mops ObjHandle mechanism to do so.
The fact that an object allocates a window record as the first part of its data is important, because it simplifies the interaction between Mops and the Toolbox. There are many cases in which Mops must determine which window is involved in event processing by calling the Toolbox, which will return a pointer to the window record. If the window record were not part of the object, Mops would have to somehow derive the address of the object's data from the window record. As it is, the window record is synonymous with the object's base address, making communication with the Toolbox much simpler. Other Mops objects, such as Controls, do not have this luxury, and must take extra steps to derive the object address.
Window objects add to the window record data a group of instance variables that keep track of the window's drag and grow characteristics, a boolean that tells whether the window is currently ‘alive’ with respect to the Toolbox, and a set of action ‘hooks’ that allow you to customize a window's behavior without necessarily having to create a subclass. These action vectors hold the xts of Mops words to execute when the window is involved in a content click, an update event, an activate event, or selection of the close box. The ClassInit: method of Window initializes the vectors to the xt of NULL, except for the activate vector, which is set to the xt of CLS (‘clear screen’, which erases the viewing area of the window).
For the Window+ class, which you should normally be using, you should leave the click handler and the update handler set to NULL (which they will be initially anyway), since clicks and drawing are handled through our view mechanism. You may, however, have a good reason to customize the activate or close handlers—for example, you may need to change menu items depending on which windows are open or in front.
Creating windows
The steps involved in creating and using a window are as follows: First, instantiate a window class (i.e. create a window object), and then initialize the action vectors of the window using the actions: method. For windows whose data exists in the dictionary or a module, this can occur at compile time:
window myWind \ create a new window object xts{ doClose doActivate null null } actions: myWind \ Set the close, activate, draw and content vectors
The Activate vector is executed when the window becomes active, and the Close vector is executed when the use clicks the Close box. Typically, you will use both of these hooks to adjust items in your menus.
The Draw vector is called when the window receives an update event, which is the Toolbox's way of telling the window to redraw itself. Note however that drawing should now be done through our view mechanism, and not by setting the window's draw handler. At the moment we are really only maintaining a draw handler for backward compatibility, and it will probably disappear in future.
If the window is of class Window+, any views associated with the window will be redrawn automatically, since the DRAW: method for Window+, among other things, calls DRAW: on the contView, which causes DRAW: to be sent to all the views.
Lastly, the Content vector is called when the user clicks the mouse in the window's content region. Here again, you should now normally handle content clicks through the view mechanism—the click handler may also disappear in future.
You can also set the window's drag and grow characteristics at compile time, if the ClassInit: defaults do not suit your needs. Each requires a boolean on the top of the stack reflecting whether the window is growable or draggable, and the four coordinates of a rectangle underneath the boolean if it is true. For example:
10 10 500 300 true setDrag: myWind false setGrow: myWind
causes myWind to be draggable, but not growable. But note, in class Window, we actually ignore the rectangle coordinates passed in for setDrag: and setGrow:, and use a default value based on the size of the screen at the time the drag or grow is actually done. This is probably more generally useful than using any fixed values for the drag or grow limits. So unless you actually want fixed values and override these methods, you can just pass any four dummy values.
When your application executes, you must send a New: message to the window to cause it to become active with the Toolbox and to draw itself on the screen. New: requires a rectangle holding the dimensions of the window's frame, a title, a procID for the window type, and booleans reflecting whether the window should be visible when created and whether it should have a close box. For instance:
10 10 300 200 put: tempRect tempRect " A New Window" docWind true true new: myWind
would create a new document window using the dimensions stored in tempRect that would be visible and have a close box. If you would rather define your window's characteristics using resources, you can call the GetNew: method to open the window using a template from a resource file.
To get a feel for how Mops' window objects can be used, it is most instructive to look at an existing application, such as grDemo. Lessons 18, 19 and 20 of the Tutorial deal with grDemo, and lessons 18 and 19 in particular give a good introduction to the View and Window+ classes.
Much of the code, as you will see, is concerned with initializing the various objects properly; much of the actual work is accomplished internally to the methods already defined for those objects.
Classes
Window
Window is the basic class of windows without controls. As for PowerMops, see also Reference 11 (at present).
Superclass | GrafPort | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Source file | WindowMod.txt zWindowmod.txt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Status | Core | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Instance variables | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Indexed data | None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
System objects | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Inherits: | GrafPort, Object |
---|
setting characteristics | ||
---|---|---|
setContRect: | ( -- ) | Sets the content rectangle after the window has been resized. Also sets Mops's scrolling rectangle, used by CR, equal to the content rectangle |
SetColor: | (b -- ) | Sets the flag for whether the window is to be a color grafPort or a B&W one. Must be used before the window is created |
SetClipGrowLeft: | (b --) | A pair of methods for setting the ClipGrow flags in the ivar list |
SetClipGrowTop: | ||
setGrow: | ( l t r b T or F -- ) | Sets the window's grow limits. The old action was that if the boolean was true, the rectangle coordinates determined the mini-mum and maximum x and y values that the window could be grown. However the current action is to ignore these coordinates and use a SCREENBITS call instead. If the boolean is false, the window will not be growable |
setDrag: | ( l t r b T or F -- ) | Sets the window's drag limits. The old action was that if the boolean was true, the rectangle coordinates determined the mini-mum and maximum x and y values that the window could be dragged. However the current action is to ignore these coordinates and use a SCREENBITS call instead. If the boolean is false, the window will not be draggable |
setScroll | ( b -- ) | The passed-in boolean indicates whether scrolling is enabled for this window or not. This is primarily intended for the Mops window fWind, which supports scrolling text, and uses the temporary rectangle fpRect for this purpose. If a window doesn't support scrolling, then fpRect won't be altered when that window is active, so you can use it for your own purposes without conflict
Note however, that the "proper" way to support scrolling text is via a Scroller view within a Window+ |
setIdle: | ( xt -- ) | Sets the word which will execute in response to idle messages to the window |
set: | ( -- ) | Sets the window's grafPort as the current grafPort |
select: | ( -- ) | Makes this window the frontmost, active window |
size: | ( w h -- ) | Sets the dimensions of the window to the given width and height, without moving the window's upperleft corner |
setSize: | ( w h -- ) | The same as size:—this is for naming consistency with Rects and Views |
move: | ( x y -- ) | Moves the upperleft corner of the window to global coordinates x and y without changing its size |
center: | ( -- ) | Centers the window on the screen |
show: | ( -- ) | Calls ShowWindow to make the window visible |
hide: | ( -- ) | Calls HideWindow to make the window invisible |
actions: | ( close enact draw content 4 -- ) | Sets action vectors with the xts provided. We require an xt count (4 in this case) as this is standard for all actions: methods |
setAct: | ( enact deact -- ) | Sets the activate and deactivate vectors with the xts provided |
setDraw: | ( drawXt -- ) | Sets only the Draw action vector |
title: | ( addr len -- ) | Sets the title of the window to the passed-in string |
name: | ( addr len -- ) | An alias for title: (above) |
putRect: | ( -- l t r b ) | Sets the window's port rectangle coordinates. This and GetRect: are actually methods of the superclass GrafPort |
querying | ||
getName: | ( -- addr len ) | Returns the window's title string |
getRect: | ( -- l t r b ) | Returns the window's port rectangle coordinates |
getVSRect: | ( -- l t r b ) | Returns the window's default vertical scroll bar rectangle coordinates. (Does not require a scroll bar to be present, but if it were, this is where it would be) |
getHSRect: | ( -- l t r b ) | Returns the window's default horizontal scroll bar rectangle coordinates |
maxX: | ( -- x ) | Returns the x coordinate value which the top left corner of the window would have if the window were to be moved all the way to the right of the current screen (so the window's right hand edge would coincide with the right of the screen). Thus it is the maximum x coordinate value which the window could have without being in any way obscured. Doesn't actually move the window |
maxY: | ( -- y ) | Likewise, returns the y coordinate value which the top left corner of the window would have if the window were to be moved all the way to the bottom of the current screen |
active: | ( -- b ) | Returns true if the window is currently active |
alive: | ( -- b ) | Returns true if the window is currently alive in the Toolbox |
event handling | ||
draw: | ( -- ) | This method is executed when an update event occurs for the window. If the window is growable, a grow icon is drawn with scroll bar delimiters. The window's Draw action vector is executed |
idle: | ( -- ) | This method may be used for background processing. Whenever fEvent gets a null event out of the event queue (for instance, while waiting for the user to type a character) a late-bound idle: message is sent to the front (active) window. That win-dow's idle: method can then do any background processing necessary (such as updat-ing a clock picture). The idle method defaults to a donothing method in class Window, and should be kept short enough to keep from bogging down responsiveness to user input |
enable: | ( -- ) | This method is executed when an activate event occurs for the window. The window's Enact action vector is executed |
disable: | ( -- ) | This method is executed when a deactivate event occurs for the window. Does nothing in class Window |
update: | ( -- ) | Forces an update event to occur that will redraw the entire window. The window will not actually be redrawn until KEY is called and event handling is active |
close: | ( -- ) | This method is executed when the user clicks the window's close box. The window's Close action vector is executed, and CloseWindow is called |
release: | ( -- ) | The same as close:—this is our standard destructor name |
drag: | ( -- ) | This method is executed when a mousedown event occurs in the window's drag region. The Toolbox is called to pull a gray outline around with the mouse. If inac-tive, the window is made active after dragging |
zoom: | ( part -- ) | This method is executed in response to a click in the zoom box. part is supplied by the system when the Event code calls FindWindow—it will be 7 if the window is to be zoomed in, or 8 if it is to be zoomed out. Note that although this method is included in class Window, the remainder of zoomable window support is in class Window+, so a zoomable window should therefore be a Window+ |
grow: | ( -- ) | This method is executed when a mouse-down event occurs in the window's grow region. The Toolbox is called to pull a gray out-line around with the mouse. If inac-tive, the window is made active after growing |
content: | ( -- ) | This method is executed when a mouse-down event occurs in the window's content region. The window's Content action vector is executed |
key: | ( c -- ) | Called when a key is typed and this window is active. Here in class Window, we simply drop the key. In the subclass Window+, the key is sent to the view which is ‘in focus’—i.e. the view pointed to by the ^view_in_focus ivar |
initialization | ||
classinit: | ( -- ) | All objects of class Window are initially set to non-growable, draggable windows with null action vectors |
runtime control | ||
new: | ( ^rect tAddr tLen procID
visible goAway -- ) |
Calls the Toolbox to create a new window using this object's data as the window record. Parameters determine the window's bounds in global coordinates, the title, the type ( procID - see dlgWind, docWind, rndWind) of window, and whether it is visible and has a close box |
getNew: | ( resID -- ) | Same as new:, but uses the resource template with resource id resID |
test: | ( -- ) | Creates a test object of class Window |
Error messages - None
Window+
Window+ adds support for views, and also zooming. Unless your window is to be very basic indeed, you should use this class.
Superclass | Window | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
Source file | Window+ | |||||||||
Status | Optional | |||||||||
Instance variables | ||||||||||
| ||||||||||
Indexed data | None | |||||||||
System objects | None |
Inherit: | Window, Grafport, Object |
---|
accessing | ||
---|---|---|
setZoom: | ( b -- ) | Passed-in boolean indicates if this window will be zoomable |
getView: | ( -- ^view ) | Returns a pointer to the ContView |
setView: | ( ^view -- ) | Sets the ContView |
event handling | ||
grow: | ( -- ) | Handles a click in the grow box |
zoom: | ( -- ) | Handles a click in the zoom box |
enable: | ( -- ) | Handles an activate event. Sends enable: to the Contview, which causes enable: to be sent to all child views as well |
disable: | ( -- ) | Handles a deactivate event. Sends disable: to the Contview, which causes disable: to be sent to all child views |
content: | ( -- ) | Handles a click in the content region of the window. Sends view_for_click?: to the ContView. If this returns true, then click: is sent to the identified view. The Click handler of this view is then executed |
key: | ( c -- ) | Called when a key is typed and this window is active. The key is sent to the view which is ‘in focus’—i.e. the view pointed to by the ^view_in_focus ivar. If this pointer is nilP, there's no view in focus and we drop the key |
draw: | ( -- ) | Draws the window with its controls. draw: is sent to the ContView, which causes draw: to be sent to all child views. Any custom drawing should be done via the Draw handlers in the views |
idle: | ( -- ) | As for idle: in class Window, but also sends an idle: method to the ConView, which causes idle: to be sent to all child views |
close: | ( -- ) | Handles a click in the close box. Sends release: to the ContView, which causes release: to be sent to all child views. The storage for any controls is released via a KillControls call. Finally the window is closed and its storage released |
runtime control | ||
new: | ( ^rect tAddr tLen procID
vis goAway ^view -- ) |
As for new: on class Window, except there is one additional parameter, a View pointer. This View will become the ContView. init: is called on this ContView, setting its ViewRect to the contents rectangle of the window. new: is then called on the ContView, which causes new: to be called on all child views and controls |
getnew: | ( resID ^view -- ) | As for new:, but the window data comes from the resource given by resID |
test: | ( -- ) | Creates a test window |
Error messages - None
Events | Classes | Views and Controles |
Documentation |