2 // GrowlBezelWindowView.m
5 // Created by Jorge Salvador Caffarena on 09/09/04.
6 // Copyright 2004 Jorge Salvador Caffarena. All rights reserved.
9 #import "GrowlBezelWindowView.h"
10 #import "GrowlBezelPrefs.h"
11 #import "GrowlImageAdditions.h"
12 #import "GrowlBezierPathAdditions.h"
14 #define BORDER_RADIUS 20.0
16 @implementation GrowlBezelWindowView
18 - (id) initWithFrame:(NSRect) frame {
19 if ((self = [super initWithFrame:frame])) {
20 layoutManager = [[NSLayoutManager alloc] init];
30 [backgroundColor release];
31 [layoutManager release];
36 static void CharcoalShadeInterpolate( void *info, const CGFloat *inData, CGFloat *outData ) {
37 // const CGFloat colors[2] = {0.15, 0.35};
38 const CGFloat colors[2] = {27.0 / 255.0 * 1.5, 58.0 / 255.0};
40 CGFloat a = inData[0] * 2.0;
47 c = a * colors[1] + a_coeff * colors[0];
51 outData[3] = *(CGFloat *)info;
54 - (void) drawRect:(NSRect)rect {
56 //Make sure that we don't draw in the main thread
57 //if ([super dispatchDrawingToThread:rect]) {
58 NSRect b = [self bounds];
59 CGRect bounds = CGRectMake(b.origin.x, b.origin.y, b.size.width, b.size.height);
61 CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
63 addRoundedRectToPath(context, bounds, BORDER_RADIUS);
65 CGFloat opacityPref = BEZEL_OPACITY_DEFAULT;
66 READ_GROWL_PREF_FLOAT(BEZEL_OPACITY_PREF, GrowlBezelPrefDomain, &opacityPref);
67 CGFloat alpha = opacityPref * 0.01;
70 READ_GROWL_PREF_INT(BEZEL_STYLE_PREF, GrowlBezelPrefDomain, &style);
75 [[backgroundColor colorWithAlphaComponent:alpha] set];
76 CGContextFillPath(context);
80 CGContextSaveGState(context);
81 CGContextClip(context);
83 struct CGFunctionCallbacks callbacks = { 0U, CharcoalShadeInterpolate, NULL };
84 CGFunctionRef function = CGFunctionCreate( &alpha,
90 CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
92 src.x = CGRectGetMinX(bounds);
93 src.y = CGRectGetMinY(bounds);
94 dst.x = CGRectGetMaxX(bounds);
96 CGShadingRef shading = CGShadingCreateAxial(cspace, src, dst,
97 function, false, false);
99 CGContextDrawShading(context, shading);
101 CGShadingRelease(shading);
102 CGColorSpaceRelease(cspace);
103 CGFunctionRelease(function);
105 CGContextRestoreGState(context);
109 int sizePref = BEZEL_SIZE_NORMAL;
110 READ_GROWL_PREF_INT(BEZEL_SIZE_PREF, GrowlBezelPrefDomain, &sizePref);
113 NSRect titleRect, textRect;
117 if (sizePref == BEZEL_SIZE_NORMAL) {
118 titleRect.origin.x = 12.0;
119 titleRect.origin.y = 90.0;
120 titleRect.size.width = 187.0;
121 titleRect.size.height = 30.0;
122 textRect.origin.x = 12.0;
123 textRect.origin.y = 4.0;
124 textRect.size.width = 187.0;
125 textRect.size.height = 80.0;
127 maxIconSize.width = 72.0;
128 maxIconSize.height = 72.0;
132 titleRect.origin.x = 8.0;
133 titleRect.origin.y = 52.0;
134 titleRect.size.width = 143.0;
135 titleRect.size.height = 24.0;
136 textRect.origin.x = 8.0;
137 textRect.origin.y = 4.0;
138 textRect.size.width = 143.0;
139 textRect.size.height = 49.0;
141 maxIconSize.width = 48.0;
142 maxIconSize.height = 48.0;
147 NSShadow *textShadow = [[NSShadow alloc] init];
148 NSSize shadowSize = {0.0, -2.0};
149 [textShadow setShadowOffset:shadowSize];
150 [textShadow setShadowBlurRadius:3.0];
151 [textShadow setShadowColor:[NSColor blackColor]];
153 // Draw the title, resize if text too big
154 CGFloat titleFontSize = 20.0;
155 NSMutableParagraphStyle *parrafo = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
156 [parrafo setAlignment:NSCenterTextAlignment];
157 NSMutableDictionary *titleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
158 textColor, NSForegroundColorAttributeName,
159 parrafo, NSParagraphStyleAttributeName,
160 [NSFont boldSystemFontOfSize:titleFontSize], NSFontAttributeName,
161 textShadow, NSShadowAttributeName,
163 CGFloat accumulator = 0.0;
164 BOOL minFontSize = NO;
165 NSSize titleSize = [title sizeWithAttributes:titleAttributes];
167 while (titleSize.width > (NSWidth(titleRect) - (titleSize.height * 0.5))) {
168 minFontSize = ( titleFontSize < 12.9 );
171 titleFontSize -= 1.9;
173 [titleAttributes setObject:[NSFont boldSystemFontOfSize:titleFontSize] forKey:NSFontAttributeName];
174 titleSize = [title sizeWithAttributes:titleAttributes];
177 titleRect.origin.y += GrowlCGFloatCeiling(accumulator);
178 titleRect.size.height = titleSize.height;
181 [parrafo setLineBreakMode:NSLineBreakByTruncatingTail];
182 [title drawInRect:titleRect withAttributes:titleAttributes];
183 [titleAttributes release];
185 NSFont *textFont = [NSFont systemFontOfSize:14.0];
186 NSMutableDictionary *textAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
187 textColor, NSForegroundColorAttributeName,
188 parrafo, NSParagraphStyleAttributeName,
189 textFont, NSFontAttributeName,
190 textShadow, NSShadowAttributeName,
192 [textShadow release];
195 CGFloat height = [self descriptionHeight:text attributes:textAttributes width:textRect.size.width];
196 CGFloat lineHeight = [layoutManager defaultLineHeightForFont:textFont];
197 NSInteger rowCount = height / lineHeight;
199 if (rowCount > maxRows)
200 [textAttributes setObject:[NSFont systemFontOfSize:12.0] forKey:NSFontAttributeName];
201 [text drawInRect:textRect withAttributes:textAttributes];
202 [textAttributes release];
205 iconRect.origin = iconPoint;
206 iconRect.size = maxIconSize;
207 [icon setFlipped:NO];
208 [icon drawScaledInRect:iconRect operation:NSCompositeSourceOver fraction:1.0];
209 [super drawRect:rect];
213 - (void) setIcon:(NSImage *)anIcon {
215 icon = [anIcon retain];
216 [self setNeedsDisplay:YES];
219 - (void) setTitle:(NSString *)aTitle {
221 title = [aTitle copy];
222 [self setNeedsDisplay:YES];
225 - (void) setText:(NSString *)aText {
228 [self setNeedsDisplay:YES];
231 - (void) setPriority:(int)priority {
236 key = GrowlBezelVeryLowBackgroundColor;
237 textKey = GrowlBezelVeryLowTextColor;
240 key = GrowlBezelModerateBackgroundColor;
241 textKey = GrowlBezelModerateTextColor;
244 key = GrowlBezelHighBackgroundColor;
245 textKey = GrowlBezelHighTextColor;
248 key = GrowlBezelEmergencyBackgroundColor;
249 textKey = GrowlBezelEmergencyTextColor;
253 key = GrowlBezelNormalBackgroundColor;
254 textKey = GrowlBezelNormalTextColor;
258 [backgroundColor release];
260 Class NSDataClass = [NSData class];
263 READ_GROWL_PREF_VALUE(key, GrowlBezelPrefDomain, NSData *, &data);
265 CFMakeCollectable(data);
266 if (data && [data isKindOfClass:NSDataClass]) {
267 backgroundColor = [NSUnarchiver unarchiveObjectWithData:data];
269 backgroundColor = [NSColor blackColor];
271 [backgroundColor retain];
276 READ_GROWL_PREF_VALUE(textKey, GrowlBezelPrefDomain, NSData *, &data);
278 CFMakeCollectable(data);
279 if (data && [data isKindOfClass:NSDataClass]) {
280 textColor = [NSUnarchiver unarchiveObjectWithData:data];
282 textColor = [NSColor whiteColor];
289 - (CGFloat) descriptionHeight:(NSString *)theText attributes:(NSDictionary *)attributes width:(CGFloat)width {
290 NSSize containerSize;
291 containerSize.width = width;
292 containerSize.height = FLT_MAX;
293 NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:theText attributes:attributes];
294 NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:containerSize];
295 [textContainer setLineFragmentPadding:0.0];
297 [layoutManager addTextContainer:textContainer];
298 [textStorage addLayoutManager:layoutManager];
299 [layoutManager glyphRangeForTextContainer:textContainer]; // force layout
301 CGFloat textHeight = [layoutManager usedRectForTextContainer:textContainer].size.height;
302 [textContainer release];
303 [textStorage release];
305 return MAX (textHeight, 30.0);
314 - (void) setTarget:(id) object {
324 - (void) setAction:(SEL) selector {
330 - (BOOL) showsCloseBox {