TweetFollow Us on Twitter

Window Scroller
Volume Number:2
Issue Number:9
Column Tag:Advanced Mac'ing

Build a Pop-Up Window Scroller

By Scott T. Boyd, Aggieland, TX

Scott is a graduate student at Texas A&M, doing research in typesetting (TeX) and object oriented programming. He has a background in VAX/Unix and has done a lot of work on porting TeX to the Mac, but says the Lisa Compiler bugs derailed that project until another firm bought the Lisa source and fixed it. In this article, Scott presents a clever way to pup-up a minature window and scroll directly to the point of interest. This is ideal for large grafport projects and we are happy to present Scott with our Program of the Month award and $50 with thanks from MacTutor!

Fig. 1 Getting the Big Picture

Getting the Big Picture

For years computers offered no more user interface than a command line, single-keystroke menus, and full-screen text editing. The Macintosh has introduced us to the beauties of carefully designed user interfaces. The average user has come to expect pull-down menus, windows, a desktop, a pointing device, and other user interface tools. Apple has provided a set of guidelines for those who would like to extend the user's mental metaphor by providing new user interface elements.

Many solutions emerge out of the minds of frustrated users. For example, users of large computers used to have all computer output displayed on one screen in a single stream of characters. This really was not a problem until users realized they could have more than one thing going at once. To help users sort out what came from where, windows were born. Each window contains information relating specifically to the topic of interest of that window. For example, if you are editing a document in one window, you could receive mail messages in another while watching system utilization in yet another. Thus, since someone got frustrated with having input and output streams all mixed into one, windows now allow separating these streams in a sensible manner.

One element of the Macintosh interface that can be frustrating is the manner in which scroll bars operate, especially if the window uses two scroll bars, one for vertical and the other for horizontal movement. In the extreme case, consider a window containing a very large picture which takes a substantial amount of time to redraw whenever you move around with the scroll bars. If you are positioned at the top-left corner and want to move to the bottom-right corner, you are obligated to do one of two things.

First, you can move the cursor all the way to the bottom-left of the window and drag the horizontal thumb all the way to the right, move to the top of the vertical scroll bar, and move its thumb all the way to the bottom. This approach requires a great deal of mouse movement and two window updates. Remember that updating the window can take a good amount of time (depending on the complexity of the document). To make this situation worse, the user has no visual confirmation of what might be at the bottom-right of the document.

The other approach that you might be familiar with is the Show Page goodie in MacPaint. In this approach, a new window appears and a miniature version of the document is drawn. You can then move a rectangle around to show where you would like the window to be positioned. Then you hit the OK button or the Cancel button, the window goes away, and your document window reappears, showing the area you selected. This does overcome the need for a mental picture of the whole document. While this method only requires updating the window once, it has the unfortunate problem of introducing a new mode to the user. In Apple's Do's and Don'ts of a Friendly User Interface, over-using modes is the first Don't.

The problem then is a matter of giving the user some idea of what the document looks like and permitting easy access to any part of the document. Other approaches have been implemented, many of which have contributed to the ideas that go into the solution given here. This solution not only solves the primary problem, but it draws from a number of elements of the Macintosh interface that are already very familiar, hence the name: The Pop-up, Two Dimensional, Random Access, Scroll Bar Menu, or simply, OverView.

How OverView Behaves

It behaves just as it is named. At the user's request (discussed later), something akin to a menu pops up. It has the proportions of the document and it contains a miniature picture of the document. The area currently showing in the document window is highlighted. As long as the user holds down the mouse button, a gray rectangle the same size as the highlighted area moves around with the cursor, showing the area that will be selected if the button is released. Like most Macintosh controls (e.g. the scroll bar thumb), if the cursor is moved too far away from the window, the gray rectangle disappears. If the mouse is released when the rectangle is gone, the Pop-up window disappears and nothing happens. If, on the other hand, the button is released while the gray rectangle is showing, the old selection dehighlights and the new selection flashes in the same way that menu selections flash when selected. The scroll bars change appropriately, and the program gets notified that it needs to redraw the contents of the window at the new location via an update event.

With OverView, the user never perceives a change in mode, yet has access to the whole document in one easy step. Like pull-down menus, OverView will not generate activate events. It will not create update events unless a new selection is made. It appears quickly and disappears quickly. While it may seem complicated after reading this description, try using it once. It is much easier used than described.

Summoning OverView

OverView was created to view large typeset pages at varying levels of magnification. As such, it was designed to be used in a passive mode. That is, the user could only view, not change the document contents. This has an important relationship to how OverView was first used. Since clicking in the window pane (the area of the window where the actual document is, excluding controls) had no implicit meaning, that was used to activate OverView. However, in documents where text editing or object editing (e.g. MacWrite, MacDraw) takes place, clicking in the pane has other meanings. Another method of summoning OverView is called for. Andy Hertzfeld gets credit for the idea of putting an eyeball icon at the bottom-left of the window and scooting the horizontal scroll bar over to the right. Clicking on the eye could summon OverView. Another possibility is similar to the zoom box capability added in the new ROMs. The eyeball could be placed in the title bar between the close box and the title. Clicking on the eye would function almost exactly like a pull-down menu.

Making the choice on this is left to you, the creative program designer, to see what users like best. Keep in mind that it gets tiresome having to move the cursor to an exact point on the screen to use a function, especially if you happen to spend a lot of time far away from that spot. That was the beauty of the very first approach, because it was always available whenever you were in the window of interest. A typical power-user trick could come in handy for non-passive windows. Perhaps Option- click or Command-click or Command-Option-click could be used (as in PageMaker™).

Operational Details

