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.

Summary

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}

INTERFACE

{Compiler Switch Settings}
{$R+}
{$OV+}
uses MemTypes, QuickDraw, OSIntf, ToolIntf, SANE;
const
 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);

IMPLEMENTATION

Procedure NewOverView {( var OV_pagePict : bitMap; 
 var OV : WindowPtr; viewRect : Rect; factor : Real )};
var
 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- ScreenBits.bounds.top-MenuBarHeight;
 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 := (bitRect.bottom-bitRect.top) * offRowBytes;
 with OV_pagePict do
 begin
 baseAddr := QDPtr( NewPtr( sizeOfOff ));
 rowBytes := offRowBytes;
 bounds   := bitRect;
 end;
 
 {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)};
var
 offPort,
 oldPort: GrafPtr;
begin
 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)};
var
 MenuFlash: ^Integer;{system global}
 value, {value returned by TrackGrayRgn}
 h, v:  LongInt; {}
 pane,  {}
 tempPt:  Point; {}
 scope, {size of window pane scaled into OV window}
 tempRect,
 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;
 begin
 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^.portRect.top - 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;
 begin
 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^.portRect.top then v := theWindow^.portRect.top;
 {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;
 var
 sizeOfOff: Size;
 offRowBytes:  Integer;
 underRect,
 bitRect: Rect;
 dummy  : Point;
 offPort,
 oldPort: GrafPtr;
 begin
 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, -bitrect.top );
 {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
 begin
 baseAddr := QDPtr( NewPtr( sizeOfOff ));
 rowbytes := offRowBytes;
 bounds   := bitRect;{using HOMEd rectangle}
 end;

 {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;
 var
 boxWidth, 
 boxHeight: integer;
 begin 
 OV_SaveBits;
 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 - scope.top;
 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;
 begin
   underRect := underScope.bounds;
 {home the rectangle}
   OffsetRect(underRect,-underRect.left, -underRect.top);
 {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;
 begin
 HLock( Handle( dragRectRgn ));  {good habit!}
 for i := 1 to 2*MenuFlash^ do begin
 InvertRect( dragRectRgn^^.rgnBBox );
 delay( 4,j );
 end;
 HUnLock( Handle( dragRectRgn ));  {yep!}
 end;
 {------------------------}
 begin {OV_HandleSelection}
 if (HiWord(value)<>-32768) or (LoWord(value)<>-32768)
 then   {user actually made a selection}
 begin
 InvertRect( scope );{turn off current selection}
 OV_FlashSelection;
 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^^.rgnBBox.top 
);
 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 );
 end
 else   {no selection was made}
 begin
 ShowHide( OV, FALSE ); {hide window}
 SetPort( oldPort );
 OV_RestoreBits; {replace underneath bits}
 BeginUpdate( theWindow );
 {steal update events}
 EndUpdate  ( theWindow );
 end;
 end; {OV_HandleSelection}
 {----------------------------------}
 Procedure OV_TidyUp;
 begin
 DisposeRgn( dragRectRgn );
 end; {OV_TidyUp}
 {----------------------------------}
begin
 OV_Prepare;
 OV_PositionOverView;
 OV_ShowOverView;
 OV_HandleSelection;
 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;

const
 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}

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

type modes = (screen,image,laser);

var 
 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}

var
 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 }

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

{--------------------------------------------------------------------------}

procedure SetUpControls;
{ Create and initialize TheWindow's verti and hor scroll bars }
var
 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, 
Longint(0));
 HScrollBar  := NewControl(TheWindow, HScrollRect,'',TRUE, 0, 0, viewRect.right,ScrollBarProc, 
Longint(0));
end;  {SetUpControls}

{--------------------------------------------------------------------------}

procedure SetUpMenus;
var 
 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}
 AppendMenu(FileMenu,'Quit');
 EditMenu := NewMenu(EditID,'Edit'); {create Edit menu}
 InsertMenu(EditMenu, 0); {Install at end of bar}
 AppendMenu(EditMenu,'Undo;(-;Cut;Copy;Paste;Clear');
 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! }

var 
 paneSize : Point;
begin
 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^.portrect.top - SBarHeight;
 SetPt(ScrollPosition,0,0);
 SetCtlValue(VScrollBar,0);
 SetCtlValue(HScrollBar,0);
 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);

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

{--------------------------------------------------------------------------}

procedure DoMenuClick;
{  Handle mouse-down event in menu bar.  }
var
 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}
 begin
 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}
 end;
 HiliteMenu(0);                      {Unhighlight menu title}
 end; {if MenuChoice}
end; {DoMenuClick}

{----------------------------------------------------------}

procedure DoMouseDown;
{  Handle mouse-down event.  }
var
 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,
MScope,myBitMap,HScrollBar,VScrollBar);
 InDrag:         {Do nothing};
 InGrow:         {Do nothing};
 InGoAway:    if TrackGoAway(TheWindow, TheEvent.where) 
 then ExitToShell;
 end; {case}
end;  {DoMouseDown}

{----------------------------------------------------------}

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

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

 SetUpMenus;

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

 {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 );
 
 repeat
 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}
end.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Art Text 3.2.3 - $49.99
Art Text is graphic design software specifically tuned for lettering, typography, text mockups and various artistic text effects. Supplied with a great variety of ready to use styles and materials,... Read more
RapidWeaver 7.5.1 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
PDFKey Pro 4.3.9 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
ClamXav 2.15.2 - Virus checker based on...
ClamXav is a popular virus checker for OS X. I have been working on ClamXav for more than 10 years now, and over those years, I have invested a huge amount of my own time and energy into bringing... Read more
TechTool Pro 9.5.3 - Hard drive and syst...
TechTool Pro has long been one of the foremost utilities for keeping your Mac running smoothly and efficiently. With the release of version 9, it has become more proficient than ever. TechTool... Read more
Safari Technology Preview 11.1 - The new...
Safari Technology Preview contains the most recent additions and improvements to WebKit and the latest advances in Safari web technologies. And once installed, you will receive notifications of... Read more
Google Chrome 61.0.3163.91 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Dropbox 35.4.20 - Cloud backup and synch...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
GraphicConverter 10.5 - $39.95
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
Chromium 61.0.3163.91 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 61.0.3163.91: Release notes were unavailable... Read more

