From 2b4de1033dcb6f55f0fb10c685d459dc706b3fbe Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Thu, 20 Jan 2022 14:59:26 -0800 Subject: [PATCH] Playlist View: Replace Cell-based table with View-based table. It needs some work still, though. --- Base.lproj/MainMenu.xib | 285 +++++++++++++++++- Cog.xcodeproj/project.pbxproj | 6 - Playlist/PlaylistController.h | 56 ++-- Playlist/PlaylistController.m | 157 +++++++++- Playlist/PlaylistLoader.m | 6 + .../FontSizetoLineHeightTransformer.m | 4 +- 6 files changed, 451 insertions(+), 63 deletions(-) diff --git a/Base.lproj/MainMenu.xib b/Base.lproj/MainMenu.xib index a0eba4f0f..4e61e785d 100644 --- a/Base.lproj/MainMenu.xib +++ b/Base.lproj/MainMenu.xib @@ -32,9 +32,9 @@ - + - + @@ -52,13 +52,32 @@ + + + + + + + + + + + + + + + + + + + + - @@ -70,14 +89,32 @@ - - - - - StatusImageTransformer - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -91,13 +128,32 @@ + + + + + + + + + + + + + + + + + + + + - @@ -153,13 +248,32 @@ + + + + + + + + + + + + + + + + + + + + - @@ -173,6 +287,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -193,6 +327,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -210,6 +364,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -226,6 +400,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -242,6 +436,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -262,6 +476,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -282,6 +516,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -293,6 +547,7 @@ + FontSizetoLineHeightTransformer @@ -317,7 +572,7 @@ - + diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index cf3b6f6c0..a2d043ae3 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -176,7 +176,6 @@ 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 8E07AB790AAC930B00A4B32F /* PreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E07AB770AAC930B00A4B32F /* PreferencesController.m */; }; - 8E1296DB0A2BA9CE00443124 /* PlaylistHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */; }; 8E6889240AAA403C00AD3950 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E6889230AAA403C00AD3950 /* Carbon.framework */; }; 8E75757109F31D5A0080F1EE /* DNDArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75752C09F31D5A0080F1EE /* DNDArrayController.m */; }; 8E75757209F31D5A0080F1EE /* PlaylistController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E75752E09F31D5A0080F1EE /* PlaylistController.m */; }; @@ -1013,8 +1012,6 @@ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8E07AB760AAC930B00A4B32F /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PreferencesController.h; path = Preferences/PreferencesController.h; sourceTree = ""; }; 8E07AB770AAC930B00A4B32F /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = PreferencesController.m; path = Preferences/PreferencesController.m; sourceTree = ""; }; - 8E1296D80A2BA9CE00443124 /* PlaylistHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PlaylistHeaderView.h; sourceTree = ""; }; - 8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PlaylistHeaderView.m; sourceTree = ""; }; 8E6889230AAA403C00AD3950 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; 8E75752B09F31D5A0080F1EE /* DNDArrayController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNDArrayController.h; sourceTree = ""; }; 8E75752C09F31D5A0080F1EE /* DNDArrayController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DNDArrayController.m; sourceTree = ""; }; @@ -1760,8 +1757,6 @@ 8E75752E09F31D5A0080F1EE /* PlaylistController.m */, 8E75753109F31D5A0080F1EE /* PlaylistView.h */, 8E75753209F31D5A0080F1EE /* PlaylistView.m */, - 8E1296D80A2BA9CE00443124 /* PlaylistHeaderView.h */, - 8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */, 1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */, 1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */, 8E75752B09F31D5A0080F1EE /* DNDArrayController.h */, @@ -2442,7 +2437,6 @@ 8E75757309F31D5A0080F1EE /* PlaylistEntry.m in Sources */, 8E75757409F31D5A0080F1EE /* PlaylistView.m in Sources */, 8E75757509F31D5A0080F1EE /* Shuffle.m in Sources */, - 8E1296DB0A2BA9CE00443124 /* PlaylistHeaderView.m in Sources */, 8E07AB790AAC930B00A4B32F /* PreferencesController.m in Sources */, 177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */, 177EC0270B8BC2CF0000BC8C /* TrackingCell.m in Sources */, diff --git a/Playlist/PlaylistController.h b/Playlist/PlaylistController.h index eb1a20436..b753fcfe3 100644 --- a/Playlist/PlaylistController.h +++ b/Playlist/PlaylistController.h @@ -37,6 +37,8 @@ typedef NS_ENUM(NSInteger, URLOrigin) { IBOutlet PlaylistLoader *playlistLoader; IBOutlet SpotlightWindowController *spotlightWindowController; IBOutlet PlaybackController *playbackController; + + NSValueTransformer * statusImageTransformer; NSMutableArray *shuffleList; NSMutableArray *queueList; @@ -48,45 +50,45 @@ typedef NS_ENUM(NSInteger, URLOrigin) { NSUndoManager *undoManager; } -@property(nonatomic, retain) PlaylistEntry *currentEntry; -@property(retain) NSString *totalTime; +@property(nonatomic, retain) PlaylistEntry * _Nullable currentEntry; +@property(retain) NSString * _Nullable totalTime; // Private Methods - (void)updateTotalTime; - (void)updatePlaylistIndexes; -- (IBAction)stopAfterCurrent:(id)sender; +- (IBAction)stopAfterCurrent:(id _Nullable )sender; // PUBLIC METHODS - (void)setShuffle:(ShuffleMode)s; - (ShuffleMode)shuffle; - (void)setRepeat:(RepeatMode)r; - (RepeatMode)repeat; -- (NSArray *)filterPlaylistOnAlbum:(NSString *)album; +- (NSArray * _Nullable)filterPlaylistOnAlbum:(NSString * _Nullable)album; -- (PlaylistEntry *)getNextEntry:(PlaylistEntry *)pe; -- (PlaylistEntry *)getPrevEntry:(PlaylistEntry *)pe; +- (PlaylistEntry * _Nullable)getNextEntry:(PlaylistEntry * _Nullable)pe; +- (PlaylistEntry * _Nullable)getPrevEntry:(PlaylistEntry * _Nullable)pe; /* Methods for undoing various actions */ -- (NSUndoManager *)undoManager; +- (NSUndoManager * _Nullable)undoManager; -- (IBAction)toggleShuffle:(id)sender; +- (IBAction)toggleShuffle:(id _Nullable)sender; -- (IBAction)toggleRepeat:(id)sender; +- (IBAction)toggleRepeat:(id _Nullable)sender; -- (IBAction)randomizeList:(id)sender; +- (IBAction)randomizeList:(id _Nullable)sender; -- (IBAction)removeDuplicates:(id)sender; -- (IBAction)removeDeadItems:(id)sender; +- (IBAction)removeDuplicates:(id _Nullable)sender; +- (IBAction)removeDeadItems:(id _Nullable)sender; -- (IBAction)showEntryInFinder:(id)sender; -- (IBAction)clearFilterPredicate:(id)sender; -- (IBAction)clear:(id)sender; +- (IBAction)showEntryInFinder:(id _Nullable)sender; +- (IBAction)clearFilterPredicate:(id _Nullable)sender; +- (IBAction)clear:(id _Nullable)sender; //- (IBAction)showTagEditor:(id)sender; // Spotlight -- (IBAction)searchByArtist:(id)sender; -- (IBAction)searchByAlbum:(id)sender; +- (IBAction)searchByArtist:(id _Nullable)sender; +- (IBAction)searchByAlbum:(id _Nullable)sender; // FUN PLAYLIST MANAGEMENT STUFF! - (BOOL)next; @@ -96,25 +98,25 @@ typedef NS_ENUM(NSInteger, URLOrigin) { - (void)addShuffledListToFront; - (void)resetShuffleList; -- (PlaylistEntry *)shuffledEntryAtIndex:(NSInteger)i; -- (PlaylistEntry *)entryAtIndex:(NSInteger)i; +- (PlaylistEntry * _Nullable)shuffledEntryAtIndex:(NSInteger)i; +- (PlaylistEntry * _Nullable)entryAtIndex:(NSInteger)i; // Event inlets: -- (void)willInsertURLs:(NSArray *)urls origin:(URLOrigin)origin; -- (void)didInsertURLs:(NSArray *)urls origin:(URLOrigin)origin; +- (void)willInsertURLs:(NSArray * _Nullable)urls origin:(URLOrigin)origin; +- (void)didInsertURLs:(NSArray * _Nullable)urls origin:(URLOrigin)origin; // queue methods -- (IBAction)toggleQueued:(id)sender; -- (IBAction)emptyQueueList:(id)sender; +- (IBAction)toggleQueued:(id _Nullable)sender; +- (IBAction)emptyQueueList:(id _Nullable)sender; - (void)emptyQueueListUnsynced; -- (NSMutableArray *)queueList; +- (NSMutableArray * _Nullable)queueList; // reload metadata of selection -- (IBAction)reloadTags:(id)sender; +- (IBAction)reloadTags:(id _Nullable)sender; -- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet +- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet * _Nullable)indexSet toIndex:(NSUInteger)insertIndex; -- (void)insertObjectsUnsynced:(NSArray *)objects atArrangedObjectIndexes:(NSIndexSet *)indexes; +- (void)insertObjectsUnsynced:(NSArray * _Nullable)objects atArrangedObjectIndexes:(NSIndexSet * _Nullable)indexes; @end diff --git a/Playlist/PlaylistController.m b/Playlist/PlaylistController.m index 461d1c1ee..2841007d7 100644 --- a/Playlist/PlaylistController.m +++ b/Playlist/PlaylistController.m @@ -27,7 +27,13 @@ @synthesize currentEntry; @synthesize totalTime; +static NSArray * cellIdentifiers = nil; + + (void)initialize { + cellIdentifiers = @[@"index", @"status", @"title", @"albumartist", @"artist", + @"album", @"length", @"year", @"genre", @"track", @"path", + @"filename", @"codec"]; + NSValueTransformer *repeatNoneTransformer = [[RepeatModeTransformer alloc] initWithMode:RepeatModeNoRepeat]; [NSValueTransformer setValueTransformer:repeatNoneTransformer forName:@"RepeatNoneTransformer"]; @@ -100,11 +106,14 @@ - (void)awakeFromNib { [super awakeFromNib]; - + + statusImageTransformer = [NSValueTransformer valueTransformerForName:@"StatusImageTransformer"]; + [self addObserver:self forKeyPath:@"arrangedObjects" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil]; + [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.fontSize" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:nil]; } - (void)observeValueForKeyPath:(NSString *)keyPath @@ -115,6 +124,9 @@ [self updatePlaylistIndexes]; [self updateTotalTime]; } + else if ([keyPath isEqualToString:@"values.fontSize"]) { + [self updateRowSize]; + } } static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_block_t block) { @@ -215,19 +227,109 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc } } -- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn { - if ([self shuffle] != ShuffleOff) [self resetShuffleList]; +- (NSView * _Nullable)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn * _Nullable)tableColumn row:(NSInteger)row { + NSImage * cellImage = nil; + NSString * cellText = @""; + NSString * cellIdentifier = @""; + NSTextAlignment cellTextAlignment = NSTextAlignmentLeft; + + PlaylistEntry * pe = [[self arrangedObjects] objectAtIndex:row]; + + float fontSize = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] floatForKey:@"fontSize"]; + + if (pe) { + cellIdentifier = [tableColumn identifier]; + NSUInteger index = [cellIdentifiers indexOfObject:cellIdentifier]; + + switch (index) { + case 0: + cellText = [NSString stringWithFormat:@"%ld", [pe index] + 1]; + cellTextAlignment = NSTextAlignmentRight; + break; + + case 1: + cellImage = [statusImageTransformer transformedValue:[pe status]]; + break; + + case 2: + if ([pe title]) cellText = [pe title]; + break; + + case 3: + if ([pe albumartist]) cellText = [pe albumartist]; + break; + + case 4: + if ([pe artist]) cellText = [pe artist]; + break; + + case 5: + if ([pe album]) cellText = [pe album]; + break; + + case 6: + cellText = [pe lengthText]; + cellTextAlignment = NSTextAlignmentRight; + break; + + case 7: + if ([pe year]) cellText = [NSString stringWithFormat:@"%@", [pe year]]; + cellTextAlignment = NSTextAlignmentRight; + break; + + case 8: + if ([pe genre]) cellText = [pe genre]; + break; + + case 9: + if ([pe track]) cellText = [NSString stringWithFormat:@"%@", [pe track]]; + cellTextAlignment = NSTextAlignmentRight; + break; + + case 10: + if ([pe path]) cellText = [pe path]; + break; + + case 11: + if ([pe filename]) cellText = [pe filename]; + break; + + case 12: + if ([pe codec]) cellText = [pe codec]; + break; + } + } + + NSView * view = [tableView makeViewWithIdentifier:cellIdentifier owner:nil]; + if (view) { + NSTableCellView * cellView = (NSTableCellView *) view; + if (cellView.textField) { + NSFont * font = [NSFont systemFontOfSize:fontSize]; + + cellView.textField.font = font; + cellView.textField.stringValue = cellText; + cellView.textField.alignment = cellTextAlignment; + + if (cellView.textField.intrinsicContentSize.width > cellView.textField.frame.size.width - 8) + cellView.textField.toolTip = cellText; + else + cellView.textField.toolTip = [pe status]; + } + if (cellView.imageView) { + cellView.imageView.image = cellImage; + } + cellView.rowSizeStyle = NSTableViewRowSizeStyleCustom; + } + + return view; } -- (NSString *)tableView:(NSTableView *)tv - toolTipForCell:(NSCell *)cell - rect:(NSRectPointer)rect - tableColumn:(NSTableColumn *)tc - row:(NSInteger)row - mouseLocation:(NSPoint)mouseLocation { - DLog(@"GETTING STATUS FOR ROW: %li: %@!", row, - [[[self arrangedObjects] objectAtIndex:row] statusMessage]); - return [[[self arrangedObjects] objectAtIndex:row] statusMessage]; +- (void)updateRowSize { + [self.tableView reloadData]; +} + +- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn { + if ([self shuffle] != ShuffleOff) [self resetShuffleList]; } - (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet @@ -865,6 +967,13 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc pe.current = YES; + NSMutableIndexSet * refreshSet = [[NSMutableIndexSet alloc] init]; + + if (currentEntry != nil) [refreshSet addIndex:currentEntry.index]; + if (pe != nil) [refreshSet addIndex:pe.index]; + + [self.tableView reloadDataForRowIndexes:refreshSet columnIndexes:[NSIndexSet indexSetWithIndex:1]]; + if (pe != nil) [self.tableView scrollRowToVisible:pe.index]; currentEntry = pe; @@ -957,6 +1066,8 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc - (IBAction)toggleQueued:(id)sender { SQLiteStore *store = [SQLiteStore sharedStore]; + NSMutableIndexSet * refreshSet = [[NSMutableIndexSet alloc] init]; + for (PlaylistEntry *queueItem in [self selectedObjects]) { if (queueItem.queued) { queueItem.queued = NO; @@ -964,7 +1075,7 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc [queueList removeObject:queueItem]; - [store queueRemovePlaylistItems:@[queueItem]]; + [store queueRemovePlaylistItems:@[[NSNumber numberWithInteger:[queueItem index]]]]; } else { queueItem.queued = YES; queueItem.queuePosition = (int) [queueList count]; @@ -974,9 +1085,13 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc [store queueAddItem:[queueItem index]]; } + [refreshSet addIndex:[queueItem index]]; + DLog(@"TOGGLE QUEUED: %i", queueItem.queued); } + [self.tableView reloadDataForRowIndexes:refreshSet columnIndexes:[NSIndexSet indexSetWithIndex:1]]; + int i = 0; for (PlaylistEntry *cur in queueList) { cur.queuePosition = i++; @@ -986,14 +1101,20 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc - (IBAction)removeFromQueue:(id)sender { SQLiteStore *store = [SQLiteStore sharedStore]; + NSMutableIndexSet * refreshSet = [[NSMutableIndexSet alloc] init]; + for (PlaylistEntry *queueItem in [self selectedObjects]) { queueItem.queued = NO; queueItem.queuePosition = -1; [queueList removeObject:queueItem]; [store queueRemovePlaylistItems:@[queueItem]]; + + [refreshSet addIndex:[queueItem index]]; } + [self.tableView reloadDataForRowIndexes:refreshSet columnIndexes:[NSIndexSet indexSetWithIndex:1]]; + int i = 0; for (PlaylistEntry *cur in queueList) { cur.queuePosition = i++; @@ -1002,6 +1123,8 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc - (IBAction)addToQueue:(id)sender { SQLiteStore *store = [SQLiteStore sharedStore]; + + NSMutableIndexSet * refreshSet = [[NSMutableIndexSet alloc] init]; for (PlaylistEntry *queueItem in [self selectedObjects]) { queueItem.queued = YES; @@ -1009,8 +1132,12 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc [queueList addObject:queueItem]; [store queueAddItem:[queueItem index]]; + + [refreshSet addIndex:[queueItem index]]; } + [self.tableView reloadDataForRowIndexes:refreshSet columnIndexes:[NSIndexSet indexSetWithIndex:1]]; + int i = 0; for (PlaylistEntry *cur in queueList) { cur.queuePosition = i++; @@ -1019,6 +1146,10 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc - (IBAction)stopAfterCurrent:(id)sender { currentEntry.stopAfter = !currentEntry.stopAfter; + + NSIndexSet * refreshSet = [NSIndexSet indexSetWithIndex:[currentEntry index]]; + + [self.tableView reloadDataForRowIndexes:refreshSet columnIndexes:[NSIndexSet indexSetWithIndex:1]]; } - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { diff --git a/Playlist/PlaylistLoader.m b/Playlist/PlaylistLoader.m index 5cf7d05f4..f79282ede 100755 --- a/Playlist/PlaylistLoader.m +++ b/Playlist/PlaylistLoader.m @@ -762,6 +762,8 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc if (count) { + NSMutableIndexSet * refreshSet = [[NSMutableIndexSet alloc] init]; + [playlistController emptyQueueListUnsynced]; for (i = 0; i < count; ++i) @@ -772,7 +774,11 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc pe.queued = YES; [[playlistController queueList] addObject:pe]; + + [refreshSet addIndex:[pe index]]; } + + [playlistView.documentView reloadDataForRowIndexes:refreshSet columnIndexes:[NSIndexSet indexSetWithIndex:1]]; } //Clear the selection diff --git a/Transformers/FontSizetoLineHeightTransformer.m b/Transformers/FontSizetoLineHeightTransformer.m index 9e3eeb3f6..b5cf1b908 100644 --- a/Transformers/FontSizetoLineHeightTransformer.m +++ b/Transformers/FontSizetoLineHeightTransformer.m @@ -17,8 +17,8 @@ // Convert from font size to height in playlist view - (id)transformedValue:(id)value { NSFont *font = [NSFont systemFontOfSize:[(NSNumber *)value floatValue]]; - NSLayoutManager *layoutManager = [[NSLayoutManager alloc]init]; - float fRowSize = [layoutManager defaultLineHeightForFont:font]; + NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; + float fRowSize = [layoutManager defaultLineHeightForFont:font] * 1.2; return [NSNumber numberWithFloat: fRowSize]; }