OverView has a few very special features. Some were mentioned above. Others are listed here. For example, the pop-up window always remains within the boundaries of the front window. This is important for the prevention of the generation of update events. OverView knows that the only window it will ever affect is the front window, so it can easily convince that window that it was not affected (see the code).

OverView provides flexibility by taking advantage of the information available to it about the front window. By looking at the size of the window pane and comparing it to the size of the document, it scales the rectangles appropriately. It also takes advantage of the available screen size (just in case bigger screens just happen to come along).

Every window which will have its own OverView Pop-up needs a WindowPtr and a BitMap. NewOverView works by creating a new window for the Pop-up window. It then creates an offscreen bitmap into which a miniature of the document can be drawn with UpdateOverView. Then, whenever it is summoned, OverViewSelect makes its window appear after saving the bits underneath it into a temporary bitmap. It shows the Pop-up window without deactivating the document window by using ShowHide and some trickery. It copies the offscreen bitmap miniature into the OverView window and calls TrackGrayRgn to get the user's selection. It then hides the window, restores the bits underneath the Pop-up window, and sets the scroll bars based on the new selection.

The Interface

The code is broken up into three procedures: InitOverView, UpdateOverView, and OverView- Select. The code is in the form of a Macintosh Workshop Pascal (MPW Pascal) Unit, which can be compiled separately and linked in just like any of the Toolbox Managers. For now, it is enough to know that MPW Pascal is essentially Lisa Pascal. OverView was initially written in TML Pascal as a straight program. The conversion to MPW Pascal took five minutes and was mostly changing the include files and compiler switches. For more information, see the MPW Section below.

NewOverView should be called once for every window that will have an OverView window. Pass in an empty bitmap, an empty window pointer, a rectangle with the size of the virtual document (origin at 0,0), and a size factor (a real number between 0 and 1). NewOverView creates a new window whose height is determined by the available screen height multiplied by the size factor. NewOverView creates an offscreen bitmap and fills in the BitMap's record.

It is your program's responsibility to keep the miniature picture up to date. You can draw into it by passing your drawing procedure and the bitmap to UpdateOverView. It will not do any drawing or erasing. It simply sets things up to do the drawing, calls your drawing routine, and resets everything to normal before exiting. Thus, rather than erasing and redrawing the entire picture, you might just draw the parts that have changed if that is less work or less time consuming.

Whenever you decide to summon OverViewSelect, call it by passing in the point from the MouseDown event, the rectangle (origin at 0,0) with the dimensions of your virtual document, the point that corresponds to the upper-left corner of the viewing window (in terms of the size of the virtual document), the bitmap from NewOverView, and handles to the horizontal and vertical scroll bars.

Beware that the viewing window should not be permitted to resize any smaller than the OverView pop-up window. The trick used for soaking up update events will not be reliable if the OverView window overlaps any other windows. Just be sure to set the pop-up window size as the smallest size allowed whenever growing a window.

Changing the size of the virtual document is fine as long as the ratio of the sides remains the same. If that changes, the old window and bitmap should be disposed of and new ones allocated.

Watch out! If you choose a Pop-up window size that is too large, CopyBits freaks out. This will lead to unpredictable behavior. The OverView code needs to be modified so that it never attempts to CopyBits any sections larger than 3K at a time. Unfortunately, deadline pressure prevented this fix. A factor of 0.5 works just fine on all currently available Mac-type hardware (except on the XL), but 0.6 is too much. The fix will certainly be available before the new hardware hits the market. The problem with the XL appeared just at press time, so it has not been tracked down yet.

Understanding the OverView Code

When you call OverViewSelect, a number of things happen. The window is positioned so it stays within the boundaries of the FrontWindow. Then, before actually displaying the window, the screen bits where it will appear are saved into an offscreen bitmap. The window appears, the miniature picture is blasted into the window, the relative size of the current selection is computed, the current viewing selection is highlighted, and the user is given an identically-sized gray rectangle to drag around, which is tracked until a MouseUp. If a selection is made, the old selection is dehighlighted and the new selection is flashed MenuFlash times. The window is hidden and the screen bits are copied back into place. If a selection was made, the scroll bars are set appropriately. Otherwise, the update events for the FrontWindow are cleared.

Note that the window position on the virtual document is stored in a scroll position variable as well as in the scroll bars themselves. Figure 1 shows the organization of the important variables and how they relate to each other. The position of the window on the document is directly related to the settings of the scroll bars. The size of the highlighted area and the draggable gray region are proportional to the size of the window pane relative to the document's overall size. Figure 2 shows a picture document and should help you get a better feel for how everything looks. Please understand that the miniature picture as printed has much higher resolution than the screen (300 dots per inch versus 72 d.p.i.), so it looks much better on paper. In addition, the sharp reader will notice that the eyeballs were not used to summon the OverView window in either Figure 1 or 2. They are shown to let you get the visual effect of the different placement.

The code uses two offscreen bitmaps. The first stores the miniature picture. Create it with NewOverView before using any of the other OverView routines. Dispose of it when you are done with it. The second bitmap stores the bits underneath the pop-up window whenever it appears. It is allocated dynamically before showing the pop-up window and deallocated right after hiding the window. The Mac's menu manager works in a similar manner, allocating and deallocating on demand.

