home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 36.1 KB | 1,276 lines | [TEXT/KAHL] |
- //------------------------- © 1994-1995 by James G. Stout --------------------------
- // File : cdef3D.c
- // Date : May 2, 1994
- // Author : Jim Stout
- // Purpose : A CDEF to implement some very subtle 3D pushButtons, checkBoxes &
- // : radioButtons. These will even "do 3D" on a white background.
- // :
- // : checkBox & radioButton controls can have an embossed titles if
- // : they are used on a colored background.
- // :
- // : This version uses varCode 4 (undefined in the standard CDEF) to
- // : provide a push button that will use the window background color as
- // : the body color for the button.
- // :
- // : There are several build switches to control this CDEF. See below.
- // :
- // : If you find a use for this, I'd love to know about it. Bug reports
- // : are always interesting.
- // :
- // : Internet : JimS@WRQ.COM(work hours, PST)
- // : AppleLink : WRQ (daily)
- // : CompuServe : 73240,2052 (weekly or so)
- // : AOL : JasG (weekly or so)
- // : eWorld : Jim Stout (weekly or so)
- // :
- //----------------------------------------------------------------------------------
-
- //#define _DEBUGCDEF 1 // allows inline debugging in a test project
-
- //----------------------------------------------------------------------------------
- // The following switches control the appearance of push buttons & check boxes
- //----------------------------------------------------------------------------------
-
- #define _USETINGE 1 // add window tinge color to button frame (if no 'cctb')
- #define _EMBOSS 1 // emboss radioButton & checkBox titles
- //#define _REALCHECK 1 // use a checkMark instead of an 'x' in checkBoxes
- //#define _RECTPUSH 1 // draw a Rectangular button, not oval
-
- //----------------------------------------------------------------------------------
- // The next switch controls the use of offscreen (GWorld) drawing. There are 2
- // advantages to using this:
- //
- // 1. Elimination of "flicker" as the embossed titles are drawn.
- // 2. To get '3d' controls in old style GrafPorts (no 'dctb' resources) that
- // are displayed on color devices.
- //
- // This does mean performance & memory hits, but hopefully, minor. Also, the
- // code size for the CDEF will increase. GWorlds are not used for push buttons.
- //
- // I recommend using this if you want to use this CDEF on non-white backgrounds
- // and you have set the _EMBOSS switch above.
- //----------------------------------------------------------------------------------
-
- #define _USEOFFSCREEN 1
-
- //----------------------------------------------------------------------------------
- // The next 2 switches force push buttons to always use a black frame & body color
- // of _GRAYSHADE. 'cctb' colors are used for the title.
- //----------------------------------------------------------------------------------
-
- //#define _GRAYBUTTONS 1
- #define _GRAYSHADE 0xeeee
-
- //----------------------------------------------------------------------------------
-
- #include "fatCDEF.h"
-
- #include <Controls.h>
- #include <LowMem.h>
- #include <GestaltEqu.h>
- #include <Memory.h>
- #include <QDOffscreen.h>
- #include <ToolUtils.h>
- #include <Traps.h>
- #include <Types.h>
-
- #include "colorCDEF.h"
- #include "grayCDEF.h"
- #include "miscCDEF.h"
-
- #include "cdef3D.h"
-
- #ifdef _DEBUGCDEF
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param);
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
- #else
-
- //==================================================================================
- // CDEF main
- //==================================================================================
-
- pascal long main (short varCode, ControlHandle theCtl, short message, long param)
- #endif
- {
- long ret = 0L;
- short ctlType;
- Point p;
- GrafPtr thisPort;
- CDEFHandle hCdef;
- SignedByte cState, dState;
-
- #include "fatEntry.c"
-
- cState = HGetState((Handle)theCtl);
- HLock((Handle)theCtl);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
-
- //----------------------------------------------------------------------------------
- // Process messages to control
- //----------------------------------------------------------------------------------
-
- switch(message) {
-
- case initCntl:
-
- GetPort(&thisPort);
- hCdef = (CDEFHandle)NewHandle(sizeof(CDEFData));
- if(hCdef) {
- (**hCdef).txFont = thisPort->txFont;
- (**hCdef).txSize = thisPort->txSize;
- (**hCdef).txFace = thisPort->txFace;
- (**theCtl).contrlData = (Handle)hCdef;
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
- break;
-
- case dispCntl:
- if((**theCtl).contrlData) {
- hCdef = (CDEFHandle)(**theCtl).contrlData;
-
- HUnlock((**theCtl).contrlData);
- DisposeHandle((**theCtl).contrlData);
-
- (**theCtl).contrlData = 0;
- }
- break;
-
- case drawCntl:
- if((**theCtl).contrlVis != 0 &&
- ((WindowPeek)(**theCtl).contrlOwner)->visible)
- doDraw(theCtl, varCode);
- break;
-
- case testCntl:
- p.v=HiWord(param);
- p.h=LoWord(param);
- ctlType = varCode;
- if(varCode & useWindFont)
- ctlType ^= useWindFont;
-
- if(PtInRect(p,&(*theCtl)->contrlRect)) {
- switch(ctlType) {
- case 0:
- case 4:
- ret = inButton;
- break;
-
- default:
- ret = inCheckBox;
- break;
- }
- }
- break;
-
- case calcCRgns:
- RectRgn((RgnHandle)(param & 0x7fffffffL), &(*theCtl)->contrlRect);
- break;
-
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle)(param), &(*theCtl)->contrlRect);
- break;
- }
-
- if((**theCtl).contrlData)
- HSetState((**theCtl).contrlData, dState);
- HSetState((Handle)theCtl, cState);
-
- #include "fatExit.c"
-
- return (ret);
- }
-
- //==================================================================================
- // If running with System 7, use DeviceLoop to gracefully handle multiple screens.
- // Simulate DeviceLoop if using System 6...
- //==================================================================================
-
- static void doDraw(ControlHandle theCtl, short varCode)
- {
- short saveMode, txF, txS;
- unsigned char saveFace;
- GrafPtr savePort, thisPort;
- devLoopHandle hDl;
- RgnHandle saveClip, hRgn;
- DeviceLoopDrawingUPP drawControlUPP;
-
- //----------------------------------------------------------------------------------
- // set window font & size info
- //----------------------------------------------------------------------------------
- GetPort(&savePort);
- SetPort((**theCtl).contrlOwner);
- GetPort(&thisPort);
-
- saveMode = thisPort->txMode;
- saveFace = thisPort->txFace;
-
- if(!(varCode & useWindFont)) { // use system font
- txF = thisPort->txFont; // save current
- txS = thisPort->txSize;
- TextFont(LMGetSysFontFam()); // set system as current
- TextSize(LMGetSysFontSize());
- TextFace(normal);
- }
- TextMode(srcOr);
-
- //----------------------------------------------------------------------------------
- // Create our data handle to pass to DeviceLoop
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)NewHandle(sizeof(devLoopData));
- if(hDl) {
- drawControlUPP = NewDeviceLoopDrawingProc(drawControl);
-
- (**hDl).theCtl = theCtl;
- (**hDl).varCode = varCode;
- (**hDl).controlRect = (**theCtl).contrlRect;
-
- //----------------------------------------------------------------------------------
- // Do the clip region properly. Thanks Ari!
- //----------------------------------------------------------------------------------
-
- saveClip = NewRgn();
- GetClip(saveClip);
-
- hRgn = NewRgn();
- RectRgn(hRgn, &(**hDl).controlRect);
- SectRgn(saveClip, hRgn, hRgn);
-
- if(EmptyRgn(hRgn)) { // if empty, don't waste
- DisposeRgn(saveClip); // time drawing...
- DisposeRgn(hRgn);
- return;
- }
-
- //----------------------------------------------------------------------------------
- // Call DeviceLoop to take care of our drawing
- //----------------------------------------------------------------------------------
-
- if(getOSVers() >= 0x0700) {
- DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
- else {
- sys6DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
-
- SetClip(saveClip);
- DisposeRgn(hRgn);
- DisposeHandle((Handle)hDl);
- DisposeRoutineDescriptor(drawControlUPP);
- }
- //----------------------------------------------------------------------------------
- // restore window font & size info
- //----------------------------------------------------------------------------------
-
- if(!(varCode & useWindFont)) {
- TextFont(txF);
- TextSize(txS);
- }
- TextMode(saveMode);
- TextFace(saveFace);
- SetPort(savePort);
- }
-
- //==================================================================================
- // main drawing routine for all variations of the control. Also
- // handles setting of colors, inactive control drawing.
- //
- // This is called by DeviceLoop, but in this case, we just pay attention to the
- // "depth" and "userData" parameters.
- //==================================================================================
-
- pascal void drawControl (short depth, short dFlags, GDHandle theDevice, long userData)
- {
- #pragma unused (dFlags, theDevice)
- ControlHandle theCtl;
- short varCode, xferMode, qdVers, lnHt,lnAdj;
- OSErr err;
- Rect ctlRect, offRect;
- RgnHandle saveClip, ctlClip = 0;
- FontInfo f;
- PenState savePen;
- Boolean grayOK = false, inColor = false, inactive = false, bwPort = true;
- Boolean bgInColor = false, pushBtn = false, useOffscreen = false;
- RGBColor saveFore={0,0,0}, saveBack={-1,-1,-1}, rgbGray;
- #ifdef _GRAYBUTTONS
- RGBColor bodyGray = {_GRAYSHADE, _GRAYSHADE, _GRAYSHADE};
- #endif
- GrafPtr thisPort;
- CGrafPtr savePort, offPort=0;
- GDHandle saveDevice;
- PixMapHandle offPix;
- CDEFHandle hCdef;
- devLoopHandle hDl;
-
- //----------------------------------------------------------------------------------
- // Can we draw?
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)userData; // need control & varCode
- if(hDl) {
- theCtl = (**hDl).theCtl;
- varCode = (**hDl).varCode;
- }
- else {
- return;
- }
-
- hCdef = (CDEFHandle)(**theCtl).contrlData;
- if(!hCdef) {
- return;
- }
-
- //----------------------------------------------------------------------------------
- // Figure out what kind of control we are drawing
- //----------------------------------------------------------------------------------
-
- if(varCode & useWindFont)
- varCode ^= useWindFont;
-
- if(varCode != checkBoxProc && varCode != radioButProc) {
- pushBtn = true;
- }
-
- //----------------------------------------------------------------------------------
- // Initialize for drawing
- //----------------------------------------------------------------------------------
-
- if((*theCtl)->contrlHilite == 255)
- inactive = true;
-
- GetPenState(&savePen);
- GetPort(&thisPort);
- ctlRect = offRect = (*theCtl)->contrlRect;
-
- if((thisPort->txFont != (**hCdef).txFont) || // if font changed,
- (thisPort->txSize != (**hCdef).txSize) || // clear rect to erase
- (thisPort->txFace != (**hCdef).txFace)) { // old font
- (**hCdef).txFont = thisPort->txFont;
- (**hCdef).txSize = thisPort->txSize;
- (**hCdef).txFace = thisPort->txFace;
- EraseRect(&ctlRect);
- }
-
-
- //----------------------------------------------------------------------------------
- // Should we draw in color?
- //
- // What kind of port are we drawing to ? DeviceLoop may have called us with a
- // depth > 1, but for an old-style 1 bit port ( but the GDevice is multi-bit).
- //
- // If so, then set depth to 1 unless we have Color Quickdraw and want to use
- // offscreen drawing to force color controls in the old style grafport.
- //----------------------------------------------------------------------------------
-
- if((((CGrafPtr)thisPort)->portVersion & 0x8000)) // have a color grafPort
- bwPort = false;
-
- #ifdef _USEOFFSCREEN
-
- qdVers = getQDVers();
-
- if(bwPort && qdVers < gestalt32BitQD12) // can't force colors
- depth = 1; // in b&w port unless
- // we have ColorQD
- #else
-
- if(bwPort)
- depth = 1;
-
- #endif
-
- if(depth > 2) { // either color port or
- inColor = true; // color GDevice
- saveColors(&saveFore, &saveBack);
- bgInColor = true;
- if(saveBack.red == 65535 && // is bg white?
- saveBack.green == 65535 &&
- saveBack.blue == 65535)
- bgInColor = false;
- }
-
- //----------------------------------------------------------------------------------
- // Figure out how we should draw - offscreen or not...
- //----------------------------------------------------------------------------------
-
- #ifdef _USEOFFSCREEN
-
- if(inColor && qdVers >= gestalt32BitQD12) { // can use GWorlds
- if(bwPort) // to get 3D in b&w ports
- useOffscreen = true;
- else
- if(!pushBtn && bgInColor) // or to avoid flicker on
- useOffscreen = true; // radio/check titles
- }
-
- //----------------------------------------------------------------------------------
- // Can we draw off screen ?
- //----------------------------------------------------------------------------------
-
- if(useOffscreen) {
- err = NewGWorld(&offPort, 0, &offRect, nil, nil, 0L);
- if(err == noErr && offPort) { // got offscreen port
- offPix = getLockedPixels(&offPort, qdVers); // get pixels
- if(offPix) {
- GetGWorld(&savePort, &saveDevice); // save old port stuff
- SetGWorld(offPort, nil); // set to offscreen port
- SetOrigin(offRect.left, offRect.top); // and initialize it...
- RGBForeColor(&saveFore);
- RGBBackColor(&saveBack);
- TextFont(thisPort->txFont);
- TextSize(thisPort->txSize);
- TextFace(thisPort->txFace);
- TextMode(srcOr);
- EraseRect(&offRect);
- }
- else {
- DisposeGWorld(offPort);
- offPort = 0;
- }
- }
- else
- offPort = 0;
- }
-
- #endif // _USEOFFSCREEN
-
- //----------------------------------------------------------------------------------
- // Set the correct colors for drawing the control frames.
- //----------------------------------------------------------------------------------
-
- if(inColor) {
- setPartColor(theCtl, cFrameColor, true); // foreground
- if(pushBtn) {
- #ifdef _GRAYBUTTONS
- ForeColor(blackColor); // foreground
- if(!(varCode & useWindBG)) {
- RGBBackColor(&bodyGray); // background
- }
- #else
- if(!(varCode & useWindBG)) {
- setPartColor(theCtl, cBodyColor, false);// background
- }
- #endif
- }
- if(inactive) { // get a gray that is
- if(getGray(&rgbGray)) // relative to current
- RGBForeColor(&rgbGray); // fore & background colors
- }
- }
-
- //----------------------------------------------------------------------------------
- // Finish init of drawing port
- // Set a 1 by 1, solid pattern pen for our drawing.
- //----------------------------------------------------------------------------------
-
- PenSize(1,1);
- PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
-
- //----------------------------------------------------------------------------------
- // Get font info so the title lines up correctly
- //----------------------------------------------------------------------------------
-
- GetFontInfo(&f); // needed for title routine
- lnAdj = f.descent + f.leading;
- lnHt = f.ascent + lnAdj;
-
- //----------------------------------------------------------------------------------
- // Finally, draw controls into GWorld (if set, otherwise to screen).
- //----------------------------------------------------------------------------------
-
- if(varCode == checkBoxProc)
- drawCheck(theCtl, &ctlRect, inColor);
- else
- if(varCode == radioButProc)
- drawRadio(theCtl, &ctlRect, inColor, inactive);
- else
- if(pushBtn)
- drawPush(theCtl, &offRect, varCode, inColor, lnHt, lnAdj);
-
- //----------------------------------------------------------------------------------
- // Set correct colors and draw the control titles. Must set the correct fore/back
- // colors so the getGray routine returns the correct gray for dimmed controls.
- //----------------------------------------------------------------------------------
-
- if(inColor) {
-
- #ifdef _EMBOSS
- if( !pushBtn && bgInColor) {
- ForeColor(whiteColor);
- drawTitle (theCtl, &offRect, varCode, lnHt, lnAdj, EMBOSS, !PUSHED);
- }
- #endif
-
- setPartColor(theCtl, cTextColor, true); // title color
-
- if(inactive) { // need a grayed title
- if(pushBtn) {
- #ifdef _GRAYBUTTONS
- RGBBackColor(&bodyGray);
- #else
- setPartColor(theCtl, cBodyColor, false);
- #endif
- }
- else {
- RGBBackColor(&saveBack);
- }
-
- grayOK = getGray(&rgbGray);
- if(grayOK) {
- RGBForeColor(&rgbGray);
- }
- }
- }
- if(!pushBtn || inactive) {
- drawTitle(theCtl, &offRect, varCode, lnHt, lnAdj, NORMAL, !PUSHED);
- }
-
- //----------------------------------------------------------------------------------
- // If we drew offscreen, restore the onscreen port and blit the control image.
- //----------------------------------------------------------------------------------
-
- #ifdef _USEOFFSCREEN
-
- if(offPort) {
- SetGWorld(savePort, saveDevice);
-
- //----------------------------------------------------------------------------------
- // Blit the pushButton or titles for the other controls to the screen (avoiding
- // flicker on embossed titles).
- //----------------------------------------------------------------------------------
-
- if(pushBtn) {
- xferMode = srcCopy; // cover any pattern completely
- ForeColor(blackColor);
- BackColor(whiteColor);
- }
- else {
- xferMode = transparent; // overlay on pattern
- restoreColors(&saveFore, &saveBack);
- offRect.left+=14;
- ctlRect.left+=14;
- }
- if(pushBtn || (**theCtl).contrlTitle[0])
- CopyBits( &WINBITMAP( offPort ), &WINBITMAP( savePort ),
- &offRect, &ctlRect, xferMode, nil );
-
- //----------------------------------------------------------------------------------
- // Finally, blit the checkBox & radioButton indicators to the screen. Doing this
- // last & with a proper clip region and srcCopy transfer mode insures that they
- // will appear correctly on patterned backgrounds or when drawn on top of a picture
- // (as in Web browsers).
- //----------------------------------------------------------------------------------
-
- if(!pushBtn) {
- ForeColor(blackColor);
- BackColor(whiteColor);
- ctlRect.left-=14;
- saveClip = NewRgn();
- GetClip(saveClip);
- ctlClip = NewRgn();
- OpenRgn();
- getIndicatorRect(&ctlRect, &offRect);
- if(varCode == checkBoxProc) {
- if((offRect.top > ctlRect.top) && (offRect.bottom < ctlRect.bottom))
- InsetRect(&offRect, -1, -1);
- FrameRect(&offRect);
- }
- else
- FrameOval(&offRect);
- CloseRgn(ctlClip);
- SetClip(ctlClip);
-
- CopyBits( &WINBITMAP( offPort ), &WINBITMAP( savePort ),
- &offRect, &offRect, srcCopy, nil );
-
- SetClip(saveClip);
- DisposeRgn(ctlClip);
- }
- unlockPixels(offPix, qdVers);
- DisposeGWorld(offPort);
- }
-
- #endif // _USEOFFSCREEN
-
- //----------------------------------------------------------------------------------
- // gray inactive controls the System 6 way if needed (couldn't get gray for title)
- //----------------------------------------------------------------------------------
-
- if(!grayOK && inactive) { // gray out the old way
- PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
- PenMode(patBic);
- if(pushBtn)
- InsetRect(&ctlRect, 2, 2); // only interior of button
- else
- ctlRect.left+=18; // not the indicator area
- ClipRect(&ctlRect);
- PaintRect(&ctlRect);
- }
-
- //----------------------------------------------------------------------------------
- // Clean up and leave
- //----------------------------------------------------------------------------------
-
- if(inColor)
- restoreColors(&saveFore, &saveBack);
- SetPenState(&savePen);
- }
-
- //==================================================================================
- // The push button drawing routine for a regular oval button
- //==================================================================================
-
- static void drawPush(ControlHandle theCtl, Rect *r, short varCode, Boolean inColor,
- short lnHt, short lnAdj)
- {
- short radius;
- Boolean pushed=false;
- RGBColor saveFore, saveBack;
-
- //----------------------------------------------------------------------------------
- // At least 1 lazy programmer has used narrow buttons to create
- // simple lines to separate items in a dialog. Hence this
- // funny looking check.
-
- if((r->bottom - r->top) < 5 || (r->right - r->left) < 5) {
- FrameRect(r);
- return;
- }
-
- //----------------------------------------------------------------------------------
-
- if((*theCtl)->contrlHilite == inButton ||
- (**theCtl).contrlHilite == 1)
- pushed = true;
-
- //----------------------------------------------------------------------------------
- // Set our colors for drawing the button. ForeColor has been set to cFrameColor.
- //----------------------------------------------------------------------------------
-
-
- if(inColor) { // 3D button
- saveColors(&saveFore, &saveBack);
-
- //----------------------------------------------------------------------------------
- // Draw the button and title
- //----------------------------------------------------------------------------------
-
- do3DPush(theCtl, varCode, r, pushed); // draw button
-
- drawTitle(theCtl, r, varCode, lnHt, lnAdj, EMBOSS, pushed);
-
- if((**theCtl).contrlHilite != 0xFF) {
- setPartColor(theCtl, cTextColor, true);
- drawTitle(theCtl, r, varCode, lnHt, lnAdj, !EMBOSS, pushed);
- }
- restoreColors(&saveFore, &saveBack);
- }
-
- //----------------------------------------------------------------------------------
- // If not in color, draw a button that is identical to the standard Mac button.
- //----------------------------------------------------------------------------------
-
- else { // normal button
- radius = (r->bottom - r->top)/2;
- FillRoundRect(r, radius, radius,
- (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
- drawTitle(theCtl, r, varCode, lnHt, lnAdj, !EMBOSS, !PUSHED);
- if(pushed)
- InvertRoundRect(r, radius, radius);
- FrameRoundRect(r, radius, radius);
- }
- }
-
- //==================================================================================
- // A little utility routine to return that portion of the controlRect that the
- // CheckBox or RadioButton should occupy.
- //==================================================================================
-
- static void getIndicatorRect(Rect *ctlRect, Rect *r)
- {
- Point p;
-
- *r = *ctlRect;
- p.h = r->left;
- p.v = r->bottom - (r->bottom - r->top)/2 - 1; // get pen loc for drawing
-
- r->left+=2; // calculate the destination
- r->bottom = p.v+7; // rect for a check/radio
- r->right = r->left+12; // indicator
- r->top = r->bottom-12;
- }
-
- //==================================================================================
- // The check box drawing routine
- //==================================================================================
-
- static void drawCheck(ControlHandle theCtl, Rect *ctlRect, Boolean inColor)
- {
- Rect r;
- RGBColor saveFore, saveBack, rgbA = {0xAAAA,0xAAAA,0xAAAA};
-
- getIndicatorRect(ctlRect, &r);
-
- if(inColor) {
- saveColors(&saveFore, &saveBack);
- BackColor(whiteColor);
- }
-
- FillRect(&r, (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
- FrameRect(&r);
-
- if(inColor) { // a VERY slight
- RGBForeColor(&rgbA); // 3D effect.
- MoveTo(r.left-1,r.bottom);
- LineTo(r.left-1,r.top-1);
- LineTo(r.right,r.top-1);
-
- ForeColor(whiteColor);
- Move(0,1);
- LineTo(r.right,r.bottom);
- LineTo(r.left,r.bottom);
-
- restoreColors(&saveFore, &saveBack);
- }
-
- if((*theCtl)->contrlHilite == inCheckBox ||
- (**theCtl).contrlHilite == 1) { // hilited button
- InsetRect(&r, 1, 1);
- FrameRect(&r);
- InsetRect(&r, -1, -1);
- }
-
- if((*theCtl)->contrlValue != OFF) { // button center
- #ifdef _REALCHECK
- MoveTo(r.left+2,r.top+5);
- Line(0,2);
- Move(1,-1);
- Line(0,2);
- Move(1,-1);
- Line(0,2);
- Move(1,-1);
- Line(0,-2);
- Move(1,1);
- Line(0,-2);
- Move(1,1);
- Line(0,-2);
- Move(1,1);
- Line(0,-2);
- Move(1,1);
- Line(0,-2);
- #else
- MoveTo(r.right-2, r.top+1);
- LineTo(r.left+1, r.bottom-2);
- MoveTo(r.left, r.top);
- LineTo(r.right-2, r.bottom-2);
- #endif
- }
- }
-
- //==================================================================================
- // The radio button drawing routine
- //==================================================================================
-
- static void drawRadio(ControlHandle theCtl, Rect *ctlRect, Boolean inColor,
- Boolean inactive)
- {
- Rect r;
- RGBColor saveBack;
-
- getIndicatorRect(ctlRect, &r);
-
- if(inColor) {
- GetBackColor(&saveBack);
- BackColor(whiteColor);
- }
-
- FillOval(&r, (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
- FrameOval(&r);
-
- if(inColor && !inactive)
- do3DRadio(theCtl, &r); // button shading
-
- if((*theCtl)->contrlHilite == inCheckBox ||
- (**theCtl).contrlHilite == 1) { // hilited button
- InsetRect(&r, 1, 1);
- FrameOval(&r);
- InsetRect(&r, -1, -1);
- }
- if((*theCtl)->contrlValue != OFF) { // button center
- InsetRect(&r, 3, 3);
- PaintOval(&r);
- }
- if(inColor)
- RGBBackColor(&saveBack);
- }
-
- //==================================================================================
- // Draw a shaded 3D radioButton with a "squishy" look.
- //==================================================================================
-
- static void do3DRadio(ControlHandle theCtl, Rect *r)
- {
- RGBColor rgbA = {0xAAAA, 0xAAAA, 0xAAAA};
- RGBColor rgbB = {0xBBBB, 0xBBBB, 0xBBBB};
- RGBColor rgbD = {0xDDDD, 0xDDDD, 0xDDDD};
- RGBColor rgbE = {0xEEEE, 0xEEEE, 0xEEEE};
- RGBColor saveFore;
-
- GetForeColor(&saveFore);
-
- if((**theCtl).contrlValue) { // button is ON, draw it so that
- RGBForeColor(&rgbA); // it appears depressed.
- MoveTo(r->right-5, r->top+1);
- Line(-3,0);
- Move(0,1);
- Line(-2,0);
- Move(1,1);
- Line(-1,0);
- Line(0,1);
- Line(-1,0);
- Line(0,3);
-
- RGBForeColor(&rgbB);
- Move(1,2);
- Line(0,-4);
- Move(3,-3);
- Line(3,0);
-
- RGBForeColor(&rgbD);
- Move(0,1);
- Line(0,0);
- Move(-5,5);
- Line(0,1);
- }
- else { // button is OFF, draw so that
- RGBForeColor(&rgbA); // it appears raised.
- MoveTo(r->left+4, r->bottom-2);
- Line(3,0);
- Move(0,-1);
- Line(2,0);
- Move(-1,-1);
- Line(1,0);
- Line(0,-1);
- Line(1,0);
- Line(0,-3);
-
- RGBForeColor(&rgbB);
- Move(-1,-2);
- Line(0,4);
- Line(-3,3);
- Line(-1,0);
- Move(1,-1);
- Line(2,-2);
-
- RGBForeColor(&rgbD);
-
- Move(0,-1);
- Line(0,-3);
- Move(-1,4);
- Line(-3,3);
- Line(-1,0);
-
- RGBForeColor(&rgbE);
- Move(0,-1);
- Line(1,0);
- Move(1,-1);
- Line(2,-2);
- Line(0,-4);
- Move(-1,4);
- Line(-2,2);
- }
- RGBForeColor(&saveFore);
- }
-
- //==================================================================================
- // Draw the control titles - handles multiple lines and 3D embossing
- //==================================================================================
-
- static void drawTitle (ControlHandle theCtl, Rect *ctlRect, short varCode, short lnHt,
- short lnAdj, Boolean emboss, Boolean pushed)
- {
- Rect r;
- short inx=1,lnCnt=1,lnSpace,ctlSpace,v,h,adj=0;
- Str255 s;
-
- if((*theCtl)->contrlTitle[0] == 0)
- return;
- r = *ctlRect;
-
- do { // count number of lines
- if((*theCtl)->contrlTitle[inx++] == 0x0d)
- lnCnt++;
- }while (inx <= (*theCtl)->contrlTitle[0]);
-
- lnSpace = lnCnt * lnHt; // required space
- ctlSpace = r.bottom - r.top; // available height
- v = r.bottom; // baseline
- v-=(ctlSpace - lnSpace)/2; // minus free space
- v-=lnAdj; // minus descent+leading
- v-=((lnCnt-1)*lnHt); // minus other lines
- // v is now base for line 1
- for(inx=1;inx<=lnCnt;inx++) {
- getNextLine((*theCtl)->contrlTitle, s, inx);
- if(s[0]) {
- if(varCode == radioButProc || varCode == checkBoxProc)
- h = r.left + 18;
- else
- h = r.left + (r.right - r.left - StringWidth(s))/2;
-
- if(emboss & pushed)
- adj = -1;
- else
- if(emboss)
- adj = 1;
-
- MoveTo(h+adj, v+adj);
- DrawString(s);
- }
- v+=lnHt;
- }
- }
-
- //==================================================================================
- // Grab the next line of a control title (assumes lines separated by CR)
- //==================================================================================
-
- static void getNextLine(Str255 t, Str255 s, short line)
- {
- short inx=1,len=0,lnCnt=1;
-
- s[0] = 0; // always default to null string
-
- do {
- if(t[inx] == 0x0d) // next line
- lnCnt++;
- else
- if(lnCnt == line) { // return this line
- len++;
- s[0] = len;
- s[len] = t[inx];
- }
- inx++;
- }while (inx <= t[0]);
- }
-
- #ifdef _RECTPUSH
- //==================================================================================
- // Utility routines for the Rectangular 3D push button
- //==================================================================================
- static void topLeftInner(Rect *r)
- {
- MoveTo(r->right-3,r->top+2);
- LineTo(r->left+2, r->top+2);
- LineTo(r->left+2, r->bottom-3);
- }
- static void topLeftOuter(Rect *r)
- {
- MoveTo(r->right-2,r->top+1);
- LineTo(r->left+1, r->top+1);
- LineTo(r->left+1, r->bottom-2);
- }
- static void bottomRightOuter(Rect *r)
- {
- MoveTo(r->left+2, r->bottom-2);
- LineTo(r->right-2,r->bottom-2);
- LineTo(r->right-2,r->top+2);
- }
- static void bottomRightInner(Rect *r)
- {
- MoveTo(r->left+3, r->bottom-3);
- LineTo(r->right-3, r->bottom-3);
- LineTo(r->right-3, r->top+3);
- }
-
- //==================================================================================
- // Draw a Rectangular 3D pushButton
- //==================================================================================
-
- static void do3DPush(ControlHandle theCtl, short varCode, Rect *r, Boolean pushed)
- {
- RGBColor tingeColor[6];
- Boolean okToTinge=false;
-
- GetForeColor(&tingeColor[vDark]);
- GetBackColor(&tingeColor[vLight]);
-
- #ifndef _GRAYBUTTONS
-
- if(tingeColor[vDark].red == 0 && // only use system tinge on b&w buttons
- tingeColor[vDark].green == 0 && // (i.e. without a custom 'cctb')
- tingeColor[vDark].blue == 0 &&
- tingeColor[vLight].red == 65535 &&
- tingeColor[vLight].green == 65535 &&
- tingeColor[vLight].blue == 65535) {
-
- okToTinge = true;
- }
-
- if(!(varCode & useWindBG) && okToTinge) {
- setPartColor(theCtl, cBodyColor, false); // set bgColor
- GetBackColor(&tingeColor[vLight]);
- }
-
- #endif
-
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0xc, &tingeColor[dark]);
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x9, &tingeColor[medDark]);
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x7, &tingeColor[medLight]);
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x3, &tingeColor[light]);
-
- if(pushed) {
- RGBBackColor(&tingeColor[medLight]);
- RGBForeColor(&tingeColor[light]);
- }
-
- FillRect(r, (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
-
- RGBForeColor(&tingeColor[vDark]);
- FrameRect(r);
-
- if(pushed) {
- RGBForeColor(&tingeColor[dark]);
- topLeftOuter(r);
-
- RGBForeColor(&tingeColor[medDark]);
- topLeftInner(r);
-
- RGBForeColor(&tingeColor[light]);
- bottomRightInner(r);
-
- RGBForeColor(&tingeColor[vLight]);
- bottomRightOuter(r);
- RGBForeColor(&tingeColor[light]);
- }
- else {
- RGBForeColor(&tingeColor[vLight]);
- #ifdef _USETINGE
- if(okToTinge) {
- setSysColor(cTingeLight, true);
- }
- #endif
- topLeftOuter(r);
-
- ForeColor(whiteColor);
- topLeftInner(r);
-
- RGBForeColor(&tingeColor[light]);
- #ifdef _USETINGE
- if(okToTinge) {
- setSysColor(cTingeLight, true);
- }
- #endif
- bottomRightInner(r);
-
- RGBForeColor(&tingeColor[medLight]);
- bottomRightOuter(r);
- ForeColor(whiteColor);
- }
- }
- #else
-
- //==================================================================================
- // Utility routines for the Oval 3D push button
- //==================================================================================
-
- static void topLeftInner(Rect *r)
- {
- MoveTo(r->right-4, r->top+2);
- LineTo(r->left+3, r->top+2);
- Move(0,1);
- LineTo(r->left+2, r->top+3);
- LineTo(r->left+2, r->bottom-4);
- }
- static void topLeftOuter(Rect *r)
- {
- MoveTo(r->right-4,r->top+1);
- LineTo(r->left+3,r->top+1);
- Move(-1,1);
- LineTo(r->left+2,r->top+2);
- Move(-1,1);
- LineTo(r->left+1,r->bottom-4);
- }
- static void bottomRightOuter(Rect *r)
- {
- MoveTo(r->left+3, r->bottom-2);
- LineTo(r->right-4,r->bottom-2);
- Move(1,-1);
- LineTo(r->right-2,r->bottom-4);
- LineTo(r->right-2,r->top+3);
- }
- static void bottomRightInner(Rect *r)
- {
- MoveTo(r->left+2, r->bottom-3);
- LineTo(r->right-4, r->bottom-3);
- Move(0,-1);
- LineTo(r->right-3, r->bottom-4);
- LineTo(r->right-3, r->top+2);
- }
-
- //==================================================================================
- // Draw an Oval 3D pushButton
- //==================================================================================
- static void do3DPush(ControlHandle theCtl, short varCode, Rect *r, Boolean pushed)
- {
- RGBColor tingeColor[6];
- Boolean okToTinge=false;
-
- GetForeColor(&tingeColor[vDark]);
- GetBackColor(&tingeColor[vLight]);
-
- #ifndef _GRAYBUTTONS
-
- if(tingeColor[vDark].red == 0 && // only use system tinge on b&w buttons
- tingeColor[vDark].green == 0 && // (i.e. without a custom 'cctb')
- tingeColor[vDark].blue == 0 &&
- tingeColor[vLight].red == 65535 &&
- tingeColor[vLight].green == 65535 &&
- tingeColor[vLight].blue == 65535) {
-
- okToTinge = true;
- }
-
- if(!(varCode & useWindBG) && okToTinge) {
- setPartColor(theCtl, cBodyColor, false); // set bgColor
- GetBackColor(&tingeColor[vLight]);
- }
-
- #endif
-
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0xc, &tingeColor[dark]);
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x9, &tingeColor[medDark]);
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x7, &tingeColor[medLight]);
- mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x3, &tingeColor[light]);
-
- if(pushed) {
- RGBBackColor(&tingeColor[medLight]);
- RGBForeColor(&tingeColor[light]);
- }
-
- FillRoundRect(r, 10, 10,
- (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
-
- RGBForeColor(&tingeColor[vDark]);
- FrameRoundRect(r, 10, 10);
-
- if(pushed) {
- RGBForeColor(&tingeColor[dark]);
- topLeftOuter(r);
-
- RGBForeColor(&tingeColor[medDark]);
- topLeftInner(r);
-
- RGBForeColor(&tingeColor[light]);
- bottomRightInner(r);
-
- RGBForeColor(&tingeColor[vLight]);
- bottomRightOuter(r);
- RGBForeColor(&tingeColor[light]);
- }
- else {
-
- RGBForeColor(&tingeColor[vLight]);
- #ifdef _USETINGE
- if(okToTinge) {
- setSysColor(cTingeLight, true);
- }
- #endif
- topLeftOuter(r);
-
- ForeColor(whiteColor);
- topLeftInner(r);
-
- RGBForeColor(&tingeColor[light]);
- #ifdef _USETINGE
- if(okToTinge) {
- setSysColor(cTingeLight, true);
- }
- #endif
- bottomRightInner(r);
-
- RGBForeColor(&tingeColor[medLight]);
- bottomRightOuter(r);
- ForeColor(whiteColor);
- }
- }
- #endif
-
- //==================================================================================
- // NOTICE: This routine stolen from Troy Gaul & the Infinity Windoid.
- // Thanks, Troy!
- //==================================================================================
-
- static void mixColor(RGBColor *light, RGBColor *dark, short shade,
- RGBColor *result)
- {
- shade = 0x0F - shade;
- // This is necessary because we give shades between light and
- // dark (0% is light), but for colors, $0000 is black and $FFFF
- // is dark.
-
- result->red = (long) (light->red - dark->red) * shade / 15 + dark->red;
- result->green = (long) (light->green - dark->green) * shade / 15 + dark->green;
- result->blue = (long) (light->blue - dark->blue) * shade / 15 + dark->blue;
- }
-
- #ifdef _USEOFFSCREEN
-
- //==================================================================================
- // Lock down the offPort pixels and return a locked handle to the locked pixels
- //==================================================================================
-
- static PixMapHandle getLockedPixels(CGrafPtr * offPort, short qdVers)
- {
- PixMapHandle pmHdl;
-
- if(qdVers >= gestalt32BitQD13) { // no bug in the
- pmHdl = GetGWorldPixMap(*offPort); // GetGWorldPixMap routine
- if(!LockPixels(pmHdl)) {
- pmHdl = 0;
- }
- }
- else
- pmHdl = (*offPort)->portPixMap;
-
- if(pmHdl)
- HLock((Handle)pmHdl);
- return(pmHdl);
- }
-
- //==================================================================================
- // Unlock PixMapHandle & pixels
- //==================================================================================
-
- static void unlockPixels(PixMapHandle pmHdl, short qdVers)
- {
- if(pmHdl) {
- HUnlock((Handle)pmHdl);
- if(qdVers >= gestalt32BitQD13) { // no bug in the
- UnlockPixels(pmHdl); // GetGWorldPixMap routine
- }
- }
- }
-
- //==================================================================================
- // Return QD version number from Gestalt
- //==================================================================================
-
- static short getQDVers()
- {
- OSErr err;
- long gResult;
-
- if(trapAvailable(_Gestalt)) {
- err = Gestalt(gestaltQuickdrawVersion,&gResult);
- if(err == noErr)
- return(LoWord(gResult));
- }
- return(gestaltOriginalQD);
- }
-
- #endif // _USEOFFSCREEN