Plugins/Displays/iCal/GrowliCalWindowView.m
author boredzo
Sun Jul 06 15:14:04 2008 +0000 (2008-07-06)
changeset 4136 642c27e46937
parent 3983 6820c1d7096a
child 4246 4f52d1d98978
permissions -rw-r--r--
Release the bar color after creating it. Fixes a leak that I found using leaks.
zaudragon@3188
     1
//
zaudragon@3189
     2
//  GrowliCalWindowView.m
zaudragon@3188
     3
//  Growl
zaudragon@3188
     4
//
zaudragon@3188
     5
//  Created by Nelson Elhage on Wed Jun 09 2004.
zaudragon@3188
     6
//  Name changed from KABubbleWindowView.m by Justin Burns on Fri Nov 05 2004.
zaudragon@3189
     7
//	Adapted for iCal by Takumi Murayama on Thu Aug 17 2006.
zaudragon@3188
     8
//  Copyright (c) 2004-2006 The Growl Project. All rights reserved.
zaudragon@3188
     9
//
zaudragon@3188
    10
zaudragon@3189
    11
#import "GrowliCalWindowView.h"
zaudragon@3188
    12
#import "GrowlDefinesInternal.h"
zaudragon@3189
    13
#import "GrowliCalDefines.h"
zaudragon@3188
    14
#import "GrowlImageAdditions.h"
zaudragon@3188
    15
#import "GrowlBezierPathAdditions.h"
zaudragon@3188
    16
#import "NSMutableAttributedStringAdditions.h"
zaudragon@3188
    17
#import <WebKit/WebPreferences.h>
zaudragon@3188
    18
zaudragon@3188
    19
/* to get the limit pref */
zaudragon@3189
    20
#import "GrowliCalPrefsController.h"
zaudragon@3188
    21
zaudragon@3188
    22
/* Hardcoded geometry values */
zaudragon@3188
    23
#define PANEL_WIDTH_PX			270.0f /*!< Total width of the panel, including border */
zaudragon@3202
    24
#define BORDER_WIDTH_PX			  1.0f
zaudragon@3197
    25
#define BORDER_RADIUS_PX		  6.0f
zaudragon@3202
    26
#define PANEL_VSPACE_PX			  1.0f /*!< Vertical padding from bounds to content area */
zaudragon@3197
    27
#define PANEL_HSPACE_PX			  6.0f /*!< Horizontal padding from bounds to content area */
zaudragon@3188
    28
#define ICON_SIZE_PX			 32.0f /*!< The width and height of the (square) icon */
zaudragon@3188
    29
#define ICON_SIZE_LARGE_PX		 48.0f /*!< The width and height of the (square) icon */
zaudragon@3202
    30
#define ICON_HSPACE_PX			  3.0f /*!< Horizontal space between icon and title/description */
zaudragon@3188
    31
#define TITLE_VSPACE_PX			  5.0f /*!< Vertical space between title and description */
rudy@3235
    32
#define TITLE_FONT_SIZE_PTS		 11.0f
rudy@3235
    33
#define DESCR_FONT_SIZE_PTS		 11.0f
zaudragon@3188
    34
#define MAX_TEXT_ROWS				5  /*!< The maximum number of rows of text, used only if the limit preference is set. */
zaudragon@3202
    35
#define MIN_TEXT_HEIGHT			(PANEL_VSPACE_PX + PANEL_VSPACE_PX + iconSize + 1)
zaudragon@3188
    36
#define TEXT_AREA_WIDTH			(PANEL_WIDTH_PX - PANEL_HSPACE_PX - PANEL_HSPACE_PX - iconSize - ICON_HSPACE_PX)
zaudragon@3188
    37
zaudragon@3189
    38
