You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

283 lines
11 KiB

/*****************************************************************************
* VLCLibraryWindowToolbarDelegate.m: MacOS X interface module
*****************************************************************************
* Copyright (C) 2023 VLC authors and VideoLAN
*
* Authors: Claudio Cambra <developer@claudiocambra.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#import "VLCLibraryWindowToolbarDelegate.h"
#import "extensions/NSString+Helpers.h"
#import "library/VLCLibraryWindow.h"
#import "library/VLCLibraryWindowSidebarRootViewController.h"
#import "library/VLCLibraryWindowSplitViewController.h"
#import "main/VLCMain.h"
#import "menus/VLCMainMenu.h"
#import "menus/renderers/VLCRendererMenuController.h"
NSString * const VLCLibraryWindowTrackingSeparatorToolbarItemIdentifier =
@"VLCLibraryWindowTrackingSeparatorToolbarItemIdentifier";
@implementation VLCLibraryWindowToolbarDelegate
#pragma mark - XIB handling
- (void)awakeFromNib
{
self.toolbar.allowsUserCustomization = NO;
if (@available(macOS 11.0, *)) {
const NSInteger navSidebarToggleToolbarItemIndex =
[self.toolbar.items indexOfObject:self.toggleNavSidebarToolbarItem];
NSAssert(navSidebarToggleToolbarItemIndex != NSNotFound,
@"Could not find navigation sidebar toggle toolbar item!");
const NSInteger trackingSeparatorItemIndex = navSidebarToggleToolbarItemIndex + 1;
[self.toolbar
insertItemWithItemIdentifier:VLCLibraryWindowTrackingSeparatorToolbarItemIdentifier
atIndex:trackingSeparatorItemIndex];
_trackingSeparatorToolbarItem =
[self.toolbar.items objectAtIndex:trackingSeparatorItemIndex];
}
NSNotificationCenter * const notificationCenter = NSNotificationCenter.defaultCenter;
[notificationCenter addObserver:self
selector:@selector(renderersChanged:)
name:VLCRendererAddedNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(renderersChanged:)
name:VLCRendererRemovedNotification
object:nil];
self.libraryViewModeToolbarItem.toolTip = _NS("Grid View or List View");
self.sortOrderToolbarItem.toolTip = _NS("Select Sorting Mode");
self.togglePlayQueueToolbarItem.toolTip = _NS("Toggle Play Queue");
self.vlcIconToolbarItem.minSize = NSMakeSize(18, 18);
self.vlcIconToolbarItem.maxSize = NSMakeSize(18, 18);
NSImageView * const vlcIconImageView = [[NSImageView alloc] initWithFrame:NSZeroRect];
vlcIconImageView.image = NSApp.applicationIconImage;
self.vlcIconToolbarItem.view = vlcIconImageView;;
// Hide renderers toolbar item at first. Start discoveries and wait for notifications about
// renderers being added or removed to keep hidden or show depending on outcome
[self hideToolbarItem:self.renderersToolbarItem];
[VLCMain.sharedInstance.mainMenu.rendererMenuController startRendererDiscoveries];
[self updatePlayqueueToggleState];
}
#pragma mark - toolbar delegate methods
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier
willBeInsertedIntoToolbar:(BOOL)flag
{
if ([itemIdentifier isEqualToString:VLCLibraryWindowTrackingSeparatorToolbarItemIdentifier]) {
if (@available(macOS 11.0, *)) {
return [NSTrackingSeparatorToolbarItem
trackingSeparatorToolbarItemWithIdentifier:itemIdentifier
splitView:self.libraryWindow.mainSplitView
dividerIndex:VLCLibraryWindowNavigationSidebarSplitViewDividerIndex];
}
}
return nil;
}
#pragma mark - renderers toolbar item handling
- (IBAction)rendererControlAction:(id)sender
{
[NSMenu popUpContextMenu:VLCMain.sharedInstance.mainMenu.rendererMenu
withEvent:NSApp.currentEvent
forView:sender];
}
- (void)renderersChanged:(NSNotification *)notification
{
const NSUInteger rendererCount =
VLCMain.sharedInstance.mainMenu.rendererMenuController.rendererItems.count;
const BOOL rendererToolbarItemVisible =
[self.toolbar.items containsObject:self.renderersToolbarItem];
if (rendererCount > 0 && !rendererToolbarItemVisible) {
[self insertToolbarItem:self.renderersToolbarItem
inFrontOf:@[self.sortOrderToolbarItem,
self.libraryViewModeToolbarItem,
self.forwardsToolbarItem,
self.backwardsToolbarItem]];
} else if (rendererCount == 0 && rendererToolbarItemVisible) {
[self hideToolbarItem:self.renderersToolbarItem];
}
}
#pragma mark - play queue toggle toolbar item handling
- (void)updatePlayqueueToggleState
{
NSView * const multifunctionSidebar =
self.libraryWindow.splitViewController.multifunctionSidebarViewController.view;
NSSplitView * const sv = self.libraryWindow.mainSplitView;
self.libraryWindow.playQueueToggle.state =
![sv.arrangedSubviews containsObject:multifunctionSidebar] ||
[sv isSubviewCollapsed:multifunctionSidebar]
? NSControlStateValueOff
: NSControlStateValueOn;
}
#pragma mark - item visibility handling
- (void)hideToolbarItem:(NSToolbarItem *)toolbarItem
{
const NSInteger toolbarItemIndex = [self.toolbar.items indexOfObject:toolbarItem];
if (toolbarItemIndex != NSNotFound) {
[self.toolbar removeItemAtIndex:toolbarItemIndex];
}
}
/*
* Try to insert the toolbar item ahead of a group of possible toolbar items.
* "items" should contain items sorted from the trailing edge of the toolbar to leading edge.
* "toolbarItem" will be inserted as close to the trailing edge as possible.
*
* If you have: | item1 | item2 | item3 | item4 |
* and the "items" parameter is an array containing @[item6, item5, item2, item1]
* then the "toolbarItem" provided to this function will place toolbarItem thus:
* | item1 | item2 | toolbarItem | item3 | item4 |
*/
- (void)insertToolbarItem:(NSToolbarItem *)toolbarItem inFrontOf:(NSArray<NSToolbarItem *> *)items
{
NSParameterAssert(toolbarItem != nil);
NSParameterAssert(items != nil);
NSParameterAssert(toolbarItem.itemIdentifier.length > 0);
// Build toolbar item index map once to avoid double iteration
NSArray<NSToolbarItem *> * const toolbarItems = self.toolbar.items;
NSMapTable * const itemIndexMap = [NSMapTable strongToStrongObjectsMapTable];
for (NSUInteger i = 0; i < toolbarItems.count; i++) {
[itemIndexMap setObject:@(i) forKey:toolbarItems[i]];
}
NSNumber * const toolbarItemIndexNumber = [itemIndexMap objectForKey:toolbarItem];
if (toolbarItemIndexNumber != nil) {
return;
}
for (NSToolbarItem * const item in items) {
NSNumber * const itemIndexNumber = [itemIndexMap objectForKey:item];
if (itemIndexNumber != nil) {
const NSInteger itemIndex = itemIndexNumber.integerValue;
[self.toolbar insertItemWithItemIdentifier:toolbarItem.itemIdentifier
atIndex:itemIndex + 1];
return;
}
}
[self.toolbar insertItemWithItemIdentifier:toolbarItem.itemIdentifier atIndex:0];
}
#pragma mark - convenience methods for hiding/showing and positioning certain toolbar items
- (void)setForwardsBackwardsToolbarItemsVisible:(BOOL)visible
{
if (!visible) {
[self hideToolbarItem:self.forwardsToolbarItem];
[self hideToolbarItem:self.backwardsToolbarItem];
return;
}
[self insertToolbarItem:self.backwardsToolbarItem
inFrontOf:@[self.trackingSeparatorToolbarItem,
self.toggleNavSidebarToolbarItem,
self.vlcIconToolbarItem]];
[self insertToolbarItem:self.forwardsToolbarItem
inFrontOf:@[self.backwardsToolbarItem,
self.trackingSeparatorToolbarItem,
self.toggleNavSidebarToolbarItem,
self.vlcIconToolbarItem]];
}
- (void)setSortOrderToolbarItemVisible:(BOOL)visible
{
if (!visible) {
[self hideToolbarItem:self.sortOrderToolbarItem];
return;
}
[self insertToolbarItem:self.sortOrderToolbarItem
inFrontOf:@[self.libraryViewModeToolbarItem,
self.forwardsToolbarItem,
self.backwardsToolbarItem,
self.trackingSeparatorToolbarItem,
self.toggleNavSidebarToolbarItem,
self.vlcIconToolbarItem]];
}
- (void)setLibrarySearchToolbarItemVisible:(BOOL)visible
{
if (!visible) {
[self hideToolbarItem:self.librarySearchToolbarItem];
[self.libraryWindow clearFilterString];
return;
}
// Display as far to the right as possible, but not in front of the multifunc bar toggle button
NSMutableArray<NSToolbarItem *> * const currentToolbarItems = self.toolbar.items.mutableCopy;
if (currentToolbarItems.lastObject == self.togglePlayQueueToolbarItem) {
[currentToolbarItems removeLastObject];
}
NSArray * const reversedCurrentToolbarItems =
currentToolbarItems.reverseObjectEnumerator.allObjects;
[self insertToolbarItem:self.librarySearchToolbarItem
inFrontOf:reversedCurrentToolbarItems];
}
- (void)setViewModeToolbarItemVisible:(BOOL)visible
{
if (!visible) {
[self hideToolbarItem:self.libraryViewModeToolbarItem];
return;
}
[self insertToolbarItem:self.libraryViewModeToolbarItem
inFrontOf:@[self.forwardsToolbarItem,
self.backwardsToolbarItem,
self.trackingSeparatorToolbarItem,
self.toggleNavSidebarToolbarItem,
self.vlcIconToolbarItem]];
}
- (void)applyVisiblityFlags:(VLCLibraryWindowToolbarDisplayFlags)flags
{
[self setForwardsBackwardsToolbarItemsVisible:flags & VLCLibraryWindowToolbarDisplayFlagNavigationButtons];
[self setSortOrderToolbarItemVisible:flags & VLCLibraryWindowToolbarDisplayFlagSortOrderButton];
[self setLibrarySearchToolbarItemVisible:flags & VLCLibraryWindowToolbarDisplayFlagLibrarySearchBar];
[self setViewModeToolbarItemVisible:flags & VLCLibraryWindowToolbarDisplayFlagToggleViewModeSegmentButton];
}
@end