Plugins/Displays/Brushed/GrowlBrushedWindowView.m
author Rudy Richter
Sat Aug 01 20:43:39 2009 -0400 (2009-08-01)
changeset 4259 0e9b6b0b1e25
parent 4246 4f52d1d98978
child 4541 9a290d3de636
permissions -rw-r--r--
Plugins: clang warnings
boredzo@2402
     1
//
boredzo@2402
     2
//  GrowlBrushedWindowView.m
boredzo@2402
     3
//  Display Plugins
boredzo@2402
     4
//
boredzo@2402
     5
//  Created by Ingmar Stein on 12/01/2004.
ingmarstein@3040
     6
//  Copyright 2004-2006 The Growl Project. All rights reserved.
boredzo@2402
     7
//
boredzo@2402
     8
boredzo@2402
     9
#import "GrowlBrushedWindowView.h"
boredzo@2402
    10
#import "GrowlBrushedDefines.h"
boredzo@2402
    11
#import "GrowlDefinesInternal.h"
boredzo@2402
    12
#import "GrowlImageAdditions.h"
boredzo@2402
    13
#import "GrowlBezierPathAdditions.h"
boredzo@2402
    14
#import "NSMutableAttributedStringAdditions.h"
boredzo@2402
    15
#import <WebKit/WebPreferences.h>
boredzo@2402
    16
boredzo@2402
    17
#define GrowlBrushedTextAreaWidth	(GrowlBrushedNotificationWidth - GrowlBrushedPadding - iconSize - GrowlBrushedIconTextPadding - GrowlBrushedPadding)
boredzo@2402
    18
#define GrowlBrushedMinTextHeight	(GrowlBrushedPadding + iconSize + GrowlBrushedPadding)
boredzo@2402
    19
boredzo@2402
    20
@implementation GrowlBrushedWindowView
boredzo@2402
    21
boredzo@2402
    22
- (id) initWithFrame:(NSRect) frame {
boredzo@2402
    23
	if ((self = [super initWithFrame:frame])) {
boredzo@2402
    24
		textFont = [[NSFont systemFontOfSize:GrowlBrushedTextFontSize] retain];
boredzo@2402
    25
		textLayoutManager = [[NSLayoutManager alloc] init];
boredzo@2402
    26
		titleLayoutManager = [[NSLayoutManager alloc] init];
boredzo@2402
    27
		lineHeight = [textLayoutManager defaultLineHeightForFont:textFont];
boredzo@2402
    28
		textShadow = [[NSShadow alloc] init];
Rudy@4246
    29
		[textShadow setShadowOffset:NSMakeSize(0.0, -2.0)];
Rudy@4246
    30
		[textShadow setShadowBlurRadius:3.0];
Rudy@4246
    31
		[textShadow setShadowColor:[[[self window] backgroundColor] blendedColorWithFraction:0.5
boredzo@2402
    32
																					 ofColor:[NSColor blackColor]]];
boredzo@2402
    33
boredzo@2402
    34
		int size = GrowlBrushedSizePrefDefault;
boredzo@2402
    35
		READ_GROWL_PREF_INT(GrowlBrushedSizePref, GrowlBrushedPrefDomain, &size);
boredzo@2402
    36
		if (size == GrowlBrushedSizeLarge) {
boredzo@2402
    37
			iconSize = GrowlBrushedIconSizeLarge;
boredzo@2402
    38
		} else {
boredzo@2402
    39
			iconSize = GrowlBrushedIconSize;
boredzo@2402
    40
		}
boredzo@2402
    41
	}
boredzo@2402
    42
boredzo@2402
    43
	return self;
boredzo@2402
    44
}
boredzo@2402
    45
boredzo@2402
    46
