source: trunk/macosx/TorrentCell.m @ 639

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

Sort by Progress (and therefore State) will now sort completed torrents by ratio.
Added license info to ImageBackgroundView?.
Use system control text color for main font color rather than black.

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