source: trunk/macosx/TorrentCell.m @ 7569

Last change on this file since 7569 was 7569, checked in by livings124, 12 years ago

extremely trivial adjustments

  • Property svn:keywords set to Date Rev Author Id
File size: 30.2 KB
Line 
1/******************************************************************************
2 * $Id: TorrentCell.m 7569 2009-01-02 02:41:54Z livings124 $
3 *
4 * Copyright (c) 2006-2008 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 "GroupsController.h"
28#import "NSStringAdditions.h"
29#import "ProgressGradients.h"
30
31#define BAR_HEIGHT 12.0f
32
33#define IMAGE_SIZE_REG 32.0f
34#define IMAGE_SIZE_MIN 16.0f
35
36#define NORMAL_BUTTON_WIDTH 14.0f
37#define ACTION_BUTTON_WIDTH 16.0f
38
39//ends up being larger than font height
40#define HEIGHT_TITLE 16.0f
41#define HEIGHT_STATUS 12.0f
42
43#define PADDING_HORIZONTAL 3.0f
44#define PADDING_BETWEEN_IMAGE_AND_TITLE 5.0f
45#define PADDING_BETWEEN_IMAGE_AND_BAR 7.0f
46#define PADDING_ABOVE_TITLE 4.0f
47#define PADDING_ABOVE_MIN_STATUS 4.0f
48#define PADDING_BETWEEN_TITLE_AND_MIN_STATUS 2.0f
49#define PADDING_BETWEEN_TITLE_AND_PROGRESS 1.0f
50#define PADDING_BETWEEN_PROGRESS_AND_BAR 2.0f
51#define PADDING_BETWEEN_TITLE_AND_BAR_MIN 3.0f
52#define PADDING_BETWEEN_BAR_AND_STATUS 2.0f
53
54#define PIECES_TOTAL_PERCENT 0.6f
55
56#define MAX_PIECES (18*18)
57
58@interface TorrentCell (Private)
59
60- (void) drawBar: (NSRect) barRect;
61- (void) drawRegularBar: (NSRect) barRect;
62- (void) drawPiecesBar: (NSRect) barRect;
63
64- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
65- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
66            inBounds: (NSRect) bounds;
67- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
68- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
69
70- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color;
71- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color;
72
73- (NSString *) buttonString;
74- (NSString *) statusString;
75- (NSString *) minimalStatusString;
76
77@end
78
79@implementation TorrentCell
80
81//only called once and the main table is always needed, so don't worry about releasing
82- (id) init
83{
84    if ((self = [super init]))
85        {
86        fDefaults = [NSUserDefaults standardUserDefaults];
87       
88        NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
89        [paragraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
90   
91        fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
92                                [NSFont messageFontOfSize: 12.0f], NSFontAttributeName,
93                                paragraphStyle, NSParagraphStyleAttributeName, nil];
94        fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
95                                [NSFont messageFontOfSize: 9.0f], NSFontAttributeName,
96                                paragraphStyle, NSParagraphStyleAttributeName, nil];
97        [paragraphStyle release];
98       
99        fBluePieceColor = [[NSColor colorWithCalibratedRed: 0.0f green: 0.4f blue: 0.8f alpha: 1.0f] retain];
100        fBarBorderColor = [[NSColor colorWithCalibratedWhite: 0.0f alpha: 0.2f] retain];
101    }
102        return self;
103}
104
105- (NSRect) iconRectForBounds: (NSRect) bounds
106{
107    CGFloat imageSize = [fDefaults boolForKey: @"SmallView"] ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG;
108   
109    NSRect result = bounds;
110    result.origin.x += PADDING_HORIZONTAL;
111    result.origin.y += floorf((result.size.height - imageSize) * 0.5f);
112    result.size = NSMakeSize(imageSize, imageSize);
113   
114    return result;
115}
116
117- (NSRect) titleRectForBounds: (NSRect) bounds
118{
119    return [self rectForTitleWithString: [self attributedTitleWithColor: nil]
120            basedOnMinimalStatusRect: [self minimalStatusRectForBounds: bounds] inBounds: bounds];
121}
122
123- (NSRect) minimalStatusRectForBounds: (NSRect) bounds
124{
125    if (![fDefaults boolForKey: @"SmallView"])
126        return NSZeroRect;
127   
128    return [self rectForMinimalStatusWithString: [self attributedStatusString: [self minimalStatusString] withColor: nil]
129            inBounds: bounds];
130}
131
132- (NSRect) progressRectForBounds: (NSRect) bounds
133{
134    if ([fDefaults boolForKey: @"SmallView"])
135        return NSZeroRect;
136   
137    return [self rectForProgressWithString: [self attributedStatusString: [[self representedObject] progressString] withColor: nil]
138            inBounds: bounds];
139}
140
141- (NSRect) barRectForBounds: (NSRect) bounds
142{
143    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
144   
145    NSRect result = bounds;
146    result.size.height = BAR_HEIGHT;
147    result.origin.x += (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_BAR;
148   
149    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE;
150    if (minimal)
151        result.origin.y += PADDING_BETWEEN_TITLE_AND_BAR_MIN;
152    else
153        result.origin.y += PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
154   
155    result.size.width = round(NSMaxX(bounds) - result.origin.x - PADDING_HORIZONTAL - 2.0f * (PADDING_HORIZONTAL + NORMAL_BUTTON_WIDTH));
156   
157    return result;
158}
159
160- (NSRect) statusRectForBounds: (NSRect) bounds
161{
162    if ([fDefaults boolForKey: @"SmallView"])
163        return NSZeroRect;
164   
165    return [self rectForStatusWithString: [self attributedStatusString: [self statusString] withColor: nil] inBounds: bounds];
166}
167
168- (NSRect) controlButtonRectForBounds: (NSRect) bounds
169{
170    NSRect result = bounds;
171    result.size.height = NORMAL_BUTTON_WIDTH;
172    result.size.width = NORMAL_BUTTON_WIDTH;
173    result.origin.x = NSMaxX(bounds) - 2.0f * (PADDING_HORIZONTAL + NORMAL_BUTTON_WIDTH);
174   
175    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE - (NORMAL_BUTTON_WIDTH - BAR_HEIGHT) * 0.5f;
176    if ([fDefaults boolForKey: @"SmallView"])
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    return result;
182}
183
184- (NSRect) revealButtonRectForBounds: (NSRect) bounds
185{
186    NSRect result = bounds;
187    result.size.height = NORMAL_BUTTON_WIDTH;
188    result.size.width = NORMAL_BUTTON_WIDTH;
189    result.origin.x = NSMaxX(bounds) - (PADDING_HORIZONTAL + NORMAL_BUTTON_WIDTH);
190   
191    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE - (NORMAL_BUTTON_WIDTH - BAR_HEIGHT) * 0.5f;
192    if ([fDefaults boolForKey: @"SmallView"])
193        result.origin.y += PADDING_BETWEEN_TITLE_AND_BAR_MIN;
194    else
195        result.origin.y += PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
196   
197    return result;
198}
199
200- (NSRect) actionButtonRectForBounds: (NSRect) bounds
201{
202    NSRect result = [self iconRectForBounds: bounds];
203    if (![fDefaults boolForKey: @"SmallView"])
204    {
205        result.origin.x += (result.size.width - ACTION_BUTTON_WIDTH) * 0.5f;
206        result.origin.y += (result.size.height - ACTION_BUTTON_WIDTH) * 0.5f;
207        result.size.width = ACTION_BUTTON_WIDTH;
208        result.size.height = ACTION_BUTTON_WIDTH;
209    }
210   
211    return result;
212}
213
214- (NSUInteger) hitTestForEvent: (NSEvent *) event inRect: (NSRect) cellFrame ofView: (NSView *) controlView
215{
216    NSPoint point = [controlView convertPoint: [event locationInWindow] fromView: nil];
217   
218    if (NSMouseInRect(point, [self controlButtonRectForBounds: cellFrame], [controlView isFlipped])
219        || NSMouseInRect(point, [self revealButtonRectForBounds: cellFrame], [controlView isFlipped]))
220        return NSCellHitContentArea | NSCellHitTrackableArea;
221   
222    return NSCellHitContentArea;
223}
224
225+ (BOOL) prefersTrackingUntilMouseUp
226{
227    return YES;
228}
229
230- (BOOL) trackMouse: (NSEvent *) event inRect: (NSRect) cellFrame ofView: (NSView *) controlView untilMouseUp: (BOOL) flag
231{
232    fTracking = YES;
233   
234    [self setControlView: controlView];
235   
236    NSPoint point = [controlView convertPoint: [event locationInWindow] fromView: nil];
237   
238    NSRect controlRect= [self controlButtonRectForBounds: cellFrame];
239    BOOL checkControl = NSMouseInRect(point, controlRect, [controlView isFlipped]);
240   
241    NSRect revealRect = [self revealButtonRectForBounds: cellFrame];
242    BOOL checkReveal = NSMouseInRect(point, revealRect, [controlView isFlipped]);
243   
244    [(TorrentTableView *)controlView removeButtonTrackingAreas];
245   
246    while ([event type] != NSLeftMouseUp)
247    {
248        point = [controlView convertPoint: [event locationInWindow] fromView: nil];
249       
250        if (checkControl)
251        {
252            BOOL inControlButton = NSMouseInRect(point, controlRect, [controlView isFlipped]);
253            if (fMouseDownControlButton != inControlButton)
254            {
255                fMouseDownControlButton = inControlButton;
256                [controlView setNeedsDisplayInRect: cellFrame];
257            }
258        }
259        else if (checkReveal)
260        {
261            BOOL inRevealButton = NSMouseInRect(point, revealRect, [controlView isFlipped]);
262            if (fMouseDownRevealButton != inRevealButton)
263            {
264                fMouseDownRevealButton = inRevealButton;
265                [controlView setNeedsDisplayInRect: cellFrame];
266            }
267        }
268        else;
269       
270        //send events to where necessary
271        if ([event type] == NSMouseEntered || [event type] == NSMouseExited)
272            [NSApp sendEvent: event];
273        event = [[controlView window] nextEventMatchingMask:
274                    (NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSMouseEnteredMask | NSMouseExitedMask)];
275    }
276   
277    fTracking = NO;
278
279    if (fMouseDownControlButton)
280    {
281        fMouseDownControlButton = NO;
282       
283        [(TorrentTableView *)controlView toggleControlForTorrent: [self representedObject]];
284    }
285    else if (fMouseDownRevealButton)
286    {
287        fMouseDownRevealButton = NO;
288        [controlView setNeedsDisplayInRect: cellFrame];
289       
290        [[self representedObject] revealData];
291    }
292    else;
293   
294    [controlView updateTrackingAreas];
295   
296    return YES;
297}
298
299- (void) addTrackingAreasForView: (NSView *) controlView inRect: (NSRect) cellFrame withUserInfo: (NSDictionary *) userInfo
300            mouseLocation: (NSPoint) mouseLocation
301{
302    NSTrackingAreaOptions options = NSTrackingEnabledDuringMouseDrag | NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways;
303   
304    //control button
305    NSRect controlButtonRect = [self controlButtonRectForBounds: cellFrame];
306    NSTrackingAreaOptions controlOptions = options;
307    if (NSMouseInRect(mouseLocation, controlButtonRect, [controlView isFlipped]))
308    {
309        controlOptions |= NSTrackingAssumeInside;
310        [(TorrentTableView *)controlView setControlButtonHover: [[userInfo objectForKey: @"Row"] intValue]];
311    }
312   
313    NSMutableDictionary * controlInfo = [userInfo mutableCopy];
314    [controlInfo setObject: @"Control" forKey: @"Type"];
315    NSTrackingArea * area = [[NSTrackingArea alloc] initWithRect: controlButtonRect options: controlOptions owner: controlView
316                                userInfo: controlInfo];
317    [controlView addTrackingArea: area];
318    [controlInfo release];
319    [area release];
320   
321    //reveal button
322    NSRect revealButtonRect = [self revealButtonRectForBounds: cellFrame];
323    NSTrackingAreaOptions revealOptions = options;
324    if (NSMouseInRect(mouseLocation, revealButtonRect, [controlView isFlipped]))
325    {
326        revealOptions |= NSTrackingAssumeInside;
327        [(TorrentTableView *)controlView setRevealButtonHover: [[userInfo objectForKey: @"Row"] intValue]];
328    }
329   
330    NSMutableDictionary * revealInfo = [userInfo mutableCopy];
331    [revealInfo setObject: @"Reveal" forKey: @"Type"];
332    area = [[NSTrackingArea alloc] initWithRect: revealButtonRect options: revealOptions owner: controlView userInfo: revealInfo];
333    [controlView addTrackingArea: area];
334    [revealInfo release];
335    [area release];
336   
337    //action button
338    NSRect actionButtonRect = [self iconRectForBounds: cellFrame]; //use the whole icon
339    NSTrackingAreaOptions actionOptions = options;
340    if (NSMouseInRect(mouseLocation, actionButtonRect, [controlView isFlipped]))
341    {
342        actionOptions |= NSTrackingAssumeInside;
343        [(TorrentTableView *)controlView setActionButtonHover: [[userInfo objectForKey: @"Row"] intValue]];
344    }
345   
346    NSMutableDictionary * actionInfo = [userInfo mutableCopy];
347    [actionInfo setObject: @"Action" forKey: @"Type"];
348    area = [[NSTrackingArea alloc] initWithRect: actionButtonRect options: actionOptions owner: controlView userInfo: actionInfo];
349    [controlView addTrackingArea: area];
350    [actionInfo release];
351    [area release];
352}
353
354- (void) setControlHover: (BOOL) hover
355{
356    fHoverControl = hover;
357}
358
359- (void) setRevealHover: (BOOL) hover
360{
361    fHoverReveal = hover;
362}
363
364- (void) setActionHover: (BOOL) hover
365{
366    fHoverAction = hover;
367}
368
369- (void) setActionPushed: (BOOL) pushed
370{
371    fMouseDownActionButton = pushed;
372}
373
374- (void) drawInteriorWithFrame: (NSRect) cellFrame inView: (NSView *) controlView
375{
376    Torrent * torrent = [self representedObject];
377   
378    const BOOL minimal = [fDefaults boolForKey: @"SmallView"];
379   
380    //group coloring
381    NSRect iconRect = [self iconRectForBounds: cellFrame];
382   
383    NSInteger groupValue = [torrent groupValue];
384    if (groupValue != -1)
385    {
386        NSRect groupRect = NSInsetRect(iconRect, -1.0f, -2.0f);
387        if (!minimal)
388        {
389            groupRect.size.height--;
390            groupRect.origin.y--;
391        }
392        const CGFloat radius = minimal ? 3.0f : 6.0f;
393       
394        NSColor * groupColor = [[GroupsController groups] colorForIndex: groupValue],
395                * darkGroupColor = [groupColor blendedColorWithFraction: 0.2f ofColor: [NSColor whiteColor]];
396       
397        //border
398        NSBezierPath * bp = [NSBezierPath bezierPathWithRoundedRect: groupRect xRadius: radius yRadius: radius];
399        [darkGroupColor set];
400        [bp setLineWidth: 2.0f];
401        [bp stroke];
402       
403        //inside
404        bp = [NSBezierPath bezierPathWithRoundedRect: groupRect xRadius: radius yRadius: radius];
405        NSGradient * gradient = [[NSGradient alloc] initWithStartingColor: [groupColor blendedColorWithFraction: 0.7f
406                                    ofColor: [NSColor whiteColor]] endingColor: darkGroupColor];
407        [gradient drawInBezierPath: bp angle: 90.0f];
408        [gradient release];
409    }
410   
411    //error image
412    const BOOL error = [torrent isError];
413    if (error && !fErrorImage)
414    {
415        fErrorImage = [NSImage imageNamed: @"Error.png"];
416        [fErrorImage setFlipped: YES];
417    }
418   
419    //icon
420    if (!minimal || !(!fTracking && fHoverAction)) //don't show in minimal mode when hovered over
421    {
422        NSImage * icon = (minimal && error) ? fErrorImage : [torrent icon];
423        [icon drawInRect: iconRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0f];
424    }
425   
426    if (error && !minimal)
427    {
428        NSRect errorRect = NSMakeRect(NSMaxX(iconRect) - IMAGE_SIZE_MIN, NSMaxY(iconRect) - IMAGE_SIZE_MIN,
429                                        IMAGE_SIZE_MIN, IMAGE_SIZE_MIN);
430        [fErrorImage drawInRect: errorRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0f];
431    }
432   
433    //text color
434    NSColor * titleColor, * statusColor;
435    if ([self backgroundStyle] == NSBackgroundStyleDark)
436        titleColor = statusColor = [NSColor whiteColor];
437    else
438    {
439        titleColor = [NSColor controlTextColor];
440        statusColor = [NSColor darkGrayColor];
441    }
442   
443    //minimal status
444    NSRect minimalStatusRect;
445    if (minimal)
446    {
447        NSAttributedString * minimalString = [self attributedStatusString: [self minimalStatusString] withColor: statusColor];
448        minimalStatusRect = [self rectForMinimalStatusWithString: minimalString inBounds: cellFrame];
449       
450        [minimalString drawInRect: minimalStatusRect];
451    }
452   
453    //title
454    NSAttributedString * titleString = [self attributedTitleWithColor: titleColor];
455    NSRect titleRect = [self rectForTitleWithString: titleString basedOnMinimalStatusRect: minimalStatusRect inBounds: cellFrame];
456    [titleString drawInRect: titleRect];
457   
458    //progress
459    if (!minimal)
460    {
461        NSAttributedString * progressString = [self attributedStatusString: [torrent progressString] withColor: statusColor];
462        NSRect progressRect = [self rectForProgressWithString: progressString inBounds: cellFrame];
463       
464        [progressString drawInRect: progressRect];
465    }
466   
467    //bar
468    [self drawBar: [self barRectForBounds: cellFrame]];
469   
470    //control button
471    NSString * controlImageSuffix;
472    if (fMouseDownControlButton)
473        controlImageSuffix = @"On.png";
474    else if (!fTracking && fHoverControl)
475        controlImageSuffix = @"Hover.png";
476    else
477        controlImageSuffix = @"Off.png";
478   
479    NSImage * controlImage;
480    if ([torrent isActive])
481        controlImage = [NSImage imageNamed: [@"Pause" stringByAppendingString: controlImageSuffix]];
482    else
483    {
484        if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
485            controlImage = [NSImage imageNamed: [@"ResumeNoWait" stringByAppendingString: controlImageSuffix]];
486        else if ([torrent waitingToStart])
487            controlImage = [NSImage imageNamed: [@"Pause" stringByAppendingString: controlImageSuffix]];
488        else
489            controlImage = [NSImage imageNamed: [@"Resume" stringByAppendingString: controlImageSuffix]];
490    }
491   
492    [controlImage setFlipped: YES];
493    [controlImage drawInRect: [self controlButtonRectForBounds: cellFrame] fromRect: NSZeroRect operation: NSCompositeSourceOver
494        fraction: 1.0f];
495   
496    //reveal button
497    NSString * revealImageString;
498    if (fMouseDownRevealButton)
499        revealImageString = @"RevealOn.png";
500    else if (!fTracking && fHoverReveal)
501        revealImageString = @"RevealHover.png";
502    else
503        revealImageString = @"RevealOff.png";
504   
505    NSImage * revealImage = [NSImage imageNamed: revealImageString];
506    [revealImage setFlipped: YES];
507    [revealImage drawInRect: [self revealButtonRectForBounds: cellFrame] fromRect: NSZeroRect operation: NSCompositeSourceOver
508        fraction: 1.0f];
509   
510    //action button
511    NSString * actionImageString;
512    if (fMouseDownActionButton)
513        actionImageString = @"ActionOn.png";
514    else if (!fTracking && fHoverAction)
515        actionImageString = @"ActionHover.png";
516    else
517        actionImageString = nil;
518   
519    if (actionImageString)
520    {
521        NSImage * actionImage = [NSImage imageNamed: actionImageString];
522        [actionImage setFlipped: YES];
523        [actionImage drawInRect: [self actionButtonRectForBounds: cellFrame] fromRect: NSZeroRect operation: NSCompositeSourceOver
524            fraction: 1.0f];
525    }
526   
527    //status
528    if (!minimal)
529    {
530        NSAttributedString * statusString = [self attributedStatusString: [self statusString] withColor: statusColor];
531        [statusString drawInRect: [self rectForStatusWithString: statusString inBounds: cellFrame]];
532    }
533}
534
535@end
536
537@implementation TorrentCell (Private)
538
539- (void) drawBar: (NSRect) barRect
540{
541    CGFloat piecesBarPercent = [(TorrentTableView *)[self controlView] piecesBarPercent];
542    if (piecesBarPercent > 0.0f)
543    {
544        NSRect regularBarRect = barRect, piecesBarRect = barRect;
545        piecesBarRect.size.height *= PIECES_TOTAL_PERCENT * piecesBarPercent;
546        regularBarRect.size.height -= piecesBarRect.size.height;
547        piecesBarRect.origin.y += regularBarRect.size.height;
548       
549        [self drawRegularBar: regularBarRect];
550        [self drawPiecesBar: piecesBarRect];
551    }
552    else
553    {
554        [[self representedObject] setPreviousFinishedPieces: nil];
555       
556        [self drawRegularBar: barRect];
557    }
558   
559    [fBarBorderColor set];
560    [NSBezierPath strokeRect: NSInsetRect(barRect, 0.5f, 0.5f)];
561}
562
563- (void) drawRegularBar: (NSRect) barRect
564{
565    Torrent * torrent = [self representedObject];
566   
567    NSInteger leftWidth = barRect.size.width;
568    CGFloat progress = [torrent progress];
569   
570    if (progress < 1.0f)
571    {
572        CGFloat rightProgress = 1.0f - progress, progressLeft = [torrent progressLeft];
573        NSInteger rightWidth = leftWidth * rightProgress;
574        leftWidth -= rightWidth;
575       
576        if (progressLeft < rightProgress)
577        {
578            NSInteger rightNoIncludeWidth = rightWidth * ((rightProgress - progressLeft) / rightProgress);
579            rightWidth -= rightNoIncludeWidth;
580           
581            NSRect noIncludeRect = barRect;
582            noIncludeRect.origin.x += barRect.size.width - rightNoIncludeWidth;
583            noIncludeRect.size.width = rightNoIncludeWidth;
584           
585            [[ProgressGradients progressLightGrayGradient] drawInRect: noIncludeRect angle: 90];
586        }
587       
588        if (rightWidth > 0)
589        {
590            if ([torrent isActive] && ![torrent allDownloaded] && ![torrent isChecking]
591                && [fDefaults boolForKey: @"DisplayProgressBarAvailable"])
592            {
593                NSInteger notAvailableWidth = ceil(rightWidth * [torrent notAvailableDesired]);
594                if (notAvailableWidth > 0)
595                {
596                    rightWidth -= notAvailableWidth;
597                   
598                    NSRect notAvailableRect = barRect;
599                    notAvailableRect.origin.x += leftWidth + rightWidth;
600                    notAvailableRect.size.width = notAvailableWidth;
601                   
602                    [[ProgressGradients progressRedGradient] drawInRect: notAvailableRect angle: 90];
603                }
604            }
605           
606            if (rightWidth > 0)
607            {
608                NSRect includeRect = barRect;
609                includeRect.origin.x += leftWidth;
610                includeRect.size.width = rightWidth;
611               
612                [[ProgressGradients progressWhiteGradient] drawInRect: includeRect angle: 90];
613            }
614        }
615    }
616   
617    if (leftWidth > 0)
618    {
619        NSRect completeRect = barRect;
620        completeRect.size.width = leftWidth;
621       
622        if ([torrent isActive])
623        {
624            if ([torrent isChecking])
625                [[ProgressGradients progressYellowGradient] drawInRect: completeRect angle: 90];
626            else if ([torrent isSeeding])
627            {
628                NSInteger ratioLeftWidth = leftWidth * (1.0f - [torrent progressStopRatio]);
629                leftWidth -= ratioLeftWidth;
630               
631                if (ratioLeftWidth > 0)
632                {
633                    NSRect ratioLeftRect = barRect;
634                    ratioLeftRect.origin.x += leftWidth;
635                    ratioLeftRect.size.width = ratioLeftWidth;
636                   
637                    [[ProgressGradients progressLightGreenGradient] drawInRect: ratioLeftRect angle: 90];
638                }
639               
640                if (leftWidth > 0)
641                {
642                    completeRect.size.width = leftWidth;
643                   
644                    [[ProgressGradients progressGreenGradient] drawInRect: completeRect angle: 90];
645                }
646            }
647            else
648                [[ProgressGradients progressBlueGradient] drawInRect: completeRect angle: 90];
649        }
650        else
651        {
652            if ([torrent waitingToStart])
653            {
654                if ([torrent progressLeft] <= 0.0f)
655                    [[ProgressGradients progressDarkGreenGradient] drawInRect: completeRect angle: 90];
656                else
657                    [[ProgressGradients progressDarkBlueGradient] drawInRect: completeRect angle: 90];
658            }
659            else
660                [[ProgressGradients progressGrayGradient] drawInRect: completeRect angle: 90];
661        }
662    }
663}
664
665- (void) drawPiecesBar: (NSRect) barRect
666{
667    Torrent * torrent = [self representedObject];
668   
669    NSInteger pieceCount = MIN([torrent pieceCount], MAX_PIECES);
670    float * piecesPercent = malloc(pieceCount * sizeof(float));
671    [torrent getAmountFinished: piecesPercent size: pieceCount];
672   
673    NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
674                                    pixelsWide: pieceCount pixelsHigh: 1 bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
675                                    isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
676   
677    NSIndexSet * previousFinishedIndexes = [torrent previousFinishedPieces];
678    NSMutableIndexSet * finishedIndexes = [NSMutableIndexSet indexSet];
679   
680    for (NSInteger i = 0; i < pieceCount; i++)
681    {
682        NSColor * pieceColor;
683        if (piecesPercent[i] == 1.0f)
684        {
685            if (previousFinishedIndexes && ![previousFinishedIndexes containsIndex: i])
686                pieceColor = [NSColor orangeColor];
687            else
688                pieceColor = fBluePieceColor;
689            [finishedIndexes addIndex: i];
690        }
691        else
692            pieceColor = [[NSColor whiteColor] blendedColorWithFraction: piecesPercent[i] ofColor: fBluePieceColor];
693       
694        //it's faster to just set color instead of checking previous color
695        [bitmap setColor: pieceColor atX: i y: 0];
696    }
697   
698    free(piecesPercent);
699   
700    [torrent setPreviousFinishedPieces: [finishedIndexes count] > 0 ? finishedIndexes : nil]; //don't bother saving if none are complete
701   
702    //actually draw image
703    [bitmap drawInRect: barRect];
704    [bitmap release];
705}
706
707- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
708{
709    NSRect result = bounds;
710    result.size = [string size];
711   
712    result.origin.x += bounds.size.width - result.size.width - PADDING_HORIZONTAL;
713    result.origin.y += PADDING_ABOVE_MIN_STATUS;
714   
715    return result;
716}
717
718- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
719            inBounds: (NSRect) bounds
720{
721    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
722   
723    NSRect result = bounds;
724    result.origin.y += PADDING_ABOVE_TITLE;
725    result.origin.x += PADDING_HORIZONTAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_TITLE;
726   
727    result.size = [string size];
728    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONTAL
729                            - (minimal ? PADDING_BETWEEN_TITLE_AND_MIN_STATUS + statusRect.size.width : 0));
730   
731    return result;
732}
733
734- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
735{
736    NSRect result = bounds;
737    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS;
738    result.origin.x += PADDING_HORIZONTAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
739   
740    result.size = [string size];
741    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONTAL);
742   
743    return result;
744}
745
746- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
747{
748    NSRect result = bounds;
749    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS
750                        + PADDING_BETWEEN_PROGRESS_AND_BAR + BAR_HEIGHT + PADDING_BETWEEN_BAR_AND_STATUS;
751    result.origin.x += PADDING_HORIZONTAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
752   
753    result.size = [string size];
754    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONTAL);
755   
756    return result;
757}
758
759- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color
760{
761    if (color)
762        [fTitleAttributes setObject: color forKey: NSForegroundColorAttributeName];
763   
764    NSString * title = [[self representedObject] name];
765    return [[[NSAttributedString alloc] initWithString: title attributes: fTitleAttributes] autorelease];
766}
767
768- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color
769{
770    if (color)
771        [fStatusAttributes setObject: color forKey: NSForegroundColorAttributeName];
772   
773    return [[[NSAttributedString alloc] initWithString: string attributes: fStatusAttributes] autorelease];
774}
775
776- (NSString *) buttonString
777{
778    if (fMouseDownRevealButton || (!fTracking && fHoverReveal))
779        return NSLocalizedString(@"Reveal the data file in Finder", "Torrent cell -> button info");
780    else if (fMouseDownControlButton || (!fTracking && fHoverControl))
781    {
782        Torrent * torrent = [self representedObject];
783        if ([torrent isActive])
784            return NSLocalizedString(@"Pause the transfer", "Torrent Table -> tooltip");
785        else
786        {
787            if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
788                return NSLocalizedString(@"Resume the transfer right away", "Torrent cell -> button info");
789            else if ([torrent waitingToStart])
790                return NSLocalizedString(@"Stop waiting to start", "Torrent cell -> button info");
791            else
792                return NSLocalizedString(@"Resume the transfer", "Torrent cell -> button info");
793        }
794    }
795    else if (!fTracking && fHoverAction)
796        return NSLocalizedString(@"Change transfer settings", "Torrent Table -> tooltip");
797    else
798        return nil;
799}
800
801- (NSString *) statusString
802{
803    NSString * buttonString;
804    if ((buttonString = [self buttonString]))
805        return buttonString;
806    else
807        return [[self representedObject] statusString];
808}
809
810- (NSString *) minimalStatusString
811{
812    NSString * buttonString;
813    if ((buttonString = [self buttonString]))
814        return buttonString;
815    else
816    {
817        Torrent * torrent = [self representedObject];
818        return [fDefaults boolForKey: @"DisplaySmallStatusRegular"] ? [torrent shortStatusString] : [torrent remainingTimeString];
819    }
820}
821
822@end
Note: See TracBrowser for help on using the repository browser.