refactor: remove vector from pieces view (#4587)

This commit is contained in:
Charles Kerr 2023-01-17 09:10:23 -06:00 committed by GitHub
parent e4c5981545
commit 74c8248237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 127 additions and 130 deletions

View File

@ -2,10 +2,7 @@
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#include <vector>
#include <libtransmission/transmission.h>
#include <libtransmission/utils.h>
#import "PiecesView.h"
#import "Torrent.h"
@ -13,31 +10,96 @@
#import "NSApplicationAdditions.h"
static NSInteger const kMaxAcross = 18;
static NSInteger const kMaxCells = kMaxAcross * kMaxAcross;
static CGFloat const kBetweenPadding = 1.0;
static int8_t const kHighPeers = 10;
enum
static NSColor* const DoneColor = NSColor.systemBlueColor;
static NSColor* const BlinkColor = NSColor.systemOrangeColor;
static NSColor* const HighColor = NSColor.systemGreenColor; // high availability
typedef struct PieceInfo
{
PIECE_NONE,
PIECE_SOME,
PIECE_HIGH_PEERS,
PIECE_FINISHED,
PIECE_FLASHING
};
int8_t available[kMaxCells];
float complete[kMaxCells];
} PieceInfo;
@interface PiecesView ()
@property(nonatomic) std::vector<int8_t> fPieces;
@property(nonatomic) NSInteger fNumPieces;
@property(nonatomic) NSInteger fAcross;
@property(nonatomic) NSInteger fWidth;
@property(nonatomic) NSInteger fExtraBorder;
@end
@implementation PiecesView
{
PieceInfo fPieceInfo;
NSString* fRenderedHashString;
}
- (NSColor*)backgroundColor
{
return NSApp.darkMode ? NSColor.blackColor : NSColor.whiteColor;
}
- (BOOL)isCompletenessDone:(float)val
{
return val >= 1.0F;
}
- (BOOL)isCompletenessNone:(float)val
{
return val <= 0.0F;
}
- (NSColor*)completenessColor:(float)oldVal newVal:(float)newVal noBlink:(BOOL)noBlink
{
if ([self isCompletenessDone:newVal])
{
return noBlink || [self isCompletenessDone:oldVal] ? DoneColor : BlinkColor;
}
if ([self isCompletenessNone:newVal])
{
return noBlink || [self isCompletenessNone:oldVal] ? [self backgroundColor] : BlinkColor;
}
return [[self backgroundColor] blendedColorWithFraction:newVal ofColor:DoneColor];
}
- (BOOL)isAvailabilityDone:(uint8_t)val
{
return val == (uint8_t)-1;
}
- (BOOL)isAvailabilityNone:(uint8_t)val
{
return val == 0;
}
- (BOOL)isAvailabilityHigh:(uint8_t)val
{
return val >= kHighPeers;
}
- (NSColor*)availabilityColor:(int8_t)oldVal newVal:(int8_t)newVal noBlink:(bool)noBlink
{
if ([self isAvailabilityDone:newVal])
{
return noBlink || [self isAvailabilityDone:oldVal] ? DoneColor : BlinkColor;
}
if ([self isAvailabilityNone:newVal])
{
return noBlink || [self isAvailabilityNone:oldVal] ? [self backgroundColor] : BlinkColor;
}
if ([self isAvailabilityHigh:newVal])
{
return noBlink || [self isAvailabilityHigh:oldVal] ? HighColor : BlinkColor;
}
CGFloat percent = CGFloat(newVal) / kHighPeers;
return [[self backgroundColor] blendedColorWithFraction:percent ofColor:HighColor];
}
- (void)drawRect:(NSRect)dirtyRect
{
@ -63,29 +125,17 @@ enum
- (void)setTorrent:(Torrent*)torrent
{
[self clearView];
_torrent = (torrent && !torrent.magnet) ? torrent : nil;
if (_torrent)
{
//determine relevant values
_fNumPieces = MIN(_torrent.pieceCount, kMaxAcross * kMaxAcross);
_fAcross = static_cast<NSInteger>(ceil(sqrt(_fNumPieces)));
CGFloat const width = self.bounds.size.width;
_fWidth = static_cast<NSInteger>((width - (_fAcross + 1) * kBetweenPadding) / _fAcross);
_fExtraBorder = static_cast<NSInteger>((width - ((_fWidth + kBetweenPadding) * _fAcross + kBetweenPadding)) / 2);
}
NSImage* back = [[NSImage alloc] initWithSize:self.bounds.size];
self.image = back;
self.image = [[NSImage alloc] initWithSize:self.bounds.size];
[self clearView];
[self setNeedsDisplay];
}
- (void)clearView
{
self.fPieces.clear();
fRenderedHashString = nil;
memset(&fPieceInfo, 0, sizeof(PieceInfo));
}
- (void)updateView
@ -95,116 +145,63 @@ enum
return;
}
NSInteger numPieces = self.fNumPieces;
//determine if first time
BOOL const first = std::empty(self.fPieces);
if (first)
{
_fPieces.resize(numPieces);
}
auto pieces = std::vector<int8_t>{};
auto piecesPercent = std::vector<float>{};
// get the previous state
PieceInfo const oldInfo = fPieceInfo;
BOOL const first = ![self.torrent.hashString isEqualToString:fRenderedHashString];
// get the current state
BOOL const showAvailability = [NSUserDefaults.standardUserDefaults boolForKey:@"PiecesViewShowAvailability"];
if (showAvailability)
NSInteger const numCells = MIN(_torrent.pieceCount, kMaxCells);
PieceInfo info;
[self.torrent getAvailability:info.available size:numCells];
[self.torrent getAmountFinished:info.complete size:numCells];
// compute bounds and color of each cell
NSInteger const across = (NSInteger)ceil(sqrt(numCells));
CGFloat const fullWidth = self.bounds.size.width;
NSInteger const cellWidth = (NSInteger)((fullWidth - (across + 1) * kBetweenPadding) / across);
NSInteger const extraBorder = (NSInteger)((fullWidth - ((cellWidth + kBetweenPadding) * across + kBetweenPadding)) / 2);
NSMutableArray<NSValue*>* cellBounds = [NSMutableArray arrayWithCapacity:numCells];
NSMutableArray<NSColor*>* cellColors = [NSMutableArray arrayWithCapacity:numCells];
for (NSInteger index = 0; index < numCells; index++)
{
pieces.resize(numPieces);
[self.torrent getAvailability:std::data(pieces) size:std::size(pieces)];
}
else
{
piecesPercent.resize(numPieces);
[self.torrent getAmountFinished:std::data(piecesPercent) size:std::size(piecesPercent)];
NSInteger const row = index / across;
NSInteger const col = index % across;
cellBounds[index] = [NSValue valueWithRect:NSMakeRect(
col * (cellWidth + kBetweenPadding) + kBetweenPadding + extraBorder,
fullWidth - (row + 1) * (cellWidth + kBetweenPadding) - extraBorder,
cellWidth,
cellWidth)];
cellColors[index] = showAvailability ?
[self availabilityColor:oldInfo.available[index] newVal:info.available[index] noBlink:first] :
[self completenessColor:oldInfo.complete[index] newVal:info.complete[index] noBlink:first];
}
NSMutableArray<NSValue*>* fillRects = [NSMutableArray arrayWithCapacity:numPieces];
NSMutableArray<NSColor*>* fillColors = [NSMutableArray arrayWithCapacity:numPieces];
NSColor* defaultColor = NSApp.darkMode ? NSColor.blackColor : NSColor.whiteColor;
NSInteger usedCount = 0;
for (NSInteger index = 0; index < numPieces; index++)
// build an image with the cells
if (numCells > 0)
{
NSColor* pieceColor = nil;
if (showAvailability ? pieces[index] == -1 : piecesPercent[index] == 1.0)
{
if (first || self.fPieces[index] != PIECE_FINISHED)
self.image = [NSImage imageWithSize:self.bounds.size flipped:NO drawingHandler:^BOOL(NSRect /*dstRect*/) {
NSRect cFillRects[numCells];
for (NSInteger i = 0; i < numCells; ++i)
{
if (!first && self.fPieces[index] != PIECE_FLASHING)
{
pieceColor = NSColor.systemOrangeColor;
self.fPieces[index] = PIECE_FLASHING;
}
else
{
pieceColor = NSColor.systemBlueColor;
self.fPieces[index] = PIECE_FINISHED;
}
cFillRects[i] = cellBounds[i].rectValue;
}
}
else if (showAvailability ? pieces[index] == 0 : piecesPercent[index] == 0.0)
{
if (first || self.fPieces[index] != PIECE_NONE)
NSColor* cFillColors[numCells];
for (NSInteger i = 0; i < numCells; ++i)
{
pieceColor = defaultColor;
self.fPieces[index] = PIECE_NONE;
cFillColors[i] = cellColors[i];
}
}
else if (showAvailability && pieces[index] >= kHighPeers)
{
if (first || self.fPieces[index] != PIECE_HIGH_PEERS)
{
pieceColor = NSColor.systemGreenColor;
self.fPieces[index] = PIECE_HIGH_PEERS;
}
}
else
{
//always redraw "mixed"
CGFloat percent = showAvailability ? (CGFloat)pieces[index] / kHighPeers : piecesPercent[index];
NSColor* fullColor = showAvailability ? NSColor.systemGreenColor : NSColor.systemBlueColor;
pieceColor = [defaultColor blendedColorWithFraction:percent ofColor:fullColor];
self.fPieces[index] = PIECE_SOME;
}
if (pieceColor)
{
NSInteger const across = index % self.fAcross;
NSInteger const down = index / self.fAcross;
fillRects[usedCount] = [NSValue
valueWithRect:NSMakeRect(
across * (self.fWidth + kBetweenPadding) + kBetweenPadding + self.fExtraBorder,
self.bounds.size.width - (down + 1) * (self.fWidth + kBetweenPadding) - self.fExtraBorder,
self.fWidth,
self.fWidth)];
fillColors[usedCount] = pieceColor;
usedCount++;
}
}
if (usedCount > 0)
{
self.image = [NSImage imageWithSize:self.bounds.size flipped:NO drawingHandler:^BOOL(NSRect dstRect) {
NSRect cFillRects[usedCount];
for (NSInteger i = 0; i < usedCount; ++i)
{
cFillRects[i] = fillRects[i].rectValue;
}
NSColor* cFillColors[usedCount];
for (NSInteger i = 0; i < usedCount; ++i)
{
cFillColors[i] = fillColors[i];
}
NSRectFillListWithColors(cFillRects, cFillColors, usedCount);
NSRectFillListWithColors(cFillRects, cFillColors, numCells);
return YES;
}];
[self setNeedsDisplay];
}
// save the current state so we can compare it later
fPieceInfo = info;
fRenderedHashString = self.torrent.hashString;
}
- (BOOL)acceptsFirstMouse:(NSEvent*)event