Ticket #2352: ProgressFlash-Selfcontained.diff

File ProgressFlash-Selfcontained.diff, 12.8 KB (added by mortennorby, 13 years ago)
  • PiecesView.h

     
    2929@interface PiecesView : NSImageView
    3030{
    3131    int8_t  * fPieces;
     32        float   * fPrevPiecesPercent;
    3233   
    3334    NSColor * fGreenAvailabilityColor, * fBluePieceColor;
     35        NSColor * fPercentProgressColor0, * fPercentProgressColor1;
    3436   
    3537    Torrent * fTorrent;
    3638    NSInteger fNumPieces, fAcross, fWidth, fExtraBorder;
     39               
     40        BOOL      prevShowAvailability;
     41        NSDate  * prevRunDate;
    3742}
    3843
    3944- (void) setTorrent: (Torrent *) torrent;
     
    4146- (void) clearView;
    4247- (void) updateView;
    4348
     49- (void) resamplePiecesPercentOriginalSet: (float *)unsampledPiecesPercent count: (int) pieceCount newSet:  (float *) piecesPercent count: (int) tabCount;
     50- (void) resamplePiecesOriginalSet: (int8_t *)unsampledPieces count: (int) pieceCount newSet:  (int8_t *) tab count: (int) tabCount;
     51
    4452@end
  • PiecesView.m

     
    3838    PIECE_SOME,
    3939    PIECE_HIGH_PEERS,
    4040    PIECE_FINISHED,
    41     PIECE_FLASHING
     41    PIECE_FLASHING_COMPLETION,
     42        PIECE_FLASHING_PROGRESS_0,
     43        PIECE_FLASHING_PROGRESS_1
    4244};
    4345
     46
    4447@implementation PiecesView
    4548
    4649- (void) awakeFromNib
     
    4952    fGreenAvailabilityColor = [[NSColor colorWithCalibratedRed: 0.0 green: 1.0 blue: 0.4 alpha: 1.0] retain];
    5053    fBluePieceColor = [[NSColor colorWithCalibratedRed: 0.0 green: 0.4 blue: 0.8 alpha: 1.0] retain];
    5154   
     55    //store box colors for the yellow flash on progress
     56        fPercentProgressColor0 = [[NSColor colorWithCalibratedRed: 0.900f green: 0.900f blue: 0.165f alpha: 1.0f] retain];
     57        fPercentProgressColor1 = [[NSColor colorWithCalibratedRed: 0.925f green: 0.925f blue: 0.171f alpha: 1.0f] retain];     
     58       
    5259    //actually draw the box
    5360    [self setTorrent: nil];
    5461}
     
    5966   
    6067    [fGreenAvailabilityColor release];
    6168    [fBluePieceColor release];
    62    
     69        [fPercentProgressColor0 release];
     70    [fPercentProgressColor1 release];
     71 
    6372    [super dealloc];
    6473}
    6574
     
    97106- (void) clearView
    98107{
    99108    tr_free(fPieces);
     109        tr_free(fPrevPiecesPercent);
    100110    fPieces = NULL;
     111        fPrevPiecesPercent = NULL;
    101112}
    102113
    103114- (void) updateView
    104115{
    105116    if (!fTorrent)
    106117        return;
    107    
    108     //determine if first time
    109     const BOOL first = fPieces == NULL;
    110     if (first)
    111         fPieces = (int8_t *)tr_malloc(fNumPieces * sizeof(int8_t));
    112 
    113     int8_t * pieces = NULL;
    114     float * piecesPercent = NULL;
    115    
    116     const BOOL showAvailablity = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"];
    117     if (showAvailablity)
     118                   
     119    int8_t * pieces = NULL, * unsampledPieces = NULL;
     120    float * piecesPercent = NULL, * unsampledPiecesPercent = NULL;
     121           
     122    BOOL showAvailablity = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"];
     123       
     124        if (showAvailablity)
    118125    {   
    119         pieces = (int8_t *)tr_malloc(fNumPieces * sizeof(int8_t));
    120         [fTorrent getAvailability: pieces size: fNumPieces];
     126                unsampledPieces = (int8_t *)tr_malloc([fTorrent pieceCount] * sizeof(int8_t));
     127                pieces = (int8_t *)tr_malloc(fNumPieces * sizeof(int8_t));
     128                [fTorrent getAvailability: unsampledPieces size: [fTorrent pieceCount]];
     129               
     130                [self resamplePiecesOriginalSet: unsampledPieces count: [fTorrent pieceCount] newSet: pieces count: fNumPieces];
    121131    }
    122132    else
    123133    {   
    124         piecesPercent = (float *)tr_malloc(fNumPieces * sizeof(float));
    125         [fTorrent getAmountFinished: piecesPercent size: fNumPieces];
     134                unsampledPiecesPercent = (float *)tr_malloc([fTorrent pieceCount] * sizeof(float));
     135                piecesPercent = (float *)tr_malloc(fNumPieces * sizeof(float));
     136                [fTorrent getAmountFinished: unsampledPiecesPercent size: [fTorrent pieceCount]];
     137               
     138                [self resamplePiecesPercentOriginalSet: unsampledPiecesPercent count: [fTorrent pieceCount] newSet: piecesPercent count: fNumPieces];
    126139    }
    127140   
     141    //determine if first time
     142    const BOOL first = fPieces == NULL;
     143    if (first) {
     144        fPieces = (int8_t *)tr_malloc(fNumPieces * sizeof(int8_t));
     145                fPrevPiecesPercent = (float *)tr_malloc(fNumPieces * sizeof(float));
     146        }
     147
     148        if ( first || !showAvailablity && prevShowAvailability  ) {
     149                // First run after switching view from availability to progress
     150                // (or first run altogether) so previous pieces are set to 200%
     151                // to avoid a huge flash of yellow.
     152                for ( int i = 0; i < fNumPieces; i++ ) {
     153                        fPrevPiecesPercent[i] = 2.0f;
     154                }
     155        }
     156       
    128157    NSImage * image = [self image];
    129158   
    130159    NSRect fillRects[fNumPieces];
     
    134163   
    135164    for (NSInteger index = 0; index < fNumPieces; index++)
    136165    {
    137         NSColor * pieceColor = nil;
    138        
    139         if (showAvailablity ? pieces[index] == -1 : piecesPercent[index] == 1.0)
    140         {
    141             if (first || fPieces[index] != PIECE_FINISHED)
    142             {
    143                 if (!first && fPieces[index] != PIECE_FLASHING)
    144                 {
    145                     pieceColor = [NSColor orangeColor];
    146                     fPieces[index] = PIECE_FLASHING;
    147                 }
    148                 else
    149                 {
    150                     pieceColor = fBluePieceColor;
    151                     fPieces[index] = PIECE_FINISHED;
    152                 }
    153             }
    154         }
    155         else if (showAvailablity ? pieces[index] == 0 : piecesPercent[index] == 0.0)
    156         {
    157             if (first || fPieces[index] != PIECE_NONE)
    158             {
    159                 pieceColor = [NSColor whiteColor];
    160                 fPieces[index] = PIECE_NONE;
    161             }
    162         }
    163         else if (showAvailablity && pieces[index] >= HIGH_PEERS)
    164         {
    165             if (first || fPieces[index] != PIECE_HIGH_PEERS)
    166             {
    167                 pieceColor = fGreenAvailabilityColor;
    168                 fPieces[index] = PIECE_HIGH_PEERS;
    169             }
    170         }
    171         else
    172         {
    173             //always redraw "mixed"
    174             CGFloat percent = showAvailablity ? (CGFloat)pieces[index]/HIGH_PEERS : piecesPercent[index];
    175             NSColor * fullColor = showAvailablity ? fGreenAvailabilityColor : fBluePieceColor;
    176             pieceColor = [[NSColor whiteColor] blendedColorWithFraction: percent ofColor: fullColor];
    177             fPieces[index] = PIECE_SOME;
    178         }
    179        
    180         if (pieceColor)
    181         {
    182             const NSInteger across = index % fAcross,
    183                             down = index / fAcross;
    184             fillRects[usedCount] = NSMakeRect(across * (fWidth + BETWEEN) + BETWEEN + fExtraBorder,
    185                                                 [image size].width - (down + 1) * (fWidth + BETWEEN) - fExtraBorder,
    186                                                 fWidth, fWidth);
    187             fillColors[usedCount] = pieceColor;
    188            
    189             usedCount++;
    190         }
    191     }
    192    
    193     if (usedCount > 0)
    194     {
    195         [image lockFocus];
    196         NSRectFillListWithColors(fillRects, fillColors, usedCount);
    197         [image unlockFocus];
    198         [self setNeedsDisplay];
    199     }
    200    
     166                NSColor * pieceColor = nil;
     167               
     168                if (showAvailablity ? pieces[index] == -1 : piecesPercent[index] == 1.0)
     169                {
     170                        if (first || fPieces[index] != PIECE_FINISHED)
     171                        {
     172                                if (!first && fPieces[index] != PIECE_FLASHING_COMPLETION)
     173                                {
     174                                        pieceColor = [NSColor orangeColor];
     175                                        fPieces[index] = PIECE_FLASHING_COMPLETION;
     176                                }
     177                                else
     178                                {
     179                                        pieceColor = fBluePieceColor;
     180                                        fPieces[index] = PIECE_FINISHED;
     181                                }
     182                        }
     183                }
     184                else if (showAvailablity ? pieces[index] == 0 : piecesPercent[index] == 0.0)
     185                {
     186                        if (first || fPieces[index] != PIECE_NONE)
     187                        {
     188                                pieceColor = [NSColor whiteColor];
     189                                fPieces[index] = PIECE_NONE;
     190                        }
     191                }
     192                else if ( !showAvailablity && ( piecesPercent[index] > fPrevPiecesPercent[index] ) )
     193                {               
     194                        // There is progress compared to the previous run - show it!
     195                        if ( fPieces[index] == PIECE_FLASHING_PROGRESS_1 ) {
     196                                pieceColor = fPercentProgressColor0;
     197                                fPieces[index] = PIECE_FLASHING_PROGRESS_0;
     198                        }
     199                        else {
     200                                pieceColor = fPercentProgressColor1;
     201                                fPieces[index] = PIECE_FLASHING_PROGRESS_1;
     202                        }                               
     203                }
     204                else if (showAvailablity && pieces[index] >= HIGH_PEERS)
     205                {
     206                        if (first || fPieces[index] != PIECE_HIGH_PEERS)
     207                        {
     208                                pieceColor = fGreenAvailabilityColor;
     209                                fPieces[index] = PIECE_HIGH_PEERS;
     210                        }
     211                }
     212                else
     213                {
     214                        //always redraw "mixed"
     215                        CGFloat percent = showAvailablity ? (CGFloat)pieces[index]/HIGH_PEERS : piecesPercent[index];
     216                        NSColor * fullColor = showAvailablity ? fGreenAvailabilityColor : fBluePieceColor;
     217                        pieceColor = [[NSColor whiteColor] blendedColorWithFraction: percent ofColor: fullColor];
     218                        fPieces[index] = PIECE_SOME;
     219                }
     220               
     221               
     222                if (pieceColor)
     223                {
     224                        const NSInteger across = index % fAcross,
     225                        down = index / fAcross;
     226                        fillRects[usedCount] = NSMakeRect(across * (fWidth + BETWEEN) + BETWEEN + fExtraBorder,
     227                                                                                          [image size].width - (down + 1) * (fWidth + BETWEEN) - fExtraBorder,
     228                                                                                          fWidth, fWidth);
     229                        fillColors[usedCount] = pieceColor;
     230                       
     231                        usedCount++;   
     232                }
     233        }
     234       
     235        if (usedCount > 0)
     236        {
     237                [image lockFocus];
     238                NSRectFillListWithColors(fillRects, fillColors, usedCount);
     239                [image unlockFocus];
     240                [self setNeedsDisplay];
     241        }       
     242       
     243        if ( !showAvailablity ) {
     244                memcpy(fPrevPiecesPercent,  piecesPercent, fNumPieces * sizeof(float));
     245        }
     246       
    201247    tr_free(pieces);
    202248    tr_free(piecesPercent);
     249        tr_free(unsampledPieces);
     250        tr_free(unsampledPiecesPercent);
     251       
     252        prevShowAvailability = showAvailablity;
    203253}
    204254
     255- (void) resamplePiecesPercentOriginalSet: (float *)unsampledPiecesPercent count: (int) pieceCount newSet:  (float *) piecesPercent count: (int) tabCount
     256{       
     257    for( int i = 0; i < tabCount; ++i )
     258    {
     259                int first_piece = pieceCount * i / tabCount;
     260                float first_piece_fract = 1.0f - ((float)pieceCount * i / tabCount - first_piece );
     261               
     262                int last_piece;
     263                float last_piece_fract;
     264                if ( pieceCount * ( i + 1 ) % tabCount ) {
     265                        last_piece = pieceCount * ( i + 1 ) / tabCount;
     266                        last_piece_fract = ((float)pieceCount * (i + 1) / tabCount -  last_piece );
     267                }
     268                else {
     269                        // Handle boundary cases, for instance the last piece of the torrent
     270                        last_piece = pieceCount * ( i + 1 ) / tabCount - 1;
     271                        last_piece_fract = 1.0f;
     272                }
     273               
     274               
     275                float sum = 0.0f, avg;
     276               
     277                // The flag complete is used to keep track of the interval. If
     278                // all pieces in the interval are complete, the downsampled
     279                // value is set to exactly 1.0f to avoid rounding errors.
     280                BOOL complete = TRUE;
     281               
     282                if ( first_piece == last_piece ) {
     283                        avg =  unsampledPiecesPercent[first_piece];
     284                        complete = ( avg == 1.0f );
     285                }
     286                else {
     287
     288                        sum += unsampledPiecesPercent[first_piece] * first_piece_fract;
     289                        complete &= (unsampledPiecesPercent[first_piece] == 1.0f);
     290                       
     291                        sum += unsampledPiecesPercent[last_piece] * last_piece_fract;
     292                        complete &= (unsampledPiecesPercent[last_piece] == 1.0f);
     293                       
     294                        for ( int j = first_piece + 1; j < last_piece; j++ ) {
     295                                sum += unsampledPiecesPercent[j];
     296                                complete &= (unsampledPiecesPercent[j] == 1.0f);
     297                        }
     298                       
     299                        avg = sum * tabCount / pieceCount;
     300                }
     301               
     302                piecesPercent[i] = complete ? 1.0f : avg;
     303    }
     304}
     305
     306- (void) resamplePiecesOriginalSet: (int8_t *)unsampledPieces count: (int) pieceCount newSet:  (int8_t *) tab count: (int) tabCount
     307{
     308    for( int i = 0; i < tabCount; ++i )
     309    {                   
     310                int first_piece = pieceCount * i / tabCount;
     311                float first_piece_fract = 1.0f - ((float)pieceCount * i / tabCount - first_piece );
     312               
     313                int last_piece;
     314                float last_piece_fract;
     315                if ( pieceCount * ( i + 1 ) % tabCount ) {
     316                        last_piece = pieceCount * ( i + 1 ) / tabCount;
     317                        last_piece_fract = ((float)pieceCount * (i + 1) / tabCount -  last_piece );
     318                }
     319                else {
     320                        // Handle boundary cases, for instance the last piece of the torrent
     321                        last_piece = pieceCount * ( i + 1 ) / tabCount - 1;
     322                        last_piece_fract = 1.0f;
     323                }
     324
     325                float sum = 0.0f, result;
     326               
     327                if ( first_piece == last_piece ) {
     328                        if ( unsampledPieces[first_piece] != -1 ) {
     329                                result = unsampledPieces[first_piece];
     330                        }
     331                        else {
     332                                result = -1;
     333                        }
     334                }
     335                else {
     336                        float incompleteCount = 0.0f;
     337                       
     338                        if ( unsampledPieces[first_piece] != -1 )
     339                        {       
     340                                sum += unsampledPieces[first_piece] * first_piece_fract;
     341                                incompleteCount += first_piece_fract;
     342                        }
     343                       
     344                        if ( unsampledPieces[last_piece] != -1 )
     345                        {       
     346                                sum += unsampledPieces[last_piece] * last_piece_fract;
     347                                incompleteCount += last_piece_fract;
     348                        }
     349                       
     350                        int j;
     351                        for ( j = first_piece + 1; j < last_piece; j++ ) {
     352                                if ( unsampledPieces[j] != -1 )
     353                                {       
     354                                        sum += unsampledPieces[j];
     355                                        incompleteCount += 1.0f;
     356                                }
     357                        }
     358                       
     359                        if ( incompleteCount > 0 ) {
     360                                result = sum / incompleteCount;
     361                        }
     362                        else {
     363                                result = -1;
     364                        }
     365                }
     366               
     367                tab[i] = (int)result;
     368    }
     369}
     370
    205371- (BOOL) acceptsFirstMouse: (NSEvent *) event
    206372{
    207373    return YES;