|
rudy@2886
|
1 |
//
|
|
rudy@2886
|
2 |
// GrowlNanoWindowView.m
|
|
rudy@2886
|
3 |
// Display Plugins
|
|
rudy@2886
|
4 |
//
|
|
rudy@2886
|
5 |
// Created by Rudy Richter on 12/12/2005.
|
|
ingmarstein@3040
|
6 |
// Copyright 2005-2006, The Growl Project. All rights reserved.
|
|
rudy@2886
|
7 |
//
|
|
rudy@2886
|
8 |
|
|
rudy@2886
|
9 |
#import "GrowlNanoWindowView.h"
|
|
rudy@2886
|
10 |
#import "GrowlNanoPrefs.h"
|
|
rudy@2886
|
11 |
#import "GrowlImageAdditions.h"
|
|
rudy@2886
|
12 |
|
|
rudy@2945
|
13 |
extern CGLayerRef CGLayerCreateWithContext() __attribute__((weak_import));
|
|
rudy@2945
|
14 |
|
|
Rudy@4246
|
15 |
void addRoundedBottomToPath(CGContextRef context, CGRect rect, CGFloat radius);
|
|
Rudy@4246
|
16 |
|
|
Rudy@4246
|
17 |
|
|
Rudy@4246
|
18 |
void addRoundedBottomToPath(CGContextRef context, CGRect rect, CGFloat radius) {
|
|
Rudy@4246
|
19 |
CGFloat minX = CGRectGetMinX(rect);
|
|
Rudy@4246
|
20 |
CGFloat minY = CGRectGetMinY(rect);
|
|
Rudy@4246
|
21 |
CGFloat maxX = CGRectGetMaxX(rect);
|
|
Rudy@4246
|
22 |
CGFloat maxY = CGRectGetMaxY(rect);
|
|
Rudy@4246
|
23 |
CGFloat midX = CGRectGetMidX(rect);
|
|
Rudy@4246
|
24 |
CGFloat midY = CGRectGetMidY(rect);
|
|
rudy@2886
|
25 |
|
|
rudy@2886
|
26 |
CGContextBeginPath(context);
|
|
rudy@2886
|
27 |
CGContextMoveToPoint(context, maxX, midY);
|
|
rudy@2886
|
28 |
CGContextAddLineToPoint(context, maxX, maxY);
|
|
rudy@2886
|
29 |
CGContextAddLineToPoint(context, minX, maxY);
|
|
rudy@2886
|
30 |
CGContextAddLineToPoint(context, minX, midY);
|
|
rudy@2886
|
31 |
CGContextAddArcToPoint(context, minX, minY, midX, minY, radius);
|
|
rudy@2886
|
32 |
CGContextAddArcToPoint(context, maxX, minY, maxX, midY, radius);
|
|
rudy@2886
|
33 |
CGContextClosePath(context);
|
|
rudy@2886
|
34 |
}
|
|
rudy@2886
|
35 |
|
|
rudy@2886
|
36 |
@implementation GrowlNanoWindowView
|
|
rudy@2886
|
37 |
|
|
rudy@2886
|
38 |
- (id) initWithFrame:(NSRect)frame {
|
|
rudy@2886
|
39 |
if ((self = [super initWithFrame:frame])) {
|
|
rudy@2886
|
40 |
cache = [[NSImage alloc] initWithSize:frame.size];
|
|
rudy@2886
|
41 |
needsDisplay = YES;
|
|
rudy@2886
|
42 |
}
|
|
rudy@2886
|
43 |
|
|
rudy@2886
|
44 |
return self;
|
|
rudy@2886
|
45 |
}
|
|
rudy@2886
|
46 |
|
|
rudy@2886
|
47 |
- (void) dealloc {
|
|
rudy@2886
|
48 |
[titleAttributes release];
|
|
rudy@2886
|
49 |
[textAttributes release];
|
|
rudy@2886
|
50 |
[backgroundColor release];
|
|
rudy@2886
|
51 |
[textColor release];
|
|
rudy@2886
|
52 |
[icon release];
|
|
rudy@2886
|
53 |
[title release];
|
|
rudy@2886
|
54 |
[text release];
|
|
rudy@2886
|
55 |
[cache release];
|
|
rudy@2886
|
56 |
if (layer)
|
|
rudy@2886
|
57 |
CGLayerRelease(layer);
|
|
rudy@2886
|
58 |
|
|
rudy@2886
|
59 |
[super dealloc];
|
|
rudy@2886
|
60 |
}
|
|
rudy@2886
|
61 |
|
|
rudy@2886
|
62 |
- (void) drawRect:(NSRect)rect {
|
|
rudy@3006
|
63 |
|
|
rudy@3006
|
64 |
NSGraphicsContext *context = [NSGraphicsContext currentContext];
|
|
rudy@3006
|
65 |
CGContextRef cgContext = [context graphicsPort];
|
|
rudy@3006
|
66 |
NSRect bounds = [self bounds];
|
|
rudy@3006
|
67 |
|
|
rudy@3006
|
68 |
if (needsDisplay) {
|
|
rudy@3006
|
69 |
// rects and sizes
|
|
rudy@3006
|
70 |
int sizePref = 0;
|
|
rudy@3006
|
71 |
READ_GROWL_PREF_INT(Nano_SIZE_PREF, GrowlNanoPrefDomain, &sizePref);
|
|
rudy@3006
|
72 |
NSRect titleRect, textRect;
|
|
rudy@3006
|
73 |
NSRect iconRect;
|
|
rudy@3006
|
74 |
|
|
rudy@3006
|
75 |
if (sizePref == Nano_SIZE_HUGE) {
|
|
Rudy@4246
|
76 |
titleRect.origin.x = 10.0;
|
|
Rudy@4246
|
77 |
titleRect.origin.y = NSHeight(bounds) - 28.0;
|
|
Rudy@4246
|
78 |
titleRect.size.width = NSWidth(bounds) - 32.0;
|
|
Rudy@4246
|
79 |
titleRect.size.height = 20.0;
|
|
rudy@3006
|
80 |
|
|
Rudy@4246
|
81 |
textRect.origin.y = NSHeight(bounds) - 41.0;
|
|
Rudy@4246
|
82 |
textRect.size.height = 15.0;
|
|
rudy@3006
|
83 |
|
|
Rudy@4246
|
84 |
iconRect.origin.x = 230.0;
|
|
Rudy@4246
|
85 |
iconRect.origin.y = NSHeight(bounds) - 40.0;
|
|
Rudy@4246
|
86 |
iconRect.size.width = 32.0;
|
|
Rudy@4246
|
87 |
iconRect.size.height = 32.0;
|
|
rudy@3176
|
88 |
} else {
|
|
Rudy@4246
|
89 |
titleRect.origin.x = 10.0;
|
|
Rudy@4246
|
90 |
titleRect.origin.y = NSHeight(bounds) - 14.0;
|
|
Rudy@4246
|
91 |
titleRect.size.width = NSWidth(bounds) - 16.0;
|
|
Rudy@4246
|
92 |
titleRect.size.height = 12.0;
|
|
rudy@3176
|
93 |
|
|
Rudy@4246
|
94 |
textRect.origin.y = NSHeight(bounds) - 22.0;
|
|
Rudy@4246
|
95 |
textRect.size.height = 10.0;
|
|
rudy@3176
|
96 |
|
|
Rudy@4246
|
97 |
iconRect.origin.x = 160.0;
|
|
Rudy@4246
|
98 |
iconRect.origin.y = NSHeight(bounds) - 20.0;
|
|
Rudy@4246
|
99 |
iconRect.size.width = 16.0;
|
|
Rudy@4246
|
100 |
iconRect.size.height = 16.0;
|
|
rudy@3176
|
101 |
}
|
|
rudy@3006
|
102 |
textRect.origin.x = titleRect.origin.x;
|
|
rudy@3006
|
103 |
textRect.size.width = titleRect.size.width;
|
|
rudy@3006
|
104 |
|
|
rudy@3006
|
105 |
//draw to cache
|
|
rudy@3006
|
106 |
/*if (CGLayerCreateWithContext) {
|
|
rudy@3006
|
107 |
if (!layer)
|
|
rudy@3006
|
108 |
layer = CGLayerCreateWithContext(cgContext, CGSizeMake(bounds.size.width, bounds.size.height), NULL);
|
|
rudy@3006
|
109 |
[NSGraphicsContext setCurrentContext:
|
|
rudy@3006
|
110 |
[NSGraphicsContext graphicsContextWithGraphicsPort:CGLayerGetContext(layer) flipped:NO]];
|
|
rudy@3006
|
111 |
} else {
|
|
rudy@3006
|
112 |
[cache lockFocus];
|
|
rudy@3006
|
113 |
}*/
|
|
rudy@3006
|
114 |
|
|
rudy@3006
|
115 |
NSRect c = [self bounds];
|
|
rudy@3006
|
116 |
CGRect b = CGRectMake(c.origin.x, c.origin.y, c.size.width, c.size.height);
|
|
Rudy@4246
|
117 |
addRoundedBottomToPath(cgContext, b, 10.0);
|
|
Rudy@4246
|
118 |
|
|
Rudy@4246
|
119 |
CGFloat opacityPref = Nano_DEFAULT_OPACITY;
|
|
rudy@3006
|
120 |
READ_GROWL_PREF_FLOAT(Nano_OPACITY_PREF, GrowlNanoPrefDomain, &opacityPref);
|
|
Rudy@4246
|
121 |
CGFloat alpha = opacityPref * 0.01;
|
|
rudy@3006
|
122 |
[[backgroundColor colorWithAlphaComponent:alpha] set];
|
|
rudy@3006
|
123 |
CGContextFillPath(cgContext);
|
|
rudy@3006
|
124 |
|
|
rudy@3006
|
125 |
////NSRectFill(bounds);
|
|
rudy@3006
|
126 |
[title drawInRect:titleRect withAttributes:titleAttributes];
|
|
rudy@3006
|
127 |
|
|
rudy@3006
|
128 |
[text drawInRect:textRect withAttributes:textAttributes];
|
|
rudy@3006
|
129 |
[icon setFlipped:NO];
|
|
Rudy@4246
|
130 |
[icon drawScaledInRect:iconRect operation:NSCompositeSourceOver fraction:1.0];
|
|
rudy@3006
|
131 |
|
|
rudy@3006
|
132 |
/*if (CGLayerCreateWithContext)
|
|
rudy@3006
|
133 |
[NSGraphicsContext setCurrentContext:context];
|
|
rudy@3006
|
134 |
else
|
|
rudy@3006
|
135 |
[cache unlockFocus];
|
|
rudy@3006
|
136 |
|
|
rudy@3006
|
137 |
needsDisplay = NO;*/
|
|
rudy@3006
|
138 |
}
|
|
rudy@3006
|
139 |
|
|
rudy@3006
|
140 |
// draw background
|
|
rudy@3006
|
141 |
//[[NSColor clearColor] set];
|
|
rudy@3006
|
142 |
//NSRectFill(rect);
|
|
rudy@3006
|
143 |
//CGContextFillPath(cgContext);
|
|
rudy@3006
|
144 |
// draw cache to screen
|
|
rudy@3006
|
145 |
NSRect imageRect = rect;
|
|
rudy@3006
|
146 |
int effect = Nano_EFFECT_SLIDE;
|
|
rudy@3006
|
147 |
READ_GROWL_PREF_BOOL(Nano_EFFECT_PREF, GrowlNanoPrefDomain, &effect);
|
|
rudy@3006
|
148 |
if (effect == Nano_EFFECT_SLIDE) {
|
|
rudy@3006
|
149 |
if (CGLayerCreateWithContext)
|
|
Rudy@4246
|
150 |
imageRect.origin.y = 0.0;
|
|
rudy@3006
|
151 |
} else if (effect == Nano_EFFECT_WIPE) {
|
|
rudy@3006
|
152 |
rect.size.height -= imageRect.origin.y;
|
|
rudy@3006
|
153 |
imageRect.size.height -= imageRect.origin.y;
|
|
rudy@3006
|
154 |
if (!CGLayerCreateWithContext)
|
|
Rudy@4246
|
155 |
imageRect.origin.y = 0.0;
|
|
rudy@3006
|
156 |
}
|
|
rudy@3006
|
157 |
|
|
rudy@3006
|
158 |
if (CGLayerCreateWithContext) {
|
|
rudy@3006
|
159 |
CGRect cgRect;
|
|
rudy@3006
|
160 |
cgRect.origin.x = imageRect.origin.x;
|
|
rudy@3006
|
161 |
cgRect.origin.y = imageRect.origin.y;
|
|
rudy@3006
|
162 |
cgRect.size.width = rect.size.width;
|
|
rudy@3006
|
163 |
if (effect == Nano_EFFECT_WIPE) {
|
|
rudy@3006
|
164 |
cgRect.size.height = rect.size.height;
|
|
rudy@3006
|
165 |
CGContextClipToRect(cgContext, cgRect);
|
|
rudy@2886
|
166 |
}
|
|
rudy@3006
|
167 |
cgRect.size.height = bounds.size.height;
|
|
rudy@3006
|
168 |
CGContextDrawLayerInRect(cgContext, cgRect, layer);
|
|
rudy@3006
|
169 |
} else {
|
|
Rudy@4246
|
170 |
[cache drawInRect:rect fromRect:imageRect operation:NSCompositeSourceOver fraction:1.0];
|
|
rudy@3006
|
171 |
}
|
|
rudy@2886
|
172 |
}
|
|
rudy@2886
|
173 |
|
|
rudy@2886
|
174 |
- (void) setIcon:(NSImage *)anIcon {
|
|
rudy@2886
|
175 |
[icon autorelease];
|
|
rudy@2886
|
176 |
icon = [anIcon retain];
|
|
rudy@2886
|
177 |
[self setNeedsDisplay:(needsDisplay = YES)];
|
|
rudy@2886
|
178 |
}
|
|
rudy@2886
|
179 |
|
|
rudy@2886
|
180 |
- (void) setTitle:(NSString *)aTitle {
|
|
rudy@2886
|
181 |
[title autorelease];
|
|
rudy@2886
|
182 |
title = [aTitle copy];
|
|
rudy@2886
|
183 |
[self setNeedsDisplay:(needsDisplay = YES)];
|
|
rudy@2886
|
184 |
}
|
|
rudy@2886
|
185 |
|
|
rudy@2886
|
186 |
- (void) setText:(NSString *)aText {
|
|
rudy@2886
|
187 |
[text autorelease];
|
|
rudy@2886
|
188 |
text = [aText copy];
|
|
rudy@2886
|
189 |
[self setNeedsDisplay:(needsDisplay = YES)];
|
|
rudy@2886
|
190 |
}
|
|
rudy@2886
|
191 |
|
|
rudy@2886
|
192 |
- (void) setPriority:(int)priority {
|
|
rudy@2886
|
193 |
NSString *key;
|
|
rudy@2886
|
194 |
NSString *textKey;
|
|
rudy@2886
|
195 |
switch (priority) {
|
|
rudy@2886
|
196 |
case -2:
|
|
rudy@2886
|
197 |
key = GrowlNanoVeryLowBackgroundColor;
|
|
rudy@2886
|
198 |
textKey = GrowlNanoVeryLowTextColor;
|
|
rudy@2886
|
199 |
break;
|
|
rudy@2886
|
200 |
case -1:
|
|
rudy@2886
|
201 |
key = GrowlNanoModerateBackgroundColor;
|
|
rudy@2886
|
202 |
textKey = GrowlNanoModerateTextColor;
|
|
rudy@2886
|
203 |
break;
|
|
rudy@2886
|
204 |
case 1:
|
|
rudy@2886
|
205 |
key = GrowlNanoHighBackgroundColor;
|
|
rudy@2886
|
206 |
textKey = GrowlNanoHighTextColor;
|
|
rudy@2886
|
207 |
break;
|
|
rudy@2886
|
208 |
case 2:
|
|
rudy@2886
|
209 |
key = GrowlNanoEmergencyBackgroundColor;
|
|
rudy@2886
|
210 |
textKey = GrowlNanoEmergencyTextColor;
|
|
rudy@2886
|
211 |
break;
|
|
rudy@2886
|
212 |
case 0:
|
|
rudy@2886
|
213 |
default:
|
|
rudy@2886
|
214 |
key = GrowlNanoNormalBackgroundColor;
|
|
rudy@2886
|
215 |
textKey = GrowlNanoNormalTextColor;
|
|
rudy@2886
|
216 |
break;
|
|
rudy@2886
|
217 |
}
|
|
rudy@2886
|
218 |
|
|
rudy@2886
|
219 |
[backgroundColor release];
|
|
rudy@2886
|
220 |
|
|
Rudy@4246
|
221 |
CGFloat opacityPref = Nano_DEFAULT_OPACITY;
|
|
rudy@2886
|
222 |
READ_GROWL_PREF_FLOAT(Nano_OPACITY_PREF, GrowlNanoPrefDomain, &opacityPref);
|
|
Rudy@4246
|
223 |
CGFloat alpha = opacityPref * 0.01;
|
|
rudy@2886
|
224 |
|
|
rudy@2886
|
225 |
Class NSDataClass = [NSData class];
|
|
rudy@2886
|
226 |
NSData *data = nil;
|
|
rudy@2886
|
227 |
|
|
rudy@2886
|
228 |
READ_GROWL_PREF_VALUE(key, GrowlNanoPrefDomain, NSData *, &data);
|
|
Rudy@4259
|
229 |
if(data)
|
|
Rudy@4259
|
230 |
CFMakeCollectable(data);
|
|
rudy@2886
|
231 |
if (data && [data isKindOfClass:NSDataClass])
|
|
rudy@2886
|
232 |
backgroundColor = [NSUnarchiver unarchiveObjectWithData:data];
|
|
rudy@2886
|
233 |
else
|
|
rudy@2886
|
234 |
backgroundColor = [NSColor blackColor];
|
|
rudy@2886
|
235 |
backgroundColor = [[backgroundColor colorWithAlphaComponent:alpha] retain];
|
|
rudy@2886
|
236 |
[data release];
|
|
rudy@2886
|
237 |
data = nil;
|
|
rudy@2886
|
238 |
|
|
rudy@2886
|
239 |
[textColor release];
|
|
rudy@2886
|
240 |
READ_GROWL_PREF_VALUE(textKey, GrowlNanoPrefDomain, NSData *, &data);
|
|
Rudy@4259
|
241 |
if(data)
|
|
Rudy@4259
|
242 |
CFMakeCollectable(data);
|
|
rudy@2886
|
243 |
if (data && [data isKindOfClass:NSDataClass])
|
|
rudy@2886
|
244 |
textColor = [NSUnarchiver unarchiveObjectWithData:data];
|
|
rudy@2886
|
245 |
else
|
|
rudy@2886
|
246 |
textColor = [NSColor whiteColor];
|
|
rudy@2886
|
247 |
[textColor retain];
|
|
rudy@2886
|
248 |
[data release];
|
|
rudy@2886
|
249 |
|
|
Rudy@4246
|
250 |
CGFloat titleFontSize;
|
|
Rudy@4246
|
251 |
CGFloat textFontSize;
|
|
rudy@2886
|
252 |
int sizePref = 0;
|
|
rudy@2886
|
253 |
READ_GROWL_PREF_INT(Nano_SIZE_PREF, GrowlNanoPrefDomain, &sizePref);
|
|
rudy@2886
|
254 |
|
|
rudy@2886
|
255 |
if (sizePref == Nano_SIZE_HUGE) {
|
|
Rudy@4246
|
256 |
titleFontSize = 14.0;
|
|
Rudy@4246
|
257 |
textFontSize = 12.0;
|
|
rudy@2886
|
258 |
} else {
|
|
Rudy@4246
|
259 |
titleFontSize = 10.0;
|
|
Rudy@4246
|
260 |
textFontSize = 8.0;
|
|
rudy@2886
|
261 |
}
|
|
rudy@2886
|
262 |
|
|
rudy@2886
|
263 |
NSShadow *textShadow = [[NSShadow alloc] init];
|
|
rudy@2886
|
264 |
|
|
Rudy@4246
|
265 |
NSSize shadowSize = {0.0, -2.0};
|
|
rudy@2886
|
266 |
[textShadow setShadowOffset:shadowSize];
|
|
Rudy@4246
|
267 |
[textShadow setShadowBlurRadius:3.0];
|
|
rudy@2886
|
268 |
[textShadow setShadowColor:[NSColor blackColor]];
|
|
rudy@2886
|
269 |
|
|
rudy@2886
|
270 |
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
rudy@2886
|
271 |
[paragraphStyle setAlignment:NSLeftTextAlignment];
|
|
rudy@2886
|
272 |
[paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
|
|
rudy@2886
|
273 |
[titleAttributes release];
|
|
rudy@2886
|
274 |
titleAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
|
|
rudy@2886
|
275 |
textColor, NSForegroundColorAttributeName,
|
|
rudy@2886
|
276 |
paragraphStyle, NSParagraphStyleAttributeName,
|
|
rudy@2886
|
277 |
[NSFont boldSystemFontOfSize:titleFontSize], NSFontAttributeName,
|
|
rudy@2886
|
278 |
textShadow, NSShadowAttributeName,
|
|
rudy@2886
|
279 |
nil];
|
|
rudy@2886
|
280 |
[paragraphStyle release];
|
|
rudy@2886
|
281 |
|
|
rudy@2886
|
282 |
paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
rudy@2886
|
283 |
[paragraphStyle setAlignment:NSLeftTextAlignment];
|
|
rudy@2886
|
284 |
[textAttributes release];
|
|
rudy@2886
|
285 |
textAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
|
|
rudy@2886
|
286 |
textColor, NSForegroundColorAttributeName,
|
|
rudy@2886
|
287 |
paragraphStyle, NSParagraphStyleAttributeName,
|
|
rudy@2886
|
288 |
[NSFont messageFontOfSize:textFontSize], NSFontAttributeName,
|
|
rudy@2886
|
289 |
textShadow, NSShadowAttributeName,
|
|
rudy@2886
|
290 |
nil];
|
|
rudy@2886
|
291 |
[paragraphStyle release];
|
|
rudy@2886
|
292 |
[textShadow release];
|
|
rudy@2886
|
293 |
}
|
|
rudy@2886
|
294 |
|
|
rudy@2886
|
295 |
- (id) target {
|
|
rudy@2886
|
296 |
return target;
|
|
rudy@2886
|
297 |
}
|
|
rudy@2886
|
298 |
|
|
rudy@2886
|
299 |
- (void) setTarget:(id) object {
|
|
rudy@2886
|
300 |
target = object;
|
|
rudy@2886
|
301 |
}
|
|
rudy@2886
|
302 |
|
|
rudy@2886
|
303 |
#pragma mark -
|
|
rudy@2886
|
304 |
|
|
rudy@2886
|
305 |
- (SEL) action {
|
|
rudy@2886
|
306 |
return action;
|
|
rudy@2886
|
307 |
}
|
|
rudy@2886
|
308 |
|
|
rudy@2886
|
309 |
- (void) setAction:(SEL) selector {
|
|
rudy@2886
|
310 |
action = selector;
|
|
rudy@2886
|
311 |
}
|
|
rudy@2886
|
312 |
|
|
rudy@2886
|
313 |
#pragma mark -
|
|
rudy@2886
|
314 |
|
|
rudy@2886
|
315 |
- (BOOL) needsDisplay {
|
|
rudy@2886
|
316 |
return needsDisplay && [super needsDisplay];
|
|
rudy@2886
|
317 |
}
|
|
rudy@2886
|
318 |
|
|
rudy@2886
|
319 |
@end
|