Selective Color
Volume Number: | | 10
|
Issue Number: | | 1
|
Column Tag: | | C Workshop
|
Related Info: Dialog Manager
Selective Color
Using custom color buttons on color and black and white Macs
By Mark W. Batten, Washington, D.C.
Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.
Custom color buttons enliven any application, but if the programmer is writing software that must run on both black-and-white and color machines (as most of us are), it may seem daunting to write code that will draw the button different ways on differently configured machines. This article demonstrates a simple scheme to create buttons that are smart enough to be custom-drawn on color machines, and as regular Toolbox buttons on black-and-white machines.
The key to the technique is the Toolbox routine SetDItem. Although generally used only to change a dialog items rectangle, SetDItem is actually quite powerful; it lets you change just about everything associated with a dialog item. In this example, well use it to point the Mac to our own CDEF to draw the button on color machines.
Setting Up The Resources
First, you need to create the CDEF that draws the color button. At the end of this article is source code for a sample button with a nice 3-D appearance.
(This particular CDEF uses an auxiliary control record (as described in Inside Macintosh, Vol. 5, pp. 216-18) to tell it what colors to draw the control in. If youve never encountered these arcane things, dont worry; you dont need to understand them to implement the scheme described in the article).
Second, create a dialog (DLOG) and a dialog item list (DITL) for your application as you normally would. Be sure that your DLOG will not be displayed when its loaded (in ResEdit, be sure the Initially visible box is unchecked). The DITL should use normal, vanilla buttons for OK and Cancel. That way, the resource is all set up to run normally on black-and-white machine, without any more work.
For this example, you also need to create two other resources: a dialog color table (dctb) and a control color table (cctb). (The correct values for the sample are listed at the end of this article). The dctb serves two functions here: first, when you call GetNewDialog to read in a dialog, the Mac will automatically make it a color dialog, based on a CGrafPort, if the Mac finds a dctb with the same ID as the DLOG resource. Second, the dctb colors the content area of the dialog, which makes our button look better. The CDEF uses the cctb resource to determine what colors to use when drawing the custom button.
Making The Switch
On a black-and-white Mac, the dialog will perform as its supposed to, without any special code in your application. To do something fancier on color machines, your application just has to alert the Dialog Manager to use our custom CDEF instead of the standard one. Here are the necessary steps.
1. In your applications initialization routines, load the CDEF resource and the cctb color table into variables, like this:
/* 1 */
Handle myCDEF; /* handle to our custom CDEF */
CTabHandle CtrlCTab;/* handle to colors for our control */
myCDEF=GetResource('CDEF',32);
CtrlCTab=(CTabHandle)GetResource('cctb',128);
2. When youre ready to create the dialog, load it with GetNewDialog (or build it from scratch with NewDialog). Then call the following routine, which uses SetDItem to tell the Mac where to find our custom code. Pass the DialogPtr in d and the item number of the button you want to convert in i:
/* 2 */
ConvertToColorButtons(d,i)
DialogPtr d;
int i;
{
int j;
Handle tItem;
Rect box;
char n[31];
GetDItem(d,i,&j,&tItem,&box);
if(j==ctrlItem+btnCtrl ||
j==ctrlItem+btnCtrl+itemDisable){
SetCtlColor(tItem,CtrlCTab);
(**((ControlHandle)tItem)).contrlDefProc=myCDEF;
j&=127;
SetDItem(d,i,j,tItem,&box);
}
}
Here's the CDEF code.
pascal long main(var,CH,msg,par)
int msg,var;
ControlHandle CH;
long par;
{
long l;
l=0L;
switch(msg){
case 0:
doDraw(CH);
break;
case 1:
l=(long)doTest(par,CH);
break;
case 2:
doCalc(par,CH);
break;
}
return l;
}
doTest(par,CH)
long par;
ControlHandle CH;
{
Point pt;
pt.v=HiWord(par);
pt.h=LoWord(par);
return (int)PtInRect(pt,&((**CH).contrlRect));
}
doCalc(par,CH)
RgnHandle par;
ControlHandle CH;
{
par=(RgnHandle)((long)par&0x7FFFFFFF);
RectRgn(par,&((**CH).contrlRect));
}
doDraw(CH)
ControlHandle CH;
{
int j,k,*p;
Handle tItem;
Rect r;
RGBColor rgb,rgb1,rgb2;
AuxCtlHandle ax;
FontInfo inf;
r=(**CH).contrlRect;
j=StringWidth((**CH).contrlTitle);
GetFontInfo(&inf);
k=inf.ascent+inf.descent;
k=(r.top+r.bottom+k)/2;
MoveTo((r.left+r.right-j)/2,k-inf.descent);
DrawString((**CH).contrlTitle);
GetAuxCtl(CH,&ax);
p=(int *)&(**(**ax).acCTable).ctTable[0].rgb.red;
rgb.red=p[0]; /* 21845, 0x5555*/
rgb.green=p[1]; /* 21845, 0x5555*/
rgb.blue=p[2]; /* 21845, 0x5555*/
rgb1.red=p[4]; /* 34952, 0x8888*/
rgb1.green=p[5];/* 34952, 0x8888*/
rgb1.blue=p[6]; /* 34952, 0x8888*/
rgb2.red=rgb2.green=rgb2.blue=0xFFFF;
PenSize(2,2);
RGBForeColor(&rgb);
MoveTo(r.right-2,r.top);
LineTo(r.left,r.top);
LineTo(r.left,r.bottom-2);
RGBForeColor(&rgb2);
MoveTo(r.right-2,r.top+1);
LineTo(r.right-2,r.bottom-2);
LineTo(r.left,r.bottom-2);
rgb2.red=rgb2.green=rgb2.blue=0;
RGBForeColor(&rgb2);
InsetRect(&r,2,2);
FrameRect(&r);
InsetRect(&r,2,2);
if(!(**CH).contrlHilite){
PenSize(1,1);
RGBForeColor(&rgb);
MoveTo(r.left,r.top);
LineTo(r.left,r.bottom-2);
PenSize(2,2);
LineTo(r.right-2,r.bottom-2);
Move(0,-1);
PenSize(1,1);
RGBForeColor(&rgb1);
LineTo(r.left+1,r.bottom-3);
LineTo(r.left+1,r.top);
LineTo(r.right-1,r.top);
Move(0,1);
rgb2.red=rgb2.green=rgb2.blue=0xFFFF;
RGBForeColor(&rgb2);
LineTo(r.left+2,r.top+1);
}
else {
MoveTo(r.right-2,r.top);
RGBForeColor(&rgb);
LineTo(r.left,r.top);
PenSize(1,1);
LineTo(r.left,r.bottom-3);
PenSize(3,3);
LineTo(r.right-3,r.bottom-3);
PenSize(1,1);
Move(2,-1);
RGBForeColor(&rgb1);
LineTo(r.left+1,r.bottom-4);
LineTo(r.left+1,r.top+2);
LineTo(r.right-1,r.top+2);
}
rgb2.red=rgb2.green=rgb2.blue=0;
RGBForeColor(&rgb2);
}
The values for the color table resources for the example are as follows:
The control color table (type 'cctb') has two entries. The part codes are just 0 and 1 (the CDEF doesn't really use these) and the colors are { 0x5555,0x5555,0x5555 } and { 0x8888,0x8888,0x8888 }.
The dialog color table (type 'dctb') must have five entries, with part codes of 0-4, and colors as follows: { 0xAAAA,0xAAAA,0xAAAA }, { 0x5555,0x5555, 0x5555 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }.