Plugins/Displays/Bezel/GrowlBezelWindowView.m
author Rudy Richter
Sat Aug 01 20:43:39 2009 -0400 (2009-08-01)
changeset 4259 0e9b6b0b1e25
parent 4246 4f52d1d98978
child 4262 1e66707c1402
permissions -rw-r--r--
Plugins: clang warnings
boredzo@2402
     1
//
boredzo@2402
     2
//  GrowlBezelWindowView.m
boredzo@2402
     3
//  Display Plugins
boredzo@2402
     4
//
boredzo@2402
     5
//  Created by Jorge Salvador Caffarena on 09/09/04.
boredzo@2402
     6
//  Copyright 2004 Jorge Salvador Caffarena. All rights reserved.
boredzo@2402
     7
//
boredzo@2402
     8
boredzo@2402
     9
#import "GrowlBezelWindowView.h"
boredzo@2402
    10
#import "GrowlBezelPrefs.h"
boredzo@2402
    11
#import "GrowlImageAdditions.h"
boredzo@2402
    12
#import "GrowlBezierPathAdditions.h"
boredzo@2402
    13
Rudy@4246
    14
#define BORDER_RADIUS 20.0
boredzo@2402
    15
boredzo@2402
    16
@implementation GrowlBezelWindowView
boredzo@2402
    17
boredzo@2402
    18
- (id) initWithFrame:(NSRect) frame {
boredzo@2402
    19
	if ((self = [super initWithFrame:frame])) {
boredzo@2402
    20
		layoutManager = [[NSLayoutManager alloc] init];
boredzo@2402
    21
	}
boredzo@2402
    22
	return self;
boredzo@2402
    23
}
boredzo@2402
    24
boredzo@2402
    25
- (void) dealloc {
boredzo@2402
    26
	[icon            release];
boredzo@2402
    27
	[title           release];
boredzo@2402
    28
	[text            release];
boredzo@2402
    29
	[textColor       release];
boredzo@2402
    30
	[backgroundColor release];
boredzo@2402
    31
	[layoutManager   release];
boredzo@2402
    32
boredzo@2402
    33
	[super dealloc];
boredzo@2402
    34
}
boredzo@2402
    35
Rudy@4246
    36
static void CharcoalShadeInterpolate( void *info, const CGFloat *inData, CGFloat *outData ) {
Rudy@4246
    37
//	const CGFloat colors[2] = {0.15, 0.35};
Rudy@4246
    38
	const CGFloat colors[2] = {27.0 / 255.0 * 1.5, 58.0 / 255.0};
Rudy@4246
    39
Rudy@4246
    40
	CGFloat a = inData[0] * 2.0;
Rudy@4246
    41
	CGFloat a_coeff;
Rudy@4246
    42
	CGFloat c;
Rudy@4246
    43
Rudy@4246
    44
	if (a > 1.0)
Rudy@4246
    45
		a = 2.0 - a;
Rudy@4246
    46
	a_coeff = 1.0 - a;
boredzo@2402
    47
	c = a * colors[1] + a_coeff * colors[0];
boredzo@2402
    48
	outData[0] = c;
boredzo@2402
    49
	outData[1] = c;
boredzo@2402
    50
	outData[2] = c;
Rudy@4246
    51
	outData[3] = *(CGFloat *)info;
boredzo@2402
    52
}
boredzo@2402
    53
boredzo@2402
    54
