source: trunk/macosx/TorrentCell.m @ 3664

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

get reordering of torrent queue working again in trunk (thanks to cocoadev mailing list)

  • Property svn:keywords set to Date Rev Author Id
File size: 17.0 KB
Line 
1/******************************************************************************
2 * $Id: TorrentCell.m 3664 2007-10-31 17:23:56Z 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 "NSStringAdditions.h"
28#import "CTGradientAdditions.h"
29
30#define BAR_HEIGHT 12.0
31
32#define IMAGE_SIZE_REG 32.0
33#define IMAGE_SIZE_MIN 16.0
34
35//end up being larger than font height
36#define HEIGHT_TITLE 16.0
37#define HEIGHT_STATUS 12.0
38
39#define PADDING_HORIZONAL 2.0
40#define PADDING_ABOVE_IMAGE_REG 9.0
41#define PADDING_BETWEEN_IMAGE_AND_TITLE 5.0
42#define PADDING_BETWEEN_IMAGE_AND_BAR 7.0
43#define PADDING_ABOVE_TITLE 3.0
44#define PADDING_ABOVE_MIN_STATUS 4.0
45#define PADDING_BETWEEN_TITLE_AND_MIN_STATUS 2.0
46#define PADDING_BETWEEN_TITLE_AND_PROGRESS 1.0
47#define PADDING_BETWEEN_PROGRESS_AND_BAR 2.0
48#define PADDING_BETWEEN_TITLE_AND_BAR_MIN 3.0
49#define PADDING_BETWEEN_BAR_AND_STATUS 2.0
50
51@interface TorrentCell (Private)
52
53- (void) drawBar: (NSRect) barRect;
54
55- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
56- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
57            inBounds: (NSRect) bounds;
58- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
59- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
60
61- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color;
62- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color;
63
64@end
65
66@implementation TorrentCell
67
68//only called one, so don't worry about release
69- (id) init
70{
71    if ((self = [super init]))
72        {
73        fDefaults = [NSUserDefaults standardUserDefaults];
74       
75        NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
76        [paragraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
77   
78        fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
79                                [NSFont messageFontOfSize: 12.0], NSFontAttributeName,
80                                paragraphStyle, NSParagraphStyleAttributeName, nil];
81        fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
82                                [NSFont messageFontOfSize: 9.0], NSFontAttributeName,
83                                paragraphStyle, NSParagraphStyleAttributeName, nil];
84        [paragraphStyle release];
85       
86        fBarOverlayColor = [[NSColor colorWithDeviceWhite: 0.0 alpha: 0.2] retain];
87    }
88        return self;
89}
90
91- (NSRect) iconRectForBounds: (NSRect) bounds
92{
93    NSRect result = bounds;
94   
95    result.origin.x += PADDING_HORIZONAL;
96   
97    float imageSize;
98    if ([fDefaults boolForKey: @"SmallView"])
99    {
100        imageSize = IMAGE_SIZE_MIN;
101        result.origin.y += (result.size.height - imageSize) * 0.5;
102    }
103    else
104    {
105        imageSize = IMAGE_SIZE_REG;
106        result.origin.y += PADDING_ABOVE_IMAGE_REG;
107    }
108   
109    result.size = NSMakeSize(imageSize, imageSize);
110   
111    return result;
112}
113
114- (NSRect) titleRectForBounds: (NSRect) bounds
115{
116    return [self rectForTitleWithString: [self attributedTitleWithColor: nil]
117            basedOnMinimalStatusRect: [self minimalStatusRectForBounds: bounds] inBounds: bounds];
118}
119
120- (NSRect) minimalStatusRectForBounds: (NSRect) bounds
121{
122    Torrent * torrent = [self representedObject];
123    NSString * string = [fDefaults boolForKey: @"DisplaySmallStatusRegular"]
124                            ? [torrent shortStatusString] : [torrent remainingTimeString];
125    return [self rectForMinimalStatusWithString: [self attributedStatusString: string withColor: nil] inBounds: bounds];
126}
127
128- (NSRect) progressRectForBounds: (NSRect) bounds
129{
130    return [self rectForProgressWithString: [self attributedStatusString: [[self representedObject] progressString] withColor: nil]
131                    inBounds: bounds];
132}
133
134- (NSRect) barRectForBounds: (NSRect) bounds
135{
136    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
137   
138    NSRect result = bounds;
139    result.size.height = BAR_HEIGHT;
140    result.origin.x = PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_BAR;
141   
142    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE;
143    if (minimal)
144        result.origin.y += PADDING_BETWEEN_TITLE_AND_BAR_MIN;
145    else
146        result.origin.y += PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
147   
148    result.size.width = round(NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL - BUTTONS_TOTAL_WIDTH);
149   
150    return result;
151}
152
153- (NSRect) statusRectForBounds: (NSRect) bounds
154{
155    return [self rectForStatusWithString: [self attributedStatusString: [[self representedObject] statusString] withColor: nil]
156                    inBounds: bounds];
157}
158
159- (NSUInteger) hitTestForEvent: (NSEvent *) event inRect: (NSRect) cellFrame ofView: (NSView *) controlView
160{
161    return NSCellHitContentArea;
162}
163
164- (void) drawInteriorWithFrame: (NSRect) cellFrame inView: (NSView *) controlView
165{
166    [super drawInteriorWithFrame: cellFrame inView: controlView];
167   
168    Torrent * torrent = [self representedObject];
169   
170    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
171   
172    //error image
173    BOOL error = [torrent isError];
174    if (error && !fErrorImage)
175    {
176        fErrorImage = [[NSImage imageNamed: @"Error.png"] copy];
177        [fErrorImage setFlipped: YES];
178    }
179   
180    //icon
181    NSImage * icon = minimal && error ? fErrorImage : [torrent icon];
182    NSRect iconRect = [self iconRectForBounds: cellFrame];
183    [icon drawInRect: iconRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
184   
185    if (error && !minimal)
186    {
187        NSRect errorRect = NSMakeRect(NSMaxX(iconRect) - IMAGE_SIZE_MIN, NSMaxY(iconRect) - IMAGE_SIZE_MIN,
188                                        IMAGE_SIZE_MIN, IMAGE_SIZE_MIN);
189        [fErrorImage drawInRect: errorRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
190    }
191   
192    //text color
193    NSColor * titleColor, * statusColor;
194    if ([self isHighlighted]
195            && [[self highlightColorWithFrame: cellFrame inView: controlView] isEqual: [NSColor alternateSelectedControlColor]])
196    {
197        titleColor = [NSColor whiteColor];
198        statusColor = [NSColor whiteColor];
199    }
200    else
201    {
202        titleColor = [NSColor controlTextColor];
203        statusColor = [NSColor darkGrayColor];
204    }
205   
206    //minimal status
207    NSRect minimalStatusRect;
208    if (minimal)
209    {
210        NSString * string = [fDefaults boolForKey: @"DisplaySmallStatusRegular"]
211                            ? [torrent shortStatusString] : [torrent remainingTimeString];
212        NSAttributedString * minimalString = [self attributedStatusString: string withColor: statusColor];
213        minimalStatusRect = [self rectForMinimalStatusWithString: minimalString inBounds: cellFrame];
214       
215        [minimalString drawInRect: minimalStatusRect];
216    }
217   
218    //title
219    NSAttributedString * titleString = [self attributedTitleWithColor: titleColor];
220    NSRect titleRect = [self rectForTitleWithString: titleString basedOnMinimalStatusRect: minimalStatusRect inBounds: cellFrame];
221    [titleString drawInRect: titleRect];
222   
223    //progress
224    if (!minimal)
225    {
226        NSAttributedString * progressString = [self attributedStatusString: [torrent progressString] withColor: statusColor];
227        NSRect progressRect = [self rectForProgressWithString: progressString inBounds: cellFrame];
228        [progressString drawInRect: progressRect];
229    }
230   
231    //bar
232    NSRect barRect = [self barRectForBounds: cellFrame];
233    [self drawBar: barRect];
234   
235    //status
236    if (!minimal)
237    {
238        NSAttributedString * statusString = [self attributedStatusString: [torrent statusString] withColor: statusColor];
239        [statusString drawInRect: [self rectForStatusWithString: statusString inBounds: cellFrame]];
240    }
241}
242
243@end
244
245@implementation TorrentCell (Private)
246
247- (void) drawBar: (NSRect) barRect
248{
249    Torrent * torrent = [self representedObject];
250   
251    int leftWidth = barRect.size.width;
252    float progress = [torrent progress];
253   
254    if (progress < 1.0)
255    {
256        float rightProgress = 1.0 - progress, progressLeft = [torrent progressLeft];
257        int rightWidth = leftWidth * rightProgress;
258        leftWidth -= rightWidth;
259       
260        if (progressLeft < rightProgress)
261        {
262            int rightNoIncludeWidth = rightWidth * ((rightProgress - progressLeft) / rightProgress);
263            rightWidth -= rightNoIncludeWidth;
264           
265            NSRect noIncludeRect = barRect;
266            noIncludeRect.origin.x += barRect.size.width - rightNoIncludeWidth;
267            noIncludeRect.size.width = rightNoIncludeWidth;
268           
269            if (!fLightGrayGradient)
270                fLightGrayGradient = [[CTGradient progressLightGrayGradient] retain];
271            [fLightGrayGradient fillRect: noIncludeRect angle: -90];
272        }
273       
274        if (rightWidth > 0)
275        {
276            int availableWidth = 0;
277            /*if (![fDefaults boolForKey: @"DisplayProgressBarAvailable"])
278            {
279                //NSLog(@"notAvailableWidth %d rightWidth %d", notAvailableWidth, rightWidth);
280                availableWidth = MAX(0, (float)rightWidth - barRect.size.width * [torrent notAvailableDesired]);
281               
282                if (availableWidth > 0)
283                {
284                    rightWidth -= availableWidth;
285                   
286                    NSRect availableRect = barRect;
287                    availableRect.origin.x += leftWidth;
288                    availableRect.size.width = availableWidth;
289                   
290                    if (!fYellowGradient)
291                        fYellowGradient = [[CTGradient progressYellowGradient] retain];
292                    [fYellowGradient fillRect: availableRect angle: -90];
293                }
294            }*/
295           
296            if (rightWidth > 0)
297            {
298                NSRect includeRect = barRect;
299                includeRect.origin.x += leftWidth + availableWidth;
300                includeRect.size.width = rightWidth;
301               
302                if (!fWhiteGradient)
303                    fWhiteGradient = [[CTGradient progressWhiteGradient] retain];
304                [fWhiteGradient fillRect: includeRect angle: -90];
305            }
306        }
307    }
308   
309    if (leftWidth > 0)
310    {
311        NSRect completeRect = barRect;
312        completeRect.size.width = leftWidth;
313       
314        if ([torrent isActive])
315        {
316            if ([torrent isChecking])
317            {
318                if (!fYellowGradient)
319                    fYellowGradient = [[CTGradient progressYellowGradient] retain];
320                [fYellowGradient fillRect: completeRect angle: -90];
321            }
322            else if ([torrent isSeeding])
323            {
324                int ratioLeftWidth = leftWidth * (1.0 - [torrent progressStopRatio]);
325                leftWidth -= ratioLeftWidth;
326               
327                if (ratioLeftWidth > 0)
328                {
329                    NSRect ratioLeftRect = barRect;
330                    ratioLeftRect.origin.x += leftWidth;
331                    ratioLeftRect.size.width = ratioLeftWidth;
332                   
333                    if (!fLightGreenGradient)
334                        fLightGreenGradient = [[CTGradient progressLightGreenGradient] retain];
335                    [fLightGreenGradient fillRect: ratioLeftRect angle: -90];
336                }
337               
338                if (leftWidth > 0)
339                {
340                    completeRect.size.width = leftWidth;
341                   
342                    if (!fGreenGradient)
343                        fGreenGradient = [[CTGradient progressGreenGradient] retain];
344                    [fGreenGradient fillRect: completeRect angle: -90];
345                }
346            }
347            else
348            {
349                if (!fBlueGradient)
350                    fBlueGradient = [[CTGradient progressBlueGradient] retain];
351                [fBlueGradient fillRect: completeRect angle: -90];
352            }
353        }
354        else
355        {
356            if ([torrent waitingToStart])
357            {
358                if ([torrent progressLeft] <= 0.0)
359                {
360                    if (!fDarkGreenGradient)
361                        fDarkGreenGradient = [[CTGradient progressDarkGreenGradient] retain];
362                    [fDarkGreenGradient fillRect: completeRect angle: -90];
363                }
364                else
365                {
366                    if (!fDarkBlueGradient)
367                        fDarkBlueGradient = [[CTGradient progressDarkBlueGradient] retain];
368                    [fDarkBlueGradient fillRect: completeRect angle: -90];
369                }
370            }
371            else
372            {
373                if (!fGrayGradient)
374                    fGrayGradient = [[CTGradient progressGrayGradient] retain];
375                [fGrayGradient fillRect: completeRect angle: -90];
376            }
377        }
378    }
379   
380    [fBarOverlayColor set];
381    [NSBezierPath strokeRect: NSInsetRect(barRect, 0.5, 0.5)];
382}
383
384- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
385{
386    if (![fDefaults boolForKey: @"SmallView"])
387        return NSZeroRect;
388   
389    NSRect result = bounds;
390    result.size = [string size];
391   
392    result.origin.x += bounds.size.width - result.size.width - PADDING_HORIZONAL;
393    result.origin.y += PADDING_ABOVE_MIN_STATUS;
394   
395    return result;
396}
397
398- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
399            inBounds: (NSRect) bounds
400{
401    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
402   
403    NSRect result = bounds;
404    result.origin.y += PADDING_ABOVE_TITLE;
405    result.origin.x += PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_TITLE;
406   
407    result.size = [string size];
408    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL
409                            - (minimal ? PADDING_BETWEEN_TITLE_AND_MIN_STATUS + statusRect.size.width : 0));
410   
411    return result;
412}
413
414- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
415{
416    if ([fDefaults boolForKey: @"SmallView"])
417        return NSZeroRect;
418   
419    NSRect result = bounds;
420    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS;
421    result.origin.x += PADDING_HORIZONAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
422   
423    result.size = [string size];
424    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL);
425   
426    return result;
427}
428
429- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
430{
431    if ([fDefaults boolForKey: @"SmallView"])
432        return NSZeroRect;
433   
434    NSRect result = bounds;
435    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS
436                        + PADDING_BETWEEN_PROGRESS_AND_BAR + BAR_HEIGHT + PADDING_BETWEEN_BAR_AND_STATUS;
437    result.origin.x += PADDING_HORIZONAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
438   
439    result.size = [string size];
440    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL);
441   
442    return result;
443}
444
445- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color
446{
447    if (color)
448        [fTitleAttributes setObject: color forKey: NSForegroundColorAttributeName];
449   
450    NSString * title = [[self representedObject] name];
451    return [[[NSAttributedString alloc] initWithString: title attributes: fTitleAttributes] autorelease];
452}
453
454- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color
455{
456    if (color)
457        [fStatusAttributes setObject: color forKey: NSForegroundColorAttributeName];
458   
459    return [[[NSAttributedString alloc] initWithString: string attributes: fStatusAttributes] autorelease];
460}
461
462@end
Note: See TracBrowser for help on using the repository browser.