home *** CD-ROM | disk | FTP | other *** search
- // ***********************************************************************************
-
- // ProgressCDEF © Andrew Regan, 1996 (Andrew_G.D._Regan@iconex.mactel.org)
-
- // ProgressCDEF is substantially based upon FinderProgressBar 2.0 (which is © Chris Larson)
- // but features substantial alterations made by me: considerable additions, improvement
- // of existing features, a general cleaning-up, and the cutting of a couple of irrelevancies.
-
- // Conditions – I quote from Chris Larson's original terms:
- // " ... Source file of a CDEF which mimics the progress bar used in the Finder.
- // This source file and its compiled derivatives may be freely used within any
- // freeware/shareware/postcardware/beerware/… as long as you mention my name
- // in your credits. Neither this source nor its compiled derivatives are
- // in the public domain and may not be use in any form in public domain software.
- // Neither this source nor its compiled derivatives may be used in any form in a
- // commercial product without the expressed, written consent of the author (me)... " *
-
- // I ask no money for the use of ProgressCDEF, as my interest in distributing it is
- // as a service to others: to improve the quality of shareware software, etc.
- // Hopefully it will drive several inferior products out of the market.
-
- // ***********************************************************************************/
-
- #ifndef powerc
- #include <A4Stuff.h>
- #endif
-
- #include "Gestalt.h"
- #include "Palettes.h"
-
- #define kIsColorPort 0xC000
- #define kBarberStripeWidth 8
- #define kFPBFrameCount 16 // The number of frames in the “Barber Pole” animation loop.
-
- void GetWctbColor( WindowPtr w, RGBColor *lite, RGBColor *dark, long rc, short variation);
- pascal long main( short varCode, ControlRef theControlHandle, short message, long param);
- void BeginDraw( ControlRef theControlHandle, short varCode);
- RGBColor* FindColorInTable( WCTabHandle colorTable, short id);
- void DrawNormalBar( ControlPtr theControl, RGBColor *barColor, RGBColor *bodyColor, short col);
- void DrawBarberPoleBar( ControlPtr theControl, RGBColor *barColor, RGBColor *bodyColor, short col);
-
- #ifdef powerc
- short CalculateBarBoundry( short boxLeft, short boxRight, ControlPtr theControl);
- #else
- asm short CalculateBarBoundry( short boxLeft, short boxRight, ControlPtr theControl);
- #endif
-
-
- static const RGBColor gBlackColor = {0,0,0}, midGrey = {32767,32767,32767};
-
-
- /*******************************************************************************
-
- ••• main •••
-
- *******************************************************************************/
- pascal long main( short varCode, ControlHandle theControlHandle, short message, long param)
- {
- ControlPtr theControl;
- SignedByte controlRecState;
- long returnValue;
-
-
- #ifndef powerc
- long oldA4 = SetCurrentA4();
- #endif
-
- controlRecState = HGetState( (Handle) theControlHandle);
- HLock( (Handle) theControlHandle);
-
- returnValue = 0;
- theControl = *theControlHandle;
-
- switch (message)
- {
- case drawCntl:
- if ( theControl->contrlVis) BeginDraw( theControlHandle, varCode);
- break;
- case testCntl:
- if ( PtInRect( *(Point*)(¶m), &(theControl->contrlRect)) ) returnValue = 50;
- break;
- case calcCRgns: param &= 0x7FFFFFFF;
- case calcCntlRgn:
- RectRgn( (RgnHandle) param, &(theControl->contrlRect));
- break;
- default: break;
- }
-
- HSetState( (Handle) theControlHandle, controlRecState);
-
- #ifndef powerc
- SetA4(oldA4);
- #endif
-
- return returnValue;
- }
-
-
- /*******************************************************************************
-
- ••• BeginDraw •••
-
- Save off all the stuff we’re going to change, figure out which colors to use (and
- whether we need to dither) and call the appropriate drawing routine.
-
- *******************************************************************************/
- void BeginDraw( ControlRef c, short varCode)
- {
- AuxWinHandle awh;
- RgnHandle rgn, oldClip;
- ControlPtr theControl = *c;
- GrafPtr savePort, g = theControl->contrlOwner;
- RGBColor oldFore, oldBack, windowBack;
- RGBColor frameColor = gBlackColor, barColor, bodyColor;
- Pattern pat;
- PenState oldPen;
- Rect theBox = theControl->contrlRect;
- long rc = theControl->contrlRfCon;
- short useColor;
- Boolean doDither = false;
-
-
- GetPort(&savePort);
- SetPort(g);
-
- /* Determine if Color Quickdraw exists and should be used. Actually,
- this simply looks to see if the control’s owning port is a color port. If so, it infers
- the existence of CQD and uses it. If not, we’re drawing into a B/W port anyway, so who
- cares if CQD is present? */
-
- useColor = (((g->portBits.rowBytes) & kIsColorPort) == kIsColorPort);
-
- GetIndPattern( &pat, 0, 4);
- GetPenState(&oldPen);
- PenNormal();
-
- if (useColor)
- {
- GetForeColor(&oldFore);
- GetBackColor(&oldBack);
-
- GetWctbColor( g, &bodyColor, &barColor, rc, varCode);
-
- // Retrieve the window content color (background color) of the control’s owner.
-
- GetAuxWin( g, &awh);
- windowBack = *FindColorInTable( (WCTabHandle) (*awh)->awCTable, wContentColor);
- }
-
- if ( theControl->contrlHilite == kControlInactiveControlPart)
- {
- if ( varCode < 8) doDither = true;
- }
-
- // Draw the bar’s frame. Since this is always the same and will always lie within the control’s
- // rectangle (thus making the clipping region mind the control’s rectangle would have no effect)
- // we can do it here, before mucking with the clipping region.
-
- if (useColor)
- {
- if (doDither) RGBForeColor(&midGrey);
- else RGBForeColor(&frameColor);
- RGBBackColor(&windowBack);
- }
- else
- {
- if (doDither) PenPat(&pat);
- }
-
- FrameRect(&theBox);
- InsetRect( &theBox, 1, 1);
-
- if (doDither) PenNormal();
-
- // Save the current port’s clip region and set it to the intersection of the clip region with
- // the newly inset rectangle (so it won’t allow overwriting of the freshly drawn frame).
-
- oldClip = NewRgn();
- GetClip(oldClip);
-
- rgn = NewRgn(); RectRgn( rgn, &theBox); SectRgn( rgn, oldClip, rgn);
- SetClip(rgn); DisposeRgn(rgn);
-
- // Figure out if we are supposed to draw the “Barber Pole” or the regular bar.
- // In that case, take the frame number from
- // the low word of the RfCon. Frames are numbered from 0 to ( kFPBFrameCount - 1 ), inclusive.
-
- // variation codes:
- // 1 = do not colour according to tinges
- // >= 8 = do not dim
- // refCon >= 1000 = draw BarberPole
-
- if ( rc >= 1000)
- {
- DrawBarberPoleBar( theControl, &barColor, &bodyColor, useColor);
- }
- else DrawNormalBar( theControl, &barColor, &bodyColor, useColor);
-
- // Dither the progress bar if we’re supposed to
-
- if (doDither)
- {
- if (useColor) RGBBackColor(&windowBack);
- PenMode(notPatBic);
- PenPat(&pat);
- PaintRect(&theControl->contrlRect);
- }
-
- if (useColor)
- {
- RGBForeColor(&oldFore);
- RGBBackColor(&oldBack);
- }
-
- SetPenState(&oldPen);
-
- SetClip(oldClip);
- DisposeRgn(oldClip);
-
- SetPort(savePort);
- }
-
-
- /*******************************************************************************
-
- ••• DrawNormalBar •••
-
- Draw the progress bar according to the control settings using the colors given
- in the parameters.
-
- *******************************************************************************/
- void DrawNormalBar( ControlPtr theControl, RGBColorPtr barColor, RGBColorPtr bodyColor, short useColor)
- {
- Rect theBox = theControl->contrlRect;
-
- InsetRect( &theBox,1,1);
- theBox.right = CalculateBarBoundry( theBox.left, theBox.right, theControl);
-
- // Set up colors so that the bar will map to black on a 1-bit device; then draw the bar.
-
- if (useColor)
- {
- RGBForeColor(barColor);
- BackColor(30);
- }
-
- PaintRect(&theBox);
-
- // Now set up theBox to draw the “empty” space not yet filled by the bar.
-
- theBox.left = theBox.right;
- theBox.right = theControl->contrlRect.right - 1;
-
- // Set up colors so that the space will map to white on a 1-bit device; then draw the space.
-
- if (useColor)
- {
- RGBForeColor(bodyColor);
- BackColor(33);
- }
- else PenMode(patBic);
-
- PaintRect(&theBox);
- }
-
-
- /*******************************************************************************
-
- ••• DrawBarberPoleBar •••
-
- *******************************************************************************/
- void DrawBarberPoleBar( ControlPtr theControl, RGBColor *barColor, RGBColor *bodyColor, short useColor)
- {
- Rect theBox = theControl->contrlRect;
- short i, height, frameNumber;
-
-
- InsetRect( &theBox, 1, 1);
- PenSize( kBarberStripeWidth, 1);
-
- // Set up the colors. On a 1-bit device, one of these should map to white and the other black. It
- // doesn’t _really_ matter which maps to which as long as they’re different.
-
- if (useColor)
- {
- RGBForeColor(barColor);
- RGBBackColor(bodyColor);
- }
-
- // Compute the horizontal starting point for drawing. Note that each drawing loop draws one
- // stripe of each color (with grey drawn first). This starting point is set far enough to the
- // left to make the first set of stripes drawn hit the lower left corner of the bar.
-
- height = theBox.bottom - theBox.top;
- frameNumber = theControl->contrlValue % kFPBFrameCount;
-
- i = height + frameNumber + 2 * kBarberStripeWidth - 2;
- i = i / ( 2 * kBarberStripeWidth );
- i = theBox.left - i * 2 * kBarberStripeWidth + frameNumber;
-
- // Now back bias the starting location to account for the first increment.
-
- i -= kBarberStripeWidth;
-
- // Until we would start drawing to the right of the bar, draw a pair of lines, slanting to the
- // right, first of the two in the bar color, second in the fill color.
-
- while ( i < theBox.right)
- {
- i += kBarberStripeWidth;
- PenMode(patCopy);
- MoveTo( i, theBox.top);
- LineTo( i + height, theBox.bottom - 1);
-
- i += kBarberStripeWidth;
- PenMode(patBic);
- MoveTo( i, theBox.top);
- LineTo( i + height, theBox.bottom - 1);
- }
- }
-
-
- /*******************************************************************************
-
- ••• CalculateBarBoundry •••
-
- Given the edges of the progress bar and the control’s setting, determine
- where the right edge of the progress bar belongs.
- On the PowerPC architecture, this is implemented in C; while on the 680x0
- it is implemented in assembly. This is done because the 68000 does not
- support 32-bit multiplies in hardware, 32-bit multiplies are not strictly
- necessary (the 16->32 multiply and 32->16 divide will suffice), and the
- compiler was not using the mulu.w and divu.w instructions correctly. (Well,
- it was using them correctly in the C sense, but that’s not what I wanted
- them to do.)
-
- *******************************************************************************/
- #ifdef powerc
-
- short CalculateBarBoundry(short boxLeft, short boxRight, ControlPtr theControl)
- {
- short result = boxLeft;
- short min = theControl->contrlMin;
- short max = theControl->contrlMax;
- short val = theControl->contrlValue;
- long top = ( boxRight - boxLeft ) * ( val - min );
- long bottom = max - min;
-
- if ( bottom != 0 ) result += top / bottom;
- return result;
- }
-
- #else
-
-
- /*******************************************************************************
-
- ••• CalculateBarBoundry •••
-
- A couple of notes about the assembly language. This method will calculate the correct answer no
- matter what values are given as long as the following conditions hold:
- (1) boxRight >= boxLeft, and
- (2) contrlMax >= contrlValue >= contrlMin.
- Both of these should be met in normal circumstances. If these restrictions hold, then the
- differences (both in the numerator and the one in the denominator) will fit into 16-bit unsigned
- integers. That means that I can use the mulu.w and divu.w instructions to perform the multiply
- and divide, instead of requiring the addition of the software library for 32 bit multiplication
- on the 68000 (The software library was twice the size of this code resource last time I checked).
- The only other thing to note is that a division by zero can’t happen. The denominator is zero
- only when contrlMax == contrlMin. If this is the case, then contrlValue == contrlMin and the
- branch before the multiply will be taken, so the division instruction is never reached.
-
- *******************************************************************************/
- asm short CalculateBarBoundry(short boxLeft, short boxRight, ControlPtr theControl)
- {
- fralloc // Give ourselves a stack frame
-
- move.w boxRight,d1 // Right edge of the box to d1
- move.w boxLeft,d0 // Left edge of the box to d0
- sub.w d0,d1 // Width of the box to d0
-
- movea.l theControl,a0 // Store the control pointer in a0
- move.w struct (ControlRecord.contrlValue)(a0),d2 // Control’s value to d2
- sub.w struct (ControlRecord.contrlMin)(a0),d2 // Normalized value to d2
-
- beq @1 // If normalized value == 0, exit. (Note
- // that d0 already holds left edge)
-
- mulu.w d2,d1 // box width * normalized value to d1
-
- move.w struct (ControlRecord.contrlMax)(a0),d2 // Control’s max to d2
- sub.w struct (ControlRecord.contrlMin)(a0),d2 // Normalized maximum to d2
-
- divu.w d2,d1 // width * value / maximum to d1. Note that
- // divide by zero can’t happen here.
-
- add.w d1,d0 // Offset left edge by amount in d1
-
- @1:
- frfree // Remove the stack frame
- rts // Outa here...
- }
-
- #endif
-
-
- /*******************************************************************************
-
- ••• FindColorInTable •••
-
- Return a pointer to the RGBColor matching the given id. Return the first entry
- in the table if none match. Note that this routine will not cause memory to
- move, but since it returns a pointer which references a handle’s block, one
- must be sure to lock the handle if the pointer is going to be used in or
- after a call that may move memory (like RGBForeColor() or RGBBackColor()).
-
- *******************************************************************************/
- RGBColor* FindColorInTable( WCTabHandle colorTable, short id)
- {
- short i;
-
- for ( i = (*colorTable)->ctSize; i != 0; i--)
- {
- if ( (*colorTable)->ctTable[i].value == id ) break;
- }
-
- return ( &( (*colorTable)->ctTable[i].rgb ));
- }
-
-
- /*******************************************************************************
-
- ••• GetWctbColor •••
-
- *******************************************************************************/
- void GetWctbColor( WindowPtr w, RGBColor *lite, RGBColor *dark, long rc, short variation)
- {
- AuxWinHandle awHndl;
- OSErr err = 1;
- long gestaltResponse;
- short count, dk = 0x4444;
- Boolean makeBlack = false, useAaron;
-
-
- GetAuxWin( w, &awHndl);
- count = (*(WCTabHandle) ((*awHndl)->awCTable))->ctSize;
-
- if ( count < 11) // must have at least wTingeLight
- {
- GetAuxWin( nil, &awHndl);
- count = (*(WCTabHandle) ((*awHndl)->awCTable))->ctSize;
- }
-
- err = Gestalt( 'Aarn', &gestaltResponse);
- useAaron = (( err == noErr) && ( rc < 1000));
-
- if (( count < 11) || ( variation == 1) || useAaron)
- {
- lite->red = lite->green = 0xCCCC; // defaults when ~Aaron installed
- lite->blue = 0xFFFF;
- }
- else
- {
- *lite = (*(WCTabHandle) ((*awHndl)->awCTable))->ctTable[11].rgb; // wTingeLight
- if (( lite->red == lite->green) && ( lite->green == lite->blue) && ( lite->blue == 0))
- {
- lite->red = lite->green = lite->blue = 0xFFFF;
- makeBlack = true;
- }
- }
-
- if ( err != noErr) ++dk;
- if (makeBlack) dk = 0;
- dark->red = dark->green = dark->blue = dk;
- }