source: trunk/macosx/TorrentCell.m @ 4132

Last change on this file since 4132 was 4132, checked in by livings124, 15 years ago

use a simpler method for determining text color of table cells on leopard

  • Property svn:keywords set to Date Rev Author Id
File size: 21.2 KB
Line 
1/******************************************************************************
2 * $Id: TorrentCell.m 4132 2007-12-12 05:01:31Z livings124 $
3 *
4 * Copyright (c) 2006-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "TorrentCell.h"
26#import "TorrentTableView.h"
27#import "NSApplicationAdditions.h"
28#import "NSStringAdditions.h"
29#import "CTGradientAdditions.h"
30
31#define BAR_HEIGHT 12.0
32
33#define IMAGE_SIZE_REG 32.0
34#define IMAGE_SIZE_MIN 16.0
35
36//end up being larger than font height
37#define HEIGHT_TITLE 16.0
38#define HEIGHT_STATUS 12.0
39
40#define PADDING_HORIZONAL 2.0
41#define PADDING_ABOVE_IMAGE_REG 9.0
42#define PADDING_BETWEEN_IMAGE_AND_TITLE 5.0
43#define PADDING_BETWEEN_IMAGE_AND_BAR 7.0
44#define PADDING_ABOVE_TITLE 3.0
45#define PADDING_ABOVE_MIN_STATUS 4.0
46#define PADDING_BETWEEN_TITLE_AND_MIN_STATUS 2.0
47#define PADDING_BETWEEN_TITLE_AND_PROGRESS 1.0
48#define PADDING_BETWEEN_PROGRESS_AND_BAR 2.0
49#define PADDING_BETWEEN_TITLE_AND_BAR_MIN 3.0
50#define PADDING_BETWEEN_BAR_AND_STATUS 2.0
51
52#define MAX_PIECES 324
53#define BLANK_PIECE -99
54
55@interface TorrentCell (Private)
56
57- (void) drawBar: (NSRect) barRect;
58- (void) drawRegularBar: (NSRect) barRect;
59- (void) drawPiecesBar: (NSRect) barRect;
60
61- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
62- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
63            inBounds: (NSRect) bounds;
64- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
65- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
66
67- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color;
68- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color;
69
70@end
71
72@implementation TorrentCell
73
74//only called one, so don't worry about release
75- (id) init
76{
77    if ((self = [super init]))
78        {
79        fDefaults = [NSUserDefaults standardUserDefaults];
80       
81        NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
82        [paragraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
83   
84        fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
85                                [NSFont messageFontOfSize: 12.0], NSFontAttributeName,
86                                paragraphStyle, NSParagraphStyleAttributeName, nil];
87        fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
88                                [NSFont messageFontOfSize: 9.0], NSFontAttributeName,
89                                paragraphStyle, NSParagraphStyleAttributeName, nil];
90        [paragraphStyle release];
91       
92        //store box colors
93        fGrayColor = [[NSColor colorWithCalibratedRed: 0.9 green: 0.9 blue: 0.9 alpha: 1.0] retain];
94        fBlue1Color = [[NSColor colorWithCalibratedRed: 0.8 green: 1.0 blue: 1.0 alpha: 1.0] retain];
95        fBlue2Color = [[NSColor colorWithCalibratedRed: 0.6 green: 1.0 blue: 1.0 alpha: 1.0] retain];
96        fBlue3Color = [[NSColor colorWithCalibratedRed: 0.6 green: 0.8 blue: 1.0 alpha: 1.0] retain];
97        fBlue4Color = [[NSColor colorWithCalibratedRed: 0.4 green: 0.6 blue: 1.0 alpha: 1.0] retain];
98        fBlueColor = [[NSColor colorWithCalibratedRed: 0.0 green: 0.4 blue: 0.8 alpha: 1.0] retain];
99       
100        fBarOverlayColor = [[NSColor colorWithDeviceWhite: 0.0 alpha: 0.2] retain];
101    }
102        return self;
103}
104
105- (id) copyWithZone: (NSZone *) zone
106{
107    TorrentCell * copy = [super copyWithZone: zone];
108   
109    copy->fBitmap = nil;
110    copy->fPieces = NULL;
111   
112    return copy;
113}
114
115- (void) dealloc
116{
117    [fBitmap release];
118    if (fPieces)
119        free(fPieces);
120   
121    [super dealloc];
122}
123
124- (NSRect) iconRectForBounds: (NSRect) bounds
125{
126    NSRect result = bounds;
127   
128    result.origin.x += PADDING_HORIZONAL;
129   
130    float imageSize;
131    if ([fDefaults boolForKey: @"SmallView"])
132    {
133        imageSize = IMAGE_SIZE_MIN;
134        result.origin.y += (result.size.height - imageSize) * 0.5;
135    }
136    else
137    {
138        imageSize = IMAGE_SIZE_REG;
139        result.origin.y += PADDING_ABOVE_IMAGE_REG;
140    }
141   
142    result.size = NSMakeSize(imageSize, imageSize);
143   
144    return result;
145}
146
147- (NSRect) titleRectForBounds: (NSRect) bounds
148{
149    return [self rectForTitleWithString: [self attributedTitleWithColor: nil]
150            basedOnMinimalStatusRect: [self minimalStatusRectForBounds: bounds] inBounds: bounds];
151}
152
153- (NSRect) minimalStatusRectForBounds: (NSRect) bounds
154{
155    Torrent * torrent = [self representedObject];
156    NSString * string = [fDefaults boolForKey: @"DisplaySmallStatusRegular"]
157                            ? [torrent shortStatusString] : [torrent remainingTimeString];
158    return [self rectForMinimalStatusWithString: [self attributedStatusString: string withColor: nil] inBounds: bounds];
159}
160
161- (NSRect) progressRectForBounds: (NSRect) bounds
162{
163    return [self rectForProgressWithString: [self attributedStatusString: [[self representedObject] progressString] withColor: nil]
164                    inBounds: bounds];
165}
166
167- (NSRect) barRectForBounds: (NSRect) bounds
168{
169    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
170   
171    NSRect result = bounds;
172    result.size.height = BAR_HEIGHT;
173    result.origin.x = PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_BAR;
174   
175    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE;
176    if (minimal)
177        result.origin.y += PADDING_BETWEEN_TITLE_AND_BAR_MIN;
178    else
179        result.origin.y += PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
180   
181    result.size.width = round(NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL - BUTTONS_TOTAL_WIDTH);
182   
183    return result;
184}
185
186- (NSRect) statusRectForBounds: (NSRect) bounds
187{
188    return [self rectForStatusWithString: [self attributedStatusString: [[self representedObject] statusString] withColor: nil]
189                    inBounds: bounds];
190}
191
192- (NSUInteger) hitTestForEvent: (NSEvent *) event inRect: (NSRect) cellFrame ofView: (NSView *) controlView
193{
194    return NSCellHitContentArea;
195}
196
197- (void) drawInteriorWithFrame: (NSRect) cellFrame inView: (NSView *) controlView
198{
199    [super drawInteriorWithFrame: cellFrame inView: controlView];
200   
201    Torrent * torrent = [self representedObject];
202   
203    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
204   
205    //error image
206    BOOL error = [torrent isError];
207    if (error && !fErrorImage)
208    {
209        fErrorImage = [[NSImage imageNamed: @"Error.png"] copy];
210        [fErrorImage setFlipped: YES];
211    }
212   
213    //icon
214    NSImage * icon = minimal && error ? fErrorImage : [torrent icon];
215    NSRect iconRect = [self iconRectForBounds: cellFrame];
216    [icon drawInRect: iconRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
217   
218    if (error && !minimal)
219    {
220        NSRect errorRect = NSMakeRect(NSMaxX(iconRect) - IMAGE_SIZE_MIN, NSMaxY(iconRect) - IMAGE_SIZE_MIN,
221                                        IMAGE_SIZE_MIN, IMAGE_SIZE_MIN);
222        [fErrorImage drawInRect: errorRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
223    }
224   
225    //text color
226    NSColor * titleColor, * statusColor;
227    if ([NSApp isOnLeopardOrBetter] ? [self backgroundStyle] == NSBackgroundStyleDark : [self isHighlighted]
228        && [[self highlightColorWithFrame: cellFrame inView: controlView] isEqual: [NSColor alternateSelectedControlColor]])
229    {
230        titleColor = [NSColor whiteColor];
231        statusColor = [NSColor whiteColor];
232    }
233    else
234    {
235        titleColor = [NSColor controlTextColor];
236        statusColor = [NSColor darkGrayColor];
237    }
238   
239    //minimal status
240    NSRect minimalStatusRect;
241    if (minimal)
242    {
243        NSString * string = [fDefaults boolForKey: @"DisplaySmallStatusRegular"]
244                            ? [torrent shortStatusString] : [torrent remainingTimeString];
245        NSAttributedString * minimalString = [self attributedStatusString: string withColor: statusColor];
246        minimalStatusRect = [self rectForMinimalStatusWithString: minimalString inBounds: cellFrame];
247       
248        [minimalString drawInRect: minimalStatusRect];
249    }
250   
251    //title
252    NSAttributedString * titleString = [self attributedTitleWithColor: titleColor];
253    NSRect titleRect = [self rectForTitleWithString: titleString basedOnMinimalStatusRect: minimalStatusRect inBounds: cellFrame];
254    [titleString drawInRect: titleRect];
255   
256    //progress
257    if (!minimal)
258    {
259        NSAttributedString * progressString = [self attributedStatusString: [torrent progressString] withColor: statusColor];
260        NSRect progressRect = [self rectForProgressWithString: progressString inBounds: cellFrame];
261        [progressString drawInRect: progressRect];
262    }
263   
264    //bar
265    [self drawBar: [self barRectForBounds: cellFrame]];
266   
267    //status
268    if (!minimal)
269    {
270        NSAttributedString * statusString = [self attributedStatusString: [torrent statusString] withColor: statusColor];
271        [statusString drawInRect: [self rectForStatusWithString: statusString inBounds: cellFrame]];
272    }
273}
274
275@end
276
277@implementation TorrentCell (Private)
278
279- (void) drawBar: (NSRect) barRect
280{
281    if ([fDefaults boolForKey: @"PiecesBar"])
282    {
283        NSRect regularBarRect = barRect, piecesBarRect = barRect;
284        regularBarRect.size.height /= 2.5;
285        piecesBarRect.origin.y += regularBarRect.size.height;
286        piecesBarRect.size.height -= regularBarRect.size.height;
287       
288        [self drawRegularBar: regularBarRect];
289        [self drawPiecesBar: piecesBarRect];
290    }
291    else
292    {
293        if (fPieces)
294        {
295            free(fPieces);
296            fPieces = NULL;
297            [fBitmap release];
298            fBitmap = nil;
299        }
300       
301        [self drawRegularBar: barRect];
302    }
303   
304    [fBarOverlayColor set];
305    [NSBezierPath strokeRect: NSInsetRect(barRect, 0.5, 0.5)];
306}
307
308- (void) drawRegularBar: (NSRect) barRect
309{
310    Torrent * torrent = [self representedObject];
311   
312    int leftWidth = barRect.size.width;
313    float progress = [torrent progress];
314   
315    if (progress < 1.0)
316    {
317        float rightProgress = 1.0 - progress, progressLeft = [torrent progressLeft];
318        int rightWidth = leftWidth * rightProgress;
319        leftWidth -= rightWidth;
320       
321        if (progressLeft < rightProgress)
322        {
323            int rightNoIncludeWidth = rightWidth * ((rightProgress - progressLeft) / rightProgress);
324            rightWidth -= rightNoIncludeWidth;
325           
326            NSRect noIncludeRect = barRect;
327            noIncludeRect.origin.x += barRect.size.width - rightNoIncludeWidth;
328            noIncludeRect.size.width = rightNoIncludeWidth;
329           
330            if (!fLightGrayGradient)
331                fLightGrayGradient = [[CTGradient progressLightGrayGradient] retain];
332            [fLightGrayGradient fillRect: noIncludeRect angle: -90];
333        }
334       
335        if (rightWidth > 0)
336        {
337            if ([torrent isActive] && ![torrent allDownloaded] && [fDefaults boolForKey: @"DisplayProgressBarAvailable"])
338            {
339                int notAvailableWidth = MIN(barRect.size.width * [torrent notAvailableDesired], rightWidth);
340                rightWidth -= notAvailableWidth;
341               
342                if (notAvailableWidth > 0)
343                {
344                    NSRect notAvailableRect = barRect;
345                    notAvailableRect.origin.x += leftWidth + rightWidth;
346                    notAvailableRect.size.width = notAvailableWidth;
347                   
348                    if (!fRedGradient)
349                        fRedGradient = [[CTGradient progressRedGradient] retain];
350                    [fRedGradient fillRect: notAvailableRect angle: -90];
351                }
352            }
353           
354            if (rightWidth > 0)
355            {
356                NSRect includeRect = barRect;
357                includeRect.origin.x += leftWidth;
358                includeRect.size.width = rightWidth;
359               
360                if (!fWhiteGradient)
361                    fWhiteGradient = [[CTGradient progressWhiteGradient] retain];
362                [fWhiteGradient fillRect: includeRect angle: -90];
363            }
364        }
365    }
366   
367    if (leftWidth > 0)
368    {
369        NSRect completeRect = barRect;
370        completeRect.size.width = leftWidth;
371       
372        if ([torrent isActive])
373        {
374            if ([torrent isChecking])
375            {
376                if (!fYellowGradient)
377                    fYellowGradient = [[CTGradient progressYellowGradient] retain];
378                [fYellowGradient fillRect: completeRect angle: -90];
379            }
380            else if ([torrent isSeeding])
381            {
382                int ratioLeftWidth = leftWidth * (1.0 - [torrent progressStopRatio]);
383                leftWidth -= ratioLeftWidth;
384               
385                if (ratioLeftWidth > 0)
386                {
387                    NSRect ratioLeftRect = barRect;
388                    ratioLeftRect.origin.x += leftWidth;
389                    ratioLeftRect.size.width = ratioLeftWidth;
390                   
391                    if (!fLightGreenGradient)
392                        fLightGreenGradient = [[CTGradient progressLightGreenGradient] retain];
393                    [fLightGreenGradient fillRect: ratioLeftRect angle: -90];
394                }
395               
396                if (leftWidth > 0)
397                {
398                    completeRect.size.width = leftWidth;
399                   
400                    if (!fGreenGradient)
401                        fGreenGradient = [[CTGradient progressGreenGradient] retain];
402                    [fGreenGradient fillRect: completeRect angle: -90];
403                }
404            }
405            else
406            {
407                if (!fBlueGradient)
408                    fBlueGradient = [[CTGradient progressBlueGradient] retain];
409                [fBlueGradient fillRect: completeRect angle: -90];
410            }
411        }
412        else
413        {
414            if ([torrent waitingToStart])
415            {
416                if ([torrent progressLeft] <= 0.0)
417                {
418                    if (!fDarkGreenGradient)
419                        fDarkGreenGradient = [[CTGradient progressDarkGreenGradient] retain];
420                    [fDarkGreenGradient fillRect: completeRect angle: -90];
421                }
422                else
423                {
424                    if (!fDarkBlueGradient)
425                        fDarkBlueGradient = [[CTGradient progressDarkBlueGradient] retain];
426                    [fDarkBlueGradient fillRect: completeRect angle: -90];
427                }
428            }
429            else
430            {
431                if (!fGrayGradient)
432                    fGrayGradient = [[CTGradient progressGrayGradient] retain];
433                [fGrayGradient fillRect: completeRect angle: -90];
434            }
435        }
436    }
437}
438
439- (void) drawPiecesBar: (NSRect) barRect
440{
441    if (!fBitmap)
442        fBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
443            pixelsWide: MAX_PIECES pixelsHigh: barRect.size.height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
444            isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
445   
446    if (!fPieces)
447    {
448        fPieces = malloc(MAX_PIECES);
449        int i;
450        for (i = 0; i < MAX_PIECES; i++)
451            fPieces[i] = BLANK_PIECE;
452    }
453   
454    #warning add flashing orange
455   
456    Torrent * torrent = [self representedObject];
457   
458    int pieceCount = MIN([torrent pieceCount], MAX_PIECES);
459    float * piecePercent = malloc(pieceCount * sizeof(float));
460    [torrent getAmountFinished: piecePercent size: pieceCount];
461   
462    int i, h, index;
463    float increment = (float)pieceCount / MAX_PIECES;
464    NSColor * pieceColor;
465    for (i = 0; i < MAX_PIECES; i++)
466    {
467        index = i * increment;
468        pieceColor = nil;
469       
470        if (piecePercent[index] >= 1.0)
471        {
472            if (fPieces[i] != -1)
473            {
474                pieceColor = fBlueColor;
475                fPieces[i] = -1;
476            }
477        }
478        else if (piecePercent[index] <= 0.0)
479        {
480            if (fPieces[i] != 0)
481            {
482                pieceColor = fGrayColor;
483                fPieces[i] = 0;
484            }
485        }
486        else if (piecePercent[index] <= 0.25)
487        {
488            if (fPieces[i] != 1)
489            {
490                pieceColor = fBlue1Color;
491                fPieces[i] = 1;
492            }
493        }
494        else if (piecePercent[index] <= 0.5)
495        {
496            if (fPieces[i] != 2)
497            {
498                pieceColor = fBlue2Color;
499                fPieces[i] = 2;
500            }
501        }
502        else if (piecePercent[index] <= 0.75)
503        {
504            if (fPieces[i] != 3)
505            {
506                pieceColor = fBlue3Color;
507                fPieces[i] = 3;
508            }
509        }
510        else
511        {
512            if (fPieces[i] != 4)
513            {
514                pieceColor = fBlue4Color;
515                fPieces[i] = 4;
516            }
517        }
518       
519        if (pieceColor)
520            for (h = 0; h < barRect.size.height; h++)
521                [fBitmap setColor: pieceColor atX: i y: h];
522    }
523   
524    free(piecePercent);
525   
526    //actually draw image
527    [fBitmap drawInRect: barRect];
528   
529    if (!fTransparentGradient)
530        fTransparentGradient = [[CTGradient progressTransparentGradient] retain];
531    [fTransparentGradient fillRect: barRect angle: -90];
532}
533
534- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
535{
536    if (![fDefaults boolForKey: @"SmallView"])
537        return NSZeroRect;
538   
539    NSRect result = bounds;
540    result.size = [string size];
541   
542    result.origin.x += bounds.size.width - result.size.width - PADDING_HORIZONAL;
543    result.origin.y += PADDING_ABOVE_MIN_STATUS;
544   
545    return result;
546}
547
548- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
549            inBounds: (NSRect) bounds
550{
551    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
552   
553    NSRect result = bounds;
554    result.origin.y += PADDING_ABOVE_TITLE;
555    result.origin.x += PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_TITLE;
556   
557    result.size = [string size];
558    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL
559                            - (minimal ? PADDING_BETWEEN_TITLE_AND_MIN_STATUS + statusRect.size.width : 0));
560   
561    return result;
562}
563
564- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
565{
566    if ([fDefaults boolForKey: @"SmallView"])
567        return NSZeroRect;
568   
569    NSRect result = bounds;
570    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS;
571    result.origin.x += PADDING_HORIZONAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
572   
573    result.size = [string size];
574    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL);
575   
576    return result;
577}
578
579- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
580{
581    if ([fDefaults boolForKey: @"SmallView"])
582        return NSZeroRect;
583   
584    NSRect result = bounds;
585    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS
586                        + PADDING_BETWEEN_PROGRESS_AND_BAR + BAR_HEIGHT + PADDING_BETWEEN_BAR_AND_STATUS;
587    result.origin.x += PADDING_HORIZONAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
588   
589    result.size = [string size];
590    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL);
591   
592    return result;
593}
594
595- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color
596{
597    if (color)
598        [fTitleAttributes setObject: color forKey: NSForegroundColorAttributeName];
599   
600    NSString * title = [[self representedObject] name];
601    return [[[NSAttributedString alloc] initWithString: title attributes: fTitleAttributes] autorelease];
602}
603
604- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color
605{
606    if (color)
607        [fStatusAttributes setObject: color forKey: NSForegroundColorAttributeName];
608   
609    return [[[NSAttributedString alloc] initWithString: string attributes: fStatusAttributes] autorelease];
610}
611
612@end
Note: See TracBrowser for help on using the repository browser.