Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
IconDimming.c
/* |
File: IconDimming.c |
Contains: In System 7, selected non-open files are shown as |
dimmed icons on the desktop. This snippet shows |
two different ways to achieve the same results in |
an application. |
The first method uses a custom color search |
procedure in place of the current device's to |
create the dimming effect. Once the image has |
been copied to the destination, the custom |
search proc is then removed. |
In the second method the RGB components of the |
icon's colortable entries are all dimmed before |
the image is copied into the destination. The |
dimming algorithm used in this method simply |
darkens each RGB component in half then takes |
the two smaller components and darkens them |
in half again. In System 7, this is similar |
to what the Finder does. |
Written by: Edgar Lee |
Copyright: Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
7/9/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include<MacTypes.h> |
#include<Quickdraw.h> |
#include<Windows.h> |
#include<Dialogs.h> |
#include<TextEdit.h> |
#include<Fonts.h> |
#include<Menus.h> |
#include<Events.h> |
#include<Resources.h> |
/* Constant Declarations */ |
#define WWIDTH 480 |
#define WHEIGHT 180 |
#define WLEFT (((qd.screenBits.bounds.right - qd.screenBits.bounds.left) - WWIDTH) / 2) |
#define WTOP (((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - WHEIGHT) / 2) |
typedef struct |
{ |
PixMap pixmap; /* Pixmap used to store the icl8 pixel image. */ |
BitMap mask; /* Bitmap used to store the 1 bit mask image of the icl8. */ |
} |
MyIconType; |
/* Global Variable Definitions */ |
WindowPtr gWindow; |
void initMac(); |
void createWindow(); |
void loadIconResource(); |
void doEventLoop(); |
void drawIconUnchanged(); |
void drawIconUsingSearchProc(); |
void drawIconUsingCTable(); |
void DimColor( RGBColor *aColor ); |
long CompareComponents( unsigned short component0, unsigned short component1 ); |
static pascal Boolean SearchProc(); |
void main() |
{ |
MyIconType icon; |
initMac(); |
createWindow(); |
loadIconResource( &icon ); |
doEventLoop( &icon ); |
} |
void initMac() |
{ |
MaxApplZone(); |
InitGraf( &qd.thePort ); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs( nil ); |
InitCursor(); |
FlushEvents( 0, everyEvent ); |
} |
void createWindow() |
{ |
Rect rect; |
SetRect( &rect, WLEFT, WTOP, WLEFT + WWIDTH, WTOP + WHEIGHT ); |
gWindow = NewCWindow( 0L, &rect, "\pIconDimming", true, noGrowDocProc, |
(WindowPtr)-1L, true, 0L ); |
SetPort( gWindow ); |
TextFont( kFontIDGeneva ); |
TextSize( 9 ); |
} |
void loadIconResource( icon ) |
MyIconType *icon; |
{ |
Handle icnHandle; /* Handle to the icon bitmap used for the mask. */ |
Handle iclHandle; /* Handle to the icl8 resource. */ |
char depth; /* Depth of the icl8 image. */ |
Rect rect; /* Bounding rect for the image. */ |
SetRect( &rect, 0, 0, 32, 32 ); |
depth = 8; |
/* Create the mask. */ |
icnHandle = GetResource( 'ICN#', 129 ); |
HLock( icnHandle ); |
HNoPurge( icnHandle ); |
(*icon).mask.baseAddr = *icnHandle + (4 * 32); |
(*icon).mask.rowBytes = 4; |
(*icon).mask.bounds = rect; |
/* Create a pixmap for the icl8 pixel image. */ |
iclHandle = GetResource( 'icl8', 129 ); |
HLock( iclHandle ); |
HNoPurge( iclHandle ); |
(*icon).pixmap.baseAddr = *iclHandle; |
(*icon).pixmap.rowBytes = ((32 * depth) / 8) | 0x8000; |
(*icon).pixmap.bounds = rect; |
(*icon).pixmap.pmVersion = 0; |
(*icon).pixmap.packType = 0; |
(*icon).pixmap.packSize = 0; |
(*icon).pixmap.hRes = 72; |
(*icon).pixmap.vRes = 72; |
(*icon).pixmap.pixelSize = depth; |
(*icon).pixmap.planeBytes = 0; |
(*icon).pixmap.pmReserved = 0; |
(*icon).pixmap.pixelType = 0; |
(*icon).pixmap.cmpCount = 1; |
(*icon).pixmap.cmpSize = depth; |
(*icon).pixmap.pmTable = GetCTable( depth ); |
/* Give a unique seed for the pixmap's colortable. Note that this is */ |
/* necessary for two reasons. (1) The pixmap's colortable is ignored by */ |
/* copybits or copymask if the source ctable's ctseed value matches that */ |
/* of the destination's. (2) Matching ctseed values prevent any custom */ |
/* searchProcs from being called. */ |
(**(*icon).pixmap.pmTable).ctSeed = GetCTSeed(); |
} |
void drawIconUnchanged( icon ) |
MyIconType *icon; |
{ |
Str255 title = "\pOriginal 'icl8'"; |
Rect rect; |
/* Draw the original icl8 image unchanged. */ |
SetRect( &rect, 0, 0, 160, 160 ); |
CopyMask( (BitMap *)&(*icon).pixmap, &(*icon).mask, &gWindow->portBits, |
&(*icon).pixmap.bounds, &(*icon).mask.bounds, &rect ); |
MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left, |
rect.bottom + 15 ); |
DrawString( title ); |
} |
void drawIconUsingSearchProc( icon ) |
MyIconType *icon; |
{ |
Str255 title = "\p'icl8' using SearchProc Dimming"; |
Rect rect; |
GWorldPtr gworld; /* Offscreen used for the custom search procedure. */ |
CGrafPtr currentPort; /* Saved CGrafPort for later restore. */ |
GDHandle currentDevice; /* Saved gdDevice for later restore. */ |
GetGWorld( ¤tPort, ¤tDevice ); |
/* Install the custom search proc to an offscreen pixmap instead of the */ |
/* screen's in order to be courteous to other apps. */ |
NewGWorld( &gworld, 8, &(*icon).pixmap.bounds, GetCTable( 8 ), nil, 0 ); |
HLock( (Handle)(*gworld).portPixMap ); |
SetGWorld( gworld, nil ); |
AddSearch( NewColorSearchProc(SearchProc) ); |
CopyBits( (BitMapPtr)&(*icon).pixmap, (BitMapPtr)&(*gworld).portPixMap, &(*icon).pixmap.bounds, |
&(**(*gworld).portPixMap).bounds, srcCopy, nil ); |
DelSearch( NewColorSearchProc(SearchProc) ); |
SetGWorld( currentPort, currentDevice ); |
/* Now copy the dimmed pixmap image to the window. */ |
rect.left = (*icon).pixmap.bounds.right * 5; |
rect.top = (*icon).pixmap.bounds.top; |
rect.right = (*icon).pixmap.bounds.right * 5 + rect.left; |
rect.bottom = (*icon).pixmap.bounds.bottom * 5; |
CopyMask( (BitMapPtr)(*(*gworld).portPixMap), &(*icon).mask, &gWindow->portBits, |
&(**(*gworld).portPixMap).bounds, &(*icon).mask.bounds, &rect ); |
DisposeGWorld( gworld ); |
MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left, |
rect.bottom + 15 ); |
DrawString( title ); |
} |
static pascal Boolean SearchProc( color, position ) |
RGBColor *color; |
long *position; |
{ |
#pragma unused(position) |
/* Darken the RGB components in half. Note that this routine could just */ |
/* have easily called DimColor; however, I wanted to show the difference */ |
/* between just dimming the components in half to what System 7 does. */ |
color->red >>= 1; |
color->green >>= 1; |
color->blue >>= 1; |
return false; |
} |
void drawIconUsingCTable( icon ) |
MyIconType *icon; |
{ |
Str255 title = "\p'icl8' using Colortable Dimming"; |
Rect rect; |
short index; /* Index into the dimmed colortable */ |
CTabHandle dimmedClut; /* Holds dimmed version of iconÕs colortable */ |
CTabHandle savedClut; /* Saves the iconÕs original colortable */ |
/* Save the iconÕs color table and make a copy of it */ |
dimmedClut = savedClut = (*icon).pixmap.pmTable; |
HandToHand( &(Handle)dimmedClut ); |
/* Dim each of the colors in the copy of the color table */ |
for (index = 0; index <= (**dimmedClut).ctSize; ++index) |
DimColor( &(**dimmedClut).ctTable[index].rgb ); |
/* Install the dimmed copy of the color table */ |
(*icon).pixmap.pmTable = dimmedClut; |
rect.left = (*icon).pixmap.bounds.right * 10; |
rect.top = (*icon).pixmap.bounds.top; |
rect.right = (*icon).pixmap.bounds.right * 5 + rect.left; |
rect.bottom = (*icon).pixmap.bounds.bottom * 5; |
/* Now copy the dimmed pixmap image to the window. */ |
CopyMask( (BitMap *)&(*icon).pixmap, &(*icon).mask, &gWindow->portBits, |
&(*icon).pixmap.bounds, &(*icon).mask.bounds, &rect ); |
(*icon).pixmap.pmTable = savedClut; |
DisposeCTable( dimmedClut ); |
MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left, |
rect.bottom + 15 ); |
DrawString( title ); |
} |
/******************************************************************************\ |
* DimColor - Dim one color for selection |
* written by Forrest Tanaka |
* This routine dims the color thatÕs passed in the aColor parameter so that |
* itÕs suitable to use for making an icon look selected. It works by dimming |
* all components by half, and then dimming the smaller two components by half |
* again. By keeping the largest component dimmed by only half, we keep the |
* saturation of the color approximately what it was before it was dimmed. |
\******************************************************************************/ |
void DimColor( |
RGBColor *aColor) |
{ |
unsigned short *biggest; /* Pointer to the biggest component */ |
/* Dim all components by half */ |
aColor->red >>= 1; |
aColor->green >>= 1; |
aColor->blue >>= 1; |
/* If aColor isnÕt nearly gray, dim smallest 2 components again by half */ |
if (CompareComponents( aColor->red, aColor->green ) != 0 || |
CompareComponents( aColor->red, aColor->blue ) != 0) |
{ |
/* Point to the larger of red and green */ |
if (CompareComponents( aColor->red, aColor->green ) > 0) |
biggest = &aColor->red; |
else |
biggest = &aColor->green; |
/* Point to the larger of previous test and blue */ |
if (CompareComponents( aColor->blue, *biggest ) > 0) |
biggest = &aColor->blue; |
/* Dim smaller two components by half */ |
if (&aColor->red != biggest) |
aColor->red >>= 1; |
if (&aColor->green != biggest) |
aColor->green >>= 1; |
if (&aColor->blue != biggest) |
aColor->blue >>= 1; |
} |
} |
/******************************************************************************\ |
* CompareComponents - Compare two components for difference and equality |
* written by Forrest Tanaka |
* This routine compares two components of an RGBColor that are passed in the |
* component0 and component1 parameters. If theyÕre within 512 units of each |
* other, then zero is returned. Otherwise, the positive difference is returned |
* if component0 is greater than component1, or the negative of the difference |
* is returned if component1 is greater than component0. |
\******************************************************************************/ |
long CompareComponents( |
unsigned short component0, /* First component to check */ |
unsigned short component1) /* Second component to check */ |
{ |
long difference; /* Difference between components */ |
/* Calculate the difference between the components */ |
difference = (unsigned long)component0 - (unsigned long)component1; |
/* If the difference is within 512 units, then consider the components the same */ |
if ((difference < 512) && (difference > -512)) |
return 0; |
else |
return difference; |
} |
void doEventLoop( icon ) |
MyIconType *icon; |
{ |
EventRecord event; |
WindowPtr window; |
short clickArea; |
Rect screenRect; |
for (;;) |
{ |
if (WaitNextEvent( everyEvent, &event, 0, nil )) |
{ |
if (event.what == mouseDown) |
{ |
clickArea = FindWindow( event.where, &window ); |
if (clickArea == inDrag) |
{ |
screenRect = (**GetGrayRgn()).rgnBBox; |
DragWindow( window, event.where, &screenRect ); |
} |
else if (clickArea == inContent) |
{ |
if (window != FrontWindow()) |
SelectWindow( window ); |
} |
else if (clickArea == inGoAway) |
if (TrackGoAway( window, event.where )) |
return; |
} |
else if (event.what == updateEvt) |
{ |
window = (WindowPtr)event.message; |
SetPort( window ); |
BeginUpdate( window ); |
drawIconUnchanged( icon ); |
drawIconUsingSearchProc( icon ); |
drawIconUsingCTable( icon ); |
EndUpdate( window ); |
} |
} |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22