home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / System / SmoothScroll 1.0 / source / SmoothScroll.c next >
Encoding:
C/C++ Source or Header  |  1993-06-05  |  7.4 KB  |  296 lines  |  [TEXT/KAHL]

  1. //////////////
  2. //
  3. //    SmoothScroll
  4. //
  5. //    by Steve Bushell - May 3, 1993
  6. //    python@world.std.com
  7. //
  8. //    SmoothScroll is an INIT which patches the ScrollRect trap, changing
  9. //    it from an instant, jumpy scroll, to a smooth, flowing scroll.
  10. //    The degree of smoothness is based on a 'cnfg' resource stored in
  11. //    the INIT file itself.  The higher the long int in the 'cnfg' resource,
  12. //    the smoother the scrolling will be.  It is good not to set this number
  13. //    too high because the scrolling, although very smooth, can get very
  14. //    slow.  The patch is also optimized to adjust the scrolling based on
  15. //    the number of pixels it will be moving, and their depth.  The
  16. //    more pixels it will be moving, the more jumpy the scrolling becomes.
  17. //
  18. //    ©1993 Steven J. Bushell
  19. //
  20. //////////////
  21.  
  22. #include <SetUpA4.h>
  23. #include <Traps.h>
  24.  
  25. #define        Abs(x)            ((x) < 0 ? -(x) : (x))
  26.  
  27. //    Prototype for ScrollRect patch function
  28. static pascal void SmoothScroll(Rect *startRect,
  29.                                 short hDist,
  30.                                 short vDist,
  31.                                 RgnHandle updateRgn);
  32.  
  33. //    typedef for ScrollRect function pointer
  34. typedef pascal void (*ScrollRectProcPtrType)(const Rect *r,
  35.                                             short dh,
  36.                                             short dv,
  37.                                             RgnHandle updateRgn);
  38.  
  39. //    prototype or ShowIcon function
  40. void ShowIcon(short resID);
  41.  
  42. //    globals used in patch
  43. static ScrollRectProcPtrType    origScrollRect;
  44. static long                        cnfgMaxBitsPerBlit;
  45. static RgnHandle                clipRgn,tempRgn;
  46. static Boolean                    colorQDAvailable;
  47.  
  48. //    low-memory global which contains state of shift key
  49. extern Byte shiftKeyDown:0x017b;
  50.  
  51. void main(void)
  52. {
  53.     short        trap,err;
  54.     Handle        ourHandle,cnfgHandle;
  55.     THz            savedZone;
  56.     SysEnvRec    ser;
  57.  
  58.     //    prepare to use globals
  59.     RememberA0();
  60.     SetUpA4();
  61.  
  62.     //    if the shift key is down, we should not install ourselves
  63.     if (shiftKeyDown & 0x01U)
  64.         goto InstallAbort;
  65.  
  66.     //    get a grip on ourselves, and lock ourselves down
  67.     asm {
  68.         move.l a0,ourHandle
  69.     }
  70.     ourHandle = RecoverHandle((Ptr)ourHandle);
  71.     if (!ourHandle)
  72.         goto InstallAbort;
  73.     DetachResource(ourHandle);
  74.     HLock(ourHandle);
  75.     HNoPurge(ourHandle);
  76.  
  77.     //    read in the configuration setting and store it in global
  78.     cnfgHandle = GetResource('cnfg',128);
  79.     if (!cnfgHandle)
  80.         goto InstallAbort;
  81.     cnfgMaxBitsPerBlit = (**(long **)cnfgHandle);
  82.     ReleaseResource(cnfgHandle);
  83.  
  84.     //    install the patch
  85.     trap = _ScrollRect & 0x3FF;
  86.     origScrollRect = (ScrollRectProcPtrType)NGetTrapAddress( trap, ToolTrap);
  87.     NSetTrapAddress((long)SmoothScroll, trap, ToolTrap);
  88.  
  89.     //    create two regions in the System heap for use later
  90.     savedZone = GetZone();
  91.     SetZone(SysZone);
  92.     clipRgn = NewRgn();
  93.     tempRgn = NewRgn();
  94.     SetZone(savedZone);
  95.     
  96.     //    Is Color Quickdraw available?
  97.     err = SysEnvirons(1, &ser);
  98.     colorQDAvailable = err ? false : ser.hasColorQD;
  99.  
  100.     //    Success!  Show the SmoothScroll icon.
  101.     ShowIcon(128);
  102.  
  103.     //    return to normal
  104.     RestoreA4();
  105.     return;
  106.  
  107. InstallAbort:
  108.     //    Something went wrong and the patch installation was aborted!
  109.     //    Show the SmoothScroll icon with the red 'X' through it.
  110.     ShowIcon(129);
  111.     RestoreA4();
  112. }
  113.  
  114. /////////////
  115. //
  116. //    SmoothScroll
  117. //
  118. //    This is the actual patch to ScrollRect.
  119. //    It works by dividing up a single call to ScrollRect
  120. //    into multiple calls, giving the appearance of smooth
  121. //    motion.
  122. //    Note: this is a severe tail patch, as it calls the original
  123. //    trap several times.  Anyone with any better ideas can go
  124. //    and write their own patch (and of course tell me how they
  125. //    did it)!
  126. //
  127. /////////////
  128. static pascal void SmoothScroll(Rect *startRect,
  129.                                 short hDist,
  130.                                 short vDist,
  131.                                 RgnHandle updateRgn)
  132. {
  133.     short        depth,divisor,hStep,vStep;
  134.     long        totalBits;
  135.     Rect        travelRect,destRect;
  136.     GDHandle    theGDevice;
  137.     GrafPtr        thisPort;
  138.  
  139.     //    prepare to access our globals
  140.     SetUpA4();
  141.  
  142.     //    if there is no offset, there is nothing to do,
  143.     //    so we just exit
  144.     if (!hDist && !vDist)
  145.         goto EXIT;
  146.  
  147.     //    if there is both a horizontal and a vertical offset, things
  148.     //    are much too complicated for us, so we just call the
  149.     //    original trap with the original parameters and get out
  150.     if (hDist && vDist)
  151.     {
  152.     ORIG:
  153.         (origScrollRect)(startRect,hDist,vDist,updateRgn);
  154.         goto EXIT;
  155.     }
  156.  
  157.     //    find our screen depth
  158.     if (colorQDAvailable)
  159.     {
  160.         destRect = *startRect;
  161.         LocalToGlobal(&(((Point *)&destRect)[0]));
  162.         LocalToGlobal(&(((Point *)&destRect)[1]));
  163.         theGDevice = GetMaxDevice(&destRect);
  164.     
  165.         //    if we can't get our screen depth, we call the
  166.         //    original trap and get out
  167.         if (!theGDevice)
  168.             goto ORIG;
  169.         
  170.         depth = (*(*theGDevice)->gdPMap)->pixelSize;
  171.     }
  172.     else
  173.         depth = 1;
  174.  
  175.     //    calculate the total number of bits that we're going
  176.     //    to be dealing with in this scrolling sequence
  177.     totalBits = ((long)startRect->bottom-startRect->top) *
  178.                 ((long)startRect->right-startRect->left) *
  179.                 depth;
  180.  
  181.     //    if there are no bits, there's nothing to do; we just
  182.     //    set update region to nothing and then exit
  183.     if (!totalBits)
  184.     {
  185.         SetEmptyRgn(updateRgn);
  186.         goto EXIT;
  187.     }
  188.  
  189.     //    based on the configuration setting, we calculate how
  190.     //    many steps we're going to divide the scrolling sequence into
  191.     divisor = cnfgMaxBitsPerBlit / totalBits;
  192.  
  193.     //    if the result was zero, we must make it at least one step
  194.     if (!divisor)
  195.         divisor = 1;
  196.  
  197.     //    the the current port so we can access its fields
  198.     GetPort(&thisPort);
  199.  
  200.     //    set up the destination rect for scrolling
  201.     destRect = *startRect;
  202.     OffsetRect(&destRect,hDist,vDist);
  203.  
  204.     //    set up clipping area, and calculate the region that will
  205.     //    be returned as the last parameter to the function call
  206.     GetClip(clipRgn);
  207.     ClipRect(startRect);
  208.     RectRgn(updateRgn,startRect);
  209.     SectRgn(thisPort->visRgn,updateRgn,tempRgn);
  210.     CopyRgn(tempRgn,updateRgn);
  211.     OffsetRgn(tempRgn,hDist,vDist);
  212.     XorRgn(tempRgn,updateRgn,updateRgn);
  213.     SectRgn(thisPort->clipRgn,updateRgn,updateRgn);
  214.  
  215.     //    do horizontal scrolling
  216.     if (hDist)
  217.     {
  218.         travelRect = *startRect;
  219.         //    calculate number of pixels in each step
  220.         hStep = hDist / divisor;
  221.         //    if the result is zero, it is reset to a unit pixel
  222.         if (!hStep)
  223.             hStep = Abs(hDist) / hDist;
  224.         
  225.         //    are we done yet?
  226.         while (travelRect.left != destRect.left)
  227.         {
  228.             //    are we close yet?
  229.             if (Abs(destRect.left - travelRect.left) <= Abs(hStep))
  230.                 hStep = destRect.left - travelRect.left;
  231.             //    call original trap with new parameters
  232.             (origScrollRect)(&travelRect,hStep,0,tempRgn);
  233.             //    move to next step
  234.             OffsetRect(&travelRect,hStep,0);
  235.         }
  236.         goto DONE;
  237.     }
  238.  
  239.     //    do vertical scrolling
  240.     if (vDist)
  241.     {
  242.         travelRect = *startRect;
  243.         //    calculate number of pixels in each step
  244.         vStep = vDist / divisor;
  245.         //    if the result is zero, it is reset to a unit pixel
  246.         if (!vStep)
  247.             vStep = Abs(vDist) / vDist;
  248.         
  249.         //    are we done yet?
  250.         while (travelRect.top != destRect.top)
  251.         {
  252.             //    are we close yet?
  253.             if (Abs(destRect.top - travelRect.top) <= Abs(vStep))
  254.                 vStep = destRect.top - travelRect.top;
  255.             //    call original trap with new parameters
  256.             (origScrollRect)(&travelRect,0,vStep,tempRgn);
  257.             //    move to next step
  258.             OffsetRect(&travelRect,0,vStep);
  259.         }
  260.         goto DONE;
  261.     }
  262. DONE:
  263.     //    reset clipping region
  264.     SetClip(clipRgn);
  265. EXIT:
  266.     //    return to normal
  267.     RestoreA4();
  268. }
  269.  
  270. ////////////
  271. //
  272. //    ShowIcon
  273. //
  274. //    A handy little function which displays an icon at startup
  275. //    time.  This is actually just a stub which calls the real code
  276. //    which is kept in a code resource called 'Show'.  It takes
  277. //    a single parameter, the resource ID of the icon family to
  278. //    be displayed.
  279. //
  280. ////////////
  281. void ShowIcon(short resID)
  282. {
  283.     typedef void (*ShowCodeFunc)(short);
  284.     Handle    ShowCode = 0L;
  285.  
  286.     ShowCode = GetResource('Show',-4064);
  287.     if (!ShowCode)
  288.         return;
  289.  
  290.     HLock(ShowCode);
  291.     
  292.     ((ShowCodeFunc)*ShowCode)(resID);
  293.     
  294.     HUnlock(ShowCode);
  295.     ReleaseResource(ShowCode);
  296. }