The trick used to mask out update events relies on the following argument. OverViewSelect should not be called if there are outstanding update events for the front window. Update events must be handled prior to invoking OverViewSelect. Since we assume there will not be any update events for the front window, we can safely assume that any that are generated during the time that OverView is in use were generated by us. By doing a BeginUpdate and an EndUpdate for the FrontWindow, the update events are eliminated. This means that we must be sure to restore the bits that were underneath the OverView window since the window manager will not ask for the window to be updated. You should also consult Mike Schuster's C Workshop: Try Pop-Up Menus! (MacTutor, December 1985, pp.15-22) for an excellent discussion of handling bitmap allocation, rectangle placement, and other issues important to pop-ups.

As always, an intimate knowledge of Inside Macintosh will aid you immensely in understanding the code. CopyBits, DragGrayRgn, the Window Manager, the Control Manager, MapRect, MapPt, and SetPortBits should provide some interesting reading topics for you.

The Sample Program

In addition to the OverView unit, this article includes a sample program to give you a feel for how you can include OverView in your own programs. The sample program brings up a window to fill the screen. It sets up scroll bars on the right and bottom, leaving room for the eyeball at the bottom-left corner. It then waits for a KeyDown event, which will exit the program, or a MouseDown event, which will summon the OverView window.

The sample also has a menu for changing the size of the virtual document. The three sizes given are for a typeset 8.5x11" page at screen resolution, ImageWriter resolution, and LaserWriter resolution. Once again, you can see the typesetting origin of OverView and its associated tools. Notice the differences when you change sizes. The pop-up window does not change its size, but the size of the selection rectangle inside it does change. For example, the selection rectangle is much smaller when LaserWriter resolution is selected than when screen resolution is selected. This is because the window pane shows a different portion of the overall document.

A couple of general programming notes follow. First, note that the viewing window (the one that stays visible with the picture in it all the time) is sized to the full size of the screen. Thus, if it runs on a Lisa, it takes full advantage of the screen size. And, if Apple decides to come out with larger Mac screens, no problem. With the simple technique in SetUpWindow, any program can be prepared to use all available screen space. If Apple decides to offer different screen resolutions, this program will not know about it. However, with some additional code, it could use the screen resolution globals to compute the pixel size of MenuBarHeight, TitleBarHeight, ScreenMargin, SBarHeight, and SBarWidth to keep them the same size that we are all used to.

This sample shows some of the beauty of Workshop Pascal units. Since OverView is in its own separately compiled unit, the sample only needs to include it and the programmer can safely forget about the details of OverView and instead treat it just like any other Mac manager.

You might notice in the MacTutor article referenced earlier that his code does not use a window. Rather, he uses only an offscreen bitmap. While an OverView could be made in a like manner, this implementation uses a window intentionally. It seemed more natural at the time, and still does. If you have comments on this approach, please send them.

MPW -- What is it?

MPW stands for Macintosh Programmer's Workshop. It is the development environment many of us have been waiting for. Its power tools include a unix-like shell, a 68xxx assembler, a linker, a debugger, a resource editor, and a resource compiler/decompiler. With the shell, you get an environment where you can edit, manipulate files, compile, link, and run programs in multiple windows. The shell offers integration, command scripting, regular expression processing, and extensibility.

Macintosh Workshop Pascal, Macintosh Workshop C, and MacApp are available separately as MPW tools. The Pascal and C have migrated from the XL Workshop to a truly on-the-mac, for-the-mac environment.

MPW runs on just about anything except the old 128K machines. It will be coming available on the market from Apple reportedly by the end of the year. No cost has been given, but guesses are in the $500 range, depending on whether you get Pascal, C, and/or MacApp.

MacApp stands for the expandable Macintosh application. Finally, all of us who wondered why it was so hard just to put some text in a window will have a tool where you spend your time describing the differences between your application and the standard application. Things like windows, menus, updating, text editing, AppleTalk, filing, and all the ordinary things are taken care of automatically. MacApp is a revolutionary product you should pay careful attention to. It, too, will be coming available hopefully by year's end.

Workshop Pascal and TML Pascal

The simple, plain truth is, if you program in Pascal on the Mac, you are probably using TML Pascal. OverView was originally programmed with TML Pascal, as were all of my programs. At least, that is, until recently. If you want to use OverView with TML Pascal, read on.

Workshop Pascal brings a number of good things to the Mac that other Pascals just do not offer. Two in particular are Objects and Units. Objects allow you to program in an object oriented fashion. You are familiar with the objects used in the Mac interface: windows, menus, boxes, scroll bars, etc. With object programming, you can write your programs to treat objects as somewhat intelligent creatures with the ability to communicate with you. For a better description than space allows, consult the new book from Hayden Press, Object Oriented Programming for the Macintosh, by Kurt J. Schmucker. It is an excellent book, and one of the first to comprehensively address the issue of object programming.

The other benefit of Workshop Pascal is Units. The toolbox managers you know and love were written as units. A unit is a separate chunk of code. OverView is a sample of such a chunk. It consists of an interface part and an implementation part. The interface part declares constants, types, variables, and procedures that are available to the outside world. The implementation part has the actual working code, and can contain its own private constants, types, variables, and procedures.

A unit stands alone by itself. It is compiled separately. When your program says uses identifier, the compiler goes out and reads in the interface part, treating the procedure declarations like Forward declarations. You then link in the separately compiled unit with your program in the link step, just like the toolbox interfaces.

Now, what do you do if you have TML Pascal? No problem. Include the text of OverView.p directly in your program. Remove the words UNIT OverView, INTERFACE and IMPLEMENTATION and the final END. Remove the compiler switch settings. In the interface section, add FORWARD; at the end of the three procedures. Modify the uses clause to the TML equivalent. Put the interface section into the front of your program. Put the implementation section anywhere in your program.