- (void) drawRect:(NSRect)rect {
ingmarstein@2941
    55
#pragma unused(rect)
ofri@2708
    56
	//Make sure that we don't draw in the main thread
rudy@2807
    57
	//if ([super dispatchDrawingToThread:rect]) {
ofri@2708
    58
		NSRect b = [self bounds];
ofri@2708
    59
		CGRect bounds = CGRectMake(b.origin.x, b.origin.y, b.size.width, b.size.height);
ingmarstein@2721
    60
ofri@2708
    61
		CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
ingmarstein@2721
    62
ofri@2708
    63
		addRoundedRectToPath(context, bounds, BORDER_RADIUS);
ingmarstein@2721
    64
Rudy@4246
    65
		CGFloat opacityPref = BEZEL_OPACITY_DEFAULT;
rudy@2807
    66
		READ_GROWL_PREF_FLOAT(BEZEL_OPACITY_PREF, GrowlBezelPrefDomain, &opacityPref);
Rudy@4246
    67
		CGFloat alpha = opacityPref * 0.01;
ingmarstein@2721
    68
ofri@2708
    69
		int style = 0;
rudy@2807
    70
		READ_GROWL_PREF_INT(BEZEL_STYLE_PREF, GrowlBezelPrefDomain, &style);
ofri@2708
    71
		switch (style) {
ofri@2708
    72
			default:
ofri@2708
    73
			case 0:
ofri@2708
    74
				// default style
ofri@2708
    75
				[[backgroundColor colorWithAlphaComponent:alpha] set];
ofri@2708
    76
				CGContextFillPath(context);
ofri@2708
    77
				break;
ofri@2708
    78
			case 1:
ofri@2708
    79
				// charcoal
ofri@2708
    80
				CGContextSaveGState(context);
ofri@2708
    81
				CGContextClip(context);
ingmarstein@2721
    82
ofri@2708
    83
				struct CGFunctionCallbacks callbacks = { 0U, CharcoalShadeInterpolate, NULL };
ofri@2708
    84
				CGFunctionRef function = CGFunctionCreate( &alpha,
ofri@2708
    85
														   1U,
ofri@2708
    86
														   /*domain*/ NULL,
ofri@2708
    87
														   4U,
ofri@2708
    88
														   /*range*/ NULL,
ofri@2708
    89
														   &callbacks );
ofri@2708
    90
				CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
ofri@2708
    91
				CGPoint src, dst;
ofri@2708
    92
				src.x = CGRectGetMinX(bounds);
ofri@2708
    93
				src.y = CGRectGetMinY(bounds);
ofri@2708
    94
				dst.x = CGRectGetMaxX(bounds);
ofri@2708
    95
				dst.y = src.y;
ofri@2708
    96
				CGShadingRef shading = CGShadingCreateAxial(cspace, src, dst,
ofri@2708
    97
															function, false, false);
ingmarstein@2721
    98
ofri@2708
    99
				CGContextDrawShading(context, shading);
ingmarstein@2721
   100
ofri@2708
   101
				CGShadingRelease(shading);
ofri@2708
   102
				CGColorSpaceRelease(cspace);
ofri@2708
   103
				CGFunctionRelease(function);
ingmarstein@2721
   104
ofri@2708
   105
				CGContextRestoreGState(context);
ofri@2708
   106
				break;
ofri@2708
   107
		}
ingmarstein@2721
   108
ofri@2708
   109
		int sizePref = BEZEL_SIZE_NORMAL;
rudy@2807
   110
		READ_GROWL_PREF_INT(BEZEL_SIZE_PREF, GrowlBezelPrefDomain, &sizePref);
ingmarstein@2721
   111
ofri@2708
   112
		// rects
ofri@2708
   113
		NSRect titleRect, textRect;
ofri@2708
   114
		NSPoint iconPoint;
ofri@2708
   115
		int maxRows;
ofri@2708
   116
		NSSize maxIconSize;
ofri@2708
   117
		if (sizePref == BEZEL_SIZE_NORMAL) {
Rudy@4246
   118
			titleRect.origin.x = 12.0;
Rudy@4246
   119
			titleRect.origin.y = 90.0;
Rudy@4246
   120
			titleRect.size.width = 187.0;
Rudy@4246
   121
			titleRect.size.height = 30.0;
Rudy@4246
   122
			textRect.origin.x = 12.0;
Rudy@4246
   123
			textRect.origin.y = 4.0;
Rudy@4246
   124
			textRect.size.width = 187.0;
Rudy@4246
   125
			textRect.size.height = 80.0;
ofri@2708
   126
			maxRows = 4;
Rudy@4246
   127
			maxIconSize.width = 72.0;
Rudy@4246
   128
			maxIconSize.height = 72.0;
Rudy@4246
   129
			iconPoint.x = 70.0;
Rudy@4246
   130
			iconPoint.y = 120.0;
ofri@2708
   131
		} else {
Rudy@4246
   132
			titleRect.origin.x = 8.0;
Rudy@4246
   133
			titleRect.origin.y = 52.0;
Rudy@4246
   134
			titleRect.size.width = 143.0;
Rudy@4246
   135
			titleRect.size.height = 24.0;
Rudy@4246
   136
			textRect.origin.x = 8.0;
Rudy@4246
   137
			textRect.origin.y = 4.0;
Rudy@4246
   138
			textRect.size.width = 143.0;
Rudy@4246
   139
			textRect.size.height = 49.0;
ofri@2708
   140
			maxRows = 2;
Rudy@4246
   141
			maxIconSize.width = 48.0;
Rudy@4246
   142
			maxIconSize.height = 48.0;
Rudy@4246
   143
			iconPoint.x = 57.0;
Rudy@4246
   144
			iconPoint.y = 83.0;
ofri@2708
   145
		}
ingmarstein@2721
   146
ofri@2708
   147
		NSShadow *textShadow = [[NSShadow alloc] init];
Rudy@4246
   148
		NSSize shadowSize = {0.0, -2.0};
ofri@2708
   149
		[textShadow setShadowOffset:shadowSize];
Rudy@4246
   150
		[textShadow setShadowBlurRadius:3.0];
ofri@2708
   151
		[textShadow setShadowColor:[NSColor blackColor]];
ingmarstein@2721
   152
ofri@2708
   153
		// Draw the title, resize if text too big
Rudy@4246
   154
		CGFloat titleFontSize = 20.0;
ofri@2708
   155
		NSMutableParagraphStyle *parrafo = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
ofri@2708
   156
		[parrafo setAlignment:NSCenterTextAlignment];
ofri@2708
   157
		NSMutableDictionary *titleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
ofri@2708
   158
			textColor,                                   NSForegroundColorAttributeName,
ofri@2708
   159
			parrafo,                                     NSParagraphStyleAttributeName,
ofri@2708
   160
			[NSFont boldSystemFontOfSize:titleFontSize], NSFontAttributeName,
ofri@2708
   161
			textShadow,                                  NSShadowAttributeName,
ofri@2708
   162
			nil];
