source: trunk/macosx/TorrentCell.m @ 729

Last change on this file since 729 was 729, checked in by livings124, 16 years ago

Only show ratio, not upload speed, when seeding in minimal mode and set to display alternate status string.

  • Property svn:keywords set to Date Rev Author Id
File size: 14.6 KB
Line 
1/******************************************************************************
2 * $Id: TorrentCell.m 729 2006-08-06 20:40:12Z livings124 $
3 *
4 * Copyright (c) 2006 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 "StringAdditions.h"
28
29#define BAR_HEIGHT 12.0
30
31@interface TorrentCell (Private)
32
33- (void) placeBar: (NSImage *) barImage width: (float) width point: (NSPoint) point;
34- (void) buildSimpleBar: (float) width point: (NSPoint) point;
35- (void) buildAdvancedBar: (float) widthFloat point: (NSPoint) point;
36
37@end
38
39@implementation TorrentCell
40
41static NSImage * fProgressWhite, * fProgressBlue, * fProgressGray, * fProgressGreen,
42                * fProgressAdvanced, * fProgressEndWhite, * fProgressEndBlue,
43                * fProgressEndGray, * fProgressEndGreen, * fProgressEndAdvanced;
44
45// Used to optimize drawing. They contain packed RGBA pixels for every color needed.
46#define BE OSSwapBigToHostConstInt32
47static uint32_t kBorder[] =
48    { BE(0x00000005), BE(0x00000010), BE(0x00000015), BE(0x00000015),
49      BE(0x00000015), BE(0x00000015), BE(0x00000015), BE(0x00000015),
50      BE(0x00000015), BE(0x00000015), BE(0x00000010), BE(0x00000005) };
51
52static uint32_t kBack[] = { BE(0xB4B4B4FF), BE(0xE3E3E3FF) };
53
54static uint32_t kRed   = BE(0xFF6450FF), //255, 100, 80
55                kBlue1 = BE(0xA0DCFFFF), //160, 220, 255
56                kBlue2 = BE(0x78BEFFFF), //120, 190, 255
57                kBlue3 = BE(0x50A0FFFF), //80, 160, 255
58                kBlue4 = BE(0x1E46B4FF), //30, 70, 180
59                kGray  = BE(0x828282FF), //130, 130, 130
60                kGreen = BE(0x00FF00FF); //0, 255, 0
61
62- (id) init
63{
64    if ((self = [super init]))
65    {
66        fDefaults = [NSUserDefaults standardUserDefaults];
67       
68        fStatusRegular = [fDefaults boolForKey: @"SmallStatusRegular"];
69   
70        NSSize startSize = NSMakeSize(100.0, BAR_HEIGHT);
71        if (!fProgressWhite)
72        {
73            fProgressWhite = [NSImage imageNamed: @"ProgressBarWhite.png"];
74            [fProgressWhite setScalesWhenResized: YES];
75        }
76        if (!fProgressBlue)
77        {
78            fProgressBlue = [NSImage imageNamed: @"ProgressBarBlue.png"];
79            [fProgressBlue setScalesWhenResized: YES];
80            [fProgressBlue setSize: startSize];
81        }
82        if (!fProgressGray)
83        {
84            fProgressGray = [NSImage imageNamed: @"ProgressBarGray.png"];
85            [fProgressGray setScalesWhenResized: YES];
86            [fProgressGray setSize: startSize];
87        }
88        if (!fProgressGreen)
89        {
90            fProgressGreen = [NSImage imageNamed: @"ProgressBarGreen.png"];
91            [fProgressGreen setScalesWhenResized: YES];
92        }
93        if (!fProgressAdvanced)
94        {
95            fProgressAdvanced = [NSImage imageNamed: @"ProgressBarAdvanced.png"];
96            [fProgressAdvanced setScalesWhenResized: YES];
97        }
98       
99        if (!fProgressEndWhite)
100            fProgressEndWhite = [NSImage imageNamed: @"ProgressBarEndWhite.png"];
101        if (!fProgressEndBlue)
102            fProgressEndBlue = [NSImage imageNamed: @"ProgressBarEndBlue.png"];
103        if (!fProgressEndGray)
104            fProgressEndGray = [NSImage imageNamed: @"ProgressBarEndGray.png"];
105        if (!fProgressEndGreen)
106            fProgressEndGreen = [NSImage imageNamed: @"ProgressBarEndGreen.png"];
107        if (!fProgressEndAdvanced)
108            fProgressEndAdvanced = [NSImage imageNamed: @"ProgressBarEndAdvanced.png"];
109    }
110    return self;
111}
112
113- (void) setTorrent: (Torrent *) torrent
114{
115    fTorrent = torrent;
116}
117
118- (void) placeBar: (NSImage *) barImage width: (float) width point: (NSPoint) point
119{
120    if ([barImage size].width < width)
121        [barImage setSize: NSMakeSize(width * 1.5, BAR_HEIGHT)];
122
123    [barImage compositeToPoint: point fromRect: NSMakeRect(0, 0, width, BAR_HEIGHT)
124                        operation: NSCompositeSourceOver];
125}
126
127- (void) buildSimpleBar: (float) width point: (NSPoint) point
128{
129    width -= 2.0;
130    if ([fTorrent isSeeding])
131    {
132        [fProgressEndGreen compositeToPoint: point operation: NSCompositeSourceOver];
133       
134        point.x += 1.0;
135        [self placeBar: fProgressGreen width: width point: point];
136       
137        point.x += width;
138        [fProgressEndGreen compositeToPoint: point operation: NSCompositeSourceOver];
139    }
140    else
141    {
142        float completedWidth = [fTorrent progress] * width,
143                remainingWidth = width - completedWidth;
144        BOOL isActive = [fTorrent isActive];
145       
146        //left end
147        NSImage * barLeftEnd;
148        if (remainingWidth == width)
149            barLeftEnd = fProgressEndWhite;
150        else if (isActive)
151            barLeftEnd = fProgressEndBlue;
152        else
153            barLeftEnd = fProgressEndGray;
154       
155        [barLeftEnd compositeToPoint: point operation: NSCompositeSourceOver];
156       
157        //active bar
158        point.x += 1.0;
159        [self placeBar: isActive ? fProgressBlue : fProgressGray width: completedWidth point: point];
160       
161        //remaining bar
162        point.x += completedWidth;
163        [self placeBar: fProgressWhite width: remainingWidth point: point];
164       
165        //right end
166        NSImage * barRightEnd;
167        if (completedWidth < width)
168            barRightEnd = fProgressEndWhite;
169        else if (isActive)
170            barRightEnd = fProgressEndBlue;
171        else
172            barRightEnd = fProgressEndGray;
173       
174        point.x += remainingWidth;
175        [barRightEnd compositeToPoint: point operation: NSCompositeSourceOver];
176    }
177}
178
179- (void) buildAdvancedBar: (float) widthFloat point: (NSPoint) point
180{
181    //if seeding, there's no need for the advanced bar
182    if ([fTorrent isSeeding])
183    {
184        [self buildSimpleBar: widthFloat point: point];
185        return;
186    }
187
188    int width = widthFloat; //integers for bars
189   
190    NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
191        pixelsWide: width pixelsHigh: BAR_HEIGHT bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
192        isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
193
194    int h, w;
195    uint32_t * p;
196    uint8_t * bitmapData = [bitmap bitmapData];
197    int bytesPerRow = [bitmap bytesPerRow];
198
199    //left and right borders
200    p = (uint32_t *) bitmapData;
201    for(h = 0; h < BAR_HEIGHT; h++)
202    {
203        p[0] = kBorder[h];
204        p[width - 1] = kBorder[h];
205        p += bytesPerRow / 4;
206    }
207
208    int8_t * pieces = malloc(width);
209    [fTorrent getAvailability: pieces size: width];
210    int avail = 0;
211    for (w = 0; w < width; w++)
212        if (pieces[w] != 0)
213            avail++;
214
215    //first two lines: dark blue to show progression, green to show available
216    int end = lrintf(floor([fTorrent progress] * (width - 2)));
217    p = (uint32_t *) (bitmapData) + 1;
218
219    for (w = 0; w < end; w++)
220    {
221        p[w] = kBlue4;
222        p[w + bytesPerRow / 4] = kBlue4;
223    }
224    for (; w < avail; w++)
225    {
226        p[w] = kGreen;
227        p[w + bytesPerRow / 4] = kGreen;
228    }
229    for (; w < width - 2; w++)
230    {
231        p[w] = kBack[0];
232        p[w + bytesPerRow / 4] = kBack[1];
233    }
234   
235    //lines 2 to 14: blue or grey depending on whether we have the piece or not
236    uint32_t color;
237    for( w = 0; w < width - 2; w++ )
238    {
239        //point to pixel ( 2 + w, 2 ). We will then draw "vertically"
240        p = (uint32_t *) ( bitmapData + 2 * bytesPerRow ) + 1 + w;
241
242        if (pieces[w] < 0)
243            color = kGray;
244        else if (pieces[w] == 0)
245            color = kRed;
246        else if (pieces[w] == 1)
247            color = kBlue1;
248        else if (pieces[w] == 2)
249            color = kBlue2;
250        else
251            color = kBlue3;
252
253        for( h = 2; h < BAR_HEIGHT; h++ )
254        {
255            p[0] = color;
256            p = (uint32_t *) ( (uint8_t *) p + bytesPerRow );
257        }
258    }
259
260    free( pieces );
261   
262    //actually draw image
263    NSImage * img = [[NSImage alloc] initWithSize: [bitmap size]];
264    [img addRepresentation: bitmap];
265   
266    //bar size with float, not double, to match standard bar
267    [img setScalesWhenResized: YES];
268    [img setSize: NSMakeSize(widthFloat, BAR_HEIGHT)];
269   
270    [img compositeToPoint: point operation: NSCompositeSourceOver];
271    [img release];
272    [bitmap release];
273   
274    //draw overlay over advanced bar
275    [fProgressEndAdvanced compositeToPoint: point operation: NSCompositeSourceOver];
276   
277    widthFloat -= 2.0;
278    point.x += 1.0;
279    [self placeBar: fProgressAdvanced width: widthFloat point: point];
280   
281    point.x += widthFloat;
282    [fProgressEndAdvanced compositeToPoint: point operation: NSCompositeSourceOver];
283}
284
285- (void) toggleMinimalStatus
286{
287    fStatusRegular = !fStatusRegular;
288    [fDefaults setBool: fStatusRegular forKey: @"SmallStatusRegular"];
289}
290
291- (void) drawWithFrame: (NSRect) cellFrame inView: (NSView *) view
292{
293    BOOL highlighted = [self isHighlighted] && [[self highlightColorWithFrame: cellFrame inView: view]
294                                                        isEqual: [NSColor alternateSelectedControlColor]];
295    NSDictionary * nameAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
296                    highlighted ? [NSColor whiteColor] : [NSColor controlTextColor], NSForegroundColorAttributeName,
297                    [NSFont messageFontOfSize: 12.0], NSFontAttributeName, nil];
298    NSDictionary * statusAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
299                    highlighted ? [NSColor whiteColor] : [NSColor darkGrayColor], NSForegroundColorAttributeName,
300                    [NSFont messageFontOfSize: 9.0], NSFontAttributeName, nil];
301
302    NSPoint pen = cellFrame.origin;
303    const float PADDING = 3.0, LINE_PADDING = 2.0, EXTRA_NAME_SHIFT = 1.0;
304
305    if (![fDefaults boolForKey: @"SmallView"]) //regular size
306    {
307        //icon
308        NSImage * icon = [fTorrent iconFlipped];
309        NSSize iconSize = [icon size];
310       
311        pen.x += PADDING;
312        pen.y += (cellFrame.size.height - iconSize.height) * 0.5;
313       
314        [icon drawAtPoint: pen fromRect: NSMakeRect(0, 0, iconSize.width, iconSize.height)
315                operation: NSCompositeSourceOver fraction: 1.0];
316
317        float mainWidth = cellFrame.size.width - iconSize.width - 3.0 * PADDING - EXTRA_NAME_SHIFT;
318
319        //name string
320        pen.x += iconSize.width + PADDING + EXTRA_NAME_SHIFT;
321        pen.y = cellFrame.origin.y + PADDING;
322        NSAttributedString * nameString = [[fTorrent name] attributedStringFittingInWidth: mainWidth
323                                                attributes: nameAttributes];
324        [nameString drawAtPoint: pen];
325       
326        //progress string
327        pen.y += [nameString size].height + LINE_PADDING - 1.0;
328       
329        NSAttributedString * progressString = [[fTorrent progressString]
330            attributedStringFittingInWidth: mainWidth attributes: statusAttributes];
331        [progressString drawAtPoint: pen];
332
333        //progress bar
334        pen.x -= EXTRA_NAME_SHIFT;
335        pen.y += [progressString size].height + LINE_PADDING + BAR_HEIGHT;
336       
337        float barWidth = mainWidth + EXTRA_NAME_SHIFT - BUTTONS_TOTAL_WIDTH + PADDING;
338       
339        if ([fDefaults boolForKey: @"UseAdvancedBar"])
340            [self buildAdvancedBar: barWidth point: pen];
341        else
342            [self buildSimpleBar: barWidth point: pen];
343
344        //status string
345        pen.x += EXTRA_NAME_SHIFT;
346        pen.y += LINE_PADDING;
347        NSAttributedString * statusString = [[fTorrent statusString]
348            attributedStringFittingInWidth: mainWidth attributes: statusAttributes];
349        [statusString drawAtPoint: pen];
350    }
351    else //small size
352    {
353        //icon
354        NSImage * icon = [fTorrent iconSmall];
355        NSSize iconSize = [icon size];
356       
357        pen.x += PADDING;
358        pen.y += (cellFrame.size.height - iconSize.height) * 0.5;
359       
360        [icon drawAtPoint: pen fromRect: NSMakeRect(0, 0, iconSize.width, iconSize.height)
361                operation: NSCompositeSourceOver fraction: 1.0];
362
363        //name and status string
364        float mainWidth = cellFrame.size.width - iconSize.width - 3.0 * PADDING - EXTRA_NAME_SHIFT;
365       
366        NSString * realStatusString = !fStatusRegular && [fTorrent isActive] ? [fTorrent remainingTimeString]
367                                                                            : [fTorrent shortStatusString];
368       
369        NSAttributedString * statusString = [[[NSAttributedString alloc] initWithString: realStatusString
370                                                    attributes: statusAttributes] autorelease];
371        NSAttributedString * nameString = [[fTorrent name] attributedStringFittingInWidth:
372                                mainWidth - [statusString size].width - LINE_PADDING attributes: nameAttributes];
373                     
374        //place name string
375        pen.x += iconSize.width + PADDING + EXTRA_NAME_SHIFT;
376        pen.y = cellFrame.origin.y + LINE_PADDING;
377
378        [nameString drawAtPoint: pen];
379       
380        //place status string
381        pen.x = NSMaxX(cellFrame) - PADDING - [statusString size].width;
382        pen.y += ([nameString size].height - [statusString size].height) * 0.5;
383       
384        [statusString drawAtPoint: pen];
385       
386        //progress bar
387        pen.x = cellFrame.origin.x + iconSize.width + 2.0 * PADDING;
388        pen.y = cellFrame.origin.y + [nameString size].height + LINE_PADDING + PADDING + BAR_HEIGHT;
389       
390        float barWidth = mainWidth + EXTRA_NAME_SHIFT - BUTTONS_TOTAL_WIDTH + PADDING;
391       
392        if ([fDefaults boolForKey: @"UseAdvancedBar"])
393            [self buildAdvancedBar: barWidth point: pen];
394        else
395            [self buildSimpleBar: barWidth point: pen];
396    }
397   
398    [nameAttributes release];
399    [statusAttributes release];
400}
401
402@end
Note: See TracBrowser for help on using the repository browser.