static void GrowliCalShadeInterpolate( void *info, const float *inData, float *outData ) {
zaudragon@3188
    39
	float *colors = (float *) info;
zaudragon@3188
    40
zaudragon@3188
    41
	register float a = inData[0];
zaudragon@3188
    42
	register float a_coeff = 1.0f - a;
zaudragon@3188
    43
zaudragon@3188
    44
	// SIMD could come in handy here
zaudragon@3188
    45
	// outData[0..3] = a_coeff * colors[4..7] + a * colors[0..3]
rudy@3631
    46
	outData[0] = (a_coeff * colors[4]) + (a * colors[0]);
rudy@3631
    47
	outData[1] = (a_coeff * colors[5]) + (a * colors[1]);
rudy@3631
    48
	outData[2] = (a_coeff * colors[6]) + (a * colors[2]);
rudy@3631
    49
	outData[3] = (a_coeff * colors[7]) + (a * colors[3]);
zaudragon@3188
    50
}
zaudragon@3188
    51
zaudragon@3202
    52
static void addTopRoundedRectToPath(CGContextRef context, CGRect rect, float radius) {
zaudragon@3202
    53
	float minX = CGRectGetMinX(rect);
zaudragon@3202
    54
	float minY = CGRectGetMinY(rect);
zaudragon@3202
    55
	float maxX = CGRectGetMaxX(rect);
zaudragon@3202
    56
	float maxY = CGRectGetMaxY(rect);
zaudragon@3202
    57
	float midX = CGRectGetMidX(rect);
zaudragon@3202
    58
	float midY = CGRectGetMidY(rect);
zaudragon@3202
    59
	
zaudragon@3202
    60
	CGContextBeginPath(context);
zaudragon@3202
    61
	CGContextMoveToPoint(context, maxX, midY);
zaudragon@3202
    62
	CGContextAddArcToPoint(context, maxX, maxY, midX, maxY, 0);		// Bottom Right
zaudragon@3202
    63
	CGContextAddArcToPoint(context, minX, maxY, minX, midY, 0);		// Bottom Left
zaudragon@3202
    64
	CGContextAddArcToPoint(context, minX, minY, midX, minY, radius);// Top Left
zaudragon@3202
    65
	CGContextAddArcToPoint(context, maxX, minY, maxX, midY, radius);// Top Right
zaudragon@3202
    66
	CGContextClosePath(context);
zaudragon@3202
    67
}
zaudragon@3202
    68
zaudragon@3188
    69
#pragma mark -
zaudragon@3188
    70
zaudragon@3189
    71
@implementation GrowliCalWindowView
zaudragon@3188
    72
zaudragon@3188
    73
- (id) initWithFrame:(NSRect) frame {
zaudragon@3188
    74
	if ((self = [super initWithFrame:frame])) {
rudy@3236
    75
		titleFont = [[NSFont systemFontOfSize:TITLE_FONT_SIZE_PTS] retain];
rudy@3236
    76
		textFont = [[NSFont systemFontOfSize:DESCR_FONT_SIZE_PTS] retain];
zaudragon@3188
    77
		textLayoutManager = [[NSLayoutManager alloc] init];
zaudragon@3188
    78
		titleLayoutManager = [[NSLayoutManager alloc] init];
zaudragon@3188
    79
		lineHeight = [textLayoutManager defaultLineHeightForFont:textFont];
zaudragon@3188
    80
zaudragon@3189
    81
		int size = GrowliCalSizePrefDefault;
zaudragon@3189
    82
		READ_GROWL_PREF_INT(GrowliCalSizePref, GrowliCalPrefDomain, &size);
zaudragon@3189
    83
		if (size == GrowliCalSizeLarge) {
zaudragon@3188
    84
			iconSize = ICON_SIZE_LARGE_PX;
zaudragon@3188
    85
		} else {
zaudragon@3188
    86
			iconSize = ICON_SIZE_PX;
zaudragon@3188
    87
		}
zaudragon@3188
    88
	}
zaudragon@3188
    89
	return self;
zaudragon@3188
    90
}
zaudragon@3188
    91
zaudragon@3188
    92