Rudy@4246
   163
		CGFloat accumulator = 0.0;
ofri@2708
   164
		BOOL minFontSize = NO;
ofri@2708
   165
		NSSize titleSize = [title sizeWithAttributes:titleAttributes];
ingmarstein@2721
   166
Rudy@4246
   167
		while (titleSize.width > (NSWidth(titleRect) - (titleSize.height * 0.5))) {
Rudy@4246
   168
			minFontSize = ( titleFontSize < 12.9 );
ofri@2708
   169
			if (minFontSize)
ofri@2708
   170
				break;
Rudy@4246
   171
			titleFontSize -= 1.9;
Rudy@4246
   172
			accumulator += 0.5;
ofri@2708
   173
			[titleAttributes setObject:[NSFont boldSystemFontOfSize:titleFontSize] forKey:NSFontAttributeName];
ofri@2708
   174
			titleSize = [title sizeWithAttributes:titleAttributes];
ofri@2708
   175
		}
ingmarstein@2721
   176
Rudy@4246
   177
		titleRect.origin.y += GrowlCGFloatCeiling(accumulator);
ofri@2708
   178
		titleRect.size.height = titleSize.height;
ingmarstein@2721
   179
ofri@2708
   180
		if (minFontSize)
ofri@2708
   181
			[parrafo setLineBreakMode:NSLineBreakByTruncatingTail];
ofri@2708
   182
		[title drawInRect:titleRect withAttributes:titleAttributes];
ofri@2708
   183
		[titleAttributes release];
ingmarstein@2721
   184
Rudy@4246
   185
		NSFont *textFont = [NSFont systemFontOfSize:14.0];
ofri@2708
   186
		NSMutableDictionary *textAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
ofri@2708
   187
			textColor,  NSForegroundColorAttributeName,
