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

The best GIF making apps
Animated GIFs have exploded in popularity recently which is likely thanks to a combination of Tumblr, our shorter attention spans, and the simple fact they’re a lot of fun. [Read more] | Read more »
The best remote desktop apps for iOS
We've been sifting through the App Store to find the best ways to do computer tasks on a tablet. That gave us a thought - what if we could just do computer tasks from our tablets? Here's a list of the best remote desktop apps to help you use your... | Read more »
Warhammer 40,000: Freeblade guide - How...
Warhammer 40,000: Freebladejust launched in the App Store and it lets you live your childhood dream of blowing up and slashing a bunch of enemies as a massive, hulking Space Marine. It's not easy being a Space Marine though - and particularly if... | Read more »
Gopogo guide - How to bounce like the be...
Nitrome just launched a new game and, as to be expected, it's a lot of addictive fun. It's called Gopogo, and it challenges you to hoparound a bunch of platforms, avoiding enemies and picking up shiny stuff. It's not easy though - just like the... | Read more »
Sago Mini Superhero (Education)
Sago Mini Superhero 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: KAPOW! Jack the rabbit bursts into the sky as the Sago Mini Superhero! Fly with Jack as he lifts impossible weights,... | Read more »
Star Wars: Galaxy of Heroes guide - How...
Star Wars: Galaxy of Heroes is all about collecting heroes, powering them up, and using them together to defeat your foes. It's pretty straightforward stuff for the most part, but increasing your characters' stats can be a bit confusing because it... | Read more »
The best cooking apps (just in time for...
It’s that time of year again, where you’ll be gathering around the dinner table with your family and a huge feast in front of you. [Read more] | Read more »
Square Rave guide - How to grab those te...
Square Rave is an awesome little music-oriented puzzle game that smacks of games like Lumines, but with its own unique sense of gameplay. To help wrap your head around the game, keep the following tips and tricks in mind. [Read more] | Read more »
Snowboard Party 2 (Games)
Snowboard Party 2 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Crowned the best snowboarding game available on the market, Snowboard Party is back to fulfill all your adrenaline needs in... | Read more »
One Button Travel (Games)
One Button Travel 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: “To cut a long story short, If you like interactive fiction, just go buy this one.” - “Oozes the polish that... | Read more »

Price Scanner via

Holiday weekend Mac sales roundup: B&H Ph...
B&H Photo continues to have all new Macs on sale for up to $500 off MSRP as part of their Black Friday/Holiday weekend sale. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina... Read more
iMobie Releases its Ace iOS Cleaner PhoneClea...
iMobie Inc. has announced the new update of PhoneClean 4, its iOS cleaner designed to reclaim wasted space on iPhone/iPad for use and keep the device fast. Alongside, iMobie hosts a 3-day giveaway of... Read more
U.S. Cellular Offering iPad Pro
U.S. Cellular today announced that it is offering the new iPad Pro with Wi-Fi + Cellular, featuring a 12.9-inch Retina display with 5.6 million pixels — the most ever in an iOS device. U.S. Cellular... Read more
Newegg Canada Unveils Black Friday Deals for...
Newegg Canada is offering more than 1,000 deep discounts to Canadian customers this Black Friday, available now through Cyber Monday, with new deals posted throughout the week. “Black Friday is... Read more
Black Friday: Macs on sale for up to $500 off...
BLACK FRIDAY B&H Photo has all new Macs on sale for up to $500 off MSRP as part of their early Black Friday sale including free shipping plus NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $... Read more
Black Friday: Up to $125 off iPad Air 2s at B...
BLACK FRIDAY Walmart has the 16GB iPad Air 2 WiFi on sale for $100 off MSRP on their online store. Choose free shipping or free local store pickup (if available): - 16GB iPad Air 2 WiFi: $399, save $... Read more
Black Friday: iPad mini 4s on sale for $100 o...
BLACK FRIDAY Best Buy has iPad mini 4s on sale for $100 off MSRP on their online store for Black Friday. Choose free shipping or free local store pickup (if available): - 16GB iPad mini 4 WiFi: $299.... Read more
Black Friday: Apple Watch for up to $100 off...
BLACK FRIDAY Apple resellers are offering discounts and bundles with the purchase of an Apple Watch this Black Friday. Below is a roundup of the deals being offered by authorized Watch resellers:... Read more
Black Friday: Target offers 6th Generation iP...
BLACK FRIDAY Save $40 to $60 on a 6th generation iPod touch at Target with free shipping or free local store pickup (if available). Sale prices for online orders only, in-store prices may vary: -... Read more
Black Friday: Walmart and Target offer iPod n...
BLACK FRIDAY Walmart has the 16GB iPod nano (various colors) on sale for $119.20 on their online store for a limited time. That’s $30 off MSRP. Choose free shipping or free local store pickup (if... Read more

Jobs Board

*Apple* Site Security Manager - Apple (Unite...
# Apple Site Security Manager Job Number: 42975010 Culver City, Califo ia, United States Posted: Oct. 2, 2015 Weekly Hours: 40.00 **Job Summary** The Apple Site Read more
WiSE *Apple* Pay Quality Engineer - Apple (...
# WiSE Apple Pay Quality Engineer Job Number: 44313381 Santa Clara Valley, Califo ia, United States Posted: Nov. 13, 2015 Weekly Hours: 40.00 **Job Summary** Join our Read more
Holiday Retail Associate with *Apple* Knowl...
…and assertive.Someone who can troubleshoot iOS devices (iPhone and iPad) and Apple Mail issues.Someone who can offer solutions.Someone who can work weekends.Someone with Read more
*Apple* Systems Engineer (Mclean, VA and NYC...
Summary:Assist in providing strategic direction and technical leadership within the Apple portfolio, including desktops, laptops, and printing environment. This person Read more
Simply Mac *Apple* Specialist- Service Repa...
Simply Mac is the largest premier retailer of Apple products in the nation. In order to support our growing customer base, we are currently looking for a driven Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.