Renamed the product from GrowlITTSW to ITTSW. Added image size customization options...
[GrowlITTSW.git] / GrowlITTSWController.m
1 //
2 //  GrowlITTSWController.m
3 //  Growl
4 //
5 //  Created by Joseph Spiros on 2/28/09.
6 //  Copyright 2009 iThink Software. All rights reserved.
7 //
8
9 #import "GrowlITTSWController.h"
10 #import "GrowlITTSWPrefs.h"
11
12 #import <ITKit/ITWindowEffect.h>
13 #import <ITKit/ITTSWBackgroundView.h>
14
15 #import "RegexKitLite.h"
16
17 @implementation NSImage (SmoothAdditions)
18
19 - (NSImage *)imageScaledSmoothlyToSize:(NSSize)scaledSize {
20     NSImage *newImage;
21     NSImageRep *rep = [self bestRepresentationForDevice:nil];
22     
23     newImage = [[NSImage alloc] initWithSize:scaledSize];
24     [newImage lockFocus];
25     {
26         [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
27         [[NSGraphicsContext currentContext] setShouldAntialias:YES];
28         [rep drawInRect:NSMakeRect(3, 3, scaledSize.width - 6, scaledSize.height - 6)];
29     }
30     [newImage unlockFocus];
31     return [newImage autorelease];
32 }
33
34 @end
35
36 @interface GrowlITTSWController (Private)
37 - (void)syncWithPrefs;
38 @end
39
40 @implementation GrowlITTSWController
41
42 - (id)init {
43     if ( ( self = [super init] ) ) {
44                 _window = [[GrowlITTSWWindow sharedWindow] retain];
45                 [_window setExitMode:ITTransientStatusWindowExitAfterDelay];
46                 [self syncWithPrefs];
47                 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(syncWithPrefs) name:@"GrowlPreferencesChanged" object:nil];
48     }
49     
50     return self;
51 }
52
53 - (void)dealloc {
54     [_window release];
55     [super dealloc];
56 }
57
58 - (void)syncWithPrefs {
59         _imageSize = [GrowlITTSWPrefs imageSize];
60         _imageNoUpscale = [GrowlITTSWPrefs imageNoUpscale];
61         _wrapNotifications = [GrowlITTSWPrefs wrapNotifications];
62         _wrapColumns = [GrowlITTSWPrefs wrapColumns];
63         
64         NSScreen *screen = [GrowlITTSWPrefs screen];
65         ITHorizontalWindowPosition horizontalPosition = [GrowlITTSWPrefs horizontalPosition];
66         ITVerticalWindowPosition verticalPosition = [GrowlITTSWPrefs verticalPosition];
67         
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];
73         
74         ITTSWBackgroundMode backgroundStyle = [GrowlITTSWPrefs backgroundStyle];
75         NSColor *backgroundColor = [GrowlITTSWPrefs backgroundColor];
76         ITTransientStatusWindowSizing windowSize = [GrowlITTSWPrefs windowSize];
77         
78         if ([_window screen] != screen) {
79                 [_window setScreen:screen];
80         }
81         if ([_window horizontalPosition] != horizontalPosition) {
82                 [_window setHorizontalPosition:horizontalPosition];
83         }
84         if ([_window verticalPosition] != verticalPosition) {
85                 [_window setVerticalPosition:verticalPosition];
86         }
87         
88         if (![[_window entryEffect] isKindOfClass:appearanceEffect]) {
89                 [_window setEntryEffect:[[[appearanceEffect alloc] initWithWindow:_window] autorelease]];
90         }
91         if ([[_window entryEffect] effectTime] != appearanceSpeed) {
92                 [[_window entryEffect] setEffectTime:appearanceSpeed];
93         }
94         if (![[_window exitEffect] isKindOfClass:vanishEffect]) {
95                 [_window setExitEffect:[[[vanishEffect alloc] initWithWindow:_window] autorelease]];
96         }
97         if ([[_window exitEffect] effectTime] != vanishSpeed) {
98                 [[_window exitEffect]  setEffectTime:vanishSpeed];
99         }
100         if ([_window exitDelay] != vanishDelay) {
101                 [_window setExitDelay:vanishDelay];
102         }
103         
104         if ([(ITTSWBackgroundView *)[_window contentView] backgroundMode] != backgroundStyle) {
105                 [(ITTSWBackgroundView *)[_window contentView] setBackgroundMode:backgroundStyle];
106         }
107         if (([(ITTSWBackgroundView *)[_window contentView] backgroundMode] == ITTSWBackgroundColored) && ![[(ITTSWBackgroundView *)[_window contentView] backgroundColor] isEqual:backgroundColor]) {
108                 [(ITTSWBackgroundView *)[_window contentView] setBackgroundColor:backgroundColor];
109         }
110         if ([_window sizing] != windowSize) {
111                 [_window setSizing:windowSize];
112         }
113 }
114
115 - (void)showWindowWithTitle:(NSString *)title text:(NSString *)text image:(NSImage *)image {
116         if (text && ![text isEqualToString:@""] && ![text isEqualToString:@"\n"]) {
117                 text = [title stringByAppendingFormat:@"\n%@", text];
118         }
119         
120         NSSize newSize;
121         NSSize oldSize = [image size];
122         BOOL wouldUpscale = ((oldSize.width <= _imageSize) && (oldSize.height <= _imageSize));
123         
124         if (!(wouldUpscale && _imageNoUpscale)) {
125                 if (oldSize.width > oldSize.height) {
126                         newSize = NSMakeSize(_imageSize, (oldSize.height * (_imageSize / oldSize.width)));
127                 } else {
128                         newSize = NSMakeSize((oldSize.width * (_imageSize / oldSize.height)), _imageSize);
129                 }
130                 
131                 image = [[[[NSImage alloc] initWithData:[image TIFFRepresentation]] autorelease] imageScaledSmoothlyToSize:newSize];
132         }
133         
134         if (_wrapNotifications) {
135                 text = [text stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"(.{1,%i})(?: +|$)\\n?|(.{%i})", _wrapColumns, _wrapColumns] withString:@"$1$2\n"];
136         }
137         
138         //trim trailing whitespace
139         text = [text stringByReplacingOccurrencesOfRegex:@"[\\s\\r\\n]+$" withString:@""];
140         
141         NSArray *gothicChars = [NSArray arrayWithObjects:[NSString stringWithUTF8String:"☆"], [NSString stringWithUTF8String:"★"], nil];
142         NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
143         
144         if (([gothicChars count] > 0) && ([text length] > 0)) {
145                 NSMutableString *gothicRegex = [[NSMutableString alloc] init];
146                 
147                 [gothicRegex appendString:@"[\\n"];
148                 for (NSString *gothicChar in gothicChars) {
149                         [gothicRegex appendString:gothicChar];
150                 }
151                 [gothicRegex appendString:@"]+"];
152                 
153                 NSUInteger endOfLastRange = 0;
154                 NSRange foundRange;
155                 while (endOfLastRange != NSNotFound) {
156                         foundRange = [text rangeOfRegex:gothicRegex inRange:NSMakeRange(endOfLastRange, ([text length] - endOfLastRange))];
157                         if (foundRange.location != NSNotFound) {
158                                 [attributedText setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"AppleGothic" size:(18.0 / MINI_DIVISOR)], NSFontAttributeName, nil, nil] range:foundRange];
159                                 endOfLastRange = foundRange.location+foundRange.length;
160                                 if (endOfLastRange >= [text length]) {
161                                         endOfLastRange = NSNotFound;
162                                 }
163                         } else {
164                                 endOfLastRange = NSNotFound;
165                         }
166                 }
167         }
168         
169         [_window setImage:image];
170     [_window buildTextWindowWithString:attributedText];
171     [_window appear:self];
172         [attributedText release];
173 }
174
175 @end