From 9f2a981c8c40fe5dd4326cc1406b990a480872f2 Mon Sep 17 00:00:00 2001 From: SweetPPro Date: Sat, 10 Dec 2022 06:06:00 +1100 Subject: [PATCH] fix: empty tableview rows on macOS (#4333) --- Transmission.xcodeproj/project.pbxproj | 8 +++- macosx/CMakeLists.txt | 1 + macosx/Controller.mm | 3 ++ macosx/GroupTextCell.h | 9 +++++ macosx/GroupTextCell.mm | 32 ++++++++++++++++ macosx/TorrentTableView.mm | 53 +++++++++++++++++++++++++- 6 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 macosx/GroupTextCell.h create mode 100644 macosx/GroupTextCell.mm diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index a77a1f1c6..41eed8fca 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 3C7A11980D0B2EE300B5701F /* getgateway.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C7A11920D0B2EE300B5701F /* getgateway.h */; }; 3C7A11990D0B2EE300B5701F /* natpmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C7A11930D0B2EE300B5701F /* natpmp.c */; }; 3C7A119A0D0B2EE300B5701F /* natpmp.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C7A11940D0B2EE300B5701F /* natpmp.h */; }; + 454BB0562941E8D800F99F38 /* GroupTextCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 454BB0542941E8D800F99F38 /* GroupTextCell.mm */; }; 457AF8EB28604AFC00BCF74F /* Toolbar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 457AF8EA28604AFC00BCF74F /* Toolbar.mm */; }; 45A7D3292843B54D00F0C32A /* GroupPopUpButtonCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45A7D3282843B54D00F0C32A /* GroupPopUpButtonCell.mm */; }; 45A7D32C2843B55F00F0C32A /* PriorityPopUpButtonCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45A7D32B2843B55F00F0C32A /* PriorityPopUpButtonCell.mm */; }; @@ -621,6 +622,8 @@ 3C7A11920D0B2EE300B5701F /* getgateway.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = getgateway.h; sourceTree = ""; }; 3C7A11930D0B2EE300B5701F /* natpmp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = natpmp.c; sourceTree = ""; }; 3C7A11940D0B2EE300B5701F /* natpmp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = natpmp.h; sourceTree = ""; }; + 454BB0542941E8D800F99F38 /* GroupTextCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GroupTextCell.mm; sourceTree = ""; }; + 454BB0552941E8D800F99F38 /* GroupTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupTextCell.h; sourceTree = ""; }; 455C0939287767270003A078 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/PrefsWindow.strings; sourceTree = ""; }; 455C093A287767290003A078 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/PrefsWindow.strings; sourceTree = ""; }; 455C093B2877672C0003A078 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/PrefsWindow.strings; sourceTree = ""; }; @@ -1095,7 +1098,6 @@ BEFC1E1D0C07861A00B0BB3C /* completion.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = completion.cc; sourceTree = ""; }; BEFC1E1E0C07861A00B0BB3C /* clients.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = clients.h; sourceTree = ""; }; BEFC1E1F0C07861A00B0BB3C /* clients.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = clients.cc; sourceTree = ""; }; - C1425B381EE9C805001DB853 /* peer-socket.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-socket.cc"; sourceTree = ""; }; C1033E031A3279B800EF44D8 /* crypto-utils-fallback.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "crypto-utils-fallback.cc"; sourceTree = ""; }; C1033E041A3279B800EF44D8 /* crypto-utils-ccrypto.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "crypto-utils-ccrypto.cc"; sourceTree = ""; }; C1033E051A3279B800EF44D8 /* crypto-utils.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "crypto-utils.cc"; sourceTree = ""; }; @@ -1115,6 +1117,7 @@ C1425B331EE9C5EA001DB85F /* tr-assert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "tr-assert.h"; sourceTree = ""; }; C1425B341EE9C5EA001DB85F /* tr-macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "tr-macros.h"; sourceTree = ""; }; C1425B381EE9C805001DB851 /* peer-socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "peer-socket.h"; sourceTree = ""; }; + C1425B381EE9C805001DB853 /* peer-socket.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "peer-socket.cc"; sourceTree = ""; }; C16089E41F092A1E00CEFC36 /* utp_api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utp_api.cpp; sourceTree = ""; }; C16089E51F092A1E00CEFC36 /* utp_callbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utp_callbacks.cpp; sourceTree = ""; }; C16089E61F092A1E00CEFC36 /* utp_callbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utp_callbacks.h; sourceTree = ""; }; @@ -1414,6 +1417,8 @@ 4D364D9F091FBB2C00377D12 /* TorrentTableView.mm */, 4DCCBB3D09C3D71100D3CABF /* TorrentCell.h */, 4DCCBB3C09C3D71100D3CABF /* TorrentCell.mm */, + 454BB0552941E8D800F99F38 /* GroupTextCell.h */, + 454BB0542941E8D800F99F38 /* GroupTextCell.mm */, A21A9BE0106D86A800F1C3C1 /* TrackerNode.h */, A21A9BE1106D86A800F1C3C1 /* TrackerNode.mm */, A2725B6C0DE5C4F5003445E7 /* FileListNode.h */, @@ -3062,6 +3067,7 @@ A2E57BA713109E6B00A7DAB1 /* FilterBarController.mm in Sources */, A2B5B4E91880665E0071A66A /* ShareTorrentFileHelper.mm in Sources */, A22BAE281388040500FB022F /* NSMutableArrayAdditions.mm in Sources */, + 454BB0562941E8D800F99F38 /* GroupTextCell.mm in Sources */, A2966E8713DAF74C007B52DF /* GlobalOptionsPopoverViewController.mm in Sources */, A234EA541453563B000F3E97 /* NSImageAdditions.mm in Sources */, A2AB883E16A399A6008FAD50 /* VDKQueue.mm in Sources */, diff --git a/macosx/CMakeLists.txt b/macosx/CMakeLists.txt index cf7f7da80..1764aa186 100644 --- a/macosx/CMakeLists.txt +++ b/macosx/CMakeLists.txt @@ -57,6 +57,7 @@ set(${PROJECT_NAME}_SOURCES FilterBarView.mm FilterButton.mm GlobalOptionsPopoverViewController.mm + GroupTextCell.mm GroupToolbarItem.mm GroupsController.mm GroupsPrefsController.mm diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 90365127a..906da93e5 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -5223,6 +5223,9 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool self.fStackViewHeightConstraints = [NSLayoutConstraint constraintsWithVisualFormat:constraintsString options:0 metrics:nil views:views]; + + //redraw table to avoid empty cells + [self.fTableView reloadData]; } //add height constraint to fStackView diff --git a/macosx/GroupTextCell.h b/macosx/GroupTextCell.h new file mode 100644 index 000000000..cce72cd71 --- /dev/null +++ b/macosx/GroupTextCell.h @@ -0,0 +1,9 @@ +// This file Copyright © 2022 Transmission authors and contributors. +// It may be used under the MIT (SPDX: MIT) license. +// License text can be found in the licenses/ folder. + +#import + +@interface GroupTextCell : NSTextFieldCell + +@end diff --git a/macosx/GroupTextCell.mm b/macosx/GroupTextCell.mm new file mode 100644 index 000000000..de57edc86 --- /dev/null +++ b/macosx/GroupTextCell.mm @@ -0,0 +1,32 @@ +// This file Copyright © 2022 Transmission authors and contributors. +// It may be used under the MIT (SPDX: MIT) license. +// License text can be found in the licenses/ folder. + +#import "GroupTextCell.h" +#import "TorrentGroup.h" + +@implementation GroupTextCell + +//vertically align text +- (NSRect)titleRectForBounds:(NSRect)theRect +{ + NSRect titleFrame = [super titleRectForBounds:theRect]; + NSSize titleSize = [[self attributedStringValue] size]; + titleFrame.origin.y = NSMidY(theRect) - (CGFloat)1.0 - titleSize.height * (CGFloat)0.5; + titleFrame.origin.x = theRect.origin.x; + return titleFrame; +} + +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView +{ + //set font size and color + NSRect titleRect = [self titleRectForBounds:cellFrame]; + NSMutableAttributedString* string = [[self attributedStringValue] mutableCopy]; + NSDictionary* attributes = [NSDictionary + dictionaryWithObjects:@[ [NSFont boldSystemFontOfSize:11.0], [NSColor secondaryLabelColor] ] + forKeys:@[ NSFontAttributeName, NSForegroundColorAttributeName ]]; + [string addAttributes:attributes range:NSMakeRange(0, string.length)]; + [string drawInRect:titleRect]; +} + +@end diff --git a/macosx/TorrentTableView.mm b/macosx/TorrentTableView.mm index 8b792032b..509d0a0d5 100644 --- a/macosx/TorrentTableView.mm +++ b/macosx/TorrentTableView.mm @@ -13,6 +13,7 @@ #import "Torrent.h" #import "TorrentCell.h" #import "TorrentGroup.h" +#import "GroupTextCell.h" CGFloat const kGroupSeparatorHeight = 18.0; @@ -38,6 +39,7 @@ static NSTimeInterval const kToggleProgressSeconds = 0.175; @property(nonatomic) IBOutlet Controller* fController; @property(nonatomic) TorrentCell* fTorrentCell; +@property(nonatomic) GroupTextCell* fGroupTextCell; @property(nonatomic, readonly) NSUserDefaults* fDefaults; @@ -73,6 +75,7 @@ static NSTimeInterval const kToggleProgressSeconds = 0.175; _fDefaults = NSUserDefaults.standardUserDefaults; _fTorrentCell = [[TorrentCell alloc] init]; + _fGroupTextCell = [[GroupTextCell alloc] init]; NSData* groupData; if ((groupData = [_fDefaults dataForKey:@"CollapsedGroupIndexes"])) @@ -120,6 +123,9 @@ static NSTimeInterval const kToggleProgressSeconds = 0.175; //set group columns to show ratio, needs to be in awakeFromNib to size columns correctly [self setGroupStatusColumns]; + //disable highlight color and set manually in drawRow + [self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(setNeedsDisplay) name:@"RefreshTorrentTable" object:nil]; } @@ -155,7 +161,9 @@ static NSTimeInterval const kToggleProgressSeconds = 0.175; - (BOOL)outlineView:(NSOutlineView*)outlineView isGroupItem:(id)item { - return ![item isKindOfClass:[Torrent class]]; + //return no and style the groupItem cell manually in willDisplayCell + //otherwise we get unwanted padding before each group header + return NO; } - (CGFloat)outlineView:(NSOutlineView*)outlineView heightOfRowByItem:(id)item @@ -172,7 +180,16 @@ static NSTimeInterval const kToggleProgressSeconds = 0.175; } else { - return group ? [tableColumn dataCellForRow:[self rowForItem:item]] : nil; + NSString* ident = tableColumn.identifier; + NSArray* imageColumns = @[ @"Color", @"DL Image", @"UL Image" ]; + if (![imageColumns containsObject:ident]) + { + return group ? self.fGroupTextCell : nil; + } + else + { + return group ? [tableColumn dataCellForRow:[self rowForItem:item]] : nil; + } } } @@ -197,6 +214,38 @@ static NSTimeInterval const kToggleProgressSeconds = 0.175; } } +//we override row highlighting because we are custom drawing the group rows +//see isGroupItem +- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect +{ + NSColor* highlightColor = nil; + + id item = [self itemAtRow:row]; + + //we only highlight torrent cells + if ([item isKindOfClass:[Torrent class]]) + { + //use system highlight color when Transmission is active + if (self == [self.window firstResponder] && [self.window isMainWindow] && [self.window isKeyWindow]) + { + highlightColor = [NSColor alternateSelectedControlColor]; + } + else + { + highlightColor = [NSColor disabledControlTextColor]; + } + + NSIndexSet* selectedRowIndexes = [self selectedRowIndexes]; + if ([selectedRowIndexes containsIndex:row]) + { + [highlightColor setFill]; + NSRectFill([self rectOfRow:row]); + } + } + + [super drawRow:row clipRect:clipRect]; +} + - (NSRect)frameOfCellAtColumn:(NSInteger)column row:(NSInteger)row { if (column == -1)