Plugins/Displays/Nano/GrowlNanoWindowView.m
author Rudy Richter
Sat Aug 01 20:43:39 2009 -0400 (2009-08-01)
changeset 4259 0e9b6b0b1e25
parent 4246 4f52d1d98978
child 4666 59b81a267426
permissions -rw-r--r--
Plugins: clang warnings
     1 //
     2 //  GrowlNanoWindowView.m
     3 //  Display Plugins
     4 //
     5 //  Created by Rudy Richter on 12/12/2005.
     6 //  Copyright 2005-2006, The Growl Project. All rights reserved.
     7 //
     8 
     9 #import "GrowlNanoWindowView.h"
    10 #import "GrowlNanoPrefs.h"
    11 #import "GrowlImageAdditions.h"
    12 
    13 extern CGLayerRef CGLayerCreateWithContext() __attribute__((weak_import));
    14 
    15 void addRoundedBottomToPath(CGContextRef context, CGRect rect, CGFloat radius);
    16 
    17 
    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);
    25 
    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);
    34 }
    35 
    36 @implementation GrowlNanoWindowView
    37 
    38 - (id) initWithFrame:(NSRect)frame {
    39 	if ((self = [super initWithFrame:frame])) {
    40 		cache = [[NSImage alloc] initWithSize:frame.size];
    41 		needsDisplay = YES;
    42 	}
    43 
    44 	return self;
    45 }
    46 
    47 - (void) dealloc {
    48 	[titleAttributes release];
    49 	[textAttributes  release];
    50 	[backgroundColor release];
    51 	[textColor       release];
    52 	[icon            release];
    53 	[title           release];
    54 	[text            release];
    55 	[cache           release];
    56 	if (layer)
    57 		CGLayerRelease(layer);
    58 
    59 	[super dealloc];
    60 }
    61 
    62 - (void) drawRect:(NSRect)rect {
    63 		
    64 	NSGraphicsContext *context = [NSGraphicsContext currentContext];
    65 	CGContextRef cgContext = [context graphicsPort];
    66 	NSRect bounds = [self bounds];
    67 
    68 	if (needsDisplay) {
    69 		// rects and sizes
    70 		int sizePref = 0;
    71 		READ_GROWL_PREF_INT(Nano_SIZE_PREF, GrowlNanoPrefDomain, &sizePref);
    72 		NSRect titleRect, textRect;
    73 		NSRect iconRect;
    74 
    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;
    80 			
    81 			textRect.origin.y = NSHeight(bounds) - 41.0;
    82 			textRect.size.height = 15.0;
    83 			
    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;
    88 		} else {
    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;
    93 			
    94 			textRect.origin.y = NSHeight(bounds) - 22.0;
    95 			textRect.size.height = 10.0;
    96 			
    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;
   101 		}
   102 		textRect.origin.x = titleRect.origin.x;
   103 		textRect.size.width = titleRect.size.width;
   104 
   105 		//draw to cache
   106 		/*if (CGLayerCreateWithContext) {
   107 			if (!layer)
   108 				layer = CGLayerCreateWithContext(cgContext, CGSizeMake(bounds.size.width, bounds.size.height), NULL);
   109 			[NSGraphicsContext setCurrentContext:
   110 				[NSGraphicsContext graphicsContextWithGraphicsPort:CGLayerGetContext(layer) flipped:NO]];
   111 		} else {
   112 			[cache lockFocus];
   113 		}*/
   114 
   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);
   118 
   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);
   124 
   125 		////NSRectFill(bounds);
   126 		[title drawInRect:titleRect withAttributes:titleAttributes];
   127 
   128 		[text drawInRect:textRect withAttributes:textAttributes];
   129 		[icon setFlipped:NO];
   130 		[icon drawScaledInRect:iconRect operation:NSCompositeSourceOver fraction:1.0];
   131 
   132 		/*if (CGLayerCreateWithContext)
   133 			[NSGraphicsContext setCurrentContext:context];
   134 		else
   135 			[cache unlockFocus];
   136 
   137 		needsDisplay = NO;*/
   138 	}
   139 
   140 	// draw background
   141 	//[[NSColor clearColor] set];
   142 	//NSRectFill(rect);
   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;
   156 	}
   157 
   158 	if (CGLayerCreateWithContext) {
   159 		CGRect cgRect;
   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);
   166 		}
   167 		cgRect.size.height = bounds.size.height;
   168 		CGContextDrawLayerInRect(cgContext, cgRect, layer);
   169 	} else {
   170 		[cache drawInRect:rect fromRect:imageRect operation:NSCompositeSourceOver fraction:1.0];
   171 	}
   172 }
   173 
   174 - (void) setIcon:(NSImage *)anIcon {
   175 	[icon autorelease];
   176 	icon = [anIcon retain];
   177 	[self setNeedsDisplay:(needsDisplay = YES)];
   178 }
   179 
   180 - (void) setTitle:(NSString *)aTitle {
   181 	[title autorelease];
   182 	title = [aTitle copy];
   183 	[self setNeedsDisplay:(needsDisplay = YES)];
   184 }
   185 
   186 - (void) setText:(NSString *)aText {
   187 	[text autorelease];
   188 	text = [aText copy];
   189 	[self setNeedsDisplay:(needsDisplay = YES)];
   190 }
   191 
   192 - (void) setPriority:(int)priority {
   193 	NSString *key;
   194 	NSString *textKey;
   195 	switch (priority) {
   196 		case -2:
   197 			key = GrowlNanoVeryLowBackgroundColor;
   198 			textKey = GrowlNanoVeryLowTextColor;
   199 			break;
   200 		case -1:
   201 			key = GrowlNanoModerateBackgroundColor;
   202 			textKey = GrowlNanoModerateTextColor;
   203 			break;
   204 		case 1:
   205 			key = GrowlNanoHighBackgroundColor;
   206 			textKey = GrowlNanoHighTextColor;
   207 			break;
   208 		case 2:
   209 			key = GrowlNanoEmergencyBackgroundColor;
   210 			textKey = GrowlNanoEmergencyTextColor;
   211 			break;
   212 		case 0:
   213 		default:
   214 			key = GrowlNanoNormalBackgroundColor;
   215 			textKey = GrowlNanoNormalTextColor;
   216 			break;
   217 	}
   218 
   219 	[backgroundColor release];
   220 
   221 	CGFloat opacityPref = Nano_DEFAULT_OPACITY;
   222 	READ_GROWL_PREF_FLOAT(Nano_OPACITY_PREF, GrowlNanoPrefDomain, &opacityPref);
   223 	CGFloat alpha = opacityPref * 0.01;
   224 
   225 	Class NSDataClass = [NSData class];
   226 	NSData *data = nil;
   227 
   228 	READ_GROWL_PREF_VALUE(key, GrowlNanoPrefDomain, NSData *, &data);
   229 	if(data)
   230 		CFMakeCollectable(data);		
   231 	if (data && [data isKindOfClass:NSDataClass])
   232 		backgroundColor = [NSUnarchiver unarchiveObjectWithData:data];
   233 	else
   234 		backgroundColor = [NSColor blackColor];
   235 	backgroundColor = [[backgroundColor colorWithAlphaComponent:alpha] retain];
   236 	[data release];
   237 	data = nil;
   238 
   239 	[textColor release];
   240 	READ_GROWL_PREF_VALUE(textKey, GrowlNanoPrefDomain, NSData *, &data);
   241 	if(data)
   242 		CFMakeCollectable(data);		
   243 	if (data && [data isKindOfClass:NSDataClass])
   244 		textColor = [NSUnarchiver unarchiveObjectWithData:data];
   245 	else
   246 		textColor = [NSColor whiteColor];
   247 	[textColor retain];
   248 	[data release];
   249 
   250 	CGFloat titleFontSize;
   251 	CGFloat textFontSize;
   252 	int sizePref = 0;
   253 	READ_GROWL_PREF_INT(Nano_SIZE_PREF, GrowlNanoPrefDomain, &sizePref);
   254 
   255 	if (sizePref == Nano_SIZE_HUGE) {
   256 		titleFontSize = 14.0;
   257 		textFontSize = 12.0;
   258 	} else {
   259 		titleFontSize = 10.0;
   260 		textFontSize = 8.0;
   261 	}
   262 
   263 	NSShadow *textShadow = [[NSShadow alloc] init];
   264 
   265 	NSSize shadowSize = {0.0, -2.0};
   266 	[textShadow setShadowOffset:shadowSize];
   267 	[textShadow setShadowBlurRadius:3.0];
   268 	[textShadow setShadowColor:[NSColor blackColor]];
   269 
   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,
   279 		nil];
   280 	[paragraphStyle release];
   281 
   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,
   290 		nil];
   291 	[paragraphStyle release];
   292 	[textShadow release];
   293 }
   294 
   295 - (id) target {
   296 	return target;
   297 }
   298 
   299 - (void) setTarget:(id) object {
   300 	target = object;
   301 }
   302 
   303 #pragma mark -
   304 
   305 - (SEL) action {
   306 	return action;
   307 }
   308 
   309 - (void) setAction:(SEL) selector {
   310 	action = selector;
   311 }
   312 
   313 #pragma mark -
   314 
   315 - (BOOL) needsDisplay {
   316 	return needsDisplay && [super needsDisplay];
   317 }
   318 
   319 @end