Classes 5

From PowerMops
Jump to: navigation, search


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.


Recommended reading
Inside Macintosh Event Manager
Window Manager
QuickDraw
Control Manager
Mops Window
Controls
QuickDraw
Toolbox Views
Resources


Source files
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
Class Name description
32 bytes wind1 Unstructured data for the window record
handle CtlList Windows control list
12 bytes wind2 Unstructured data for the window record
rect contRect The rectangle defining the content region
rect growRect Contains the window's current grow limits
rect dragRect Contains the window's current drag limits
bool growFlg True if the window is growable
bool dragFlg True if the window is draggable
bool Alive True if the window is alive in the Toolbox
bool ScrollFlg True if window contents are to be scrollable
bool Color? True if this is a color grafPort
x-addr Idle The window's idle event action vector
x-addr Deact The window's deactivate event action vector
x-addr Content The window's content click action vector
x-addr Draw The window's update event action vector
x-addr Enact The window's activate event action vector
x-addr Close The window's close box action vector
int ResID Resource id for GetNewWindow
bool ClipGrowLeft True if you want to not outline unused VScroll
bool ClipGrowTop Ditto for unused HScroll
ptr ^view_in_focus Points to view which gets keys etc
Indexed data None
System objects
Name description
fWind The Mops system window used by the nucleus


Inherits: GrafPort, Object
Methods
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
Class Name description
ptr ^contView Pointer to the ContView— the view consisting of the whole contents of the window
bool zoomFlg True if this window is to be zoomable
Indexed data None
System objects None


Inherit: Window, Grafport, Object
Methods
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