- (void) dealloc {
boredzo@2402
    47
	[textFont           release];
boredzo@2402
    48
	[icon               release];
boredzo@2402
    49
	[textColor          release];
boredzo@2402
    50
	[textShadow         release];
boredzo@2402
    51
	[textStorage        release];
boredzo@2402
    52
	[textLayoutManager  release];
boredzo@2402
    53
	[titleStorage       release];
boredzo@2402
    54
	[titleLayoutManager release];
boredzo@2402
    55
boredzo@2402
    56
	[super dealloc];
boredzo@2402
    57
}
boredzo@2402
    58
boredzo@2402
    59
- (BOOL)isFlipped {
boredzo@2402
    60
	// Coordinates are based on top left corner
boredzo@2402
    61
    return YES;
boredzo@2402
    62
}
boredzo@2402
    63
boredzo@2402
    64
- (void) drawRect:(NSRect)rect {
rudy@2806
    65
#pragma unused(rect)
ofri@2708
    66
	//Make sure that we don't draw in the main thread
eridius@2773
    67
	//if ([super dispatchDrawingToThread:rect]) {
ofri@2708
    68
		NSRect b = [self bounds];
ofri@2708
    69
		CGRect bounds = CGRectMake(b.origin.x, b.origin.y, b.size.width, b.size.height);
ingmarstein@2721
    70
ofri@2708
    71
		CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
ingmarstein@2721
    72
ofri@2708
    73
		// clear the window
ofri@2708
    74
		CGContextClearRect(context, bounds);
ingmarstein@2721
    75
ofri@2708
    76
		// calculate bounds based on icon-float pref on or off
ofri@2708
    77
		CGRect shadedBounds;
ofri@2708
    78
		BOOL floatIcon = GrowlBrushedFloatIconPrefDefault;
ofri@2708
    79
		READ_GROWL_PREF_BOOL(GrowlBrushedFloatIconPref, GrowlBrushedPrefDomain, &floatIcon);
ofri@2708
    80
		if (floatIcon) {
Rudy@4246
    81
			CGFloat sizeReduction = GrowlBrushedPadding + iconSize + (GrowlBrushedIconTextPadding * 0.5);
Rudy@4246
    82
Rudy@4246
    83
			shadedBounds = CGRectMake(bounds.origin.x + sizeReduction + 1.0,
Rudy@4246
    84
									  bounds.origin.y + 1.0,
Rudy@4246
    85
									  bounds.size.width - sizeReduction - 2.0,
Rudy@4246
    86
									  bounds.size.height - 2.0);
ofri@2708
    87
		} else {
Rudy@4246
    88
			shadedBounds = CGRectInset(bounds, 1.0, 1.0);
ofri@2708
    89
		}
ingmarstein@2721
    90
ofri@2708
    91
		// set up path for rounded corners
ofri@2708
    92
		addRoundedRectToPath(context, shadedBounds, GrowlBrushedBorderRadius);
Rudy@4246
    93
		CGContextSetLineWidth(context, 2.0);
ingmarstein@2721
    94
ofri@2708
    95
		// draw background
ofri@2708
    96
		NSWindow *window = [self window];
ofri@2708
    97
		NSColor *bgColor = [window backgroundColor];
ofri@2708
    98
		CGPathDrawingMode drawingMode;
ofri@2708
    99
		if (mouseOver) {
ofri@2708
   100
			drawingMode = kCGPathFillStroke;
ofri@2708
   101
			[bgColor setFill];
ofri@2708
   102
			[[NSColor keyboardFocusIndicatorColor] setStroke];
ofri@2708
   103
		} else {
ofri@2708
   104
			drawingMode = kCGPathFill;
ofri@2708
   105
			[bgColor set];
ofri@2708
   106
		}
ofri@2708
   107
		CGContextDrawPath(context, drawingMode);
ingmarstein@2721
   108
ofri@2708
   109
		// draw the title and the text
ofri@2708
   110
		NSRect drawRect;
ofri@2708
   111
		drawRect.origin.x = GrowlBrushedPadding;
ofri@2708
   112
		drawRect.origin.y = GrowlBrushedPadding;
ofri@2708
   113
		drawRect.size.width = iconSize;
ofri@2708
   114
		drawRect.size.height = iconSize;
ingmarstein@2721
   115
ofri@2708
   116
		[icon setFlipped:YES];
ofri@2708
   117
		[icon drawScaledInRect:drawRect
ofri@2708
   118
					 operation:NSCompositeSourceOver
Rudy@4246
   119
					  fraction:1.0];
ingmarstein@2721
   120
ofri@2708
   121
		drawRect.origin.x += iconSize + GrowlBrushedIconTextPadding;
ingmarstein@2721
   122
ofri@2708
   123
		if (haveTitle) {
ofri@2708
   124
			[titleLayoutManager drawGlyphsForGlyphRange:titleRange atPoint:drawRect.origin];
ofri@2708
   125
			drawRect.origin.y += titleHeight + GrowlBrushedTitleTextPadding;
ofri@2708
   126
		}
ingmarstein@2721
   127
ofri@2708
   128
		if (haveText)
ofri@2708
   129
			[textLayoutManager drawGlyphsForGlyphRange:textRange atPoint:drawRect.origin];
ingmarstein@2721
   130
ofri@2708
   131
		[window invalidateShadow];
bgannin@3983
   132
		[super drawRect:rect];
eridius@2773
   133
	//}
boredzo@2402
   134
}
boredzo@2402
   135
