1/****************************************************************************** 2 * $Id: PiecesView.m 13251 2012-03-13 02:52:11Z livings124 $ 3 * 4 * Copyright (c) 2006-2012 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 "PiecesView.h" 26#import "Torrent.h" 27#import "InfoWindowController.h" 28 29#import "transmission.h" 30#import "utils.h" 31 32#define MAX_ACROSS 18 33#define BETWEEN 1.0 34 35#define HIGH_PEERS 30 36 37enum 38{ 39 PIECE_NONE, 40 PIECE_SOME, 41 PIECE_HIGH_PEERS, 42 PIECE_FINISHED, 43 PIECE_FLASHING 44}; 45 46@implementation PiecesView 47 48- (void) awakeFromNib 49{ 50 //store box colors 51 fGreenAvailabilityColor = [[NSColor colorWithCalibratedRed: 0.0 green: 1.0 blue: 0.4 alpha: 1.0] retain]; 52 fBluePieceColor = [[NSColor colorWithCalibratedRed: 0.0 green: 0.4 blue: 0.8 alpha: 1.0] retain]; 53 54 //actually draw the box 55 [self setTorrent: nil]; 56} 57 58- (void) dealloc 59{ 60 tr_free(fPieces); 61 62 [fGreenAvailabilityColor release]; 63 [fBluePieceColor release]; 64 65 [super dealloc]; 66} 67 68- (void) setTorrent: (Torrent *) torrent 69{ 70 [self clearView]; 71 72 fTorrent = (torrent && ![torrent isMagnet]) ? torrent : nil; 73 if (fTorrent) 74 { 75 //determine relevant values 76 fNumPieces = MIN([fTorrent pieceCount], MAX_ACROSS * MAX_ACROSS); 77 fAcross = ceil(sqrt(fNumPieces)); 78 79 const CGFloat width = [self bounds].size.width; 80 fWidth = (width - (fAcross + 1) * BETWEEN) / fAcross; 81 fExtraBorder = (width - ((fWidth + BETWEEN) * fAcross + BETWEEN)) / 2; 82 } 83 84 NSImage * back = [[NSImage alloc] initWithSize: [self bounds].size]; 85 [back lockFocus]; 86 87 NSGradient * gradient = [[NSGradient alloc] initWithStartingColor: [NSColor colorWithCalibratedWhite: 0.0 alpha: 0.4] 88 endingColor: [NSColor colorWithCalibratedWhite: 0.2 alpha: 0.4]]; 89 [gradient drawInRect: [self bounds] angle: 90.0]; 90 [gradient release]; 91 [back unlockFocus]; 92 93 [self setImage: back]; 94 [back release]; 95 96 [self setNeedsDisplay]; 97} 98 99- (void) clearView 100{ 101 tr_free(fPieces); 102 fPieces = NULL; 103} 104 105- (void) updateView 106{ 107 if (!fTorrent) 108 return; 109 110 //determine if first time 111 const BOOL first = fPieces == NULL; 112 if (first) 113 fPieces = (int8_t *)tr_malloc(fNumPieces * sizeof(int8_t)); 114 115 int8_t * pieces = NULL; 116 float * piecesPercent = NULL; 117 118 const BOOL showAvailablity = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"]; 119 if (showAvailablity) 120 { 121 pieces = (int8_t *)tr_malloc(fNumPieces * sizeof(int8_t)); 122 [fTorrent getAvailability: pieces size: fNumPieces]; 123 } 124 else 125 { 126 piecesPercent = (float *)tr_malloc(fNumPieces * sizeof(float)); 127 [fTorrent getAmountFinished: piecesPercent size: fNumPieces]; 128 } 129 130 NSImage * image = [self image]; 131 132 NSRect fillRects[fNumPieces]; 133 NSColor * fillColors[fNumPieces]; 134 135 NSInteger usedCount = 0; 136 137 for (NSInteger index = 0; index < fNumPieces; index++) 138 { 139 NSColor * pieceColor = nil; 140 141 if (showAvailablity ? pieces[index] == -1 : piecesPercent[index] == 1.0) 142 { 143 if (first || fPieces[index] != PIECE_FINISHED) 144 { 145 if (!first && fPieces[index] != PIECE_FLASHING) 146 { 147 pieceColor = [NSColor orangeColor]; 148 fPieces[index] = PIECE_FLASHING; 149 } 150 else 151 { 152 pieceColor = fBluePieceColor; 153 fPieces[index] = PIECE_FINISHED; 154 } 155 } 156 } 157 else if (showAvailablity ? pieces[index] == 0 : piecesPercent[index] == 0.0) 158 { 159 if (first || fPieces[index] != PIECE_NONE) 160 { 161 pieceColor = [NSColor whiteColor]; 162 fPieces[index] = PIECE_NONE; 163 } 164 } 165 else if (showAvailablity && pieces[index] >= HIGH_PEERS) 166 { 167 if (first || fPieces[index] != PIECE_HIGH_PEERS) 168 { 169 pieceColor = fGreenAvailabilityColor; 170 fPieces[index] = PIECE_HIGH_PEERS; 171 } 172 } 173 else 174 { 175 //always redraw "mixed" 176 CGFloat percent = showAvailablity ? (CGFloat)pieces[index]/HIGH_PEERS : piecesPercent[index]; 177 NSColor * fullColor = showAvailablity ? fGreenAvailabilityColor : fBluePieceColor; 178 pieceColor = [[NSColor whiteColor] blendedColorWithFraction: percent ofColor: fullColor]; 179 fPieces[index] = PIECE_SOME; 180 } 181 182 if (pieceColor) 183 { 184 const NSInteger across = index % fAcross, 185 down = index / fAcross; 186 fillRects[usedCount] = NSMakeRect(across * (fWidth + BETWEEN) + BETWEEN + fExtraBorder, 187 [image size].width - (down + 1) * (fWidth + BETWEEN) - fExtraBorder, 188 fWidth, fWidth); 189 fillColors[usedCount] = pieceColor; 190 191 usedCount++; 192 } 193 } 194 195 if (usedCount > 0) 196 { 197 [image lockFocus]; 198 NSRectFillListWithColors(fillRects, fillColors, usedCount); 199 [image unlockFocus]; 200 [self setNeedsDisplay]; 201 } 202 203 tr_free(pieces); 204 tr_free(piecesPercent); 205} 206 207- (BOOL) acceptsFirstMouse: (NSEvent *) event 208{ 209 return YES; 210} 211 212- (void) mouseDown: (NSEvent *) event 213{ 214 if (fTorrent) 215 { 216 const BOOL availability = ![[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"]; 217 [[NSUserDefaults standardUserDefaults] setBool: availability forKey: @"PiecesViewShowAvailability"]; 218 219 [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdatePiecesView" object: self]; 220 } 221 222 [super mouseDown: event]; 223} 224 225@end 226