Plugins/Displays/Bezel/GrowlBezelWindowView.m
author Rudy Richter
Sat Aug 01 20:51:06 2009 -0400 (2009-08-01)
changeset 4262 1e66707c1402
parent 4259 0e9b6b0b1e25
child 4541 9a290d3de636
permissions -rw-r--r--
Bezel: missed that clang warning
     1 //
     2 //  GrowlBezelWindowView.m
     3 //  Display Plugins
     4 //
     5 //  Created by Jorge Salvador Caffarena on 09/09/04.
     6 //  Copyright 2004 Jorge Salvador Caffarena. All rights reserved.
     7 //
     8 
     9 #import "GrowlBezelWindowView.h"
    10 #import "GrowlBezelPrefs.h"
    11 #import "GrowlImageAdditions.h"
    12 #import "GrowlBezierPathAdditions.h"
    13 
    14 #define BORDER_RADIUS 20.0
    15 
    16 @implementation GrowlBezelWindowView
    17 
    18 - (id) initWithFrame:(NSRect) frame {
    19 	if ((self = [super initWithFrame:frame])) {
    20 		layoutManager = [[NSLayoutManager alloc] init];
    21 	}
    22 	return self;
    23 }
    24 
    25 - (void) dealloc {
    26 	[icon            release];
    27 	[title           release];
    28 	[text            release];
    29 	[textColor       release];
    30 	[backgroundColor release];
    31 	[layoutManager   release];
    32 
    33 	[super dealloc];
    34 }
    35 
    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};
    39 
    40 	CGFloat a = inData[0] * 2.0;
    41 	CGFloat a_coeff;
    42 	CGFloat c;
    43 
    44 	if (a > 1.0)
    45 		a = 2.0 - a;
    46 	a_coeff = 1.0 - a;
    47 	c = a * colors[1] + a_coeff * colors[0];
    48 	outData[0] = c;
    49 	outData[1] = c;
    50 	outData[2] = c;
    51 	outData[3] = *(CGFloat *)info;
    52 }
    53 
    54 - (void) drawRect:(NSRect)rect {
    55 #pragma unused(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);
    60 
    61 		CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
    62 
    63 		addRoundedRectToPath(context, bounds, BORDER_RADIUS);
    64 
    65 		CGFloat opacityPref = BEZEL_OPACITY_DEFAULT;
    66 		READ_GROWL_PREF_FLOAT(BEZEL_OPACITY_PREF, GrowlBezelPrefDomain, &opacityPref);
    67 		CGFloat alpha = opacityPref * 0.01;
    68 
    69 		int style = 0;
    70 		READ_GROWL_PREF_INT(BEZEL_STYLE_PREF, GrowlBezelPrefDomain, &style);
    71 		switch (style) {
    72 			default:
    73 			case 0:
    74 				// default style
    75 				[[backgroundColor colorWithAlphaComponent:alpha] set];
    76 				CGContextFillPath(context);
    77 				break;
    78 			case 1:
    79 				// charcoal
    80 				CGContextSaveGState(context);
    81 				CGContextClip(context);
    82 
    83 				struct CGFunctionCallbacks callbacks = { 0U, CharcoalShadeInterpolate, NULL };
    84 				CGFunctionRef function = CGFunctionCreate( &alpha,
    85 														   1U,
    86 														   /*domain*/ NULL,
    87 														   4U,
    88 														   /*range*/ NULL,
    89 														   &callbacks );
    90 				CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
    91 				CGPoint src, dst;
    92 				src.x = CGRectGetMinX(bounds);
    93 				src.y = CGRectGetMinY(bounds);
    94 				dst.x = CGRectGetMaxX(bounds);
    95 				dst.y = src.y;
    96 				CGShadingRef shading = CGShadingCreateAxial(cspace, src, dst,
    97 															function, false, false);
    98 
    99 				CGContextDrawShading(context, shading);
   100 
   101 				CGShadingRelease(shading);
   102 				CGColorSpaceRelease(cspace);
   103 				CGFunctionRelease(function);
   104 
   105 				CGContextRestoreGState(context);
   106 				break;
   107 		}
   108 
   109 		int sizePref = BEZEL_SIZE_NORMAL;
   110 		READ_GROWL_PREF_INT(BEZEL_SIZE_PREF, GrowlBezelPrefDomain, &sizePref);
   111 
   112 		// rects
   113 		NSRect titleRect, textRect;
   114 		NSPoint iconPoint;
   115 		int maxRows;
   116 		NSSize maxIconSize;
   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;
   126 			maxRows = 4;
   127 			maxIconSize.width = 72.0;
   128 			maxIconSize.height = 72.0;
   129 			iconPoint.x = 70.0;
   130 			iconPoint.y = 120.0;
   131 		} else {
   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;
   140 			maxRows = 2;
   141 			maxIconSize.width = 48.0;
   142 			maxIconSize.height = 48.0;
   143 			iconPoint.x = 57.0;
   144 			iconPoint.y = 83.0;
   145 		}
   146 
   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]];
   152 
   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,
   162 			nil];
   163 		CGFloat accumulator = 0.0;
   164 		BOOL minFontSize = NO;
   165 		NSSize titleSize = [title sizeWithAttributes:titleAttributes];
   166 
   167 		while (titleSize.width > (NSWidth(titleRect) - (titleSize.height * 0.5))) {
   168 			minFontSize = ( titleFontSize < 12.9 );
   169 			if (minFontSize)
   170 				break;
   171 			titleFontSize -= 1.9;
   172 			accumulator += 0.5;
   173 			[titleAttributes setObject:[NSFont boldSystemFontOfSize:titleFontSize] forKey:NSFontAttributeName];
   174 			titleSize = [title sizeWithAttributes:titleAttributes];
   175 		}
   176 
   177 		titleRect.origin.y += GrowlCGFloatCeiling(accumulator);
   178 		titleRect.size.height = titleSize.height;
   179 
   180 		if (minFontSize)
   181 			[parrafo setLineBreakMode:NSLineBreakByTruncatingTail];
   182 		[title drawInRect:titleRect withAttributes:titleAttributes];
   183 		[titleAttributes release];
   184 
   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,
   191 			nil];
   192 		[textShadow release];
   193 		[parrafo release];
   194 
   195 		CGFloat height = [self descriptionHeight:text attributes:textAttributes width:textRect.size.width];
   196 		CGFloat lineHeight = [layoutManager defaultLineHeightForFont:textFont];
   197 		NSInteger rowCount = height / lineHeight;
   198 
   199 		if (rowCount > maxRows)
   200 			[textAttributes setObject:[NSFont systemFontOfSize:12.0] forKey:NSFontAttributeName];
   201 		[text drawInRect:textRect withAttributes:textAttributes];
   202 		[textAttributes release];
   203 
   204 		NSRect iconRect;
   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];
   210 	//}
   211 }
   212 
   213 - (void) setIcon:(NSImage *)anIcon {
   214 	[icon release];
   215 	icon = [anIcon retain];
   216 	[self setNeedsDisplay:YES];
   217 }
   218 
   219 - (void) setTitle:(NSString *)aTitle {
   220 	[title release];
   221 	title = [aTitle copy];
   222 	[self setNeedsDisplay:YES];
   223 }
   224 
   225 - (void) setText:(NSString *)aText {
   226 	[text release];
   227 	text = [aText copy];
   228 	[self setNeedsDisplay:YES];
   229 }
   230 
   231 - (void) setPriority:(int)priority {
   232 	NSString *key;
   233 	NSString *textKey;
   234 	switch (priority) {
   235 		case -2:
   236 			key = GrowlBezelVeryLowBackgroundColor;
   237 			textKey = GrowlBezelVeryLowTextColor;
   238 			break;
   239 		case -1:
   240 			key = GrowlBezelModerateBackgroundColor;
   241 			textKey = GrowlBezelModerateTextColor;
   242 			break;
   243 		case 1:
   244 			key = GrowlBezelHighBackgroundColor;
   245 			textKey = GrowlBezelHighTextColor;
   246 			break;
   247 		case 2:
   248 			key = GrowlBezelEmergencyBackgroundColor;
   249 			textKey = GrowlBezelEmergencyTextColor;
   250 			break;
   251 		case 0:
   252 		default:
   253 			key = GrowlBezelNormalBackgroundColor;
   254 			textKey = GrowlBezelNormalTextColor;
   255 			break;
   256 	}
   257 
   258 	[backgroundColor release];
   259 
   260 	Class NSDataClass = [NSData class];
   261 	NSData *data = nil;
   262 
   263 	READ_GROWL_PREF_VALUE(key, GrowlBezelPrefDomain, NSData *, &data);
   264 	if(data)
   265 		CFMakeCollectable(data);		
   266 	if (data && [data isKindOfClass:NSDataClass]) {
   267 			backgroundColor = [NSUnarchiver unarchiveObjectWithData:data];
   268 	} else {
   269 		backgroundColor = [NSColor blackColor];
   270 	}
   271 	[backgroundColor retain];
   272 	[data release];
   273 	data = nil;
   274 
   275 	[textColor release];
   276 	READ_GROWL_PREF_VALUE(textKey, GrowlBezelPrefDomain, NSData *, &data);
   277 	if(data)
   278 		CFMakeCollectable(data);		
   279 	if (data && [data isKindOfClass:NSDataClass]) {
   280 			textColor = [NSUnarchiver unarchiveObjectWithData:data];
   281 	} else {
   282 		textColor = [NSColor whiteColor];
   283 	}
   284 	[textColor retain];
   285 	[data release];
   286 	data = nil;
   287 }
   288 
   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];
   296 
   297 	[layoutManager addTextContainer:textContainer];
   298 	[textStorage addLayoutManager:layoutManager];
   299 	[layoutManager glyphRangeForTextContainer:textContainer];	// force layout
   300 
   301 	CGFloat textHeight = [layoutManager usedRectForTextContainer:textContainer].size.height;
   302 	[textContainer release];
   303 	[textStorage release];
   304 
   305 	return MAX (textHeight, 30.0);
   306 }
   307 
   308 #pragma mark -
   309 
   310 - (id) target {
   311 	return target;
   312 }
   313 
   314 - (void) setTarget:(id) object {
   315 	target = object;
   316 }
   317 
   318 #pragma mark -
   319 
   320 - (SEL) action {
   321 	return action;
   322 }
   323 
   324 - (void) setAction:(SEL) selector {
   325 	action = selector;
   326 }
   327 
   328 #pragma mark -
   329 
   330 - (BOOL) showsCloseBox {
   331     return NO;
   332 }
   333 
   334 @end