ofri@2708
   188
			parrafo,    NSParagraphStyleAttributeName,
ofri@2708
   189
			textFont,   NSFontAttributeName,
ofri@2708
   190
			textShadow, NSShadowAttributeName,
ofri@2708
   191
			nil];
ofri@2708
   192
		[textShadow release];
ofri@2708
   193
		[parrafo release];
ingmarstein@2721
   194
Rudy@4246
   195
		CGFloat height = [self descriptionHeight:text attributes:textAttributes width:textRect.size.width];
Rudy@4246
   196
		CGFloat lineHeight = [layoutManager defaultLineHeightForFont:textFont];
Rudy@4246
   197
		NSInteger rowCount = height / lineHeight;
ingmarstein@2721
   198
ofri@2708
   199
		if (rowCount > maxRows)
Rudy@4246
   200
			[textAttributes setObject:[NSFont systemFontOfSize:12.0] forKey:NSFontAttributeName];
ofri@2708
   201
		[text drawInRect:textRect withAttributes:textAttributes];
ofri@2708
   202
		[textAttributes release];
ingmarstein@2721
   203
ofri@2708
   204
		NSRect iconRect;
ofri@2708
   205
		iconRect.origin = iconPoint;
ofri@2708
   206
		iconRect.size = maxIconSize;
ofri@2708
   207
		[icon setFlipped:NO];
Rudy@4246
   208
		[icon drawScaledInRect:iconRect operation:NSCompositeSourceOver fraction:1.0];
bgannin@3983
   209
		[super drawRect:rect];
rudy@2807
   210
	//}
boredzo@2402
   211
}
boredzo@2402
   212
boredzo@2402
   213
- (void) setIcon:(NSImage *)anIcon {
boredzo@2402
   214
	[icon release];
boredzo@2402
   215
	icon = [anIcon retain];
boredzo@2402
   216
	[self setNeedsDisplay:YES];
boredzo@2402
   217
}
boredzo@2402
   218
boredzo@2402
   219
- (void) setTitle:(NSString *)aTitle {
boredzo@2402
   220
	[title release];
boredzo@2402
   221
	title = [aTitle copy];
boredzo@2402
   222
	[self setNeedsDisplay:YES];
boredzo@2402
   223
}
boredzo@2402
   224
boredzo@2402
   225
- (void) setText:(NSString *)aText {
boredzo@2402
   226
	[text release];
boredzo@2402
   227
	text = [aText copy];
boredzo@2402
   228
	[self setNeedsDisplay:YES];
boredzo@2402
   229
}
boredzo@2402
   230
boredzo@2402
   231