- (void) dealloc {
zaudragon@3188
    93
	[titleFont          release];
zaudragon@3188
    94
	[textFont           release];
zaudragon@3188
    95
	[icon               release];
zaudragon@3188
    96
	[textColor          release];
zaudragon@3188
    97
	[bgColor            release];
zaudragon@3188
    98
	[lightColor         release];
zaudragon@3188
    99
	[borderColor        release];
zaudragon@3188
   100
	[textStorage        release];
zaudragon@3188
   101
	[titleStorage       release];
zaudragon@3188
   102
	[textLayoutManager  release];
zaudragon@3188
   103
	[titleLayoutManager release];
zaudragon@3188
   104
zaudragon@3188
   105
	[super dealloc];
zaudragon@3188
   106
}
zaudragon@3188
   107
zaudragon@3188
   108
- (float) titleHeight {
zaudragon@3188
   109
	return haveTitle ? titleHeight : 0.0f;
zaudragon@3188
   110
}
zaudragon@3188
   111
zaudragon@3188
   112
zaudragon@3188
   113
- (void) drawRect:(NSRect) rect {
rudy@3233
   114
#pragma unused(rect)
zaudragon@3188
   115
	//Make sure that we don't draw in the main thread
zaudragon@3188
   116
	//if ([super dispatchDrawingToThread:rect]) {
zaudragon@3188
   117
		NSRect b = [self bounds];
zaudragon@3188
   118
		CGRect bounds = CGRectMake(b.origin.x, b.origin.y, b.size.width, b.size.height);
zaudragon@3188
   119
		CGRect shape = CGRectInset(bounds, BORDER_WIDTH_PX*0.5f, BORDER_WIDTH_PX*0.5f);
zaudragon@3188
   120
zaudragon@3188
   121
		CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
zaudragon@3188
   122
zaudragon@3188
   123
		// Create a path with enough room to strike the border and remain inside our frame.
zaudragon@3188
   124
		// Since the path is in the middle of the line, this means we must inset it by half the border width.
zaudragon@3188
   125
		addRoundedRectToPath(context, shape, BORDER_RADIUS_PX);
zaudragon@3188
   126
		CGContextSetLineWidth(context, BORDER_WIDTH_PX);
zaudragon@3188
   127
zaudragon@3188
   128
		CGContextSaveGState(context);
zaudragon@3188
   129
		CGContextClip(context);
zaudragon@3188
   130
zaudragon@3188
   131
		// Create a callback function to generate the
zaudragon@3188
   132
		// fill clipped graphics context with our gradient
zaudragon@3189
   133
		struct CGFunctionCallbacks callbacks = { 0U, GrowliCalShadeInterpolate, NULL };
zaudragon@3188
   134
		float colors[8];
zaudragon@3188
   135
zaudragon@3188
   136
		[lightColor getRed:&colors[0]
zaudragon@3188
   137
					 green:&colors[1]
zaudragon@3188
   138
					  blue:&colors[2]
zaudragon@3188
   139
					 alpha:&colors[3]];
zaudragon@3188
   140
zaudragon@3188
   141
		[bgColor getRed:&colors[4]
zaudragon@3188
   142
				  green:&colors[5]
zaudragon@3188
   143
				   blue:&colors[6]
zaudragon@3188
   144
				  alpha:&colors[7]];
zaudragon@3188
   145
zaudragon@3188
   146
		CGFunctionRef function = CGFunctionCreate( (void *) colors,
zaudragon@3188
   147
												   1U,
zaudragon@3188
   148
												   /*domain*/ NULL,
zaudragon@3188
   149
												   4U,
zaudragon@3188
   150
												   /*range*/ NULL,
zaudragon@3188
   151
												   &callbacks );
zaudragon@3188
   152
		CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
zaudragon@3188
   153
zaudragon@3188
   154
		CGPoint src, dst;
zaudragon@3197
   155
		src.x = CGRectGetMaxX(bounds);
zaudragon@3188
   156
		src.y = CGRectGetMaxY(bounds);
zaudragon@3197
   157
		dst.x = CGRectGetMinX(bounds);
zaudragon@3197
   158
		dst.y = src.y;
zaudragon@3202
   159
		CGShadingRef shading = CGShadingCreateAxial(cspace, dst, src,
zaudragon@3188
   160
													function, false, false);
zaudragon@3188
   161
zaudragon@3188
   162
		CGContextDrawShading(context, shading);
zaudragon@3188
   163
zaudragon@3188
   164
		CGShadingRelease(shading);
zaudragon@3202
   165
		CGFunctionRelease(function);
zaudragon@3202
   166
zaudragon@3202
   167
		CGContextRestoreGState(context);
zaudragon@3202
   168
zaudragon@3202
   169
		float tbcolor[4]; 
zaudragon@3202
   170
		tbcolor[0] = [borderColor redComponent];
zaudragon@3202
   171
		tbcolor[1] = [borderColor greenComponent];
zaudragon@3202
   172
		tbcolor[2] = [borderColor blueComponent];
zaudragon@3202
   173
		tbcolor[3] = [borderColor alphaComponent];
zaudragon@3202
   174
		CGColorRef barcolor = CGColorCreate(cspace,tbcolor);
boredzo@4136
   175
		if (barcolor) {
boredzo@4136
   176
			CGContextSetFillColorWithColor(context,barcolor);
boredzo@4136
   177
			CFRelease(barcolor);
boredzo@4136
   178
		}
zaudragon@3202
   179
		CGRect titlebar = CGRectMake(0,CGRectGetMinY(shape),CGRectGetWidth(shape),15);
zaudragon@3202
   180
		addTopRoundedRectToPath(context,titlebar,BORDER_RADIUS_PX);
zaudragon@3202
   181
		CGContextFillPath(context);
zaudragon@3188
   182
		CGColorSpaceRelease(cspace);
zaudragon@3188
   183
zaudragon@3188
   184
		addRoundedRectToPath(context, shape, BORDER_RADIUS_PX);
zaudragon@3188
   185
		CGContextSetLineWidth(context, BORDER_WIDTH_PX);
zaudragon@3202
   186
		[borderColor set];
zaudragon@3188
   187
		CGContextStrokePath(context);
zaudragon@3188
   188
zaudragon@3188
   189
		NSRect drawRect;
zaudragon@3202
   190
		drawRect.origin.x = CGRectGetMaxX(shape) - iconSize - ICON_HSPACE_PX;
zaudragon@3188
   191
		drawRect.origin.y = PANEL_VSPACE_PX;
zaudragon@3188
   192
		drawRect.size.width = iconSize;
zaudragon@3188
   193
		drawRect.size.height = iconSize;
zaudragon@3188
   194
zaudragon@3188
   195
		[icon setFlipped:YES];
zaudragon@3188
   196
		[icon drawScaledInRect:drawRect
zaudragon@3188
   197
					 operation:NSCompositeSourceOver
zaudragon@3188
   198
					  fraction:1.0f];
zaudragon@3188
   199
zaudragon@3202
   200
		drawRect.origin.x = PANEL_HSPACE_PX;
zaudragon@3188
   201
zaudragon@3188
   202
		if (haveTitle) {
zaudragon@3188
   203
			[titleLayoutManager drawGlyphsForGlyphRange:titleRange atPoint:drawRect.origin];
zaudragon@3188
   204
			drawRect.origin.y += titleHeight + TITLE_VSPACE_PX;
zaudragon@3188
   205
		}
zaudragon@3188
   206
zaudragon@3188
   207
		if (haveText)
zaudragon@3188
   208
			[textLayoutManager drawGlyphsForGlyphRange:textRange atPoint:drawRect.origin];
zaudragon@3188
   209
zaudragon@3188
   210
		[[self window] invalidateShadow];
bgannin@3983
   211
		[super drawRect:rect];
zaudragon@3188
   212
	//}
zaudragon@3188
   213
}
zaudragon@3188
   214