Stormbound: Kingdom Wars guide - how to...
Stormbound: Kingdom Wars is an excellent new RTS turned card battler out now on iOS and Android. Lovers of strategy will get a lot of enjoyment out of Stormbound's chess-like mechanics, and it's cardbased units are perfect for anyone who loves the... | Read more »
The best AR apps and games on iOS right...
iOS 11 has officially launched, and with it comes Apple's ARKit, a helpful framework that makes it easier than ever for developers to create mobile AR experiences. To celebrate the occassion, we're featuring some of the best AR apps and games on... | Read more »
Phoenix Wright: Ace Attorney - Spirit of...
Phoenix Wright: Ace Attorney - Spirit of Justice 1.00.00 Device: iOS Universal Category: Games Price: $.99, Version: 1.00.00 (iTunes) Description: ************************************************※IMPORTANT※・Please read the “When... | Read more »
Kpressor (Utilities)
Kpressor 1.0.0 Device: iOS Universal Category: Utilities Price: $4.99, Version: 1.0.0 (iTunes) Description: The ultimate ZIP compression application for iPhone and iPad. - Full integration of iOS 11 with support for multitasking.-... | Read more »
Find out how you can save £35 and win a...
Nothing raises excitement like a good competition, and we’re thrilled to announce our latest contest. We’ll be sending one lucky reader and a friend to the Summoners War World Arena Championship at Le Comedia in Paris on October 7th. It’s the... | Read more »
Another Lost Phone: Laura's Story...
Another Lost Phone: Laura's Story 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Another Lost Phone is a game about exploring the social life of a young woman whose phone you have just... | Read more »
The Witness (Games)
The Witness 1.0 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0 (iTunes) Description: You wake up, alone, on a strange island full of puzzles that will challenge and surprise you. You don't remember who you are, and... | Read more »
Egg, Inc. guide - how to build your gold...
Egg, Inc.'s been around for some time now, but don't you believe for one second that this quirky clicker game has gone out of style. The game keeps popping up on Reddit and other community forums thanks to the outlandish gameplay (plus, the... | Read more »
The best deals on the App Store this wee...
Good news, everyone! Your favorite day of the week has arrived at last -- it's discount roundup day! This fine Wednesday evening we're gathering up the hottest deals on the App Store. We've got action platformers, we've got puzzle games, we've got... | Read more »
Morphite (Games)
Morphite 1.08 Device: iOS Universal Category: Games Price: $7.99, Version: 1.08 (iTunes) Description: | Read more »

Price Scanner via MacPrices.net

OWC USB-C Travel Dock with 5 Ports Connectivi...
OWC have announced the new OWC USB-C Travel Dock, the latest addition to their line of connectivity solutions. The USB-C Travel Dock lets you connect its integrated USB-C cable to a Mac or PC laptop... Read more
Pelican Products, Inc. Unveils Cases For All...
Pelican Products, Inc. has announced the launch of its full line of cases including Voyager, Adventurer, Protector, Ambassador, Interceptor (for the Apple iPhone 8 and 8 Plus backwards compatible... Read more
$100 off new 2017 13-inch MacBook Airs
B&H Photo has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. B&H charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off... Read more
Apple restocks Certified Refurbished 13-inch...
Apple has Certified Refurbished 2015 13″ MacBook Airs available starting at $719 and 2016 models available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
Is iPhone X Really The Future Of The Smartpho...
Should iPhone X even be called a telephone? It does of course support telephony and texting, but its main feature set is oriented to other things. It is also debatable whether it makes any rational... Read more
OtterBox Announces Full Case Lineup for iPhon...
Apple revolutionized the smartphone industry 10 years ago with the original iPhone, and OtterBox has set the standard of protection from the very beginning by protecting every generation of iPhone.... Read more
LifeProof Introduces What’s NEXT Cases for iP...
LifeProof built its reputation on sleek, ultra-protective iPhone cases. From 360-degree coverage to the first screenless waterproof case, the protection pioneer has always pushed the limits.... Read more
Apple Refurbished 2016 15-inch MacBook Pros a...
Apple has Certified Refurbished 2016 15″ Touch Bar MacBook Pros available starting at $1949. An Apple one-year warranty is included with each model, and shipping is free: – 15″ 2.7GHz Touch Bar Space... Read more
Wednesday deal: 15-inch MacBook Pros for up t...
B&H Photo has 2017 15″ MacBook Pros on sale for $150-$200 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 15″ 2.8GHz MacBook Pro Space Gray: $2199, $200 off MSRP... Read more
2.6GHz Mac mini on sale for $599, $100 off MS...
B&H Photo has the 2.6GHz Mac mini (MGEN2LL/A) on sale for $599 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more

Jobs Board

Full time *Apple* Hardware Tech needed - ma...
…high level of attention to detail Ethics, integrity and trust Be a geek & Previous Apple experience a must. Previous Apple Retail or other Apple Specialist Read more
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
*Apple* Store - Technical Specialist - Apple...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
*Apple* Retail - Multiple Positions - Apple,...
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* News Product Marketing Mgr., Publish...
Job Summary The Apple News Product Marketing Manager will work closely with a cross-functional group to assist in defining and marketing new features and services. Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.