2 // GrowlNanoWindowView.m
5 // Created by Rudy Richter on 12/12/2005.
6 // Copyright 2005-2006, The Growl Project. All rights reserved.
9 #import "GrowlNanoWindowView.h"
10 #import "GrowlNanoPrefs.h"
11 #import "GrowlImageAdditions.h"
13 extern CGLayerRef CGLayerCreateWithContext() __attribute__((weak_import));
15 void addRoundedBottomToPath(CGContextRef context, CGRect rect, CGFloat radius);
18 void addRoundedBottomToPath(CGContextRef context, CGRect rect, CGFloat radius) {
19 CGFloat minX = CGRectGetMinX(rect);
20 CGFloat minY = CGRectGetMinY(rect);
21 CGFloat maxX = CGRectGetMaxX(rect);
22 CGFloat maxY = CGRectGetMaxY(rect);
23 CGFloat midX = CGRectGetMidX(rect);
24 CGFloat midY = CGRectGetMidY(rect);
26 CGContextBeginPath(context);
27 CGContextMoveToPoint(context, maxX, midY);
28 CGContextAddLineToPoint(context, maxX, maxY);
29 CGContextAddLineToPoint(context, minX, maxY);
30 CGContextAddLineToPoint(context, minX, midY);
31 CGContextAddArcToPoint(context, minX, minY, midX, minY, radius);
32 CGContextAddArcToPoint(context, maxX, minY, maxX, midY, radius);
33 CGContextClosePath(context);
36 @implementation GrowlNanoWindowView
38 - (id) initWithFrame:(NSRect)frame {
39 if ((self = [super initWithFrame:frame])) {
40 cache = [[NSImage alloc] initWithSize:frame.size];
48 [titleAttributes release];
49 [textAttributes release];
50 [backgroundColor release];
57 CGLayerRelease(layer);
62 - (void) drawRect:(NSRect)rect {
64 NSGraphicsContext *context = [NSGraphicsContext currentContext];
65 CGContextRef cgContext = [context graphicsPort];
66 NSRect bounds = [self bounds];
71 READ_GROWL_PREF_INT(Nano_SIZE_PREF, GrowlNanoPrefDomain, &sizePref);
72 NSRect titleRect, textRect;
75 if (sizePref == Nano_SIZE_HUGE) {
76 titleRect.origin.x = 10.0;
77 titleRect.origin.y = NSHeight(bounds) - 28.0;
78 titleRect.size.width = NSWidth(bounds) - 32.0;
79 titleRect.size.height = 20.0;
81 textRect.origin.y = NSHeight(bounds) - 41.0;
82 textRect.size.height = 15.0;
84 iconRect.origin.x = 230.0;
85 iconRect.origin.y = NSHeight(bounds) - 40.0;
86 iconRect.size.width = 32.0;
87 iconRect.size.height = 32.0;
89 titleRect.origin.x = 10.0;
90 titleRect.origin.y = NSHeight(bounds) - 14.0;
91 titleRect.size.width = NSWidth(bounds) - 16.0;
92 titleRect.size.height = 12.0;
94 textRect.origin.y = NSHeight(bounds) - 22.0;
95 textRect.size.height = 10.0;
97 iconRect.origin.x = 160.0;
98 iconRect.origin.y = NSHeight(bounds) - 20.0;
99 iconRect.size.width = 16.0;
100 iconRect.size.height = 16.0;
102 textRect.origin.x = titleRect.origin.x;
103 textRect.size.width = titleRect.size.width;
106 /*if (CGLayerCreateWithContext) {
108 layer = CGLayerCreateWithContext(cgContext, CGSizeMake(bounds.size.width, bounds.size.height), NULL);
109 [NSGraphicsContext setCurrentContext:
110 [NSGraphicsContext graphicsContextWithGraphicsPort:CGLayerGetContext(layer) flipped:NO]];
115 NSRect c = [self bounds];
116 CGRect b = CGRectMake(c.origin.x, c.origin.y, c.size.width, c.size.height);
117 addRoundedBottomToPath(cgContext, b, 10.0);
119 CGFloat opacityPref = Nano_DEFAULT_OPACITY;
120 READ_GROWL_PREF_FLOAT(Nano_OPACITY_PREF, GrowlNanoPrefDomain, &opacityPref);
121 CGFloat alpha = opacityPref * 0.01;
122 [[backgroundColor colorWithAlphaComponent:alpha] set];
123 CGContextFillPath(cgContext);
125 ////NSRectFill(bounds);
126 [title drawInRect:titleRect withAttributes:titleAttributes];
128 [text drawInRect:textRect withAttributes:textAttributes];
129 [icon setFlipped:NO];
130 [icon drawScaledInRect:iconRect operation:NSCompositeSourceOver fraction:1.0];
132 /*if (CGLayerCreateWithContext)
133 [NSGraphicsContext setCurrentContext:context];
141 //[[NSColor clearColor] set];
143 //CGContextFillPath(cgContext);
144 // draw cache to screen
145 NSRect imageRect = rect;
146 int effect = Nano_EFFECT_SLIDE;
147 READ_GROWL_PREF_BOOL(Nano_EFFECT_PREF, GrowlNanoPrefDomain, &effect);
148 if (effect == Nano_EFFECT_SLIDE) {
149 if (CGLayerCreateWithContext)
150 imageRect.origin.y = 0.0;
151 } else if (effect == Nano_EFFECT_WIPE) {
152 rect.size.height -= imageRect.origin.y;
153 imageRect.size.height -= imageRect.origin.y;
154 if (!CGLayerCreateWithContext)
155 imageRect.origin.y = 0.0;
158 if (CGLayerCreateWithContext) {
160 cgRect.origin.x = imageRect.origin.x;
161 cgRect.origin.y = imageRect.origin.y;
162 cgRect.size.width = rect.size.width;
163 if (effect == Nano_EFFECT_WIPE) {
164 cgRect.size.height = rect.size.height;
165 CGContextClipToRect(cgContext, cgRect);
167 cgRect.size.height = bounds.size.height;
168 CGContextDrawLayerInRect(cgContext, cgRect, layer);
170 [cache drawInRect:rect fromRect:imageRect operation:NSCompositeSourceOver fraction:1.0];
174 - (void) setIcon:(NSImage *)anIcon {
176 icon = [anIcon retain];
177 [self setNeedsDisplay:(needsDisplay = YES)];
180 - (void) setTitle:(NSString *)aTitle {
182 title = [aTitle copy];
183 [self setNeedsDisplay:(needsDisplay = YES)];
186 - (void) setText:(NSString *)aText {
189 [self setNeedsDisplay:(needsDisplay = YES)];
192 - (void) setPriority:(int)priority {
197 key = GrowlNanoVeryLowBackgroundColor;
198 textKey = GrowlNanoVeryLowTextColor;
201 key = GrowlNanoModerateBackgroundColor;
202 textKey = GrowlNanoModerateTextColor;
205 key = GrowlNanoHighBackgroundColor;
206 textKey = GrowlNanoHighTextColor;
209 key = GrowlNanoEmergencyBackgroundColor;
210 textKey = GrowlNanoEmergencyTextColor;
214 key = GrowlNanoNormalBackgroundColor;
215 textKey = GrowlNanoNormalTextColor;
219 [backgroundColor release];
221 CGFloat opacityPref = Nano_DEFAULT_OPACITY;
222 READ_GROWL_PREF_FLOAT(Nano_OPACITY_PREF, GrowlNanoPrefDomain, &opacityPref);
223 CGFloat alpha = opacityPref * 0.01;
225 Class NSDataClass = [NSData class];
228 READ_GROWL_PREF_VALUE(key, GrowlNanoPrefDomain, NSData *, &data);
230 CFMakeCollectable(data);
231 if (data && [data isKindOfClass:NSDataClass])
232 backgroundColor = [NSUnarchiver unarchiveObjectWithData:data];
234 backgroundColor = [NSColor blackColor];
235 backgroundColor = [[backgroundColor colorWithAlphaComponent:alpha] retain];
240 READ_GROWL_PREF_VALUE(textKey, GrowlNanoPrefDomain, NSData *, &data);
242 CFMakeCollectable(data);
243 if (data && [data isKindOfClass:NSDataClass])
244 textColor = [NSUnarchiver unarchiveObjectWithData:data];
246 textColor = [NSColor whiteColor];
250 CGFloat titleFontSize;
251 CGFloat textFontSize;
253 READ_GROWL_PREF_INT(Nano_SIZE_PREF, GrowlNanoPrefDomain, &sizePref);
255 if (sizePref == Nano_SIZE_HUGE) {
256 titleFontSize = 14.0;
259 titleFontSize = 10.0;
263 NSShadow *textShadow = [[NSShadow alloc] init];
265 NSSize shadowSize = {0.0, -2.0};
266 [textShadow setShadowOffset:shadowSize];
267 [textShadow setShadowBlurRadius:3.0];
268 [textShadow setShadowColor:[NSColor blackColor]];
270 NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
271 [paragraphStyle setAlignment:NSLeftTextAlignment];
272 [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
273 [titleAttributes release];
274 titleAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
275 textColor, NSForegroundColorAttributeName,
276 paragraphStyle, NSParagraphStyleAttributeName,
277 [NSFont boldSystemFontOfSize:titleFontSize], NSFontAttributeName,
278 textShadow, NSShadowAttributeName,
280 [paragraphStyle release];
282 paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
283 [paragraphStyle setAlignment:NSLeftTextAlignment];
284 [textAttributes release];
285 textAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
286 textColor, NSForegroundColorAttributeName,
287 paragraphStyle, NSParagraphStyleAttributeName,
288 [NSFont messageFontOfSize:textFontSize], NSFontAttributeName,
289 textShadow, NSShadowAttributeName,
291 [paragraphStyle release];
292 [textShadow release];
299 - (void) setTarget:(id) object {
309 - (void) setAction:(SEL) selector {
315 - (BOOL) needsDisplay {
316 return needsDisplay && [super needsDisplay];