Color 2
Volume Number: 10
Issue Number: 11
Column Tag: Getting Started
Working With Color, Part 2 
By Dave Mark, MacTech Magazine Regular Contributing Author
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Before we get into this month’s column, I’d like to take a second to talk about
some changes that are coming down the ’pike. Every month, I’m faced with a perplexing
challenge. How can I present a decent sized program in my column, and still have room
to walk through the source code? The current solution is to split the column over two
issues. The first month I present the program’s resources and source code and the
second month I actually walk through the source code, essentially giving you the source
code twice.
Unfortunately, there’s no easy way to simplify this process. If I just present the
source code as a single block, there’s no room for commentary and if I just present the
source code with comments mixed in it makes it extremely difficult to type in the code.
Not a good situation!
Fortunately, the powers-that-be came up with a pretty cool idea (which I’m
sure you’ll read about elsewhere in the magazine over the next few months). They are
putting together a small framework, called Sprocket, designed to showcase new Mac
technologies. Sprocket will start off with same pretty basic capabilities, then grow as
time goes on. It will be written entirely in C++ and will be made available to every
MacTech subscriber.
This makes life infinitely easier for us column writers! Instead of presenting a
single, monolithic application every two months, I’ll be able to focus on a few new
classes, which can be folded into the framework and, more importantly, which can be
presented and completely discussed, all in a single column.
The biggest implication this has for you is a change from C to C++. If this is a bad
thing, now’s the time to get it off your chest. Send all bitter, sarcastic complaints to
Scott Boyd, at one of the myriad addresses found on page 2 of this magazine.
I’m really looking forward to getting into this new framework and polishing my
C++ skills. I think this is a great idea and hope you do too...
Back to ColorTutor
All that said and done, let’s get back to last month’s program, ColorTutor. To
recap last month’s description, ColorTutor is a rewrite of the Mac Primer, Volume II
program of the same name. ColorTutor is a hands-on color blending environment. You
specify the foreground and background colors and patterns, then select a Color
Quickdraw drawing mode. ColorTutor uses CopyBits() to mix the foreground and
background colors. Figure 1 shows a sample.
Figure 1. The ColorTutor window.
ColorTutor first copies the Background image to the lower-right rectangle, then
copies the Source image on top of the Background using the current Mode and OpColor.
As we dig through the code, we’ll look at the parts of Color Quickdraw that make
ColorTutor possible.
Exploring the ColorTutor Source Code
ColorTutor starts off with a pair of #includes. contains the definitions we’ll need to use the Mac’s built-in color picker, while contains what
we’ll need to call Gestalt().
/* 1 */
#include
Here’s the usual cast of constants...
#define kBaseResID 128
#define kErrorALRTid 128
#define kNullFilterProc NULL
#define kMoveToFront (WindowPtr)-1L
#define kNotNormalMenu -1
#define kSleep 60L
#define mApple kBaseResID
#define iAbout 1
#define mFile kBaseResID+1
#define iQuit 1
#define mColorsPopup kBaseResID+3
#define iBlackPattern 1
#define iGrayPattern 2
#define iColorRamp 4
#define iGrayRamp 5
#define iSingleColor 6
#define mModePopup kBaseResID+4
We’ve sure got a lot of globals. Short of adding pass-through parameters to a
bunch of routines, I couldn’t think of any way to get rid of them. Any ideas?
gDone is the flag that tells us when to drop out of the main event loop. gSrcRect,
gBackRect, gDestRect, and gOpColorRect mark the boundaries of the four color
rectangles in the ColorTutor window. gSrcMenuRect, gBackMenuRect, and
gModeMenuRect mark the outline of the three popup menus. As you read through the
code, remember that ‘Src’ refers to the source color, ‘Back’ refers to the background
color, and ‘Op’ refers to the op-color (you’ll find out what the opcolor is about later in
the column).
‘Dest’ and ‘Mode’ both refer to the lower-right corner of the ColorTutor window.
‘Dest’ refers to the lower-right color rectangle which is used to mix the source and
background colors. ‘Mode’ refers to the popup menu below the ‘Dest’ rectangle and
specifies the color drawing mode used to mix the source and background colors.
/* 2 */
Boolean gDone;
Rect gSrcRect, gBackRect, gDestRect, gSrcMenuRect,
gBackMenuRect, gModeMenuRect, gOpColorRect;
The next set of globals mirror the current settings of the three popup menus.
gSrcPattern is set to either iBlackPattern or iGrayPattern, and gSrcType is one of
iColorRamp, iGrayRamp, or iSingleColor. These choices correspond directly to the
menu in Figure 2. gBackPattern and gBackType follow the exact same rules, since the
Background menu was built from the same MENU resource.
Figure 2. The popup menu that goes along with the Source and Background menus.
gCopyMode is one of the Color Quickdraw copy modes and mirrors the Mode menu
shown in Figure 3. gCopyMode is set in the routine UpdateModeMenu().
Figure 3. The Mode popup menu.
/* 3 */
short gSrcPattern, gBackPattern, gCopyMode, gSrcType, gBackType;
gSrcColor, gBackColor, and gOpColor are the colors displayed in the source,
background, and op-color rectangles in the ColorTutor window. The source and
background colors only come into play when the Single Color... item is checked in their
respective popup menus. The OpColor is always a single color and comes into play when
you use certain Color Quickdraw copying modes.
/* 4 */
RGBColor gSrcColor, gBackColor, gOpColor;
Finally, gSrcMenu, gBackMenu, and gModeMenu are handles to their respective
menus.
/* 5 */
MenuHandle gSrcMenu, gBackMenu, gModeMenu;
Here are all the function prototypes...
/* 6 */
void ToolboxInit( void );
void MenuBarInit( void );
void CreateWindow( void );
void SetUpGlobals( void );
void EventLoop( void );
void DoEvent( EventRecord * eventPtr );
void HandleMouseDown( EventRecord * eventPtr );
void HandleMenuChoice( long menuChoice );
void HandleAppleChoice( short item );
void HandleFileChoice( short item );
void DoUpdate( WindowPtr window );
void DrawContents( WindowPtr window );
void DrawColorRamp( Rect *rPtr );
void DrawGrayRamp( Rect *rPtr );
void DrawLabel( Rect *boundsPtr, Str255 s );
void DoContent( WindowPtr window, Point globalPoint );
void UpdateSrcMenu( void );
void UpdateBackMenu( void );
void UpdateModeMenu( void );
void DoSrcChoice( short item );
void DoBackChoice( short item );
void DoModeChoice( short item );
short DoPopup( MenuHandle menu, Rect *boundsPtr );
Boolean PickColor( RGBColor *colorPtr );
Boolean HasColorQD( void );
void DoError( Str255 errorString );
main() initializes the Toolbox, sets up the menu bar, then checks to see if this
machine supports Color Quickdraw. It’s important to at least initialize the Toolbox
before you check for Color Quickdraw, since we use the Toolbox to report an error if
Color Quickdraw is not present.
/* 7 */
main
void main( void )
{
ToolboxInit();
MenuBarInit();
if ( ! HasColorQD() )
DoError( "\pThis machine does not support Color QuickDraw!" );
Next, we’ll create the ColorTutor window, assign initial values to our globals,
then drop into the main event loop.
/* 8 */
CreateWindow();
SetUpGlobals();
EventLoop();
}
ToolboxInit() is pretty much the same as always. Notice the use of qd.thePort
instead of just plain thePort. THINK C and C++ assume that when you refer to a
quickdraw global (like thePort) you are referring to the corresponding quickdraw
global that gets allocated as part of each application’s memory zone. MPW and
CodeWarrior both require the “qd.” syntax, turning “thePort” into “qd.thePort”.
Since THINK C can handle either form, I’ve gone back to the “qd.” form so all my code
compiles in either environment.
/* 9 */
ToolboxInit
void ToolboxInit( void )
{
InitGraf( &qd.thePort );
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs( 0L );
InitCursor();
}