2 // GrowlITTSWController.m
5 // Created by Joseph Spiros on 2/28/09.
6 // Copyright 2009 iThink Software. All rights reserved.
9 #import "GrowlITTSWController.h"
10 #import "GrowlITTSWPrefs.h"
12 #import <ITKit/ITWindowEffect.h>
13 #import <ITKit/ITTSWBackgroundView.h>
15 #import "RegexKitLite.h"
17 @implementation NSImage (SmoothAdditions)
19 - (NSImage *)imageScaledSmoothlyToSize:(NSSize)scaledSize {
21 NSImageRep *rep = [self bestRepresentationForDevice:nil];
23 newImage = [[NSImage alloc] initWithSize:scaledSize];
26 [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
27 [[NSGraphicsContext currentContext] setShouldAntialias:YES];
28 [rep drawInRect:NSMakeRect(3, 3, scaledSize.width - 6, scaledSize.height - 6)];
30 [newImage unlockFocus];
31 return [newImage autorelease];
36 @interface GrowlITTSWController (Private)
37 - (void)syncWithPrefs;
40 @implementation GrowlITTSWController
43 if ( ( self = [super init] ) ) {
44 _window = [[GrowlITTSWWindow sharedWindow] retain];
45 [_window setExitMode:ITTransientStatusWindowExitAfterDelay];
47 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(syncWithPrefs) name:@"GrowlPreferencesChanged" object:nil];
58 - (void)syncWithPrefs {
59 _imageSize = [GrowlITTSWPrefs imageSize];
60 _imageNoUpscale = [GrowlITTSWPrefs imageNoUpscale];
61 _wrapNotifications = [GrowlITTSWPrefs wrapNotifications];
62 _wrapColumns = [GrowlITTSWPrefs wrapColumns];
64 NSScreen *screen = [GrowlITTSWPrefs screen];
65 ITHorizontalWindowPosition horizontalPosition = [GrowlITTSWPrefs horizontalPosition];
66 ITVerticalWindowPosition verticalPosition = [GrowlITTSWPrefs verticalPosition];
68 Class appearanceEffect = [GrowlITTSWPrefs appearanceEffect];
69 float appearanceSpeed = [GrowlITTSWPrefs appearanceSpeed];
70 Class vanishEffect = [GrowlITTSWPrefs vanishEffect];
71 float vanishSpeed = [GrowlITTSWPrefs vanishSpeed];
72 float vanishDelay = [GrowlITTSWPrefs vanishDelay];
74 ITTSWBackgroundMode backgroundStyle = [GrowlITTSWPrefs backgroundStyle];
75 NSColor *backgroundColor = [GrowlITTSWPrefs backgroundColor];
76 ITTransientStatusWindowSizing windowSize = [GrowlITTSWPrefs windowSize];
78 if ([_window screen] != screen) {
79 [_window setScreen:screen];
81 if ([_window horizontalPosition] != horizontalPosition) {
82 [_window setHorizontalPosition:horizontalPosition];
84 if ([_window verticalPosition] != verticalPosition) {
85 [_window setVerticalPosition:verticalPosition];
88 if (![[_window entryEffect] isKindOfClass:appearanceEffect]) {
89 [_window setEntryEffect:[[[appearanceEffect alloc] initWithWindow:_window] autorelease]];
91 if ([[_window entryEffect] effectTime] != appearanceSpeed) {
92 [[_window entryEffect] setEffectTime:appearanceSpeed];
94 if (![[_window exitEffect] isKindOfClass:vanishEffect]) {
95 [_window setExitEffect:[[[vanishEffect alloc] initWithWindow:_window] autorelease]];
97 if ([[_window exitEffect] effectTime] != vanishSpeed) {
98 [[_window exitEffect] setEffectTime:vanishSpeed];
100 if ([_window exitDelay] != vanishDelay) {
101 [_window setExitDelay:vanishDelay];
104 if ([(ITTSWBackgroundView *)[_window contentView] backgroundMode] != backgroundStyle) {
105 [(ITTSWBackgroundView *)[_window contentView] setBackgroundMode:backgroundStyle];
107 if (([(ITTSWBackgroundView *)[_window contentView] backgroundMode] == ITTSWBackgroundColored) && ![[(ITTSWBackgroundView *)[_window contentView] backgroundColor] isEqual:backgroundColor]) {
108 [(ITTSWBackgroundView *)[_window contentView] setBackgroundColor:backgroundColor];
110 if ([_window sizing] != windowSize) {
111 [_window setSizing:windowSize];
115 - (void)showWindowWithTitle:(NSString *)title desc:(NSString *)desc image:(NSImage *)image {
116 NSString *text = title;
118 if (desc && ![desc isEqualToString:@""] && ![desc isEqualToString:@"\n"]) {
119 text = [text stringByAppendingFormat:@"\n%@", desc];
123 NSSize oldSize = [image size];
124 BOOL wouldUpscale = ((oldSize.width <= _imageSize) && (oldSize.height <= _imageSize));
126 if (!(wouldUpscale && _imageNoUpscale)) {
127 if (oldSize.width > oldSize.height) {
128 newSize = NSMakeSize(_imageSize, (oldSize.height * (_imageSize / oldSize.width)));
130 newSize = NSMakeSize((oldSize.width * (_imageSize / oldSize.height)), _imageSize);
133 image = [[[[NSImage alloc] initWithData:[image TIFFRepresentation]] autorelease] imageScaledSmoothlyToSize:newSize];
136 if (_wrapNotifications) {
137 text = [text stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"(\\S\\S{%i,}|.{1,%i})(?:\\s+|$)", _wrapColumns, _wrapColumns] withString:@"$1\n"];
140 //trim trailing whitespace
141 text = [text stringByReplacingOccurrencesOfRegex:@"\\s+$" withString:@""];
143 NSArray *gothicChars = [NSArray arrayWithObjects:[NSString stringWithUTF8String:"☆"], [NSString stringWithUTF8String:"★"], nil];
144 NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
146 if (([gothicChars count] > 0) && ([text length] > 0)) {
147 NSMutableString *gothicRegex = [[NSMutableString alloc] init];
149 [gothicRegex appendString:@"[\\n"];
150 for (NSString *gothicChar in gothicChars) {
151 [gothicRegex appendString:gothicChar];
153 [gothicRegex appendString:@"]+"];
155 NSUInteger endOfLastRange = 0;
157 while (endOfLastRange != NSNotFound) {
158 foundRange = [text rangeOfRegex:gothicRegex inRange:NSMakeRange(endOfLastRange, ([text length] - endOfLastRange))];
159 if (foundRange.location != NSNotFound) {
160 [attributedText setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"AppleGothic" size:(18.0 / MINI_DIVISOR)], NSFontAttributeName, nil, nil] range:foundRange];
161 endOfLastRange = foundRange.location+foundRange.length;
162 if (endOfLastRange >= [text length]) {
163 endOfLastRange = NSNotFound;
166 endOfLastRange = NSNotFound;
171 [_window setImage:image];
172 [_window buildTextWindowWithString:attributedText];
173 [_window appear:self];
174 [attributedText release];