According to a TML spokesperson, the Object Pascal extensions and separate unit compilation will be in TML Pascal Version 2.0, expected some time before you read this! Tom has added some staff and seems to moving right along. If you have 2.0, you should not need to make any changes other than the compiler directives and the Uses clause.


This addition to the Mac interface has caught on here in Aggieland. Several people have commented that the idea was so natural that they had tried (in vain) to summon OverView while they were using MacDraw and MacPaint! If you find a good way to add an OverView capability to Draw or Paint, please let me know. My only solution right now involves FKEYs and searching the heap for windows and scroll bars, and it looks highly involved. Please use this code in your own programs if you like the way it feels.

Until the Mac has the hardware capability to zoom in and out on a document (like the Symbolics 3600), this kind of tool will give the rest of us some ability to get the big picture and feel in control of our large documents.

UNIT OverView; 
{Version 1.0 Saturday, July 12, 1986 9:47:53 PM by Scott T. Boyd of the 
MacHax™ Group.
 Many thanks to Greg Marriott of SoftWare To Go, also a member of the 
MacHax™ Group}


{Compiler Switch Settings}
uses MemTypes, QuickDraw, OSIntf, ToolIntf, SANE;
 MenuBarHeight=  20; {Height menu bar in pixels}
 TitleBarHeight  =  18; {Height of title bar in pixels}
 ScreenMargin  =   4;{Width of "safety margin" }
 SBarHeight =  15; {Height of scroll bar}
 SBarWidth=  15; {Width of scroll bar}

Procedure NewOverView( var OV_pagePict : bitMap; 
 var OV : WindowPtr; viewRect : Rect; factor : Real );
Procedure UpdateOverView( 
 Procedure drawProc; OV_pagePict : bitMap);
Procedure OverViewSelect( where: Point; viewRect : Rect; 
 VAR scrollPosition : Point; VAR OV : WindowPtr; 
 VAR OV_pagePict : bitMap; 
 HScrollBar,VScrollBar : ControlHandle);


Procedure NewOverView {( var OV_pagePict : bitMap; 
 var OV : WindowPtr; viewRect : Rect; factor : Real )};
 dummyRect: Rect;
 horizontal,{horiz. pixel size of OverView }
 vertical:Extended;{vert. pixel size }
 sizeOfOff: Size;{bytes for offscreen bitmap}
 offRowBytes:  Integer; {row bytes for offscreen bitmap}
 bitRect: Rect;  {size of OV window, bitmap}
 dummy: Point;
 offPort, {temporary working port}
 oldPort: GrafPtr; {temporary storage}