boredzo@2402
   136
- (void) setIcon:(NSImage *)anIcon {
boredzo@2402
   137
	[icon release];
boredzo@2402
   138
	icon = [anIcon retain];
boredzo@2402
   139
	[self setNeedsDisplay:YES];
boredzo@2402
   140
}
boredzo@2402
   141
bgannin@3404
   142
- (void) setTitle:(NSString *)aTitle {
boredzo@2402
   143
	haveTitle = [aTitle length] != 0;
boredzo@2402
   144
boredzo@2402
   145
	if (!haveTitle) {
boredzo@2402
   146
		[self setNeedsDisplay:YES];
boredzo@2402
   147
		return;
boredzo@2402
   148
	}
boredzo@2402
   149
boredzo@2402
   150
	if (!titleStorage) {
boredzo@2402
   151
		NSSize containerSize;
boredzo@2402
   152
		containerSize.width = GrowlBrushedTextAreaWidth;
boredzo@2402
   153
		containerSize.height = FLT_MAX;
boredzo@2402
   154
		titleStorage = [[NSTextStorage alloc] init];
boredzo@2402
   155
		titleContainer = [[NSTextContainer alloc] initWithContainerSize:containerSize];
boredzo@2402
   156
		[titleLayoutManager addTextContainer:titleContainer];	// retains textContainer
boredzo@2402
   157
		[titleContainer release];
boredzo@2402
   158
		[titleStorage addLayoutManager:titleLayoutManager];	// retains layoutManager
Rudy@4246
   159
		[titleContainer setLineFragmentPadding:0.0];
boredzo@2402
   160
	}
boredzo@2402
   161
boredzo@2402
   162
	// construct attributes for the title
boredzo@2402
   163
	NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
boredzo@2402
   164
	NSFont *titleFont = [NSFont boldSystemFontOfSize:GrowlBrushedTitleFontSize];
boredzo@2402
   165
	[paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
boredzo@2402
   166
	NSDictionary *defaultAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
boredzo@2402
   167
		titleFont,      NSFontAttributeName,
boredzo@2402
   168
		textColor,      NSForegroundColorAttributeName,
boredzo@2402
   169
		textShadow,     NSShadowAttributeName,
boredzo@2402
   170
		paragraphStyle, NSParagraphStyleAttributeName,
boredzo@2402
   171
		nil];
boredzo@2402
   172
	[paragraphStyle release];
boredzo@2402
   173
bgannin@3404
   174
	[[titleStorage mutableString] setString:aTitle];
bgannin@3404
   175
	[titleStorage setAttributes:defaultAttributes range:NSMakeRange(0, [titleStorage length])];
boredzo@2402
   176
boredzo@2402
   177
	[defaultAttributes release];
boredzo@2402
   178
boredzo@2402
   179
	titleRange = [titleLayoutManager glyphRangeForTextContainer:titleContainer];	// force layout
boredzo@2402
   180
	titleHeight = [titleLayoutManager usedRectForTextContainer:titleContainer].size.height;
boredzo@2402
   181
boredzo@2402
   182
	[self setNeedsDisplay:YES];
boredzo@2402
   183
}
boredzo@2402
   184