- (void) setPriority:(int)priority {
boredzo@2402
   232
	NSString *key;
boredzo@2402
   233
	NSString *textKey;
boredzo@2402
   234
	switch (priority) {
boredzo@2402
   235
		case -2:
boredzo@2402
   236
			key = GrowlBezelVeryLowBackgroundColor;
boredzo@2402
   237
			textKey = GrowlBezelVeryLowTextColor;
boredzo@2402
   238
			break;
boredzo@2402
   239
		case -1:
boredzo@2402
   240
			key = GrowlBezelModerateBackgroundColor;
boredzo@2402
   241
			textKey = GrowlBezelModerateTextColor;
boredzo@2402
   242
			break;
boredzo@2402
   243
		case 1:
boredzo@2402
   244
			key = GrowlBezelHighBackgroundColor;
boredzo@2402
   245
			textKey = GrowlBezelHighTextColor;
boredzo@2402
   246
			break;
boredzo@2402
   247
		case 2:
boredzo@2402
   248
			key = GrowlBezelEmergencyBackgroundColor;
boredzo@2402
   249
			textKey = GrowlBezelEmergencyTextColor;
boredzo@2402
   250
			break;
boredzo@2402
   251
		case 0:
boredzo@2402
   252
		default:
boredzo@2402
   253
			key = GrowlBezelNormalBackgroundColor;
boredzo@2402
   254
			textKey = GrowlBezelNormalTextColor;
boredzo@2402
   255
			break;
boredzo@2402
   256
	}
boredzo@2402
   257
boredzo@2402
   258
	[backgroundColor release];
boredzo@2402
   259
boredzo@2402
   260
	Class NSDataClass = [NSData class];
boredzo@2402
   261
	NSData *data = nil;
boredzo@2402
   262
rudy@2807
   263
	READ_GROWL_PREF_VALUE(key, GrowlBezelPrefDomain, NSData *, &data);
Rudy@4259
   264
	if (data && [data isKindOfClass:NSDataClass]) {
Rudy@4259
   265
			backgroundColor = [NSUnarchiver unarchiveObjectWithData:data];
Rudy@4259
   266
	} else {
boredzo@2402
   267
		backgroundColor = [NSColor blackColor];
Rudy@4259
   268
	}
boredzo@2402
   269
	[backgroundColor retain];
boredzo@2402
   270
	[data release];
boredzo@2402
   271
	data = nil;
boredzo@2402
   272
boredzo@2402
   273
	[textColor release];
rudy@2807
   274
	READ_GROWL_PREF_VALUE(textKey, GrowlBezelPrefDomain, NSData *, &data);
Rudy@4259
   275
	if(data)
Rudy@4259
   276
		CFMakeCollectable(data);		
Rudy@4259
   277
	if (data && [data isKindOfClass:NSDataClass]) {
Rudy@4259
   278
			textColor = [NSUnarchiver unarchiveObjectWithData:data];
Rudy@4259
   279
	} else {
boredzo@2402
   280
		textColor = [NSColor whiteColor];
Rudy@4259
   281
	}
boredzo@2402
   282
	[textColor retain];
boredzo@2402
   283
	[data release];
Rudy@4259
   284
	data = nil;
boredzo@2402
   285
}
boredzo@2402
   286
Rudy@4246
   287
- (CGFloat) descriptionHeight:(NSString *)theText attributes:(NSDictionary *)attributes width:(CGFloat)width {
boredzo@2402
   288
	NSSize containerSize;
boredzo@2402
   289
	containerSize.width = width;
boredzo@2402
   290
	containerSize.height = FLT_MAX;
boredzo@2402
   291
	NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:theText attributes:attributes];
boredzo@2402
   292
	NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:containerSize];
Rudy@4246
   293
	[textContainer setLineFragmentPadding:0.0];
boredzo@2402
   294
boredzo@2402
   295
	[layoutManager addTextContainer:textContainer];
boredzo@2402
   296
	[textStorage addLayoutManager:layoutManager];
boredzo@2402
   297
	[layoutManager glyphRangeForTextContainer:textContainer];	// force layout
boredzo@2402
   298
Rudy@4246
   299
	CGFloat textHeight = [layoutManager usedRectForTextContainer:textContainer].size.height;
boredzo@2402
   300
	[textContainer release];
boredzo@2402
   301
	[textStorage release];
boredzo@2402
   302
Rudy@4246
   303
	return MAX (textHeight, 30.0);
boredzo@2402
   304
}
boredzo@2402
   305
boredzo@2402
   306
#pragma mark -
boredzo@2402
   307
boredzo@2402
   308
- (id) target {
boredzo@2402
   309
	return target;
boredzo@2402
   310
}
boredzo@2402
   311
boredzo@2402
   312
- (void) setTarget:(id) object {
boredzo@2402
   313
	target = object;
boredzo@2402
   314
}
boredzo@2402
   315
boredzo@2402
   316
#pragma mark -
boredzo@2402
   317
boredzo@2402
   318
- (SEL) action {
boredzo@2402
   319
	return action;
boredzo@2402
   320
}
boredzo@2402
   321
boredzo@2402
   322
- (void) setAction:(SEL) selector {
boredzo@2402
   323
	action = selector;
boredzo@2402
   324
}
boredzo@2402
   325
boredzo@2402
   326
#pragma mark -
boredzo@2402
   327
vinay@3127
   328
- (BOOL) showsCloseBox {
vinay@3127
   329
    return NO;
vinay@3127
   330
}
vinay@3127
   331
boredzo@2402
   332
@end