1 line
23 KiB
C
Executable File
1 line
23 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
|
the limitations in the disclaimer below) provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
|
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE. */
|
|
|
|
#include "icon.h"
|
|
#define FILE_NUM 62
|
|
/* Copyright (c) 1994 by QUALCOMM Incorporated */
|
|
|
|
#pragma segment Icon
|
|
|
|
OSErr DT1GetIcon(short dtRef,OSType creator,OSType type,short iconType, Ptr data, short size);
|
|
pascal Handle ICacheGetter(ResType theType,ICacheHandle ich);
|
|
|
|
/**********************************************************************
|
|
* PlotIconFromICache - plot an icon from a cache
|
|
**********************************************************************/
|
|
OSErr PlotIconFromICache(ICacheHandle ich,IconTransformType transform,Rect *inRect)
|
|
{
|
|
if (ich)
|
|
return (PlotIconSuite(inRect,atAbsoluteCenter,transform,(*ich)->cache));
|
|
else
|
|
return (fnfErr);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* Names2Icon - turn names into an icon
|
|
**********************************************************************/
|
|
short Names2Icon(PStr baseName,PStr modifierNames)
|
|
{
|
|
short id = 0;
|
|
Str255 wholeName;
|
|
Handle resH;
|
|
OSType junk;
|
|
|
|
PCopy(wholeName,modifierNames);
|
|
PSCat(wholeName,baseName);
|
|
|
|
SetResLoad(False);
|
|
if (!(resH = GetNamedResource('icns',wholeName)))
|
|
if (!(resH = GetNamedResource('icns',baseName)))
|
|
if (!(resH = GetNamedResource('ICN#',wholeName)))
|
|
if (!(resH = GetNamedResource('ICN#',baseName)))
|
|
;
|
|
SetResLoad(True);
|
|
|
|
if (!resH) return(0);
|
|
|
|
GetResInfo(resH,&id,&junk,wholeName);
|
|
|
|
return(id);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* ICacheToRgn - turn an icon cache into a region
|
|
**********************************************************************/
|
|
OSErr ICacheToRgn(ICacheHandle ich,Rect *inRect,RgnHandle rgn)
|
|
{
|
|
if (ich)
|
|
return (IconSuiteToRgn(rgn,inRect,atAbsoluteCenter,(*ich)->cache));
|
|
else
|
|
return (fnfErr);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* ICacheGetter - all the work
|
|
**********************************************************************/
|
|
pascal Handle ICacheGetter(ResType theType,ICacheHandle ich)
|
|
{
|
|
OSErr err = noErr;
|
|
Handle data,resH;
|
|
typedef struct {short dtType; short size; OSType suiteType;} IconDesc, *IconDescPtr, **IconDescHandle;
|
|
IconDescPtr idp;
|
|
short dtRef;
|
|
static IconDesc descList[] = {
|
|
kLargeIcon, kLargeIconSize, large1BitMask,
|
|
kLarge4BitIcon, kLarge4BitIconSize, large4BitData,
|
|
kLarge8BitIcon, kLarge8BitIconSize, large8BitData,
|
|
kSmallIcon, kSmallIconSize, small1BitMask,
|
|
kSmall4BitIcon, kSmall4BitIconSize, small4BitData,
|
|
kSmall8BitIcon, kSmall8BitIconSize, small8BitData
|
|
};
|
|
|
|
idp = descList + sizeof(descList)/sizeof(IconDesc) - 1; // last item!
|
|
while ( idp >= descList && idp->suiteType != theType )
|
|
idp--;
|
|
if ( idp < descList )
|
|
return NULL;
|
|
ASSERT ( idp->suiteType == theType );
|
|
|
|
if (data = NuHandle(idp->size))
|
|
{
|
|
/*
|
|
* if we haven't found the right desktop file yet, find it now
|
|
*/
|
|
if (!(*ich)->dtRefValid)
|
|
{
|
|
// Find the correct desktop file
|
|
short volIndex;
|
|
short vRef;
|
|
|
|
for (volIndex=1;!IndexVRef(volIndex,&vRef);volIndex++)
|
|
if (!DTRef(vRef,&dtRef))
|
|
if (!DT1GetIcon(dtRef,(*ich)->creator,(*ich)->type,idp->dtType,LDRef(data),idp->size))
|
|
{
|
|
// Found it here
|
|
(*ich)->dtRef = dtRef;
|
|
(*ich)->dtRefValid = true;
|
|
break;
|
|
}
|
|
}
|
|
else if ((*ich)->dtRef)
|
|
err = DT1GetIcon((*ich)->dtRef,(*ich)->creator,(*ich)->type,idp->dtType,LDRef(data),idp->size);
|
|
UL(data);
|
|
|
|
/*
|
|
* did we fail?
|
|
*/
|
|
if (err || !(*ich)->dtRef)
|
|
{
|
|
// no icon
|
|
// if that's because we didn't find the app, return generic icon
|
|
// or, if we did find the app but for some reason its icons are damaged,
|
|
// return generic icon if asking for the B&W icon, since that icon
|
|
// should always be present
|
|
if ((!(*ich)->dtRef || theType==large1BitMask) && (resH=GetResource(theType,(*ich)->type=='APPL' ?
|
|
genericApplicationIconResource:genericDocumentIconResource)))
|
|
BMD(*resH,*data,idp->size);
|
|
else
|
|
ZapHandle(data); /* failure */
|
|
}
|
|
}
|
|
return(data);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetICache - find (or create) the icon cache entry for a type and creator
|
|
**********************************************************************/
|
|
ICacheHandle GetICache(OSType type,OSType creator)
|
|
{
|
|
ICacheHandle ich;
|
|
ICacheType ic;
|
|
DECLARE_UPP(ICacheGetter,IconGetter);
|
|
|
|
/*
|
|
* is it there already?
|
|
*/
|
|
if (ich=FindICache(type,creator)) return(ich);
|
|
|
|
/*
|
|
* not there. gotta make it
|
|
*/
|
|
if (ich=NewH(ICacheType))
|
|
{
|
|
Zero(ic);
|
|
INIT_UPP(ICacheGetter,IconGetter);
|
|
if (!MakeIconCache(&ic.cache,ICacheGetterUPP,ich))
|
|
{
|
|
ic.magic = 'iCaC';
|
|
ic.type = type;
|
|
ic.creator = creator;
|
|
**ich = ic;
|
|
LL_Push(ICache,ich);
|
|
}
|
|
else ZapHandle(ich);
|
|
}
|
|
return(ich);
|
|
}
|
|
#pragma segment Icon
|
|
|
|
/**********************************************************************
|
|
* FindICache - find the icon cache entry for a type and creator
|
|
**********************************************************************/
|
|
ICacheHandle FindICache(OSType type,OSType creator)
|
|
{
|
|
ICacheHandle ich;
|
|
|
|
for (ich=ICache;ich;ich=(*ich)->next)
|
|
{
|
|
if ((*ich)->type==type && (*ich)->creator==creator) break;
|
|
}
|
|
return(ich);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* DisposeICache - dispose of an entry in the ICache
|
|
* returns non-zero if bytes were disposed of
|
|
**********************************************************************/
|
|
long DisposeICache(ICacheHandle ich)
|
|
{
|
|
if (ich)
|
|
{
|
|
/*
|
|
* pop it from the list
|
|
*/
|
|
LL_Remove(ICache,ich,(ICacheHandle));
|
|
|
|
/*
|
|
* nuke the icon cache
|
|
*/
|
|
DisposeIconSuite((*ich)->cache,True);
|
|
|
|
/*
|
|
* and now the whole thing
|
|
*/
|
|
ZapHandle(ich);
|
|
|
|
/*
|
|
* found one!
|
|
*/
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* DTGetIconInfo - get icon info
|
|
************************************************************************/
|
|
OSErr DTGetIconInfo(short dtRef,OSType creator, short index,OSType *type)
|
|
{
|
|
DTPBRec pb;
|
|
short err;
|
|
|
|
pb.ioCompletion = nil;
|
|
pb.ioDTRefNum = dtRef;
|
|
pb.ioIndex = index;
|
|
pb.ioFileCreator = creator;
|
|
|
|
if (err=PBDTGetIconInfo(&pb,False)) return(err);
|
|
|
|
*type = pb.ioFileType;
|
|
return(pb.ioResult);
|
|
}
|
|
|
|
/************************************************************************
|
|
* DT1GetIcon - find an icon for a creator
|
|
************************************************************************/
|
|
OSErr DT1GetIcon(short dtRef,OSType creator,OSType type,short iconType, Ptr data, short size)
|
|
{
|
|
DTPBRec pb;
|
|
short err;
|
|
Str63 appName;
|
|
|
|
Zero(pb);
|
|
pb.ioNamePtr = appName;
|
|
pb.ioDTRefNum = dtRef;
|
|
pb.ioFileCreator = creator;
|
|
pb.ioFileType = type;
|
|
pb.ioDTBuffer = data;
|
|
pb.ioIconType = iconType;
|
|
pb.ioDTReqCount = size;
|
|
|
|
if (err=PBDTGetIcon(&pb,False)) return(err);
|
|
return(pb.ioResult);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* NamedIconCalc - calc where things go in a named icon
|
|
**********************************************************************/
|
|
void NamedIconCalc(Rect *inRect,PStr name,short hIndent,short vIndent,Rect *iconR,Point *textP)
|
|
{
|
|
short hi = RectHi(*inRect);
|
|
short wi = RectWi(*inRect);
|
|
Rect inner = *inRect;
|
|
short iHi;
|
|
short txFont = GetPortTextFont(GetQDGlobalsThePort());
|
|
short txSize = GetPortTextSize(GetQDGlobalsThePort());
|
|
|
|
InsetRect(&inner,hIndent,vIndent);
|
|
|
|
if (hi<14+2*vIndent)
|
|
{
|
|
/*
|
|
* no icons
|
|
*/
|
|
short lead = GetLeading(txFont,txSize);
|
|
short descent = GetDescent(txFont,txSize);
|
|
SetPt(textP,inner.left,inner.bottom - (inner.bottom-inner.top-lead)/2 - descent);
|
|
SetRect(iconR,0,0,0,0);
|
|
}
|
|
else
|
|
{
|
|
if (hi<32+2*vIndent)
|
|
{
|
|
/*
|
|
* small icons
|
|
*/
|
|
iHi = hi-2*vIndent;
|
|
iHi = MIN(iHi,16);
|
|
|
|
SetRect(iconR,0,0,iHi,iHi);
|
|
CenterRectIn(iconR,&inner);
|
|
if (wi>30)
|
|
{
|
|
OffsetRect(iconR,inner.left-iconR->left,0);
|
|
textP->h = iconR->right + INSET;
|
|
textP->v = iconR->top + GetLeading(txFont,txSize);
|
|
}
|
|
else textP->h = textP->v = 0;
|
|
}
|
|
else
|
|
{
|
|
SetRect(iconR,0,0,32,32);
|
|
if (hi>40)
|
|
{
|
|
TopCenterRectIn(iconR,&inner);
|
|
textP->v = iconR->bottom + GetAscent(txFont,txSize);
|
|
textP->h = inRect->left + (RectWi(*inRect)-StringWidth(name))/2;
|
|
textP->h = MAX(textP->h,inRect->left+hIndent);
|
|
hi = (RectHi(inner)-(textP->v+FontDescent-inner.top))/2;
|
|
if (hi<0) hi = (RectHi(inner)-32)/2;
|
|
if (hi>0)
|
|
{
|
|
textP->v += hi;
|
|
OffsetRect(iconR,0,hi);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CenterRectIn(iconR,&inner);
|
|
textP->h = textP->v = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* DupIconSuite - copy all the data out of an icon suite
|
|
**********************************************************************/
|
|
OSErr DupIconSuite(Handle fromSuite,Handle *toSuite,Boolean reuseSuite)
|
|
{
|
|
OSErr err = noErr;
|
|
Handle data, oldData;
|
|
OSType types[] = {
|
|
large1BitMask,
|
|
large4BitData,
|
|
large8BitData,
|
|
small1BitMask,
|
|
small4BitData,
|
|
small8BitData,
|
|
mini1BitMask,
|
|
mini4BitData,
|
|
mini8BitData };
|
|
short index;
|
|
|
|
|
|
if (!fromSuite) return(fnfErr);
|
|
if (!reuseSuite) *toSuite = nil;
|
|
|
|
if (*toSuite || !(err=NewIconSuite(toSuite)))
|
|
for (index=sizeof(types)/sizeof(OSType);!err && index--;)
|
|
{
|
|
if (!GetIconFromSuite(&data,fromSuite,types[index]) &&
|
|
data && // GetIconFromSuite may return no err even when there is no icon available
|
|
!(err=MyHandToHand(&data)))
|
|
{
|
|
oldData = nil;
|
|
if (reuseSuite && !GetIconFromSuite(&oldData,*toSuite,types[index]) && oldData)
|
|
ZapHandle(oldData);
|
|
err = AddIconToSuite(data,*toSuite,types[index]);
|
|
}
|
|
else if (reuseSuite && !GetIconFromSuite(&oldData,*toSuite,types[index]) && oldData)
|
|
ZapHandle(oldData);
|
|
}
|
|
|
|
|
|
if (err && !reuseSuite)
|
|
{
|
|
if (*toSuite) DisposeIconSuite(*toSuite,True);
|
|
}
|
|
else
|
|
SetSuiteLabel(*toSuite,GetSuiteLabel(fromSuite));
|
|
|
|
return(err);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* FSpGetCustomIconSuite - get a custom icon, if a file has one
|
|
**********************************************************************/
|
|
Handle FSpGetCustomIconSuite(FSSpecPtr spec,short dataSelector)
|
|
{
|
|
short iconRes, oldResFile = CurResFile();
|
|
Handle rIconSuite, theIcon = nil;
|
|
OSErr err;
|
|
|
|
// open the file
|
|
iconRes = FSpOpenResFile(spec,fsRdPerm);
|
|
if (iconRes != -1)
|
|
{
|
|
// read in the icon
|
|
err = GetIconSuite(&rIconSuite, kCustomIconResource, dataSelector);
|
|
if (rIconSuite && *rIconSuite && (err==noErr))
|
|
{
|
|
err = DupIconSuite(rIconSuite, &theIcon, false);
|
|
if (err == noErr)
|
|
{
|
|
HNoPurge(theIcon);
|
|
}
|
|
}
|
|
CloseResFile(iconRes);
|
|
}
|
|
UseResFile(oldResFile);
|
|
return theIcon;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* DupDeskIconSuite - copy all the data out of an icon suite
|
|
**********************************************************************/
|
|
OSErr DupDeskIconSuite(OSType type, OSType creator,Handle *toSuite)
|
|
{
|
|
OSErr err = noErr;
|
|
Handle data;
|
|
OSType types[] = {
|
|
large1BitMask,
|
|
large4BitData,
|
|
large8BitData,
|
|
small1BitMask,
|
|
small4BitData,
|
|
small8BitData };
|
|
short index;
|
|
ICacheHandle ich = NewZH(ICacheType);
|
|
DECLARE_UPP(ICacheGetter,IconGetter);
|
|
|
|
|
|
if (!ich) return(fnfErr);
|
|
*toSuite = nil;
|
|
|
|
(*ich)->type = type;
|
|
(*ich)->creator = creator;
|
|
|
|
INIT_UPP(ICacheGetter,IconGetter);
|
|
if (!(err=NewIconSuite(toSuite)))
|
|
for (index=sizeof(types)/sizeof(OSType);!err && index--;)
|
|
if ((data=ICacheGetter(types[index],ich)) && // GetIconFromSuite may return no err even when there is no icon available
|
|
!(err=MyHandToHand(&data)))
|
|
err = AddIconToSuite(data,*toSuite,types[index]);
|
|
|
|
if (err)
|
|
{
|
|
if (*toSuite) DisposeIconSuite(*toSuite,True);
|
|
*toSuite = nil;
|
|
}
|
|
|
|
return(err);
|
|
}
|
|
|
|
/************************************************************************
|
|
* PlotTinyIconAtPenID - plot a very small icon as though it were a character
|
|
* Icon is small icon, scaled
|
|
************************************************************************/
|
|
void PlotTinyIconAtPenID(IconTransformType transform,short icon)
|
|
{
|
|
Rect tempR;
|
|
Point penLoc;
|
|
|
|
GetPortPenLocation(GetQDGlobalsThePort(),&penLoc);
|
|
SetRect(&tempR,penLoc.h,penLoc.v-8,penLoc.h+8,penLoc.v);
|
|
PlotIconID(&tempR,atNone,transform,icon);
|
|
Move(12,0);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* PlotTinyULIconAtPenID - plot a very small icon as though it were a character
|
|
* Icon lives in UL corner of small icon
|
|
************************************************************************/
|
|
void PlotTinyULIconAtPenID(IconTransformType transform,short icon)
|
|
{
|
|
Rect tempR;
|
|
RgnHandle newClip = NewRgn();
|
|
RgnHandle oldClip;
|
|
if (newClip)
|
|
{
|
|
Point penLoc;
|
|
|
|
GetPortPenLocation(GetQDGlobalsThePort(),&penLoc);
|
|
SetRect(&tempR,penLoc.h,penLoc.v-8,penLoc.h+8,penLoc.v);
|
|
RectRgn(newClip,&tempR);
|
|
oldClip = SavePortClipRegion(GetQDGlobalsThePort());
|
|
SetPortClipRegion(GetQDGlobalsThePort(),newClip);
|
|
SectRgn(newClip,oldClip,newClip);
|
|
tempR.bottom = tempR.top+16;
|
|
tempR.right = tempR.left+16;
|
|
PlotIconID(&tempR,atNone,transform,icon);
|
|
RestorePortClipRegion(GetQDGlobalsThePort(),oldClip);
|
|
DisposeRgn(newClip);
|
|
}
|
|
Move(12,0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* RefreshRGBIcon - refresh a color icon
|
|
************************************************************************/
|
|
OSErr RefreshRGBIcon(short id,RGBColor *color,short template,Boolean *changed)
|
|
{
|
|
Str31 nameShdBe;
|
|
Str255 nameIs;
|
|
Handle res;
|
|
long type;
|
|
OSErr err = noErr;
|
|
Boolean addIt = false;
|
|
Handle maskSuite = nil;
|
|
|
|
SetResLoad(false);
|
|
res=Get1Resource('ICN#',id);
|
|
if (!res && !(err=ResError())) err = resNotFound;
|
|
/*
|
|
if ( !res ) {
|
|
err = ResError ();
|
|
if ( !err )
|
|
err = resNotFound;
|
|
}
|
|
*/
|
|
|
|
SetResLoad(true);
|
|
|
|
if (err==resNotFound) addIt = true;
|
|
else
|
|
{
|
|
GetResInfo(res,&id,&type,nameIs);
|
|
Color2String(nameShdBe,color);
|
|
addIt = !StringSame(nameShdBe,nameIs);
|
|
}
|
|
|
|
if (addIt)
|
|
{
|
|
if (template) GetIconSuite(&maskSuite, template, svAllAvailableData);
|
|
err = RGBColorToIconFamily(color,id,nameShdBe,true,maskSuite);
|
|
if (maskSuite) DisposeIconSuite(maskSuite,false);
|
|
}
|
|
|
|
if (changed) *changed = addIt && !err;
|
|
|
|
return(err);
|
|
}
|
|
|
|
|
|
#ifdef LABEL_ICONS
|
|
|
|
#define kicl8Size 1024
|
|
#define kics8Size 256
|
|
#define kicm8Size 192
|
|
|
|
#define kicl4Size 512
|
|
#define kics4Size 128
|
|
#define kicm4Size 96
|
|
|
|
#define kICNSize 256
|
|
#define kicnSize 64
|
|
#define kicmSize 48
|
|
|
|
|
|
OSErr RGBColorToNBitIcon( RGBColor* theColor, short bitDepth, short iconID, ConstStr255Param name, Boolean overWrite, Handle maskSuite );
|
|
OSErr GetNBitColors( short bitDepth, RGBColor* theColor, Byte maskIndex, Byte* colorIndex, Byte* compIndex, Boolean computeComposite );
|
|
void BuildNBitIconFromMask( Handle icon, Handle mask, Byte colorIndex, Byte compIndex, short bitDepth, short size );
|
|
|
|
OSErr RGBColorToIconFamily( RGBColor* theColor, short iconID, ConstStr255Param name, Boolean overWrite, Handle maskSuite )
|
|
{
|
|
OSErr theErr;
|
|
|
|
theErr = RGBColorToNBitIcon( theColor, 1, iconID, name, overWrite, maskSuite );
|
|
if( theErr ) return( theErr );
|
|
|
|
theErr = RGBColorToNBitIcon( theColor, 4, iconID, name, overWrite, maskSuite );
|
|
if( theErr ) return( theErr );
|
|
|
|
theErr = RGBColorToNBitIcon( theColor, 8, iconID, name, overWrite, maskSuite );
|
|
if( theErr ) return( theErr );
|
|
|
|
return( noErr );
|
|
}
|
|
|
|
OSErr RGBColorToNBitIcon( RGBColor* theColor, short bitDepth, short iconID, ConstStr255Param name, Boolean overWrite, Handle maskSuite )
|
|
{
|
|
enum
|
|
{
|
|
depth8,
|
|
depth4,
|
|
depth1
|
|
};
|
|
enum
|
|
{
|
|
large,
|
|
small,
|
|
mini,
|
|
numIconSizes
|
|
};
|
|
OSErr theErr;
|
|
short tmpSize;
|
|
Byte colorIndex, maskIndex=0, compIndex=0;
|
|
short depthIndex, i;
|
|
Handle icons[numIconSizes], masks[numIconSizes], tmpRes, mask;
|
|
static struct IconInfo{ short depth; long type[numIconSizes]; short size[numIconSizes]; }
|
|
iconInfo[] = { depth8, {kLarge8BitData, kSmall8BitData, kMini8BitData}, {kicl8Size, kics8Size, kicm8Size},
|
|
depth4, {kLarge4BitData, kSmall4BitData, kMini4BitData}, {kicl4Size, kics4Size, kicm4Size},
|
|
depth1, {kLarge1BitMask, kSmall1BitMask, kMini1BitMask}, {kICNSize, kicnSize, kicmSize } };
|
|
|
|
switch( bitDepth )
|
|
{
|
|
case 8:
|
|
depthIndex = depth8;
|
|
break;
|
|
case 4:
|
|
depthIndex = depth4;
|
|
break;
|
|
case 1:
|
|
depthIndex = depth1;
|
|
break;
|
|
default:
|
|
return( paramErr );
|
|
break;
|
|
}
|
|
|
|
if( maskSuite )
|
|
{
|
|
for( i=0; i<numIconSizes; i++ )
|
|
{
|
|
theErr = GetIconFromSuite( &masks[i], maskSuite, iconInfo[depthIndex].type[i] );
|
|
switch( theErr )
|
|
{
|
|
case noErr:
|
|
break;
|
|
case paramErr:
|
|
masks[i] = nil;
|
|
break;
|
|
default:
|
|
return( theErr );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for( i=0; i<numIconSizes; i++ )
|
|
{
|
|
icons[i] = NuHTempBetter( iconInfo[depthIndex].size[i] );
|
|
if( !icons[i] ) return( MemError() );
|
|
}
|
|
|
|
//get index for composite color (between mask and main color)
|
|
//first, find a valid mask
|
|
tmpSize = 0;
|
|
mask = nil;
|
|
for( i=0; i<numIconSizes; i++ )
|
|
{
|
|
if( masks[i] )
|
|
{
|
|
tmpSize = iconInfo[depthIndex].size[i];
|
|
mask = masks[i];
|
|
}
|
|
}
|
|
|
|
//find a pixel in the mask that isn't white
|
|
for( i=0; i<tmpSize; i++ )
|
|
if( (*mask)[i] )
|
|
{
|
|
maskIndex = (*mask)[i];
|
|
i = tmpSize;
|
|
}
|
|
|
|
theErr = GetNBitColors( bitDepth, theColor, maskIndex, &colorIndex, &compIndex, mask != nil );
|
|
if( theErr ) return( theErr );
|
|
|
|
//build each icon
|
|
for( i=0; i<numIconSizes; i++ )
|
|
BuildNBitIconFromMask( icons[i], masks[i], colorIndex, compIndex, bitDepth, iconInfo[depthIndex].size[i] );
|
|
|
|
for( i=0; i<numIconSizes; i++ )
|
|
{
|
|
//if overWrite is enabled, then deleted any duplicates
|
|
if( overWrite )
|
|
{
|
|
if( tmpRes = Get1Resource( iconInfo[depthIndex].type[i], iconID ) )
|
|
{
|
|
RemoveResource( tmpRes );
|
|
theErr = ResError(); if( theErr ) return( theErr );
|
|
}
|
|
}
|
|
//if no overwrite, then return a duplicate file name error if there are already such resources
|
|
else
|
|
{
|
|
tmpRes = Get1Resource( iconInfo[depthIndex].type[i], iconID );
|
|
if( tmpRes ){ ReleaseResource( tmpRes ); return( dupFNErr ); }
|
|
}
|
|
}
|
|
|
|
//add the resource
|
|
for( i=0; i<numIconSizes; i++ )
|
|
{
|
|
if( !name )
|
|
AddResource( icons[i], iconInfo[depthIndex].type[i], iconID, "\p" );
|
|
else
|
|
AddResource( icons[i], iconInfo[depthIndex].type[i], iconID, name );
|
|
theErr = ResError(); if( theErr ) return( theErr );
|
|
WriteResource( icons[i] );
|
|
theErr = ResError(); if( theErr ) return( theErr );
|
|
SetResAttrs( icons[i], resPurgeable );
|
|
theErr = ResError(); if( theErr ) return( theErr );
|
|
}
|
|
|
|
return( noErr );
|
|
}
|
|
|
|
OSErr GetNBitColors( short bitDepth, RGBColor* theColor, Byte maskIndex, Byte* colorIndex, Byte* compIndex, Boolean computeComposite )
|
|
{
|
|
OSErr theErr;
|
|
GWorldPtr offscreenGWorld;
|
|
CGrafPtr oldPort;
|
|
GDHandle oldGD;
|
|
Rect smallRect={0,0,1,1};
|
|
RGBColor tmpRGB;
|
|
|
|
GetGWorld( &oldPort, &oldGD );
|
|
|
|
theErr = NewGWorld( &offscreenGWorld, bitDepth, &smallRect, nil, nil, 0 );
|
|
|
|
SetGWorld( offscreenGWorld, nil );
|
|
|
|
*colorIndex = Color2Index( theColor );
|
|
if( computeComposite )
|
|
{
|
|
Index2Color ( maskIndex, &tmpRGB );
|
|
|
|
//get a composite of the mask color and the desired color index
|
|
tmpRGB.red = ( tmpRGB.red + theColor->red )/2;
|
|
tmpRGB.green = ( tmpRGB.green + theColor->green )/2;
|
|
tmpRGB.blue = ( tmpRGB.blue + theColor->blue )/2;
|
|
|
|
*compIndex = Color2Index( &tmpRGB );
|
|
}
|
|
|
|
SetGWorld( oldPort, oldGD );
|
|
|
|
DisposeGWorld( offscreenGWorld );
|
|
|
|
return( theErr );
|
|
}
|
|
|
|
void BuildNBitIconFromMask( Handle icon, Handle mask, Byte colorIndex, Byte compIndex, short bitDepth, short size )
|
|
{
|
|
short i, j;
|
|
Byte byteVal;
|
|
|
|
if( mask )
|
|
{
|
|
switch( bitDepth )
|
|
{
|
|
case 1:
|
|
//bit by bit...
|
|
for( i=0; i<size/2; i++ )
|
|
{
|
|
(*icon)[i] = 0x00;
|
|
for( j=0; j<8; j++ )
|
|
{
|
|
byteVal = 1 << j;
|
|
if( (*mask)[i] & byteVal )
|
|
(*icon)[i] |= byteVal;
|
|
else
|
|
(*icon)[i] |= ( colorIndex << j );
|
|
}
|
|
}
|
|
//copy the mask
|
|
for( ; i<size; i++ )
|
|
(*icon)[i] = (*mask)[i];
|
|
break;
|
|
case 4:
|
|
for( i=0; i<size; i++ )
|
|
{
|
|
//clear all of the bits
|
|
(*icon)[i] = 0x00;
|
|
|
|
//set first 4 bits
|
|
if( (*mask)[i] & 0x0f )
|
|
(*icon)[i] |= ( compIndex & 0x0f );
|
|
else
|
|
(*icon)[i] |= ( colorIndex & 0x0f );
|
|
|
|
//set 2nd 4 bits
|
|
if( (*mask)[i] & 0xf0 )
|
|
(*icon)[i] |= ( ( compIndex << 4 ) & 0xf0 );
|
|
else
|
|
(*icon)[i] |= ( ( colorIndex << 4 ) & 0xf0 );
|
|
}
|
|
break;
|
|
case 8:
|
|
//thank heaven for whole bytes!
|
|
for( i=0; i<size; i++ )
|
|
if( (*mask)[i] )
|
|
(*icon)[i] = compIndex;
|
|
else
|
|
(*icon)[i] = colorIndex;
|
|
break;
|
|
}
|
|
}
|
|
//for no mask, just set all the bytes in the icon
|
|
else
|
|
{
|
|
switch( bitDepth )
|
|
{
|
|
case 1:
|
|
//it's all or nothing
|
|
if( colorIndex )
|
|
byteVal = 0xff;
|
|
else
|
|
byteVal = 0x00;
|
|
|
|
for( i=0; i<size/2; i++ )
|
|
(*icon)[i] = byteVal;
|
|
|
|
//make (outgoing) icon mask all black
|
|
for( ; i<size; i++ )
|
|
(*icon)[i] = 0xff;
|
|
break;
|
|
case 4:
|
|
//2 pixels per byte
|
|
byteVal = (colorIndex << 4) | colorIndex;
|
|
for( i=0; i<size; i++ )
|
|
(*icon)[i] = byteVal;
|
|
break;
|
|
case 8:
|
|
//1 pixel per byte
|
|
for( i=0; i<size; i++ )
|
|
(*icon)[i] = colorIndex;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#undef PlotIconID
|
|
/************************************************************************
|
|
* MyPlotIconID - ploticonid pacifying Spotlight
|
|
************************************************************************/
|
|
OSErr MyPlotIconID (Rect *theRect, IconAlignmentType align, IconTransformType transform, short theResID)
|
|
{
|
|
OSErr err;
|
|
SLDisable();
|
|
err = PlotIconID(theRect,align,transform,theResID);
|
|
SLEnable();
|
|
return(err);
|
|
}
|
|
#endif
|