Removing the use of private CoreGraphics APIs to draw shadows, and replacing with...
[ITKit.git] / ITIconAndTextStatusWindow.m
1 /*
2  *      ITKit
3  *  ITIconAndTextStatusWindow
4  *    ITTransientStatusWindow subclass to show an icon and text.
5  *
6  *  Original Author : Kent Sutherland <ksutherland@ithinksw.com>
7  *   Responsibility : Kent Sutherland <mjudy@ithinksw.com>
8  *   Responsibility : Joseph Spiros <joseph.spiros@ithinksw.com>
9  *
10  *  Copyright (c) 2002 - 2004 iThink Software.
11  *  All Rights Reserved
12  *
13  */
14
15 #import "ITIconAndTextStatusWindow.h"
16 #import "ITWindowPositioning.h"
17 #import "ITWindowEffect.h"
18 #import "ITImageView.h"
19 #import "ITTextField.h"
20
21 #define SW_PAD             24.00
22 #define SW_SPACE           24.00
23 #define SW_MINW           211.00
24 #define SW_BORDER          32.00
25 #define SW_METER_PAD        4.00
26 #define SW_BUTTON_PAD_R    30.00
27 #define SW_BUTTON_PAD_B    24.00
28 #define SW_BUTTON_DIV      12.00
29 #define SW_BUTTON_EXTRA_W   8.00
30 #define SW_SHADOW_SAT       1.25
31 #define SMALL_DIVISOR       1.33333
32 #define MINI_DIVISOR        1.66667
33
34 @implementation ITIconAndTextStatusWindow
35
36 /*************************************************************************/
37 #pragma mark -
38 #pragma mark INITIALIZATION / DEALLOCATION METHODS
39 /*************************************************************************/
40
41 - (id)initWithContentView:(NSView *)contentView
42       exitMode:(ITTransientStatusWindowExitMode)exitMode
43       backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType
44 {
45     if ( ( self = [super initWithContentView:contentView exitMode:exitMode backgroundType:backgroundType] ) ) {
46         //Defaults
47         _image  = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
48         [self setSizing:ITTransientStatusWindowRegular];
49     }
50     return self;
51 }
52
53 - (void)dealloc
54 {
55     [_image release];
56     [super dealloc];
57 }
58
59 - (void)setImage:(NSImage *)newImage
60 {
61     [_image autorelease];
62     _image = [newImage copy];
63 }
64
65 /*************************************************************************/
66 #pragma mark -
67 #pragma mark INSTANCE METHODS
68 /*************************************************************************/
69
70 - (NSRect)setupWindowWithDataSize:(NSSize)dataSize
71 {
72     float        divisor       = 1.0;
73     NSRect       imageRect;
74     float        imageWidth    = 0.0;
75     float        imageHeight   = 0.0;
76     float        dataWidth     = dataSize.width;
77     float        dataHeight    = dataSize.height;
78     float        contentHeight = 0.0;
79     float        windowWidth   = 0.0;
80     float        windowHeight  = 0.0;
81     NSRect       visibleFrame  = [[self screen] visibleFrame];
82     NSPoint      screenOrigin  = visibleFrame.origin;
83     float        screenWidth   = visibleFrame.size.width;
84     float        screenHeight  = visibleFrame.size.height;
85     float        maxWidth      = ( screenWidth  - (SW_BORDER * 2) );
86     float        maxHeight     = ( screenHeight - (SW_BORDER * 2) );
87     float        excessWidth   = 0.0;
88     float        excessHeight  = 0.0;
89     NSPoint      windowOrigin = NSZeroPoint;
90     ITImageView *imageView;
91     BOOL         shouldAnimate = ( ! (([self visibilityState] == ITWindowAppearingState) ||
92                                       ([self visibilityState] == ITWindowVanishingState)) );
93         
94     if ( [self sizing] == ITTransientStatusWindowSmall ) {
95         divisor = SMALL_DIVISOR;
96     } else if ( [self sizing] == ITTransientStatusWindowMini ) {
97         divisor = MINI_DIVISOR;
98     }
99
100 //  Get image width and height.
101     imageWidth  = ( [_image size].width  / divisor );
102     imageHeight = ( [_image size].height / divisor );
103     
104 //  Set the content height to the greater of the text and image heights.
105     contentHeight = ( ( imageHeight > dataHeight ) ? imageHeight : dataHeight );
106
107 //  Setup the Window, and remove all its contentview's subviews.
108     windowWidth  = ( (SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor) + dataWidth + (SW_PAD / divisor) );
109     windowHeight = ( (SW_PAD / divisor) + contentHeight + (SW_PAD / divisor) );
110     
111 //  Constrain size to max limits.  Adjust data sizes accordingly.
112     excessWidth  = (windowWidth  - maxWidth );
113     excessHeight = (windowHeight - maxHeight);
114
115     if ( excessWidth > 0.0 ) {
116         windowWidth = maxWidth;
117         dataWidth -= excessWidth;
118     }
119     
120     if ( excessHeight > 0.0 ) {
121         windowHeight = maxHeight;
122         dataHeight -= excessHeight;
123     }
124     
125     if ( [self horizontalPosition] == ITWindowPositionLeft ) {
126         windowOrigin.x = ( SW_BORDER + screenOrigin.x );
127     } else if ( [self horizontalPosition] == ITWindowPositionCenter ) {
128         windowOrigin.x = ( screenOrigin.x + (screenWidth / 2) - (windowWidth / 2) );
129     } else if ( [self horizontalPosition] == ITWindowPositionRight ) {
130         windowOrigin.x = ( screenOrigin.x + screenWidth - (windowWidth + SW_BORDER) );
131     }
132     
133     if ( [self verticalPosition] == ITWindowPositionTop ) {
134         windowOrigin.y = ( screenOrigin.y + screenHeight - (windowHeight + SW_BORDER) );
135     } else if ( [self verticalPosition] == ITWindowPositionMiddle ) {
136 //      Middle-oriented windows should be slightly proud of the screen's middle.
137         windowOrigin.y = ( (screenOrigin.y + (screenHeight / 2) - (windowHeight / 2)) + (screenHeight / 8) );
138     } else if ( [self verticalPosition] == ITWindowPositionBottom ) {
139         windowOrigin.y = ( SW_BORDER + screenOrigin.y );
140     }
141     
142     [self setFrame:NSMakeRect( windowOrigin.x,
143                                windowOrigin.y,
144                                windowWidth,
145                                windowHeight) display:YES animate:shouldAnimate];
146
147     [[[self contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
148     
149 //  Setup, position, fill, and add the image view to the content view.
150     imageRect = NSMakeRect( (SW_PAD / divisor),
151                             ((SW_PAD / divisor) + ((contentHeight - imageHeight) / 2)),
152                             imageWidth,
153                             imageHeight );
154     imageView = [[[ITImageView alloc] initWithFrame:imageRect] autorelease];
155     [imageView setAutoresizingMask:(NSViewMinYMargin | NSViewMaxYMargin)];
156     [imageView setImage:_image];
157     [imageView setCastsShadow:YES];
158     [[self contentView] addSubview:imageView];
159
160     return NSMakeRect( ((SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor)),
161                        ((SW_PAD / divisor) + ((contentHeight - dataHeight) / 2)),
162                        dataWidth,
163                        dataHeight);
164 }
165
166 - (void)buildTextWindowWithString:(NSString *)text
167 {
168     float         divisor       = 1.0;
169     float         dataWidth     = 0.0;
170     float         dataHeight    = 0.0;
171     NSRect        dataRect;
172     NSArray      *lines         = [text componentsSeparatedByString:@"\n"];
173     id            oneLine       = nil;
174     NSEnumerator *lineEnum      = [lines objectEnumerator];
175     float         baseFontSize  = 18.0;
176     ITTextField  *textField;
177     NSFont       *font;
178     NSDictionary *attr;
179
180     if ( [self sizing] == ITTransientStatusWindowSmall ) {
181         divisor = SMALL_DIVISOR;
182     } else if ( [self sizing] == ITTransientStatusWindowMini ) {
183         divisor = MINI_DIVISOR;
184     }
185
186     font = [NSFont fontWithName:@"LucidaGrande-Bold" size:(baseFontSize / divisor)];
187     attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
188     
189 //      Iterate over each line to get text width and height
190     while ( (oneLine = [lineEnum nextObject]) ) {
191 //          Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
192         float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
193 //          Add the height of this line to the total text height
194         dataHeight += [oneLine sizeWithAttributes:attr].height;
195 //          If this line wider than the last one, set it as the text width.
196         dataWidth = ( ( dataWidth > oneLineWidth ) ? dataWidth : oneLineWidth );
197     }
198     
199 //      Add 4.0 to the final dataHeight to accomodate the shadow.
200     dataHeight += 4.0;
201
202     dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
203     
204 //      Create, position, setup, fill, and add the text view to the content view.
205     textField = [[[ITTextField alloc] initWithFrame:dataRect] autorelease];
206     [textField setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)];
207     [textField setEditable:NO];
208     [textField setSelectable:NO];
209     [textField setBordered:NO];
210     [textField setDrawsBackground:NO];
211     [textField setFont:font];
212     [textField setTextColor:[NSColor whiteColor]];
213     [textField setCastsShadow:YES];
214     [[textField cell] setWraps:NO];
215     [textField setStringValue:text];
216     [textField setShadowSaturation:SW_SHADOW_SAT];
217     [[self contentView] addSubview:textField];
218     
219 //      Display the window.
220     [[self contentView] setNeedsDisplay:YES];
221 }
222
223 @end