bgannin@3404
   185
- (void) setText:(NSString *)aText {
boredzo@2402
   186
	haveText = [aText length] != 0;
boredzo@2402
   187
boredzo@2402
   188
	if (!haveText) {
boredzo@2402
   189
		[self setNeedsDisplay:YES];
boredzo@2402
   190
		return;
boredzo@2402
   191
	}
boredzo@2402
   192
boredzo@2402
   193
	if (!textStorage) {
boredzo@2402
   194
		NSSize containerSize;
boredzo@2402
   195
		BOOL limitPref = GrowlBrushedLimitPrefDefault;
boredzo@2402
   196
		READ_GROWL_PREF_BOOL(GrowlBrushedLimitPref, GrowlBrushedPrefDomain, &limitPref);
boredzo@2402
   197
		containerSize.width = GrowlBrushedTextAreaWidth;
boredzo@2402
   198
		if (limitPref)
boredzo@2402
   199
			containerSize.height = lineHeight * GrowlBrushedMaxLines;
boredzo@2402
   200
		else
boredzo@2402
   201
			containerSize.height = FLT_MAX;
boredzo@2402
   202
		textStorage = [[NSTextStorage alloc] init];
boredzo@2402
   203
		textContainer = [[NSTextContainer alloc] initWithContainerSize:containerSize];
boredzo@2402
   204
		[textLayoutManager addTextContainer:textContainer];	// retains textContainer
boredzo@2402
   205
		[textContainer release];
boredzo@2402
   206
		[textStorage addLayoutManager:textLayoutManager];	// retains layoutManager
Rudy@4246
   207
		[textContainer setLineFragmentPadding:0.0];
boredzo@2402
   208
	}
boredzo@2402
   209
boredzo@2402
   210
	// construct attributes for the description text
boredzo@2402
   211
	NSDictionary *defaultAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
boredzo@2402
   212
		textFont,   NSFontAttributeName,
boredzo@2402
   213
		textColor,  NSForegroundColorAttributeName,
boredzo@2402
   214
		textShadow, NSShadowAttributeName,
boredzo@2402
   215
		nil];
boredzo@2402
   216
bgannin@3404
   217
	[[textStorage mutableString] setString:aText];
bgannin@3404
   218
	[textStorage setAttributes:defaultAttributes range:NSMakeRange(0, [textStorage length])];
boredzo@2402
   219
boredzo@2402
   220
	[defaultAttributes release];
boredzo@2402
   221
boredzo@2402
   222
	textRange = [textLayoutManager glyphRangeForTextContainer:textContainer];	// force layout
boredzo@2402
   223
	textHeight = [textLayoutManager usedRectForTextContainer:textContainer].size.height;
boredzo@2402
   224
boredzo@2402
   225
	[self setNeedsDisplay:YES];
boredzo@2402
   226
}
boredzo@2402
   227
boredzo@2402
   228