begin {compute available vertical screen space}
 vertical := ScreenBits.bounds.bottom-;
 vertical := vertical * factor;
 {compute horizontal to proportion}
 horizontal := vertical * viewRect.right / viewRect.bottom;
 {create the new window record}
 SetRect(dummyRect, 0, 0, Num2Integer(horizontal), Num2Integer(vertical));
 OV := NewWindow( nil, dummyRect, '', FALSE, altDBoxProc, WindowPtr(-1), 
FALSE, LongInt(0) );
 {create offscreen bitmap}
 bitRect := OV^.portRect;
 offRowBytes := ((bitRect.right-bitRect.left) div 8) + 1;
 if Odd( offRowBytes ) then 
 offRowBytes := offRowBytes - 1;
 sizeOfOff := ( * offRowBytes;
 with OV_pagePict do
 baseAddr := QDPtr( NewPtr( sizeOfOff ));
 rowBytes := offRowBytes;
 bounds   := bitRect;
 {fill the bitmap with white}
 GetPort( oldPort ); 
 offPort := GrafPtr( NewPtr( sizeof( GrafPort )));
 OpenPort( offPort );
 SetPortBits( OV_pagePict );
 FillRect( bitRect, white );
 SetPort( oldPort );
 ClosePort( offPort );
 DisposPtr( Ptr( offPort ));
end;  {MakeOverView}

Procedure UpdateOverView {( drawProc : Procedure;
 OV_pagePict : bitMap)};
 oldPort: GrafPtr;
 GetPort( oldPort );
 offPort := GrafPtr( NewPtr( sizeof( GrafPort )));
 OpenPort( offPort );
 SetPortBits( OV_pagePict );{make drawing offscreen}
 drawProc;{let the user draw}
 SetPort( oldPort ); {return drawing to normal}
 ClosePort( offPort );
 DisposPtr( Ptr( offPort ));
end; {UpdateOverView}

Procedure OverViewSelect{( where: Point; 
 viewRect : Rect; VAR scrollPosition : Point; 
 VAR OV : WindowPtr; VAR OV_pagePict : bitMap; 
 HScrollBar,VScrollBar : ControlHandle)};
 MenuFlash: ^Integer;{system global}
 value, {value returned by TrackGrayRgn}
 h, v:  LongInt; {}
 pane,  {}
 tempPt:  Point; {}
 scope, {size of window pane scaled into OV window}
 limitRect, {limit for drag region}
 slopRect:  Rect;{slopiness allowance for dragging}
 dragRectRgn: RgnHandle;  {the region the user drags }
 oldPort: GrafPtr;
 theWindow: WindowPtr;  {holds frontWindow}
 underScope: BitMap; {offscreen bitmap}
 whichWindow :   WindowPtr; {for save and restore bits}
 Procedure OV_Prepare;
 MenuFlash := pointer($A24);
 GetPort( oldPort );
 theWindow := FrontWindow;{the active window }
 BringToFront( OV ); {make OV appear, but not really}
 SetPort( OV );  {it's now the current port}
 ShowHide( OV, FALSE );   {it's also not visible}
 MoveWindow( OV,0,0,FALSE );{home the window}

 {compute the size of the current window pane}
 pane.h := theWindow^.portRect.right - theWindow^.portRect.left - sBarWidth;
 pane.v := theWindow^.portRect.bottom - theWindow^ - sBarHeight;

 {scale the pane into the OV window to show size }
 SetRect( tempRect, 0, 0, pane.h, pane.v );
 MapRect( tempRect, viewRect, OV^.portRect );
 scope := tempRect;
 {make the region to drag around.  same size as scope}
 dragRectRgn := NewRgn;
 RectRgn( dragRectRgn,scope );
 {this works to limit the movement of dragRectRgn}
 SetRect( limitRect, 0, 0, OV^.portRect.right-scope.right+1,
OV^.portRect.bottom-scope.bottom+1 );
 {scale scrollPosition into OV for placing scope in OV}
 tempPt := scrollPosition;
 MapPt( tempPt, viewRect, OV^.portRect );
 OffSetRect( scope, tempPt.h, tempPt.v );

 end; {OV_Prepare}
 Procedure OV_PositionOverView;
 var offset : Point;
 SetPort( oldPort );
 offset := where;
 GlobalToLocal ( offset );
 h := offset.h;  {local value of mousedown}
 v := offset.v;
 {make sure it doesn't go off the bottom of the window}
 if (v + OV^.portRect.bottom) >= theWindow^.portRect.bottom
 then v := theWindow^.portRect.bottom - OV^.portRect.bottom - 1;
 {make sure it doesn't go off the right of the window}
 if (h + OV^.portRect.right) >= theWindow^.portRect.right
 then h := theWindow^.portRect.right - OV^.portRect.right - 1;
 {make sure it doesn't go off the top of the window}
 if v < theWindow^ then v := theWindow^;
 {make sure it doesn't go off the left of the window}
 if h < theWindow^.portRect.left then h := theWindow^.portRect.left;
 SetPt ( offset, h, v);
 LocalToGlobal( offset );
 h := offset.h;
 v := offset.v;
 SetPort( OV );
 MoveWindow( OV, h, v, FALSE );
 end; {OV_PositionOverView}
 procedure OV_SaveBits;
 sizeOfOff: Size;
 offRowBytes:  Integer;
 bitRect: Rect;
 dummy  : Point;
 oldPort: GrafPtr;
 GetPort( oldPort );
 {put window magager port into offport as a windowptr}
 GetWMgrPort( offPort );
 whichWindow := WindowPtr( offPort );
 {allocate a new grafport}
 offPort := GrafPtr( NewPtr( sizeof( GrafPort )));
 {home a copy of the bounds of the OV window}
 bitRect := OV^.portBits.bounds;
 offsetRect( bitRect, -bitrect.left, );
 {compute memory necessary for offscreen bitmap}
 {allocate it and setup bitmap record}
 offRowBytes := ( bitRect.right div 8 ) + 1;
 if Odd( offRowBytes ) then offRowBytes := offRowBytes -1;
 sizeOfOff := bitRect.bottom * offRowBytes;
 with underScope do
 baseAddr := QDPtr( NewPtr( sizeOfOff ));
 rowbytes := offRowBytes;
 bounds   := bitRect;{using HOMEd rectangle}

 {move a copy  back where OV will appear}
 underRect := underScope.bounds;
 OffsetRect( underRect, h-1, v-1 );
 {actually save the bits}
 OpenPort( offPort );
 SetPortBits( underScope );
 SetClip( offPort^.visRgn );
 CopyBits( whichWindow^.portBits, underScope,
underRect, underScope.bounds,srcCopy, NIL);
 SetPort( oldPort );
 ClosePort( offPort );
 DisposPtr( Ptr( offPort ));
 end; {OV_SaveBits}
 Procedure OV_ShowOverView;
 boxHeight: integer;
 ShowHide( OV, TRUE );  {now window appears}
 {blast miniature picture into OV}
 CopyBits(OV_pagePict, OV^.portBits, 
OV_pagePict.bounds, OV^.portRect,srcCopy,nil);
 {highlight the current selection}
 InvertRect( scope );
 {give the user some room to be sloppy}
 slopRect := OV^.portRect;
 InsetRect( slopRect, -25, -25 );
 GlobalToLocal( where );
 {compute size of draggable region and center it }
 boxWidth := scope.right - scope.left;
 boxHeight := scope.bottom -;
 OffsetRgn( dragRectRgn, where.h-(boxWidth div 2), 
where.v-(boxHeight div 2) );
 OffSetRect( limitRect, boxWidth div 2, boxHeight div 2); 
 {let the user drag it around}
 value := DragGrayRgn( dragRectRgn,where,limitRect, slopRect,0,nil );
 end; {OV_ShowOverView}
 Procedure OV_RestoreBits;
 var underRect: Rect;
   underRect := underScope.bounds;
 {home the rectangle}
 {position it correctly}
   OffSetRect( underRect, h-1, v-1);
 {blast stuff under window back into position}
 CopyBits( underScope, whichWindow^.portBits, 
underScope.bounds, underRect,srcCopy, NIL);
 {deallocate the bitmap space (be nice and clean)}
 DisposPtr( Ptr( underScope.baseAddr ));
 end; {OV_RestoreBits}
 Procedure OV_HandleSelection;
 Procedure OV_FlashSelection;
 var i: Integer;
 j: LongInt;
 HLock( Handle( dragRectRgn ));  {good habit!}
 for i := 1 to 2*MenuFlash^ do begin
 InvertRect( dragRectRgn^^.rgnBBox );
 delay( 4,j );
 HUnLock( Handle( dragRectRgn ));  {yep!}
 begin {OV_HandleSelection}
 if (HiWord(value)<>-32768) or (LoWord(value)<>-32768)
 then   {user actually made a selection}
 InvertRect( scope );{turn off current selection}
 ShowHide( OV, FALSE ); {hide the OV window}
 SetPort( oldPort );
 OV_RestoreBits; {blast bits back into place}

 {figure the new scrollPosition based on the top-left corner}
 {of the draggable region}
 SetPt( tempPt, dragRectRgn^^.rgnBBox.left, dragRectRgn^^ 
 MapPt( tempPt, OV^.portRect, viewRect );
 scrollPosition := tempPt;
 tempRect := viewRect;
 tempRect.bottom := tempRect.bottom - pane.v;
 tempRect.right := tempRect.right - pane.h;
 MapPt ( tempPt, tempRect, viewRect );
 {set the new scroll bar values}
 SetCtlValue( HScrollBar, tempPt.h );
 SetCtlValue( VScrollBar, tempPt.v );
 InvalRect( theWindow^.portRect );
 else   {no selection was made}
 ShowHide( OV, FALSE ); {hide window}
 SetPort( oldPort );
 OV_RestoreBits; {replace underneath bits}
 BeginUpdate( theWindow );
 {steal update events}
 EndUpdate  ( theWindow );
 end; {OV_HandleSelection}
 Procedure OV_TidyUp;
 DisposeRgn( dragRectRgn );
 end; {OV_TidyUp}
end; {OverViewSelect}
END. {UNIT OverView}

program OverView_Sample;
{OverView Sample
 Version 1.0Scott T. Boyd
 Monday, July 14, 1986 3:32:00 AM }

{Compiler Switch Settings}
{$R+}   {range checking on}
{$OV+}  {overflow checking on}

uses MemTypes, QuickDraw, OSIntf, ToolIntf, {$U OverView.p}  OverView;

 AppleID = 1;    {Menu ID for Apple menu}
    AboutItem  = 1;  {Item number for About... command}
 FileID  = 2;             {Menu ID for File menu}
    QuitItem    = 1;    {Item number for Quit command}
 EditID  = 3;             {Menu ID for Edit menu}
    UndoItem   = 1;       {Item number for Undo command}
    CutItem    = 3;       {Item number for Cut command}
    CopyItem   = 4;       {Item number for Copy command}
    PasteItem  = 5;       {Item number for Paste command}
    ClearItem  = 6;       {Item number for Clear command}
 ViewID = 4;{Menu ID for for View menu}
    ScreenItem = 1;{Item for Screen res command}
    ImageItem  = 2;{Item for 2 times magnify view cmd}
    LaserItem  = 3;{Item for 4 times magnify view cmd}

 AppleMenu     : MenuHandle;
 FileMenu        : MenuHandle;
 EditMenu      : MenuHandle;
 ViewMenu : MenuHandle;

type modes = (screen,image,laser);

 MScope,{for the OverView window record}
 TheWindow: windowPtr;  {fordocument view window}
 OldPort  : GrafPtr; {to keep things tidy}
 TheEvent : EventRecord;
 LaserViewRect,  {the different document sizes}
 ImageViewRect,  {the different document sizes}
 ScreenViewRect, {the different document sizes}
 viewRect : Rect;{the most current size}
 viewmode : modes; {the most current mode}
 myBitMap : BitMap;{OverView offscreen minipict}

 VScrollBar,{Handle to vert scroll bar}
 HScrollBar : ControlHandle;     {Handle to hor scroll bar}
 scrollPosition : Point;  {Current scroll position}


procedure SetUpWindow;
{ Create TheWindow, the "viewing" window that stays up all the time }

 dummyRect : Rect;
begin {SetUpWindow}
 with ScreenBits.bounds do {use all avail screen space}
 begin    := top+MenuBarHeight+ScreenMargin+TitleBarHeight;
 dummyRect.left   := left+ScreenMargin;
 dummyRect.bottom := bottom-ScreenMargin;
 dummyRect.right  := right-ScreenMargin;
 TheWindow := NewWindow (nil, dummyRect, 'PopUp 2D Random Access Scroll 
Bar Menu',true, NoGrowDocProc, WindowPtr(-1), true, longint(0));
end;  {SetUpWindow}


procedure SetUpControls;
{ Create and initialize TheWindow's verti and hor scroll bars }
 VScrollRect, HScrollRect : Rect;
begin   {SetUpControls}
 with TheWindow^.portRect do 
 SetRect( VScrollRect, right-15, top-1, right+1, bottom-14 );
 with TheWindow^.portRect do 
 SetRect( HScrollRect, left+15, bottom-15, right-14,  bottom+1 );
 VScrollBar  := NewControl(TheWindow, VScrollRect,'',TRUE, 0, 0, viewRect.bottom,ScrollBarProc, 
 HScrollBar  := NewControl(TheWindow, HScrollRect,'',TRUE, 0, 0, viewRect.right,ScrollBarProc, 
end;  {SetUpControls}


procedure SetUpMenus;
 appleTitle: String[1];
begin  {SetUpMenus}
 appleTitle := ' ';
 appleTitle[1] := chr(appleMark);
 AppleMenu := NewMenu(AppleID,appleTitle);   {Create Apple menu}
 AppendMenu(AppleMenu, 'Sorry, just for looks ;(-');
 AddResMenu(AppleMenu, 'DRVR');  {Add desk acc}
 InsertMenu(AppleMenu, 0);{Install at end bar}
 FileMenu := NewMenu(FileID,'File'); {create File menu}
 InsertMenu(FileMenu, 0); {Install at end of bar}
 EditMenu := NewMenu(EditID,'Edit'); {create Edit menu}
 InsertMenu(EditMenu, 0); {Install at end of bar}
 ViewMenu := NewMenu(ViewID,'Document Size');
 InsertMenu(ViewMenu, 0); {Install at end of menu bar}
 AppendMenu(ViewMenu,'Screen Resolution');
 AppendMenu(ViewMenu,'ImageWriter Resolution');
 AppendMenu(ViewMenu,'LaserWriter Resolution');
 DrawMenuBar;                      {Show new menu bar on screen}
end;  {SetUpMenus}


procedure DoViewChoice(theItem: INTEGER);
{ Handle a selection from the Document Size menu }
{ NOTE:  It's a bit of work to support multiple document sizes! }

 paneSize : Point;
 case theItem of {select the new virtual document size}
 ScreenItem: viewRect := screenViewRect;
 ImageItem: viewRect := imageViewRect;
 LaserItem: viewRect := laserViewRect;
 end; {case}

 CheckItem(ViewMenu, ScreenItem, false);     {turn off the checkmarks}
 CheckItem(ViewMenu, ImageItem, false);{definitely a brute force method}
 CheckItem(ViewMenu, LaserItem, false);
 CheckItem(ViewMenu, theItem, true);         { checkmark}
 {Reset the scroll bars for the new rectangle size}
 paneSize.h:=TheWindow^.portrect.right - TheWindow^.portrect.left - SBarWidth;
 paneSize.v:=TheWindow^.portrect.bottom - TheWindow^ - SBarHeight;
 SetCtlMax(VScrollBar,viewRect.bottom - paneSize.v);
 if viewRect.right < paneSize.h  {Lisa's wide screen}
 then SetCtlMax(HScrollBar,0) {can't scroll if it shows}
 else SetCtlMax(HScrollBar,viewRect.right - paneSize.h);

 HiliteControl(VScrollBar, 0);
 HiliteControl(HScrollBar, 0);
end; { DoViewChoice}


procedure DoMenuClick;
{  Handle mouse-down event in menu bar.  }
 menuChoice : LONGINT;    {Menu ID and item number}
 theMenu : INTEGER;{Menu ID of selected menu}
 theItem : INTEGER;{Item number of selected item}
begin {DoMenuClick}
 menuChoice := MenuSelect(TheEvent.where);   {Track mouse}
 if menuChoice <> 0 then  {Nothing to do if 0}
 theMenu := HiWord(menuChoice); {Get menu ID}
 theItem := LoWord(menuChoice);   {Get item}
 case theMenu of
 AppleID: {DoAppleChoice(theItem)};
 FileID:  if theItem = QuitItem then ExitToShell;
 EditID:  {DoEditChoice(theItem)};
 ViewID:  DoViewChoice(theItem); {only menu}
 HiliteMenu(0);                      {Unhighlight menu title}
 end; {if MenuChoice}
end; {DoMenuClick}


procedure DoMouseDown;
{  Handle mouse-down event.  }
 whichWindow : WindowPtr; {Window mouse pressed in}
 thePart : INTEGER;{Part of screen }
begin {DoMouseDown}
 {Where on the screen was mouse pressed?}
 thePart := FindWindow(TheEvent.where, whichWindow); 
 case thePart of
 InDesk:         {Do nothing};
 InMenuBar:    DoMenuClick;
 InSysWindow:  {Do nothing};
 InContent: OverViewSelect( TheEvent.where,viewRect, scrollPosition,
 InDrag:         {Do nothing};
 InGrow:         {Do nothing};
 InGoAway:    if TrackGoAway(TheWindow, TheEvent.where) 
 then ExitToShell;
 end; {case}
end;  {DoMouseDown}


Procedure DrawPoop;
 {just enough here to show you how to call it}

 InitGraf(@ThePort); {obligatory material goes here}
 InitDialogs( NIL );
 SetRect ( LaserViewRect, 0, 0, 2549, 3299 );
 SetRect ( ImageViewRect, 0, 0, 1274, 1649 );
 SetRect ( ScreenViewRect, 0, 0, 636, 824 );
 SetPt ( scrollPosition, 0, 0 );


 viewmode := screen;
 CheckItem(ViewMenu, ScreenItem, true);{turn on the checkmark}
 case viewmode of
 screen: viewRect := screenViewRect;
 image : viewRect := imageViewRect;
 laser : viewRect := laserViewRect;
 {SetUpControls is dependent on ViewRect being defined}

 {Create a window for TheWindow.  Make it 1/2 the available
  screen height.  Use myBitMap as the BitMap record, and       point 
to the new window with MScope}

 NewOverView( myBitMap, MScope, viewRect, 0.5 );
 {Draw into the offscreen bitmap with DrawPoop}
 UpdateOverView ( DrawPoop, myBitMap );
 if GetNextEvent(EveryEvent, TheEvent) then
 case TheEvent.what of
 MouseDown:  DoMouseDown;
   KeyDown:     {Do nothing};
   UpdateEvt:   {Do nothing};
   ActivateEvt: {Do nothing};
 otherwise {Do nothing};
 end {case}
 until TheEvent.what = KeyDown;  {quit if key pressed}

Community Search:
MacTech Search:

Software Updates via MacUpdate

PDFpen 8.2.1 - $74.95
PDFpen allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Features... Read more
TextMate 2.0-beta.12.25 - Code/markup ed...
TextMate is a versatile plain text editor with a unique and innovative feature set which caused it to win an Apple Design Award for Best Mac OS X Developer Tool in August 2006. A rapidly growing... Read more
TunnelBear 3.0.4 - Subscription-based pr...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more
QuickBooks R9 - Financial ma...
QuickBooks helps you manage your business easily and efficiently. Organize your finances all in one place, track money going in and out of your business, and spot areas where you can save. Built for... Read more
1Password 6.3.5 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
PDFpenPro 8.2.1 - $124.95
PDFpenPro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Create fillable forms and tables of content... Read more
1Password 6.3.5 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
QuickBooks R9 - Financial ma...
QuickBooks helps you manage your business easily and efficiently. Organize your finances all in one place, track money going in and out of your business, and spot areas where you can save. Built for... Read more
TextMate 2.0-beta.12.25 - Code/markup ed...
TextMate is a versatile plain text editor with a unique and innovative feature set which caused it to win an Apple Design Award for Best Mac OS X Developer Tool in August 2006. A rapidly growing... Read more
TunnelBear 3.0.4 - Subscription-based pr...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more

Latest Forum Discussions

See All

Best Fiends Forever Guide: How to collec...
The fiendship in Seriously's hit Best Fiends has been upgraded this time around in Best Fiends Forever. It’s a fast-paced clicker with lots of color and style--kind of reminiscent of a ‘90s animal mascot game like Crash Bandicoot. The game... | Read more »
5 apps for the budding mixologist
Creating your own cocktails is something of an art form, requiring a knack for unique tastes and devising interesting combinations. It's easy to get started right in your own kitchen, though, even if you're a complete beginner. Try using one of... | Read more »
5 mobile strategy games to try when you...
Strategy enthusiasts everywhere are celebrating the release of Civilization VI this week, and so far everyone seems pretty satisfied with the first full release in the series since 2010. The series has always been about ultra-addictive gameplay... | Read more »
Popclaire talk to us about why The Virus...
Humanity has succumbed to a virus that’s spread throughout the world. Now the dead have risen with a hunger for human flesh, and all that remain are a few survivors. One of those survivors has just called you for help. That’s the plot in POPCLAIRE’... | Read more »
Oceans & Empires preview build sets...
Hugely ambitious sea battler Oceans & Empires is available to play in preview form now on Google Play - but download it quickly, as it’s setting sail away in just a few days. [Read more] | Read more »
Rusty Lake: Roots (Games)
Rusty Lake: Roots 1.1.4 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1.4 (iTunes) Description: James Vanderboom's life drastically changes when he plants a special seed in the garden of the house he has inherited.... | Read more »
Flippy Bottle Extreme! and 3 other physi...
Flippy Bottle Extreme! takes on the bottle flipping craze with a bunch of increasingly tricky physics platforming puzzles. It's difficult and highly frustrating, but also addictive. When you begin to master the game, the sense of achievement is... | Read more »
Plants vs. Zombies Heroes guide: How to...
Plants vs. Zombies Heroes surprised us all, presenting a deep deck building experience. It's a great CCG that stands up well to the competition. There are a lot of CCGs vying for players' attention at the moment, but PvZ Heroes is definitely one... | Read more »
Arcane Online takes Online RPG’s to anot...
If you think that you need a desktop to enjoy high quality MMO gaming then Arcane Online hopes to prove you emphatically wrong. An epic fantasy Online RPG set in the land of Eldine, Arcane Online offers an abundance of features and content that... | Read more »
It’s time to step up and start your spoo...
So you’ve just downloaded Seekers Notes: Hidden Mystery, and you obviously want to hit the ground running. Well you’re in luck because you just so happen to be reading our very useful guide to playing. First released in July last year, the game has... | Read more »

Price Scanner via

Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
Apple, Samsung, Lead J.D. Power Smartphone Sa...
Customer satisfaction is much higher among smartphone owners currently subscribing to full-service wireless carriers, compared with those purchasing service through a non-contract carrier, according... Read more
Select 9-inch Apple WiFi iPad Pros on sale fo...
B&H Photo has select 9.7″ Apple WiFi iPad Pros on sale for up to $50 off MSRP, each including free shipping. B&H charges sales tax in NY only: - 9″ Space Gray 256GB WiFi iPad Pro: $799 $0 off... Read more
Apple refurbished 13-inch Retina MacBook Pros...
Apple has Certified Refurbished 13″ Retina MacBook Pros available for up to $270 off the cost of new models. An Apple one-year warranty is included with each model, and shipping is free: - 13″ 2.7GHz... Read more
Apple refurbished 15-inch Retina MacBook Pros...
Apple has Certified Refurbished 2015 15″ Retina MacBook Pros available for up to $380 off the cost of new models. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2... Read more
Apple refurbished 11-inch MacBook Airs availa...
Apple has Certified Refurbished 11″ MacBook Airs (the latest models), available for up to $170 off the cost of new models. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
Apple refurbished Apple TVs available for up...
Apple has Certified Refurbished 32GB and 64GB Apple TVs available for up to $30 off the cost of new models. Apple’s standard one-year warranty is included with each model, and shipping is free: -... Read more
15-inch Retina MacBook Pros on sale for $200...
B&H Photo has 15″ Retina Apple MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799 $200 off MSRP - 15″ 2.5GHz Retina... Read more
Apple refurbished 2016 13-inch MacBook Airs a...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 2016 13″ 1.6GHz/8GB/128GB MacBook... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more

Jobs Board

Security Data Analyst - *Apple* Information...
…data sources need to be collected to allow Information Security to better protect Apple employees and customers from a wide range of threats.Act as the subject Read more
*Apple* Retail - Multiple Positions (Multi-L...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- New Yor...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions- Yonkers...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Senior Manager, Security Engineering - *Appl...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.