home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Code Resources / Progress CDEFs 1.3 / Progress Bar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-29  |  10.7 KB  |  265 lines  |  [TEXT/KAHL]

  1. /*****************************************************************
  2.  
  3. Legal stuff:
  4.  
  5. Progress Bar CDEF 1.3 by Eddy J. Gurney. This CDEF is copyright ©1993–94 by Eddy J. Gurney
  6. and The Eccentricity Group, but is "freeware". It may be freely distributed, modified, included
  7. in any application, on a source code compilation CD-ROM, etc. as long as the following simple
  8. restrictions are met:
  9.     1) this entire copyright notice remains intact when this source is redistributed, modified, etc.
  10.     2) the copyright notice in the CDEF itself (the "copyright" string) remains intact,
  11.     3) this source, or any of its derivitave works (including the CDEF itself), are NOT made
  12.         available on or used in any form by any electronic service (or associated electronic
  13.         service) which restricts the electronic distribution of some or all of its files (ie, ZiffNet).
  14. Feel free to add your name, company, whatever to the copyright. However you can NOT remove
  15. the restrictions I've described above or add further restrictions on its use or distribution.
  16. Finally, no warranty of any kind is expressed or implied.
  17.  
  18. Usage:
  19.  
  20. This CDEF allows you to very easily use progress bars, ala the Finder's "Copying" dialog.
  21. To use it, copy the CDEF to your project's resource file. Add a "CNTL" to your dialog, and set
  22. the control's ProcID to:
  23.     16*the resource ID you gave this CDEF (default ID is 600) + variation code (see below).
  24. Next set the initial, minimum and maximum values. (ie., 0, 0, 100 for a "percentage" bar).
  25. Finally, if you would like to use custom colors for the progress bar, use a variation code of
  26. 1 instead of 0 and and edit the colors (stored in a corresponding 'cctb' resource) as desired.
  27. (FrameColor is used for the frame, BodyColor is used as the background color [never
  28. really used], TextColor is used for the "done" part of the bar, and ThumbColor is used for the
  29. "to do" part of the bar. This is the same order as they appear in Resorcerer's "CNTL" editor,
  30. so you don't have to edit the 'cctb' directly.) If you use custom controls, make sure to try
  31. them at various bit depths to make sure QuickDraw maps the done/to do parts to different
  32. colors (the default colors are OK).
  33.  
  34. After that, in your program all you have to do is call SetCtlValue() and this CDEF will 
  35. automagically draw your progress bar!
  36.  
  37. !!WARNING!! This CDEF assumes the presence of the _Gestalt trap (available in System 7 or
  38. later.) I didn't want to include the glue code to emulate _Gestalt under System 6 (to keep the
  39. size down).  If you need to use this in an application that may be running under System 6,
  40. just define SystemSevenOrLater to 0 instead of 1 and rebuild the code resource.
  41.  
  42. If someone knows of a *supported* way to check for Color QuickDraw without calling _Gestalt,
  43. let me know and I'll include it in the next release. (_SysEnvirons turned out to be just as bad
  44. since Think adds glue code to emulate SysEnvirons on system versions earlier than 4.1 or
  45. something…)
  46.  
  47. Thanks go to Joe Zobkiw's for his "Finder Progress" sample code (posted to alt.sources.mac by
  48. Ken Long) and to Scott Knaster/Keither Rollin for their "Progress Indicator" sample in Macintosh
  49. Programming Secrets. They made this much easier!
  50.  
  51. P.S. I code in Geneva 9, so if this looks unformatted, that's why. It will look fine in any window
  52. about 640 pixels wide when viewed in Geneva 9. :-)
  53.  
  54. E-mail comments, suggestions, requests to: egurney@vcd.hp.com
  55.  
  56. 1.1: First public release
  57. 1.2 changes:
  58.      . Call StripAddress() instead of &'ing off the lower 3 bytes in calcCRgns (thanks Dave Polaschek).
  59.      . Now determine whether or not to use custom colors via the variation code (thanks Steve LoBasso)
  60.      . Added capability to do vertical progress bars for "thermometers". If the progress bar
  61.        rectangle is taller than it is wide, then the progress bar will fill "up" instead of "across".
  62.      . Fixed a bug that prevented proper drawing when a control had a non-zero minimum.
  63. 1.3 changes (thanks Steve LoBasso for the suggestions):
  64.      . RGBForeColor and RGBBackColor can move memory; we copy the AuxCtlTable color data to a
  65.        temporary variable to avoid the trap overhead of HLock/HUnlock.
  66.      . A white bar would show up between the done/todo portions of the bar if you didn't change the
  67.        value of the control; this has been fixed.
  68.      . Added code to ensure the control value is never outside the control min/max range
  69.  
  70. ******************************************************************/
  71.  
  72. #ifdef SystemSevenOrLater
  73. #undef SystemSevenOrLater
  74. #endif
  75.  
  76. #define SystemSevenOrLater 1
  77.  
  78. #include <GestaltEqu.h>
  79. #include <SetUpA4.h>
  80.  
  81. const unsigned char copyright[] = "Progress Bar CDEF 1.3 ©1993–94 Eddy J. Gurney/TEG. Freeware.";
  82.  
  83. struct ControlData {
  84.     unsigned    hasColorQD    : 1;
  85.     unsigned    isVertical        : 1;
  86. };
  87.  
  88. pascal long main(short variation, ControlHandle theControl, short msg, long param)
  89. {
  90.     /* These need to be declared static to work. See the Note on p. 283 of Think C 6 User's Guide */    
  91.     const static RGBColor    kBlack = { 0, 0, 0 };
  92.     const static RGBColor    kWhite = { 0xffff, 0xffff, 0xffff };
  93.     const static RGBColor    kDarkGray = { 0x4000, 0x4000, 0x4000 };
  94.     const static RGBColor    kSteelBlue= { 0xcccc, 0xcccc, 0xffff };
  95.     long                    result;
  96.     union {
  97.         unsigned int            iControl;
  98.         struct ControlData        sControl;
  99.     } control;
  100.  
  101.     RememberA0();
  102.     SetUpA4();
  103.  
  104.     result = 0;
  105.  
  106.     switch (msg) {
  107.         case initCntl: {
  108.             long            gestaltResponse;
  109.             Rect            tempRect;
  110.  
  111.             (void)Gestalt(gestaltQuickdrawVersion, &gestaltResponse);
  112.             control.sControl.hasColorQD = (gestaltResponse >= gestalt8BitQD);
  113.             
  114.             tempRect = (*theControl)->contrlRect;
  115.             if ((tempRect.right - tempRect.left) >= (tempRect.bottom - tempRect.top))
  116.                 control.sControl.isVertical = false;
  117.             else
  118.                 control.sControl.isVertical = true;
  119.             
  120.             (*theControl)->contrlData = (Handle)control.iControl;
  121.             break;
  122.         }
  123.  
  124.         case drawCntl: {
  125.             PenState        oldPenState;
  126.             Boolean        hasColorQD;
  127.             Boolean        isVertical;
  128.             Rect            doneRect, toDoRect;
  129.             RGBColor        oldForeColor, oldBackColor, tempColor;
  130.             AuxCtlHandle    auxControlData;
  131.             short        controlValue, length;
  132.  
  133.             if ((*theControl)->contrlVis) {
  134.                 control.iControl = (unsigned int)(*theControl)->contrlData;
  135.                 hasColorQD = control.sControl.hasColorQD;
  136.                 isVertical = control.sControl.isVertical;
  137.  
  138.                 GetPenState(&oldPenState);
  139.                 PenNormal();
  140.     
  141.                 doneRect = (*theControl)->contrlRect;
  142.  
  143.                 if (hasColorQD) {
  144.                     GetForeColor(&oldForeColor);
  145.                     GetBackColor(&oldBackColor);
  146.                     /* Check if we should use custom colors, or the default Finder colors */
  147.                     if (variation == 1 && GetAuxCtl(theControl, &auxControlData)) {
  148.                         /* Because RGBForeColor/RGBBackColor can move memory, we copy the color
  149.                            to a temporary variable. This way, we avoid the trap overhead of HLock/HUnlock. */
  150.                         tempColor = (*(*auxControlData)->acCTable)->ctTable[cFrameColor].rgb;
  151.                         RGBForeColor(&tempColor);
  152.                         tempColor = (*(*auxControlData)->acCTable)->ctTable[cBodyColor].rgb;
  153.                         RGBBackColor(&tempColor);
  154.                     } else {
  155.                         auxControlData = nil;
  156.                         RGBForeColor(&kBlack);
  157.                         RGBBackColor(&kWhite);
  158.                     }
  159.                 } /* If no Color QD, we'll be drawing in black because of our call to PenNormal above */
  160.                 FrameRect(&doneRect);    /* Frame the progress bar in the frame color */
  161.  
  162.                 InsetRect(&doneRect,1, 1);
  163.                 toDoRect = doneRect;    /* Copy the rect before we change it*/
  164.                 
  165.                 /* Make sure the controlValue is in bounds. SetCtlValue does this already, but the user could
  166.                    have a bad "initial" value, or could set the contrlValue field directly.*/
  167.                 if ((*theControl)->contrlValue > (*theControl)->contrlMax)
  168.                     controlValue = (*theControl)->contrlMax;
  169.                 else if ((*theControl)->contrlValue < (*theControl)->contrlMin)
  170.                     controlValue = (*theControl)->contrlMin;
  171.                 else
  172.                     controlValue = (*theControl)->contrlValue;
  173.                 
  174.                 /* Determine how much of the progress bar to draw, making sure we don't divide by zero */
  175.                 if (length = ((*theControl)->contrlMax - (*theControl)->contrlMin)) {
  176.                     if (isVertical) {
  177.                         doneRect.top = doneRect.bottom - 
  178.                                     ((long)(controlValue - (*theControl)->contrlMin) *
  179.                                     (doneRect.bottom - doneRect.top)) / length;                    
  180.                     } else {
  181.                         doneRect.right = doneRect.left + 
  182.                                     ((long)(controlValue - (*theControl)->contrlMin) *
  183.                                     (doneRect.right - doneRect.left)) / length;
  184.                     }
  185.                 }
  186.  
  187.                 if (hasColorQD) {
  188.                     if (variation == 1 && auxControlData != nil) {
  189.                         tempColor = (*(*auxControlData)->acCTable)->ctTable[cTextColor].rgb;
  190.                         RGBForeColor(&tempColor);
  191.                      } else
  192.                         RGBForeColor(&kDarkGray);
  193.                 } /* If no Color QD, we're still drawing in black */
  194.                 PaintRect(&doneRect);    /* Draw the "done" part */ 
  195.  
  196.                 if (isVertical) {
  197.                     toDoRect.bottom = doneRect.top;
  198.                 } else {
  199.                     toDoRect.left = doneRect.right;    /* Calculate the "to do" area rectangle */
  200.                 }
  201.                 if (hasColorQD) {
  202.                     /* QD checks to see if the foreground color maps into the same color as the background
  203.                          color. If so, QD inverts the foreground color and draws with it instead. This is BAD for
  204.                          us! If the user is in 1-bit mode, "Steel Blue" will map to white, which QD sees is the
  205.                          same as the background color, and sets it to black instead… and the progress bar
  206.                          becomes "invisible"! So we "trick" QD by changing the background color, which doesn't
  207.                          matter since we never draw with it anyway. Thanks to Knaster & Rollin (Macintosh
  208.                          Programming Secrets) for describing this behavior… */
  209.                     if (variation == 1 && auxControlData != nil) {
  210.                         tempColor = (*(*auxControlData)->acCTable)->ctTable[cThumbColor].rgb;
  211.                         RGBForeColor(&tempColor);
  212.                         tempColor = (*(*auxControlData)->acCTable)->ctTable[cFrameColor].rgb;
  213.                         RGBBackColor(&tempColor);
  214.                     } else {
  215.                         RGBForeColor(&kSteelBlue);
  216.                         RGBBackColor(&kBlack);
  217.                     }
  218.                 } else { /* If no Color QD, we switch to white via patBic (force white where pattern black) mode */
  219.                     PenMode(patBic);
  220.                 }
  221.                 PaintRect(&toDoRect);    /* Draw the "to do" part */
  222.  
  223.                 if (hasColorQD) {
  224.                     RGBForeColor(&oldForeColor);
  225.                     RGBBackColor(&oldBackColor);
  226.                 }
  227.                 SetPenState(&oldPenState);
  228.             }
  229.             break;
  230.         }
  231.         
  232.         case calcCRgns:    /* This is the message sent if using 24-bit addressing */
  233.             param = (long)StripAddress((Ptr)param);        /* Mask off the high byte if necessary */
  234.             /* Fall through on purpose! */
  235.  
  236.         case calcCntlRgn:    /* Under 32-bit addressing we get this message */
  237.             RectRgn((RgnHandle)param, &(*theControl)->contrlRect);
  238.             break;
  239.  
  240.     #ifdef FOR_COMPLETENESS
  241.         case testCntl:
  242.         case dispCntl:
  243.         case posCntl:
  244.         case thumbCntl:
  245.         case dragCntl:
  246.         case autoTrack:
  247.         case undoDev:
  248.         case cutDev:
  249.         case copyDev:
  250.         case pasteDev:
  251.         case clearDev:
  252.         case cursorDev:
  253.         case calcThumbRgn:
  254.             break;    /* We don't respond to any of these messages */
  255.     #endif
  256.  
  257.         default:    /* Any other messages we don't handle or which aren't defined yet */
  258.             break;
  259.     }
  260.  
  261.     RestoreA4();
  262.  
  263.     return result;
  264. }
  265.