Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!columbia!topaz!ll-xn!cit-vax!elroy!smeagol!usc-oberon!sdcrdcf!trwrb!scgvaxd!felix!macintosh From: dubois@uwmacc.UUCP (Paul DuBois) Newsgroups: mod.mac.sources Subject: ZoomIdle1.1 (Rascal source) (part 1 of 3) Message-ID: <1392@felix.UUCP> Date: Sat, 26-Jul-86 10:30:33 EDT Article-I.D.: felix.1392 Posted: Sat Jul 26 10:30:33 1986 Date-Received: Tue, 29-Jul-86 23:28:21 EDT Sender: macintosh@felix.UUCP Reply-To: macintosh@felix.UUCP (The Moderator) Organization: FileNet Corp., Costa Mesa, CA Lines: 271 Approved: bytebug@felix.UUCP (Roger L. Long) Here is the Rascal source code for ZoomIdle1.1 --- cut --- Program ZoomIdle; (* ZoomIdle Version 1.1 25 July 1986 Screen saver desk accessory. Generates successive randomly chosen rectangles, and zooms each into the next by interpolating a series of rectangles intermediate in shape and location. Click and hold in menu bar to pause the display. Click below menu bar to terminate. To turn into a desk accessory: Compile and link ZoomIdle1.1.src. Execute DeskMaker (from within Rascal). Choose "Object -> DA" from the "Make" menu. When you get the configuration dialog, change the window type to -1 (no window). During testing from within Rascal, the statement that sets the window's windowKind field should be taken out. Changes since 1.0: Works with Macintosh XL (wider screen). Doesn't clear the menu bar until the window receives an activate event. 1.0 cleared the bar immediately, which was too early - some programs would crash when ZoomIdle exited. Paul DuBois Wisconsin Regional Primate Research Center 1220 Capitol Court University of Wisconsin-Madison Madison, WI 53706 UUCP: {allegra, ihnp4, seismo}!uwvax!uwmacc!dubois ARPA: dubois@easter dubois@unix.macc.wisc.edu *) Uses __QuickDraw __ToolTraps __OSTraps __DeskLib (*$U+*) uToolIntf; (* includes uQuickDraw *) Link __OSTraps __DeskLib : ; EventMask $102; (* mouse-down + activate *) (* zoomSteps controls the number of rectangles that are drawn in each interpolative series. zoomShow controls how many rectangles are visible at once. These two values may be varied independently, but they must both be greater than zero. *) Const zoomSteps = 15; zoomShow = 15; Var thePort: WindowPtr; theMenuBar: Handle; zRect: Rect[zoomShow]; zIndex: Integer; srcRect: Rect; zoomAway: Boolean; scrnSizeX: Integer; (* size of screen in pixels *) scrnSizeY: Integer; (* return integer between zero and max (inclusive). assumes max is non-negative. *) Function Rand (max: integer): integer; Var t: Register Integer; { t := Random (); if t < 0 then t := -t; Rand := t % (max + 1); }; (* Interpolate one rectangle smoothly into another. Each rectangle is drawn twice. Pen mode should be set to patXor, so that the first drawing shows the rectangle, the second time erases it. Gray seems to work best for the pen pattern: white is too stark a contrast, except perhaps for the very dialectic. *) Proc ZoomRect (r1, r2: Rect); Var r1left, r1top: Register Integer; hDiff, vDiff, widDiff, htDiff: Integer; l, t: Register Integer; r, b: Integer; rWid, rHt: Integer; j: Register Integer; rp: ^Rect; { r1left := r1.left; r1top := r1.top; hDiff := r2.left - r1left; (* positive if moving to right *) vDiff := r2.top - r1top; (* positive if moving down *) rWid := r1.right - r1left; rHt := r1.bottom - r1top; widDiff := (r2.right - r2.left) - rWid; htDiff := (r2.bottom - r2.top) - rHt; (* order of evaluation is important in the rect coordinate calculations. since all arithmetic is integer, you can't save time by calculating j/zoomSteps and using that - it'll usually be zero. *) loop (, j := 1, ++j, j > zoomSteps) { ++zIndex; if zIndex >= zoomShow then zIndex := 0; rp := @zRect[zIndex]; FrameRect (rp); (* erase a rectangle *) l := r1left + (hDiff * j) / zoomSteps; t := r1top + (vDiff * j) / zoomSteps; r := l + rWid + (widDiff * j) / zoomSteps; b := t + rHt + (htDiff * j) / zoomSteps; SetRect (rp, l, t, r, b); FrameRect (rp); }; }; (* Set up to allow zooming. Change the visRgn of the grafPort so can draw in the menu bar area. Do NOT blank the screen yet, since some programs (e.g., MacWrite, DiskInfo) mess with the menu bar once they figure out that they're not the front window anymore - if the screen is blanked here, they will mess up the menu bar. Must wait for the activate event to do that. On receipt of the activate event, clear the menu bar so that MenuSelect (which will be called from the main application) doesn't start merrily pulling down menus when the mouse is clicked in the menu bar. Clicking in a cleared menu bar will cause MenuSelect to do nothing but retain control until the button is released - effectively pausing the display. Initialize the rectangle array to a bunch of empty rects. This must be done for the zoom algorithm to work correctly, because one rect is erased for every one drawn. If they are set empty, the first time they are erased, nothing changes on the screen. *) Proc _Init (); { GetWMgrPort (@thePort); srcRect := thePort^.portRect; scrnSizeX := srcRect.right; scrnSizeY := srcRect.bottom; thePort := NewWindow (nil, srcRect, "", true, noGrowDocProc, -1L, true, 0L); RectRgn (thePort^.visRgn, srcRect); WindowPeek (thePort)^.windowKind := GetDARefNum (); (* Initialize the rect array. This also sets zIndex to a value that causes it to reset to zero on the first call to ZoomRect. *) loop (, zIndex := 0, ++zIndex, zIndex >= zoomShow) SetRect (zRect[zIndex], 0, 0, 0, 0); zoomAway := false; }; (* When an activate event is received, go ahead and clear the menu bar, paint the screen black, and start zooming. The ValidRect is to prevent an update event - without it everything below the menu bar gets painted white - presumably this is done by the DA wrapper provided by DeskMaker? The test to check that the activate event is really an activate and not a deactivate is necessary when testing within Rascal. Since the program will be treated as an application, it will get events other than those for just it's own window - in particular, the deactivate event for the previous window gets seen here. If the check isn't made, this is what happens: the deactivate comes in, the menu bar gets cleared the screen is painted and the pattern and mode are changed. Then the activate comes in, the menu bar is cleared again (clobbering what was just saved!) and the screen is painted again - gray this time since the penpat was just changed. Quit on first mouse click in executor window. Hide the window so all other windows will get updated. Restore the menu bar as well. *) Proc _Event (theEvent: EventRecord); Const activeFlag = 1; Var pat: Pattern; A4: PtrB; { case theEvent.what of activateEvt: { if theEvent.modifiers and activeFlag then { theMenuBar := GetMenuBar (); ClearMenuBar (); SetPort (thePort); PaintRect (srcRect (* = thePort^.portRect *)); ValidRect (srcRect); PenMode (patXor); (* do all drawing in xor *) PtrL (pat)^ := $aa55aa55L; (* with gray pattern *) PtrL (pat + 4)^ := $aa55aa55L; PenPat (pat); zoomAway := true; (* window active - can go ahead now *) }; }; mouseDown: { CloseWindow (thePort); (* cause other windows to be updated *) SetMenuBar (theMenuBar); (* restore menu bar *) DisposHandle (theMenuBar); DrawMenuBar (); Push (reg A4.L); Pop (A4); A4[-17] := 1; (* halt program *) }; end; }; Proc _Main (); Var dstRect: Rect; pt1, pt2: Point; { if zoomAway then { SetPort (thePort); ObscureCursor (); (* keep cursor hidden *) pt1.h := Rand (scrnSizeX); (* generate rect, zoom to it *) pt1.v := Rand (scrnSizeY); pt2.h := Rand (scrnSizeX); pt2.v := Rand (scrnSizeY); Pt2Rect (pt1.vh, pt2.vh, dstRect); ZoomRect (srcRect, dstRect); srcRect := dstRect; }; }; --- end ---