home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat España 20
/
macformat_20.iso
/
mac
/
Shareware
/
Desarrolladores
/
ProgressCDEF
/
ProgressCDEF.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-22
|
15KB
|
475 lines
// ***********************************************************************************
// 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;
}