- (void) setPriority:(int)priority {
boredzo@2402
   229
	NSString *textKey;
boredzo@2402
   230
	switch (priority) {
boredzo@2402
   231
		case -2:
boredzo@2402
   232
			textKey = GrowlBrushedVeryLowTextColor;
boredzo@2402
   233
			break;
boredzo@2402
   234
		case -1:
boredzo@2402
   235
			textKey = GrowlBrushedModerateTextColor;
boredzo@2402
   236
			break;
boredzo@2402
   237
		case 1:
boredzo@2402
   238
			textKey = GrowlBrushedHighTextColor;
boredzo@2402
   239
			break;
boredzo@2402
   240
		case 2:
boredzo@2402
   241
			textKey = GrowlBrushedEmergencyTextColor;
boredzo@2402
   242
			break;
boredzo@2402
   243
		case 0:
boredzo@2402
   244
		default:
boredzo@2402
   245
			textKey = GrowlBrushedNormalTextColor;
boredzo@2402
   246
			break;
boredzo@2402
   247
	}
boredzo@2402
   248
	NSData *data = nil;
boredzo@2402
   249
boredzo@2402
   250
	[textColor release];
boredzo@2402
   251
	READ_GROWL_PREF_VALUE(textKey, GrowlBrushedPrefDomain, NSData *, &data);
Rudy@4259
   252
	if(data)
Rudy@4259
   253
		CFMakeCollectable(data);		
boredzo@2402
   254
	if (data && [data isKindOfClass:[NSData class]]) {
Rudy@4259
   255
			textColor = [NSUnarchiver unarchiveObjectWithData:data];
boredzo@2402
   256
	} else {
Rudy@4259
   257
		textColor = [NSColor colorWithCalibratedWhite:0.1f alpha:1.0f];
boredzo@2402
   258
	}
boredzo@2402
   259
	[textColor retain];
boredzo@2402
   260
	[data release];
Rudy@4259
   261
	data = nil;
boredzo@2402
   262
}
boredzo@2402
   263
boredzo@2402
   264
- (void) sizeToFit {
Rudy@4246
   265
	CGFloat height = GrowlBrushedPadding + GrowlBrushedPadding + [self titleHeight] + [self descriptionHeight];
boredzo@2402
   266
	if (haveTitle && haveText)
ingmarstein@2580
   267
		height += GrowlBrushedTitleTextPadding;
ingmarstein@2580
   268
	if (height < GrowlBrushedMinTextHeight)
ingmarstein@2580
   269
		height = GrowlBrushedMinTextHeight;
boredzo@2402
   270
boredzo@2402
   271
	// resize the window so that it contains the tracking rect
ingmarstein@2580
   272
	NSWindow *window = [self window];
boredzo@2402
   273
	NSRect windowRect = [[self window] frame];
ingmarstein@2580
   274
	windowRect.origin.y -= height - windowRect.size.height;
ingmarstein@2580
   275
	windowRect.size.height = height;
evands@3582
   276
	[window setFrame:windowRect display:YES animate:YES];
boredzo@2402
   277
boredzo@2402
   278
	if (trackingRectTag)
boredzo@2402
   279
		[self removeTrackingRect:trackingRectTag];
ingmarstein@2580
   280
	trackingRectTag = [self addTrackingRect:[self frame] owner:self userData:NULL assumeInside:NO];
boredzo@2402
   281
}
boredzo@2402
   282
Rudy@4246
   283
- (CGFloat) titleHeight {
Rudy@4246
   284
	return haveTitle ? titleHeight : 0.0;
Rudy@4246
   285
}
Rudy@4246
   286
Rudy@4246
   287
- (CGFloat) descriptionHeight {
Rudy@4246
   288
	return haveText ? textHeight : 0.0;
Rudy@4246
   289
}
Rudy@4246
   290
Rudy@4246
   291
- (NSInteger) descriptionRowCount {
Rudy@4246
   292
	NSInteger rowCount = textHeight / lineHeight;
boredzo@2402
   293
	BOOL limitPref = GrowlBrushedLimitPrefDefault;
boredzo@2402
   294
	READ_GROWL_PREF_BOOL(GrowlBrushedLimitPref, GrowlBrushedPrefDomain, &limitPref);
boredzo@2402
   295
	if (limitPref)
boredzo@2402
   296
		return MIN(rowCount, GrowlBrushedMaxLines);
boredzo@2402
   297
	else
boredzo@2402
   298
		return rowCount;
boredzo@2402
   299
}
boredzo@2402
   300
boredzo@2402
   301
@end