2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import "AIMenuBarIcons.h"
18 #import <AIXtraInfo.h>
19 #import <AIUtilities/AIImageAdditions.h>
20 #import <QuartzCore/CoreImage.h>
22 #define KEY_ICONS_DICT @"Icons"
24 @interface AIMenuBarIcons (PRIVATE)
25 - (NSImage *)imageForKey:(NSString *)keyName;
26 - (BOOL)keyOfTypeExists:(NSString *)keyName;
29 @implementation AIMenuBarIcons
31 - (id)initWithURL:(NSURL *)url
33 if ((self = [super initWithURL:url])) {
34 imageStates = [[NSMutableDictionary alloc] init];
35 alternateImageStates = [[NSMutableDictionary alloc] init];
36 iconInfo = [xtraBundle objectForInfoDictionaryKey:KEY_ICONS_DICT];
41 - (NSImage *)imageOfType:(NSString *)imageType alternate:(BOOL)alternate
45 // Default to Online if key not found.
46 if (![self keyOfTypeExists:imageType]) {
47 imageType = @"Online";
50 image = [(alternate ? alternateImageStates : imageStates) objectForKey:imageType];
51 if (!image) { // Image not already stored.
53 NSImage *normalImage = [self imageOfType:imageType alternate:NO];
54 image = [self alternateImageForImage:normalImage];
55 [alternateImageStates setObject:image forKey:imageType];
57 image = [self imageForKey:imageType];
58 if (image) { // Make sure the image exists.
59 [imageStates setObject:image forKey:imageType];
66 - (NSImage *)imageForKey:(NSString *)keyName
70 // This set doesn't contain an Icons dictionary entry. It's invalid.
75 imagePath = [xtraBundle pathForImageResource:[iconInfo objectForKey:keyName]];
76 return [[[NSImage alloc] initWithContentsOfFile:imagePath] autorelease];
79 - (BOOL)keyOfTypeExists:(NSString *)keyName
81 if (!iconInfo || ![iconInfo objectForKey:keyName]) {
89 [imageStates release];
90 [alternateImageStates release];
94 #define PREVIEW_MENU_IMAGE_SIZE 18
95 #define PREVIEW_MENU_IMAGE_MARGIN 2
97 + (NSImage *)previewMenuImageForIconPackAtPath:(NSString *)inPath
100 NSBundle *menuIconsBundle = [[NSBundle alloc] initWithPath:inPath];
101 NSDictionary *imageInfo;
103 if (!menuIconsBundle) {
107 imageInfo = [menuIconsBundle objectForInfoDictionaryKey:KEY_ICONS_DICT];
110 [menuIconsBundle release];
114 image = [[NSImage alloc] initWithSize:NSMakeSize((PREVIEW_MENU_IMAGE_SIZE + PREVIEW_MENU_IMAGE_MARGIN) * 2,
115 PREVIEW_MENU_IMAGE_SIZE)];
118 if ([[menuIconsBundle objectForInfoDictionaryKey:@"XtraBundleVersion"] intValue] == 1) {
119 NSEnumerator *enumerator = [[NSArray arrayWithObjects:@"Online",@"Offline",nil] objectEnumerator];
124 while ((iconID = [enumerator nextObject])) {
125 NSString *anIconPath = [menuIconsBundle pathForImageResource:[imageInfo objectForKey:iconID]];
128 if ((anIcon = [[[NSImage alloc] initWithContentsOfFile:anIconPath] autorelease])) {
129 NSSize anIconSize = [anIcon size];
130 NSRect targetRect = NSMakeRect(xOrigin, 0, PREVIEW_MENU_IMAGE_SIZE, PREVIEW_MENU_IMAGE_SIZE);
132 if (anIconSize.width < targetRect.size.width) {
133 float difference = (targetRect.size.width - anIconSize.width)/2;
135 targetRect.size.width -= difference;
136 targetRect.origin.x += difference;
139 if (anIconSize.height < targetRect.size.height) {
140 float difference = (targetRect.size.height - anIconSize.height)/2;
142 targetRect.size.height -= difference;
143 targetRect.origin.y += difference;
146 [anIcon drawInRect:targetRect
147 fromRect:NSMakeRect(0,0,anIconSize.width,anIconSize.height)
148 operation:NSCompositeCopy
151 //Shift right in preparation for next image
152 xOrigin += PREVIEW_MENU_IMAGE_SIZE + PREVIEW_MENU_IMAGE_MARGIN;
156 [menuIconsBundle release];
159 return [image autorelease];
162 // Returns an inverted image.
163 - (NSImage *)alternateImageForImage:(NSImage *)inImage
165 NSImage *altImage = [[NSImage alloc] initWithSize:[inImage size]];
166 NSBitmapImageRep *srcImageRep = [inImage bitmapRep];
168 id monochromeFilter, invertFilter, alphaFilter;
170 monochromeFilter = [CIFilter filterWithName:@"CIColorMonochrome"];
171 [monochromeFilter setValue:[[[CIImage alloc] initWithBitmapImageRep:srcImageRep] autorelease]
172 forKey:@"inputImage"];
173 [monochromeFilter setValue:[NSNumber numberWithFloat:1.0]
174 forKey:@"inputIntensity"];
175 [monochromeFilter setValue:[[[CIColor alloc] initWithColor:[NSColor blackColor]] autorelease]
176 forKey:@"inputColor"];
178 //Now invert our greyscale image
179 invertFilter = [CIFilter filterWithName:@"CIColorInvert"];
180 [invertFilter setValue:[monochromeFilter valueForKey:@"outputImage"]
181 forKey:@"inputImage"];
183 //And turn the parts that were previously white (are now black) into transparent
184 alphaFilter = [CIFilter filterWithName:@"CIMaskToAlpha"];
185 [alphaFilter setValue:[invertFilter valueForKey:@"outputImage"]
186 forKey:@"inputImage"];
188 [altImage lockFocus];
189 id context = [CIContext contextWithCGContext:[[NSGraphicsContext currentContext] graphicsPort]
191 id result = [alphaFilter valueForKey:@"outputImage"];
192 [context drawImage:result
194 fromRect:[result extent]];
195 [altImage unlockFocus];
197 return [altImage autorelease];