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

BusyCal 2.6.6 - Powerful calendar app wi...
BusyCal is an award-winning desktop calendar that combines personal productivity features for individuals with powerful calendar sharing capabilities for families and workgroups. BusyCal's unique... Read more
MegaSeg 5.9.6 - Professional MP3 DJ appl...
MegaSeg is a complete solution for pro audio/video DJ mixing, radio automation, and music scheduling with rock-solid performance and an easy-to-use design. Mix with visual waveforms and Magic... Read more
KeyCue 7.5 - Displays all menu shortcut...
Need more than one license? Get KeyCue Family for just $15.99. KeyCue lets you view available Command key shortcuts. Simply press and hold the Command key to view a list of all available keyboard... Read more
Apple Pro Video Formats 2.0.1 - Updates...
Apple Pro Video Formats brings updates to Apple's professional-level codes for Final Cut Pro X, Motion 5, and Compressor 4. Version 2.0.1: Support for the following professional video codecs Apple... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
EtreCheck 2.2 - For troubleshooting your...
EtreCheck is a simple little app to display the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support... Read more
OmniOutliner Pro 4.2 - Pro version of th...
OmniOutliner Pro is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
VLC Media Player 2.2.1 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Nisus Writer Pro 2.1.1 - Multilingual wo...
Nisus Writer Pro is a powerful multilingual word processor, similar to its entry level products, but brings new features such as table of contents, indexing, bookmarks, widow and orphan control,... Read more
Tinderbox 6.2.0 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more

Lifeline... (Games)
Lifeline... 1.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1 (iTunes) Description: Lifeline is a playable, branching story of survival against all odds. Using your iPhone, iPad, or Apple Watch, you will help... | Read more »
Pandemic: The Board Game Has Gone Univer...
Don't let the virus win! Now you can download Pandemic: The Board Game, by F2Z Digital Media, for all of your iOS devices. The app is based on the fantastic board game by Z-man games. As employees of the CDC, you and your friends will have to work... | Read more »
Get Ready to Read Bloomberg Business on...
Fans of Bloomberg Business will soon be able to get all their news on the Apple Watch. The app lets you get the top headlines on your main screen and bookmark stories to read later. Using the motion detection in the Apple Watch, the headlines are... | Read more »
Watch This Homerun is Batting for the Ap...
Eyes Wide Games' Watch This Homerun is purportedly the first sports game coming to the Apple Watch, where you'll be up to bat as the pitcher tries to out-manuever you with fastballs, curveballs, and changeups. Using one-touch controls you can try to... | Read more »
Field Trip Can Take You on a Guided Tour...
Field Trip, by Google’s Niantic Labs, is an exploration app that gives you details about the awesome places you can discover wherever you find yourself. The app can show you local history, delicious restraunts, the best places to shop, and places to... | Read more »
Watch Your Six - SPY_WATCH is Infiltrati...
SPY_WATCH, by Bossa Studios, is a new game designed for the Apple Watch. Runmor has it your spy agency has fallen out of favor. To save it, you'll need to train-up a spy and send them on missions to earn you a stunningly suspicious reputation and... | Read more »
Both Halo: Spartan Assault and Halo: Spa...
Halo: Spartan Assault and Halo: Spartan Strike, by Microsoft, have officially landed on the App Store. Spartan Assault pits you against the Covenant with missions geared to tell the story of the origin of Spartan Ops. In Spartan Strike you'll delve... | Read more »
The Apple Watch Could Revolutionize the...
It’s not here yet but there’s that developing sneaky feeling that the Apple Watch, despite its price tag and low battery life, might yet change quite a lot about how we conduct our lives. While I don’t think it’s going to be an overnight... | Read more »
Mad Skills Motocross 2 Version 2.0 is He...
Mad Skills Motocross 2 fans got some good news this week as Turborilla has given the game its biggest update yet. Now you'll have access to Versus mode where you can compete against your friends in timed challenges. Turborilla has implemented a... | Read more »
Kids Can Practice Healthy Living With Gr...
Bobaka is releasing a new interactive book called Green Riding Hood  in May. The app teaches kids about yoga and organic style of life through mini-games and a fun take on the classic Little Red Riding Hood fairy tale. | Read more »

Price Scanner via MacPrices.net

Sale! 15-inch Retina MacBook Pros for up to $...
 MacMall has 15″ Retina MacBook Pros on sale for up to $255 off MSRP. Shipping is free: - 15″ 2.2GHz Retina MacBook Pro: $1794.99 save $205 - 15″ 2.5GHz Retina MacBook Pro: $2244.99 save $255 Adorama... Read more
New 2015 MacBook Airs on sale for up to $75 o...
Save up to $75 on the purchase of a new 2015 13″ or 11″ 1.6GHz MacBook Air at the following resellers. Shipping is free with each model: 11" 128GB MSRP $899 11" 256GB... Read more
Clearance 13-inch Retina MacBook Pros availab...
B&H Photo has leftover 2014 13″ Retina MacBook Pros on sale for up to $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.6GHz/128GB Retina MacBook Pro: $1129... Read more
Clearance 2014 MacBook Airs available startin...
B&H Photo has clearance 2014 MacBook Airs available for up to $200 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 128GB MacBook Air: $729 $170 off original MSRP... Read more
16GB iPad mini 3 on sale for $349, save $50
B&H Photo has the 16GB iPad mini 3 WiFi on sale for $349 including free shipping plus NY sales tax only. Their price is $50 off MSRP, and it’s the lowest price available for this model. Read more
Mac minis on sale for up to $75 off, starting...
MacMall has Mac minis on sale for up to $75 off MSRP including free shipping. Their prices are the lowest available for these models from any reseller: - 1.4GHz Mac mini: $459.99 $40 off - 2.6GHz Mac... Read more
Taichi Temple First Tai Chi Motion Sensor App...
Zhen Wu LLC has announced the official launch of Taichi Temple 1.0, the first motion sensor app for Tai Chi, offering a revolutionary new way to de-compress, relax and exercise all at the same time.... Read more
CleanExit – Erase your Hard Drive Quickly, Se...
CleanExit works on both Macs and PCs, securely and permanently deleting all files from any type of hard drive, flash-based drive or camera media card making the files permanently unrecoverable.... Read more
250 iPhone 6 Tips eBook Released for $1.99
Bournemouth, UK based iOS Guides has released 250 iPhone 6 Tips, a new eBook available in the iBookstore that reveals a wealth of tips and tutorials for iPhone 6 and iPhone 6 Plus. Priced at $1.99,... Read more
TigerText Introduces First Secure Enterprise...
TigerText, a provider of secure, real-time messaging for the enterprise, has announced the launch of TigerText for the Apple Watch. TigerText for the Apple Watch enables users to securely send and... Read more

Jobs Board

*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
DevOps Software Engineer - *Apple* Pay, iOS...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Pay - Site Reliability Engineer - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.