zaudragon@3188
   215
#pragma mark -
zaudragon@3188
   216
zaudragon@3188
   217
- (void) setPriority:(int)priority {
evands@3770
   218
	/* What is going on here? setPriority is the preference reader and completely ignores the priority? */
evands@3770
   219
	/* This method is completely ridiculous */
zaudragon@3188
   220
	float backgroundAlpha = 95.0f;
zaudragon@3189
   221
	READ_GROWL_PREF_FLOAT(GrowliCalOpacity, GrowliCalPrefDomain, &backgroundAlpha);
zaudragon@3188
   222
	backgroundAlpha *= 0.01f;
evands@3770
   223
evands@3770
   224
	[textColor release];
evands@3770
   225
	textColor = [[NSColor whiteColor] retain];
evands@3770
   226
evands@3770
   227
	[bgColor release];
evands@3770
   228
	[lightColor release];
evands@3770
   229
	[borderColor release];
evands@3770
   230
evands@3770
   231
	GrowliCalColorType color = GrowliCalPurple;
evands@3770
   232
	READ_GROWL_PREF_INT(GrowliCalColor, GrowliCalPrefDomain, &color);
evands@3770
   233
	switch (color) {
evands@3770
   234
		case GrowliCalPurple:
zaudragon@3205
   235
			bgColor = [NSColor colorWithCalibratedRed:0.4000f green:0.1804f blue:0.7569f alpha:backgroundAlpha];		
zaudragon@3205
   236
			lightColor = [NSColor colorWithCalibratedRed:0.6863f green:0.5294f blue:0.9765f alpha:backgroundAlpha];
zaudragon@3205
   237
			borderColor = [NSColor colorWithCalibratedRed:0.3216f green:0.0588f blue:0.6902f alpha:backgroundAlpha];
evands@3770
   238
			break;
evands@3770
   239
		
evands@3770
   240
		case GrowliCalPink:
evands@3770
   241
			bgColor = [NSColor colorWithCalibratedRed:0.7804f green:0.1098f blue:0.7725f alpha:backgroundAlpha];		
evands@3770
   242
			lightColor = [NSColor colorWithCalibratedRed:0.8157f green:0.2471f blue:0.8078f alpha:backgroundAlpha];
evands@3770
   243
			borderColor = [NSColor colorWithCalibratedRed:0.7412f green:0.0000f blue:0.7294f alpha:backgroundAlpha];
evands@3770
   244
			break;
evands@3770
   245
evands@3770
   246
		case GrowliCalGreen:
evands@3770
   247
			bgColor = [NSColor colorWithCalibratedRed:0.1490f green:0.7333f blue:0.0000f alpha:backgroundAlpha];		
zaudragon@3203
   248
			lightColor = [NSColor colorWithCalibratedRed:0.3765f green:0.8039f blue:0.2549f alpha:backgroundAlpha];
zaudragon@3203
   249
			borderColor = [NSColor colorWithCalibratedRed:0.0000f green:0.6824f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   250
			break;
evands@3770
   251
evands@3770
   252
		case GrowliCalBlue:
evands@3770
   253
			bgColor = [NSColor colorWithCalibratedRed:0.1255f green:0.3765f blue:0.9529f alpha:backgroundAlpha];		
evands@3770
   254
			lightColor = [NSColor colorWithCalibratedRed:0.3529f green:0.5647f blue:1.0000f alpha:backgroundAlpha];
evands@3770
   255
			borderColor = [NSColor colorWithCalibratedRed:0.0588f green:0.2784f blue:0.9137f alpha:backgroundAlpha];
evands@3770
   256
			break;
evands@3770
   257
evands@3770
   258
		case GrowliCalOrange:
zaudragon@3202
   259
			bgColor = [NSColor colorWithCalibratedRed:1.0000f green:0.4510f blue:0.0000f alpha:backgroundAlpha];
zaudragon@3203
   260
			lightColor = [NSColor colorWithCalibratedRed:1.0000f green:0.6235f blue:0.0941f alpha:backgroundAlpha];
zaudragon@3203
   261
			borderColor = [NSColor colorWithCalibratedRed:1.0000f green:0.4314f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   262
			break;
evands@3770
   263
evands@3770
   264
		case GrowliCalRed:
zaudragon@3202
   265
			bgColor = [NSColor colorWithCalibratedRed:1.0000f green:0.0000f blue:0.0000f alpha:backgroundAlpha];
zaudragon@3203
   266
			lightColor = [NSColor colorWithCalibratedRed:1.0000f green:0.2941f blue:0.3137f alpha:backgroundAlpha];
zaudragon@3203
   267
			borderColor = [NSColor colorWithCalibratedRed:0.9529f green:0.0000f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   268
			break;
evands@3770
   269
evands@3770
   270
		default:
evands@3770
   271
		{
evands@3770
   272
			/* When could this ever happen?!? -eds */
evands@3770
   273
			if (priority == -2) {
evands@3770
   274
				bgColor = [NSColor colorWithCalibratedRed:0.4000f green:0.1804f blue:0.7569f alpha:backgroundAlpha];		
evands@3770
   275
				lightColor = [NSColor colorWithCalibratedRed:0.6863f green:0.5294f blue:0.9765f alpha:backgroundAlpha];
evands@3770
   276
				borderColor = [NSColor colorWithCalibratedRed:0.3216f green:0.0588f blue:0.6902f alpha:backgroundAlpha];
evands@3770
   277
			} else if (priority == -1) {
evands@3770
   278
				bgColor = [NSColor colorWithCalibratedRed:0.1490f green:0.7333f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   279
				lightColor = [NSColor colorWithCalibratedRed:0.3765f green:0.8039f blue:0.2549f alpha:backgroundAlpha];
evands@3770
   280
				borderColor = [NSColor colorWithCalibratedRed:0.0000f green:0.6824f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   281
			} else if (priority == 1) {
evands@3770
   282
				bgColor = [NSColor colorWithCalibratedRed:1.0000f green:0.4510f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   283
				lightColor = [NSColor colorWithCalibratedRed:1.0000f green:0.6235f blue:0.0941f alpha:backgroundAlpha];
evands@3770
   284
				borderColor = [NSColor colorWithCalibratedRed:1.0000f green:0.4314f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   285
			} else if (priority == 2) {
evands@3770
   286
				bgColor = [NSColor colorWithCalibratedRed:1.0000f green:0.0000f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   287
				lightColor = [NSColor colorWithCalibratedRed:1.0000f green:0.2941f blue:0.3137f alpha:backgroundAlpha];
evands@3770
   288
				borderColor = [NSColor colorWithCalibratedRed:0.9529f green:0.0000f blue:0.0000f alpha:backgroundAlpha];
evands@3770
   289
			} else {
evands@3770
   290
				bgColor = [NSColor colorWithCalibratedRed:0.1255f green:0.3765f blue:0.9529f alpha:backgroundAlpha];
evands@3770
   291
				lightColor = [NSColor colorWithCalibratedRed:0.3529f green:0.5647f blue:1.0000f alpha:backgroundAlpha];
evands@3770
   292
				borderColor = [NSColor colorWithCalibratedRed:0.0588f green:0.2784f blue:0.9137f alpha:backgroundAlpha];
evands@3770
   293
			}
zaudragon@3203
   294
		}
evands@3770
   295
	}
evands@3770
   296
	
evands@3770
   297
	[bgColor retain];
evands@3770
   298
	[lightColor retain];
evands@3770
   299
	[borderColor retain];
zaudragon@3188
   300
}
zaudragon@3188
   301
zaudragon@3188
   302
- (void) setIcon:(NSImage *) anIcon {
zaudragon@3188
   303
	[icon release];
zaudragon@3188
   304
	icon = [anIcon retain];
zaudragon@3188
   305
	[self setNeedsDisplay:YES];
zaudragon@3188
   306
}
zaudragon@3188
   307
bgannin@3404
   308
- (void) setTitle:(NSString *) aTitle {
zaudragon@3188
   309
	haveTitle = [aTitle length] != 0;
zaudragon@3188
   310
zaudragon@3188
   311
	if (!haveTitle) {
zaudragon@3188
   312
		[self setNeedsDisplay:YES];
zaudragon@3188
   313
		return;
zaudragon@3188
   314
	}
zaudragon@3188
   315
zaudragon@3188
   316
	if (!titleStorage) {
zaudragon@3188
   317
		NSSize containerSize;
zaudragon@3188
   318
		containerSize.width = TEXT_AREA_WIDTH;
zaudragon@3188
   319
		containerSize.height = FLT_MAX;
zaudragon@3188
   320
		titleStorage = [[NSTextStorage alloc] init];
zaudragon@3188
   321
		titleContainer = [[NSTextContainer alloc] initWithContainerSize:containerSize];
zaudragon@3188
   322
		[titleLayoutManager addTextContainer:titleContainer];	// retains textContainer
zaudragon@3188
   323
		[titleContainer release];
zaudragon@3188
   324
		[titleStorage addLayoutManager:titleLayoutManager];	// retains layoutManager
zaudragon@3188
   325
		[titleContainer setLineFragmentPadding:0.0f];
zaudragon@3188
   326
	}
zaudragon@3188
   327
zaudragon@3188
   328
	NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
zaudragon@3188
   329
	[paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
zaudragon@3188
   330
	NSDictionary *defaultAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
zaudragon@3188
   331
		titleFont,      NSFontAttributeName,
zaudragon@3188
   332
		textColor,      NSForegroundColorAttributeName,
zaudragon@3188
   333
		paragraphStyle, NSParagraphStyleAttributeName,
zaudragon@3188
   334
		nil];
zaudragon@3188
   335
	[paragraphStyle release];
zaudragon@3188
   336
bgannin@3404
   337
	[[titleStorage mutableString] setString:aTitle];
bgannin@3404
   338
	[titleStorage setAttributes:defaultAttributes range:NSMakeRange(0, [titleStorage length])];
zaudragon@3188
   339
zaudragon@3188
   340
	[defaultAttributes release];
zaudragon@3188
   341
zaudragon@3188
   342
	titleRange = [titleLayoutManager glyphRangeForTextContainer:titleContainer];	// force layout
zaudragon@3188
   343
	titleHeight = [titleLayoutManager usedRectForTextContainer:titleContainer].size.height;
zaudragon@3188
   344
zaudragon@3188
   345
	[self setNeedsDisplay:YES];
zaudragon@3188
   346
}
zaudragon@3188
   347
bgannin@3404
   348
- (void) setText:(NSString *) aText {
zaudragon@3188
   349
	haveText = [aText length] != 0;
zaudragon@3188
   350
zaudragon@3188
   351
	if (!haveText) {
zaudragon@3188
   352
		[self setNeedsDisplay:YES];
zaudragon@3188
   353
		return;
zaudragon@3188
   354
	}
zaudragon@3188
   355
zaudragon@3188
   356
	if (!textStorage) {
zaudragon@3188
   357
		NSSize containerSize;
zaudragon@3188
   358
		BOOL limitPref = YES;
zaudragon@3189
   359
		READ_GROWL_PREF_BOOL(GrowliCalLimitPref, GrowliCalPrefDomain, &limitPref);
zaudragon@3188
   360
		containerSize.width = TEXT_AREA_WIDTH;
zaudragon@3188
   361
		if (limitPref)
zaudragon@3188
   362
			containerSize.height = lineHeight * MAX_TEXT_ROWS;
zaudragon@3188
   363
		else
zaudragon@3188
   364
			containerSize.height = FLT_MAX;
zaudragon@3188
   365
		textStorage = [[NSTextStorage alloc] init];
zaudragon@3188
   366
  		textContainer = [[NSTextContainer alloc] initWithContainerSize:containerSize];
zaudragon@3188
   367
		[textLayoutManager addTextContainer:textContainer];	// retains textContainer
zaudragon@3188
   368
		[textContainer release];
zaudragon@3188
   369
		[textStorage addLayoutManager:textLayoutManager];	// retains layoutManager
zaudragon@3188
   370
		[textContainer setLineFragmentPadding:0.0f];
zaudragon@3188
   371
	}
zaudragon@3188
   372
zaudragon@3188
   373
	NSDictionary *defaultAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
zaudragon@3188
   374
		textFont,  NSFontAttributeName,
zaudragon@3188
   375
		textColor, NSForegroundColorAttributeName,
zaudragon@3188
   376
		nil];
zaudragon@3188
   377
bgannin@3404
   378
	[[textStorage mutableString] setString:aText];
bgannin@3404
   379
	[textStorage setAttributes:defaultAttributes range:NSMakeRange(0, [textStorage length])];
zaudragon@3188
   380
zaudragon@3188
   381
	[defaultAttributes release];
zaudragon@3188
   382
zaudragon@3188
   383
	textRange = [textLayoutManager glyphRangeForTextContainer:textContainer];	// force layout
zaudragon@3188
   384
	textHeight = [textLayoutManager usedRectForTextContainer:textContainer].size.height;
zaudragon@3188
   385
zaudragon@3188
   386
	[self setNeedsDisplay:YES];
zaudragon@3188
   387
}
zaudragon@3188
   388
zaudragon@3188
   389
- (void) sizeToFit {
zaudragon@3188
   390
	float height = PANEL_VSPACE_PX + PANEL_VSPACE_PX + [self titleHeight] + [self descriptionHeight];
zaudragon@3188
   391
	if (haveTitle && haveText)
zaudragon@3188
   392
		height += TITLE_VSPACE_PX;
zaudragon@3188
   393
	if (height < MIN_TEXT_HEIGHT)
zaudragon@3188
   394
		height = MIN_TEXT_HEIGHT;
zaudragon@3188
   395
zaudragon@3188
   396
	// resize the window so that it contains the tracking rect
zaudragon@3188
   397
	NSWindow *window = [self window];
zaudragon@3188
   398
	NSRect windowRect = [window frame];
zaudragon@3188
   399
	windowRect.origin.y -= height - windowRect.size.height;
zaudragon@3188
   400
	windowRect.size.height = height;
zaudragon@3188
   401
	[window setFrame:windowRect display:NO];
zaudragon@3188
   402
zaudragon@3188
   403
	if (trackingRectTag)
zaudragon@3188
   404
		[self removeTrackingRect:trackingRectTag];
zaudragon@3188
   405
	trackingRectTag = [self addTrackingRect:[self frame] owner:self userData:NULL assumeInside:NO];
zaudragon@3188
   406
}
zaudragon@3188
   407
zaudragon@3188
   408
- (BOOL) isFlipped {
zaudragon@3188
   409
	// Coordinates are based on top left corner
zaudragon@3188
   410
    return YES;
zaudragon@3188
   411
}
zaudragon@3188
   412
zaudragon@3188
   413
- (float) descriptionHeight {
zaudragon@3188
   414
	return haveText ? textHeight : 0.0f;
zaudragon@3188
   415
}
zaudragon@3188
   416
zaudragon@3188
   417
- (int) descriptionRowCount {
zaudragon@3188
   418
	int rowCount = textHeight / lineHeight;
zaudragon@3188
   419
	BOOL limitPref = YES;
zaudragon@3189
   420
	READ_GROWL_PREF_BOOL(GrowliCalLimitPref, GrowliCalPrefDomain, &limitPref);
zaudragon@3188
   421
	if (limitPref)
zaudragon@3188
   422
		return MIN(rowCount, MAX_TEXT_ROWS);
zaudragon@3188
   423
	else
zaudragon@3188
   424
		return rowCount;
zaudragon@3188
   425
}
rudy@3298
   426
zaudragon@3188
   427
@end