...
 
Commits (12)
......@@ -57,8 +57,6 @@
1C3113F11E508C7600D4DD76 /* VLCRendererItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BBBB8B11D10A994001BD9BA /* VLCRendererItem.m */; };
1C3113F31E508C7600D4DD76 /* VLCRendererMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BBBB8A81D108A17001BD9BA /* VLCRendererMenuController.m */; };
1C3114031E508C8800D4DD76 /* AppleRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = CC6D8D9D0A878DED006F2BBE /* AppleRemote.m */; };
1C3114051E508C8800D4DD76 /* SideBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = CCCDDEF013E870BB00A35661 /* SideBarItem.m */; };
1C3114071E508C8800D4DD76 /* PXSourceList.m in Sources */ = {isa = PBXBuildFile; fileRef = CC0CD0E013DE0EAE00B0D90D /* PXSourceList.m */; };
1C31140B1E508C8800D4DD76 /* SPInvocationGrabbing.m in Sources */ = {isa = PBXBuildFile; fileRef = CCF0777A13659A8000AF19FD /* SPInvocationGrabbing.m */; };
1C31140D1E508C8800D4DD76 /* SPMediaKeyTap.m in Sources */ = {isa = PBXBuildFile; fileRef = CCF0777C13659A8000AF19FD /* SPMediaKeyTap.m */; };
1C5716AC1F5B142200678627 /* coreaudio_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C5716AB1F5B142200678627 /* coreaudio_common.c */; };
......@@ -412,6 +410,7 @@
7DB40D2920CBCEB500F63173 /* VLCMainMenu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCMainMenu.m; sourceTree = "<group>"; };
7DB40D2B20CBCEC200F63173 /* VLCStatusBarIcon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCStatusBarIcon.m; sourceTree = "<group>"; };
7DB40D2C20CBCEC200F63173 /* VLCStatusBarIcon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCStatusBarIcon.h; sourceTree = "<group>"; };
7DB5D7E820CD851F00326DFE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../../../../build/share/macosx/Info.plist; sourceTree = "<group>"; };
7DB65D5218ABD6380053B874 /* VLCAddonsWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCAddonsWindowController.h; sourceTree = "<group>"; };
7DB65D5318ABD6380053B874 /* VLCAddonsWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCAddonsWindowController.m; sourceTree = "<group>"; };
7DB7F1EB20CC036D00C2CAED /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
......@@ -464,10 +463,6 @@
8ED6C28603E2EB1C0059A3A7 /* prefs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = prefs.m; sourceTree = "<group>"; };
CC0663341566C34C003A411C /* VLCConvertAndSaveWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VLCConvertAndSaveWindowController.h; sourceTree = "<group>"; };
CC0663351566C34C003A411C /* VLCConvertAndSaveWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = VLCConvertAndSaveWindowController.m; sourceTree = "<group>"; };
CC0CD0DF13DE0EAE00B0D90D /* PXSourceList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PXSourceList.h; sourceTree = "<group>"; };
CC0CD0E013DE0EAE00B0D90D /* PXSourceList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PXSourceList.m; sourceTree = "<group>"; };
CC0CD0E113DE0EAE00B0D90D /* PXSourceListDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PXSourceListDataSource.h; sourceTree = "<group>"; };
CC0CD0E213DE0EAE00B0D90D /* PXSourceListDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PXSourceListDelegate.h; sourceTree = "<group>"; };
CC1941240B9C1F8400635F6B /* QTKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QTKit.framework; path = /System/Library/Frameworks/QTKit.framework; sourceTree = "<absolute>"; };
CC269A4615E7947F00F2FDC9 /* VLCStringUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCStringUtility.h; sourceTree = "<group>"; };
CC269A4715E7947F00F2FDC9 /* VLCStringUtility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCStringUtility.m; sourceTree = "<group>"; };
......@@ -501,8 +496,6 @@
CCBE999E0F922C51000705F8 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
CCCCDCA01413E1C000FE3DE1 /* VLCVoutView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCVoutView.h; sourceTree = "<group>"; };
CCCCDCA11413E1C000FE3DE1 /* VLCVoutView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCVoutView.m; sourceTree = "<group>"; };
CCCDDEEF13E870BB00A35661 /* SideBarItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SideBarItem.h; sourceTree = "<group>"; };
CCCDDEF013E870BB00A35661 /* SideBarItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SideBarItem.m; sourceTree = "<group>"; };
CCCE366D13817E4500694F2A /* VLCVideoEffectsWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCVideoEffectsWindowController.h; sourceTree = "<group>"; };
CCCE366E13817E4500694F2A /* VLCVideoEffectsWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = VLCVideoEffectsWindowController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
CCDBA3B313D32E200006127B /* macosx.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = macosx.m; path = ../../../modules/video_output/macosx.m; sourceTree = "<group>"; };
......@@ -584,6 +577,7 @@
6B822A031E4D2DEB00833BE1 /* README */,
6B8229FF1E4D2DD100833BE1 /* vlc.scriptSuite */,
6B822A001E4D2DD100833BE1 /* vlc.scriptTerminology */,
7DB5D7E820CD851F00326DFE /* Info.plist */,
);
name = Resources;
path = ../../../modules/gui/macosx/Resources;
......@@ -1335,24 +1329,10 @@
name = "UI Graphics";
sourceTree = "<group>";
};
CC0CD0E413DE0EB500B0D90D /* PXSourceList */ = {
isa = PBXGroup;
children = (
CCCDDEEF13E870BB00A35661 /* SideBarItem.h */,
CCCDDEF013E870BB00A35661 /* SideBarItem.m */,
CC0CD0DF13DE0EAE00B0D90D /* PXSourceList.h */,
CC0CD0E013DE0EAE00B0D90D /* PXSourceList.m */,
CC0CD0E113DE0EAE00B0D90D /* PXSourceListDataSource.h */,
CC0CD0E213DE0EAE00B0D90D /* PXSourceListDelegate.h */,
);
name = PXSourceList;
sourceTree = "<group>";
};
CC0CD0E513DE0FC600B0D90D /* Imported Code */ = {
isa = PBXGroup;
children = (
6B8223FD1E4D29F100833BE1 /* Apple Remote */,
CC0CD0E413DE0EB500B0D90D /* PXSourceList */,
CC78DA4A13DE0E0100E9603C /* SPMediaKeyTap */,
);
name = "Imported Code";
......@@ -1551,10 +1531,8 @@
6B4D50901E79781F004479B5 /* VLCHotkeyChangeWindow.m in Sources */,
1C3114031E508C8800D4DD76 /* AppleRemote.m in Sources */,
1CFE8D591EA0D42A00E94451 /* VLCErrorWindowController.m in Sources */,
1C3114051E508C8800D4DD76 /* SideBarItem.m in Sources */,
6B4D50961E7A7D16004479B5 /* NSSound+VLCAdditions.m in Sources */,
6BF093F91EE0182B0049D8B0 /* VLCTimeField.m in Sources */,
1C3114071E508C8800D4DD76 /* PXSourceList.m in Sources */,
1C31140B1E508C8800D4DD76 /* SPInvocationGrabbing.m in Sources */,
1C31140D1E508C8800D4DD76 /* SPMediaKeyTap.m in Sources */,
1C3113EF1E508C7600D4DD76 /* VLCRendererDiscovery.m in Sources */,
......@@ -1653,8 +1631,7 @@
../../../build/,
../../../modules/codec/,
);
LD_RUNPATH_SEARCH_PATHS = "";
MACOSX_DEPLOYMENT_TARGET = 10.10;
INFOPLIST_FILE = "$(SRCROOT)/../../../build/share/macosx/Info.plist";
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"-lvlccore",
......@@ -1689,8 +1666,7 @@
../../../build/,
../../../modules/codec/,
);
LD_RUNPATH_SEARCH_PATHS = "";
MACOSX_DEPLOYMENT_TARGET = 10.10;
INFOPLIST_FILE = "$(SRCROOT)/../../../build/share/macosx/Info.plist";
OTHER_LDFLAGS = (
"-lvlccore",
"-framework",
......@@ -1724,8 +1700,7 @@
../../../build/,
../../../modules/codec/,
);
LD_RUNPATH_SEARCH_PATHS = "";
MACOSX_DEPLOYMENT_TARGET = 10.10;
INFOPLIST_FILE = "$(SRCROOT)/../../../build/share/macosx/Info.plist";
OTHER_LDFLAGS = (
"-lvlccore",
"-framework",
......
......@@ -48,9 +48,6 @@ libmacosx_plugin_la_SOURCES = \
gui/macosx/VLCPLModel.h gui/macosx/VLCPLModel.m \
gui/macosx/prefs.h gui/macosx/prefs.m \
gui/macosx/prefs_widgets.h gui/macosx/prefs_widgets.m \
gui/macosx/PXSourceList.h gui/macosx/PXSourceList.m \
gui/macosx/PXSourceListDataSource.h gui/macosx/PXSourceListDelegate.h \
gui/macosx/SideBarItem.h gui/macosx/SideBarItem.m \
gui/macosx/VLCPopupPanelController.h gui/macosx/VLCPopupPanelController.m \
gui/macosx/VLCTextfieldPanelController.h gui/macosx/VLCTextfieldPanelController.m \
gui/macosx/VLCSimplePrefsController.h gui/macosx/VLCSimplePrefsController.m \
......
//
// PXSourceList.h
// PXSourceList
//
// Created by Alex Rozanski on 05/09/2009.
// Copyright 2009-10 Alex Rozanski http://perspx.com
//
#import <Cocoa/Cocoa.h>
#import "PXSourceListDelegate.h"
#import "PXSourceListDataSource.h"
@interface PXSourceList: NSOutlineView <NSOutlineViewDelegate, NSOutlineViewDataSource>
{
id <PXSourceListDelegate> _secondaryDelegate; //Used to store the publicly visible delegate
id <PXSourceListDataSource> _secondaryDataSource; //Used to store the publicly visible data source
}
@property (nonatomic) NSSize iconSize;
@property (assign) id<PXSourceListDataSource, NSOutlineViewDataSource> _Nullable dataSource;
@property (assign) id<PXSourceListDelegate, NSOutlineViewDelegate> _Nullable delegate;
- (NSUInteger)numberOfGroups; //Returns the number of groups in the Source List
- (BOOL)isGroupItem:(nonnull id)item; //Returns whether `item` is a group
- (BOOL)isGroupAlwaysExpanded:(nonnull id)group; //Returns whether `group` is displayed as always expanded
- (BOOL)itemHasBadge:(nonnull id)item; //Returns whether `item` has a badge
- (NSInteger)badgeValueForItem:(nonnull id)item; //Returns the badge value for `item`
@end
//
// PXSourceList.m
// PXSourceList
//
// Created by Alex Rozanski on 05/09/2009.
// Copyright 2009-10 Alex Rozanski http://perspx.com
//
// GC-enabled code revised by Stefan Vogt http://byteproject.net
//
#import "CompatibilityFixes.h"
#import "PXSourceList.h"
#import "SideBarItem.h"
//Layout constants
#define MIN_BADGE_WIDTH 22.0 //The minimum badge width for each item (default 22.0)
#define BADGE_HEIGHT 14.0 //The badge height for each item (default 14.0)
#define BADGE_MARGIN 5.0 //The spacing between the badge and the cell for that row
#define ROW_RIGHT_MARGIN 5.0 //The spacing between the right edge of the badge and the edge of the table column
#define ICON_SPACING 2.0 //The spacing between the icon and it's adjacent cell
#define DISCLOSURE_TRIANGLE_SPACE 18.0 //The indentation reserved for disclosure triangles for non-group items
//Drawing constants
#define BADGE_BACKGROUND_COLOR [NSColor colorWithCalibratedRed:(152/255.0) green:(168/255.0) blue:(202/255.0) alpha:1]
#define BADGE_HIDDEN_BACKGROUND_COLOR [NSColor colorWithDeviceWhite:(180/255.0) alpha:1]
#define BADGE_SELECTED_TEXT_COLOR [NSColor keyboardFocusIndicatorColor]
#define BADGE_SELECTED_UNFOCUSED_TEXT_COLOR [NSColor colorWithCalibratedRed:(153/255.0) green:(169/255.0) blue:(203/255.0) alpha:1]
#define BADGE_SELECTED_HIDDEN_TEXT_COLOR [NSColor colorWithCalibratedWhite:(170/255.0) alpha:1]
#define BADGE_FONT [NSFont boldSystemFontOfSize:11]
//Delegate notification constants
NSString * const PXSLSelectionIsChangingNotification = @"PXSourceListSelectionIsChanging";
NSString * const PXSLSelectionDidChangeNotification = @"PXSourceListSelectionDidChange";
NSString * const PXSLItemWillExpandNotification = @"PXSourceListItemWillExpand";
NSString * const PXSLItemDidExpandNotification = @"PXSourceListItemDidExpand";
NSString * const PXSLItemWillCollapseNotification = @"PXSourceListItemWillCollapse";
NSString * const PXSLItemDidCollapseNotification = @"PXSourceListItemDidCollapse";
NSString * const PXSLDeleteKeyPressedOnRowsNotification = @"PXSourceListDeleteKeyPressedOnRows";
#pragma mark -
@interface PXSourceList ()
- (NSSize)sizeOfBadgeAtRow:(NSInteger)rowIndex;
- (void)drawBadgeForRow:(NSInteger)rowIndex inRect:(NSRect)badgeFrame;
- (void)registerDelegateToReceiveNotification:(NSString*)notification withSelector:(SEL)selector;
@end
#pragma mark -
@implementation PXSourceList
@dynamic dataSource;
@dynamic delegate;
#pragma mark Init/Dealloc/Finalize
- (id)initWithCoder:(NSCoder*)decoder
{
if(self=[super initWithCoder:decoder])
{
[self setDelegate:(id<PXSourceListDelegate, NSOutlineViewDelegate>)[super delegate]];
[super setDelegate:self];
[self setDataSource:(id<PXSourceListDataSource, NSOutlineViewDataSource>)[super dataSource]];
[super setDataSource:self];
_iconSize = NSMakeSize(16,16);
}
return self;
}
- (void)dealloc
{
//Unregister the delegate from receiving notifications
[[NSNotificationCenter defaultCenter] removeObserver:_secondaryDelegate];
}
#pragma mark -
#pragma mark Custom Accessors
- (void)setDelegate:(id<PXSourceListDelegate>)aDelegate
{
//Unregister the old delegate from receiving notifications
[[NSNotificationCenter defaultCenter] removeObserver:_secondaryDelegate name:nil object:self];
_secondaryDelegate = aDelegate;
//Register the new delegate to receive notifications
[self registerDelegateToReceiveNotification:PXSLSelectionIsChangingNotification withSelector:@selector(sourceListSelectionIsChanging:)];
[self registerDelegateToReceiveNotification:PXSLSelectionDidChangeNotification withSelector:@selector(sourceListSelectionDidChange:)];
[self registerDelegateToReceiveNotification:PXSLItemWillExpandNotification withSelector:@selector(sourceListItemWillExpand:)];
[self registerDelegateToReceiveNotification:PXSLItemDidExpandNotification withSelector:@selector(sourceListItemDidExpand:)];
[self registerDelegateToReceiveNotification:PXSLItemWillCollapseNotification withSelector:@selector(sourceListItemWillCollapse:)];
[self registerDelegateToReceiveNotification:PXSLItemDidCollapseNotification withSelector:@selector(sourceListItemDidCollapse:)];
[self registerDelegateToReceiveNotification:PXSLDeleteKeyPressedOnRowsNotification withSelector:@selector(sourceListDeleteKeyPressedOnRows:)];
}
- (void)setDataSource:(id<PXSourceListDataSource>)aDataSource
{
_secondaryDataSource = aDataSource;
if ([self respondsToSelector:@selector(reloadData)])
[self reloadData];
}
- (void)setIconSize:(NSSize)newIconSize
{
_iconSize = newIconSize;
CGFloat rowHeight = [self rowHeight];
//Make sure icon height does not exceed row height; if so constrain, keeping width and height in proportion
if(_iconSize.height>rowHeight)
{
_iconSize.width = _iconSize.width * (rowHeight/_iconSize.height);
_iconSize.height = rowHeight;
}
}
#pragma mark -
#pragma mark Data Management
- (void)reloadData
{
if ([super respondsToSelector:@selector(reloadData)])
[super reloadData];
//Expand items that are displayed as always expanded
if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)] &&
[_secondaryDelegate respondsToSelector:@selector(sourceList:isGroupAlwaysExpanded:)])
{
for(NSUInteger i=0;i<[self numberOfGroups];i++)
{
id item = [_secondaryDataSource sourceList:self child:i ofItem:nil];
if([self isGroupAlwaysExpanded:item]) {
[self expandItem:item expandChildren:NO];
}
}
}
//If there are selected rows and the item hierarchy has changed, make sure a Group row isn't
//selected
if([self numberOfSelectedRows]>0) {
NSIndexSet *selectedIndexes = [self selectedRowIndexes];
NSUInteger firstSelectedRow = [selectedIndexes firstIndex];
//Is a group item selected?
if([self isGroupItem:[self itemAtRow:firstSelectedRow]]) {
//Work backwards to find the first non-group row
BOOL foundRow = NO;
for(NSUInteger i=firstSelectedRow;i>0;i--)
{
if(![self isGroupItem:[self itemAtRow:i]]) {
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];
foundRow = YES;
break;
}
}
//If there is no non-group row preceding the currently selected group item, remove the selection
//from the Source List
if(!foundRow) {
[self deselectAll:self];
}
}
}
else if(![self allowsEmptySelection]&&[self numberOfSelectedRows]==0)
{
//Select the first non-group row if no rows are selected, and empty selection is disallowed
for(NSUInteger i=0;i<[self numberOfRows];i++)
{
if(![self isGroupItem:[self itemAtRow:i]]) {
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];
break;
}
}
}
}
- (NSUInteger)numberOfGroups
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:numberOfChildrenOfItem:)]) {
return [_secondaryDataSource sourceList:self numberOfChildrenOfItem:nil];
}
return 0;
}
- (BOOL)isGroupItem:(id)item
{
//Groups are defined as root items (at level 0)
return 0==[self levelForItem:item];
}
- (BOOL)isGroupAlwaysExpanded:(id)group
{
//Make sure that the item IS a group to prevent unwanted queries sent to the data source
if([self isGroupItem:group]) {
//Query the data source
if([_secondaryDelegate respondsToSelector:@selector(sourceList:isGroupAlwaysExpanded:)]) {
return [_secondaryDelegate sourceList:self isGroupAlwaysExpanded:group];
}
}
return NO;
}
- (BOOL)itemHasBadge:(id)item
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:itemHasBadge:)]) {
return [_secondaryDataSource sourceList:self itemHasBadge:item];
}
return NO;
}
- (NSInteger)badgeValueForItem:(id)item
{
//Make sure that the item has a badge
if(![self itemHasBadge:item]) {
return NSNotFound;
}
if([_secondaryDataSource respondsToSelector:@selector(sourceList:badgeValueForItem:)]) {
return [_secondaryDataSource sourceList:self badgeValueForItem:item];
}
return NSNotFound;
}
#pragma mark -
#pragma mark Selection Handling
- (void)selectRowIndexes:(NSIndexSet*)indexes byExtendingSelection:(BOOL)extend
{
NSUInteger numberOfIndexes = [indexes count];
//Prevent empty selection if we don't want it
if(![self allowsEmptySelection]&&0==numberOfIndexes) {
return;
}
//Would use blocks but we're also targeting 10.5...
//Get the selected indexes
NSUInteger *selectedIndexes = malloc(sizeof(NSUInteger)*numberOfIndexes);
[indexes getIndexes:selectedIndexes maxCount:numberOfIndexes inIndexRange:nil];
//Loop through the indexes and only add non-group row indexes
//Allows selection across groups without selecting the group rows
NSMutableIndexSet *newSelectionIndexes = [NSMutableIndexSet indexSet];
for(NSInteger i=0;i<numberOfIndexes;i++)
{
if(![self isGroupItem:[self itemAtRow:selectedIndexes[i]]]) {
[newSelectionIndexes addIndex:selectedIndexes[i]];
}
}
//If there are any non-group rows selected
if([newSelectionIndexes count]>0) {
[super selectRowIndexes:newSelectionIndexes byExtendingSelection:extend];
}
//C memory management... *sigh*
free(selectedIndexes);
}
#pragma mark -
#pragma mark Layout
- (NSRect)frameOfOutlineCellAtRow:(NSInteger)row
{
//Return a zero-rect if the item is always expanded (a disclosure triangle will not be drawn)
if([self isGroupAlwaysExpanded:[self itemAtRow:row]]) {
return NSZeroRect;
}
return [super frameOfOutlineCellAtRow:row];
}
- (NSRect)frameOfCellAtColumn:(NSInteger)column row:(NSInteger)row
{
id item = [self itemAtRow:row];
NSCell *cell = [self preparedCellAtColumn:column row:row];
NSSize cellSize = [cell cellSize];
if (!([cell type] == NSImageCellType) && !([cell type] == NSTextCellType))
cellSize = [cell cellSizeForBounds:[super frameOfCellAtColumn:column row:row]];
NSRect cellFrame = [super frameOfCellAtColumn:column row:row];
NSRect rowRect = [self rectOfRow:row];
if([self isGroupItem:item])
{
CGFloat minX = NSMinX(cellFrame);
//Set the origin x-coord; if there are no children of the group at current, there will still be a
//margin to the left of the cell (in cellFrame), which we don't want
if([self isGroupAlwaysExpanded:[self itemAtRow:row]]) {
minX = 7;
}
return NSMakeRect(minX, NSMidY(cellFrame)-(cellSize.height/2.0), NSWidth(rowRect)-minX, cellSize.height);
}
else
{
CGFloat leftIndent = ([self levelForRow:row] -1)*[self indentationPerLevel]+DISCLOSURE_TRIANGLE_SPACE;
//Calculate space left for a badge if need be
CGFloat rightIndent = [self sizeOfBadgeAtRow:row].width+ROW_RIGHT_MARGIN;
//Allow space for an icon if need be
if(![self isGroupItem:item]&&[_secondaryDataSource respondsToSelector:@selector(sourceList:itemHasIcon:)])
{
if([_secondaryDataSource sourceList:self itemHasIcon:item]) {
leftIndent += [self iconSize].width+(ICON_SPACING*2);
}
}
return NSMakeRect(leftIndent, NSMidY(rowRect)-(cellSize.height/2.0), NSWidth(rowRect)-rightIndent-leftIndent, cellSize.height);
}
}
//This method calculates and returns the size of the badge for the row index passed to the method. If the
//row for the row index passed to the method does not have a badge, then NSZeroSize is returned.
- (NSSize)sizeOfBadgeAtRow:(NSInteger)rowIndex
{
id rowItem = [self itemAtRow:rowIndex];
//Make sure that the item has a badge
if(![self itemHasBadge:rowItem]) {
return NSZeroSize;
}
NSAttributedString *badgeAttrString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%ld", [self badgeValueForItem:rowItem]] attributes:[NSDictionary dictionaryWithObjectsAndKeys:BADGE_FONT, NSFontAttributeName, nil]];
NSSize stringSize = [badgeAttrString size];
//Calculate the width needed to display the text or the minimum width if it's smaller
CGFloat width = stringSize.width+(2*BADGE_MARGIN);
if(width<MIN_BADGE_WIDTH) {
width = MIN_BADGE_WIDTH;
}
return NSMakeSize(width, BADGE_HEIGHT);
}
#pragma mark -
#pragma mark Drawing
- (void)drawRow:(NSInteger)rowIndex clipRect:(NSRect)clipRect
{
[super drawRow:rowIndex clipRect:clipRect];
id item = [self itemAtRow:rowIndex];
//Draw an icon if the item has one
if(![self isGroupItem:item]&&[_secondaryDataSource respondsToSelector:@selector(sourceList:itemHasIcon:)])
{
if([_secondaryDataSource sourceList:self itemHasIcon:item])
{
NSRect cellFrame = [self frameOfCellAtColumn:0 row:rowIndex];
NSSize iconSize = [self iconSize];
NSRect iconRect = NSMakeRect(NSMinX(cellFrame)-iconSize.width-ICON_SPACING, NSMidY(cellFrame)-(iconSize.width/2.0f), iconSize.width, iconSize.height);
if([_secondaryDataSource respondsToSelector:@selector(sourceList:iconForItem:)])
{
NSImage *icon = [_secondaryDataSource sourceList:self iconForItem:item];
if(icon!=nil)
{
NSSize actualIconSize = [icon size];
//If the icon is *smaller* than the size retrieved from the -iconSize property, make sure we
//reduce the size of the rectangle to draw the icon in, so that it is not stretched.
if((actualIconSize.width<iconSize.width)||(actualIconSize.height<iconSize.height))
{
iconRect = NSMakeRect(NSMidX(iconRect)-(actualIconSize.width/2.0f), NSMidY(iconRect)-(actualIconSize.height/2.0f), actualIconSize.width, actualIconSize.height);
}
[icon drawInRect:iconRect
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1
respectFlipped:YES hints:nil];
}
}
}
}
//Draw the badge if the item has one
if([self itemHasBadge:item])
{
NSRect rowRect = [self rectOfRow:rowIndex];
NSSize badgeSize = [self sizeOfBadgeAtRow:rowIndex];
NSRect badgeFrame = NSMakeRect(NSMaxX(rowRect)-badgeSize.width-ROW_RIGHT_MARGIN,
NSMidY(rowRect)-(badgeSize.height/2.0),
badgeSize.width,
badgeSize.height);
[self drawBadgeForRow:rowIndex inRect:badgeFrame];
}
}
- (void)drawBadgeForRow:(NSInteger)rowIndex inRect:(NSRect)badgeFrame
{
id rowItem = [self itemAtRow:rowIndex];
NSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeFrame
xRadius:(BADGE_HEIGHT/2.0)
yRadius:(BADGE_HEIGHT/2.0)];
//Get window and control state to determine colours used
BOOL isVisible = [[NSApp mainWindow] isVisible];
BOOL isFocused = [[[self window] firstResponder] isEqual:self];
NSInteger rowBeingEdited = [self editedRow];
//Set the attributes based on the row state
NSDictionary *attributes;
NSColor *backgroundColor;
if([[self selectedRowIndexes] containsIndex:rowIndex])
{
backgroundColor = [NSColor whiteColor];
//Set the text color based on window and control state
NSColor *textColor;
if(isVisible && (isFocused || rowBeingEdited==rowIndex)) {
textColor = BADGE_SELECTED_TEXT_COLOR;
}
else if(isVisible && !isFocused) {
textColor = BADGE_SELECTED_UNFOCUSED_TEXT_COLOR;
}
else {
textColor = BADGE_SELECTED_HIDDEN_TEXT_COLOR;
}
attributes = [[NSDictionary alloc] initWithObjectsAndKeys:BADGE_FONT, NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil];
}
else
{
//Set the text colour based on window and control state
NSColor *badgeColor = [NSColor whiteColor];
if(isVisible) {
//If the data source returns a custom colour..
if([_secondaryDataSource respondsToSelector:@selector(sourceList:badgeBackgroundColorForItem:)]) {
backgroundColor = [_secondaryDataSource sourceList:self badgeBackgroundColorForItem:rowItem];
if(backgroundColor==nil)
backgroundColor = BADGE_BACKGROUND_COLOR;
}
else { //Otherwise use the default (purple-blue colour)
backgroundColor = BADGE_BACKGROUND_COLOR;
}
//If the delegate wants a custom badge text colour..
if([_secondaryDataSource respondsToSelector:@selector(sourceList:badgeTextColorForItem:)]) {
badgeColor = [_secondaryDataSource sourceList:self badgeTextColorForItem:rowItem];
if(badgeColor==nil)
badgeColor = [NSColor whiteColor];
}
}
else { //Gray colour
backgroundColor = BADGE_HIDDEN_BACKGROUND_COLOR;
}
attributes = [[NSDictionary alloc] initWithObjectsAndKeys:BADGE_FONT, NSFontAttributeName, badgeColor, NSForegroundColorAttributeName, nil];
}
[backgroundColor set];
[badgePath fill];
//Draw the badge text
NSAttributedString *badgeAttrString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%ld", [self badgeValueForItem:rowItem]] attributes:attributes];
NSSize stringSize = [badgeAttrString size];
NSPoint badgeTextPoint = NSMakePoint(NSMidX(badgeFrame)-(stringSize.width/2.0), //Center in the badge frame
NSMidY(badgeFrame)-(stringSize.height/2.0)); //Center in the badge frame
[badgeAttrString drawAtPoint:badgeTextPoint];
}
#pragma mark -
#pragma mark Keyboard Handling
- (void)keyDown:(NSEvent *)theEvent
{
NSIndexSet *selectedIndexes = [self selectedRowIndexes];
NSString *keyCharacters = [theEvent characters];
//Make sure we have a selection
if([selectedIndexes count]>0)
{
if([keyCharacters length]>0)
{
unichar firstKey = [keyCharacters characterAtIndex:0];
if(firstKey==NSUpArrowFunctionKey||firstKey==NSDownArrowFunctionKey)
{
//Handle keyboard navigation across groups
if([selectedIndexes count]==1&&!([theEvent modifierFlags] & NSShiftKeyMask))
{
int delta = firstKey==NSDownArrowFunctionKey?1:-1;
//Search "backwards" if up arrow, "forwards" if down
NSInteger newRow = [selectedIndexes firstIndex];
//Keep incrementing/decrementing the row until a non-header row is reached
do {
newRow+=delta;
//If out of bounds of the number of rows..
if(newRow<0||newRow==[self numberOfRows])
break;
} while([self isGroupItem:[self itemAtRow:newRow]]);
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
return;
}
}
else if(firstKey==NSDeleteCharacter||firstKey==NSBackspaceCharacter)
{
//Post the notification
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLDeleteKeyPressedOnRowsNotification object:self userInfo:[NSDictionary dictionaryWithObject:selectedIndexes forKey:@"rows"]];
return;
}
}
}
//We don't care about it
[super keyDown:theEvent];
}
#pragma mark -
#pragma mark Menu Handling
- (NSMenu *)menuForEvent:(NSEvent *)theEvent
{
NSMenu * m = nil;
if([_secondaryDelegate respondsToSelector:@selector(sourceList:menuForEvent:item:)]) {
NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
NSInteger row = [self rowAtPoint:clickPoint];
id clickedItem = [self itemAtRow:row];
if ([clickedItem sdtype] > 0)
m = [_secondaryDelegate sourceList:self menuForEvent:theEvent item:clickedItem];
else
m = [super menuForEvent:theEvent];
}
if (m == nil) {
m = [super menuForEvent:theEvent];
}
return m;
}
#pragma mark -
#pragma mark NSOutlineView Data Source methods
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
return [_secondaryDataSource sourceList:self numberOfChildrenOfItem:item];
}
return 0;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
return [_secondaryDataSource sourceList:self child:index ofItem:item];
}
return nil;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
return [_secondaryDataSource sourceList:self isItemExpandable:item];
}
return NO;
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
return [_secondaryDataSource sourceList:self objectValueForItem:item];
}
return nil;
}
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
[_secondaryDataSource sourceList:self setObjectValue:object forItem:item];
}
}
- (id)outlineView:(NSOutlineView *)outlineView itemForPersistentObject:(id)object
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:itemForPersistentObject:)]) {
return [_secondaryDataSource sourceList:self itemForPersistentObject:object];
}
return nil;
}
- (id)outlineView:(NSOutlineView *)outlineView persistentObjectForItem:(id)item
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:persistentObjectForItem:)]) {
return [_secondaryDataSource sourceList:self persistentObjectForItem:item];
}
return nil;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:writeItems:toPasteboard:)]) {
return [_secondaryDataSource sourceList:self writeItems:items toPasteboard:pasteboard];
}
return NO;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:validateDrop:proposedItem:proposedChildIndex:)]) {
return [_secondaryDataSource sourceList:self validateDrop:info proposedItem:item proposedChildIndex:index];
}
return NSDragOperationNone;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:acceptDrop:item:childIndex:)]) {
return [_secondaryDataSource sourceList:self acceptDrop:info item:item childIndex:index];
}
return NO;
}
- (NSArray *)outlineView:(NSOutlineView *)outlineView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedItems:(NSArray *)items
{
if([_secondaryDataSource respondsToSelector:@selector(sourceList:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:)]) {
return [_secondaryDataSource sourceList:self namesOfPromisedFilesDroppedAtDestination:dropDestination forDraggedItems:items];
}
return nil;
}
#pragma mark -
#pragma mark NSOutlineView Delegate methods
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item
{
if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldExpandItem:)]) {
return [_secondaryDelegate sourceList:self shouldExpandItem:item];
}
return YES;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item
{
//Make sure the item isn't displayed as always expanded
if([self isGroupItem:item])
{
if([self isGroupAlwaysExpanded:item]) {
return NO;
}
}
if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldCollapseItem:)]) {
return [_secondaryDelegate sourceList:self shouldCollapseItem:item];
}
return YES;
}
- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if([_secondaryDelegate respondsToSelector:@selector(sourceList:dataCellForItem:)]) {
return [_secondaryDelegate sourceList:self dataCellForItem:item];
}
NSInteger row = [self rowForItem:item];
//Return the default table column
return [[[self tableColumns] firstObject] dataCellForRow:row];
}
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if([_secondaryDelegate respondsToSelector:@selector(sourceList:willDisplayCell:forItem:)]) {
[_secondaryDelegate sourceList:self willDisplayCell:cell forItem:item];
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
{
//Make sure that the item isn't a group as they can't be selected
if(![self isGroupItem:item]) {
if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldSelectItem:)]) {
return [_secondaryDelegate sourceList:self shouldSelectItem:item];
}
}
else {
return NO;
}
return YES;
}
- (NSIndexSet *)outlineView:(NSOutlineView *)outlineView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
{
//The outline view will try to select the first row if -[allowsEmptySelection:] is set to NO – if this is a group row
//stop it from doing so and leave it to our implementation of-[reloadData] which will select the first non-group row
//for us.
if([self numberOfSelectedRows]==0) {
if([self isGroupItem:[self itemAtRow:[proposedSelectionIndexes firstIndex]]]) {
return [NSIndexSet indexSet];
}
}
if([_secondaryDelegate respondsToSelector:@selector(sourceList:selectionIndexesForProposedSelection:)]) {
return [_secondaryDelegate sourceList:self selectionIndexesForProposedSelection:proposedSelectionIndexes];
}
//Since we implement this method, something must be returned to the outline view
return proposedSelectionIndexes;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
//Group titles can't be edited
if([self isGroupItem:item])
return NO;
if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldEditItem:)]) {
return [_secondaryDelegate sourceList:self shouldEditItem:item];
}
return YES;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldTrackCell:forItem:)]) {
return [_secondaryDelegate sourceList:self shouldTrackCell:cell forItem:item];
}
return NO;
}
- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
if([_secondaryDelegate respondsToSelector:@selector(sourceList:heightOfRowByItem:)]) {
return [_secondaryDelegate sourceList:self heightOfRowByItem:item];
}
return [self rowHeight];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
{
return [self isGroupItem:item];
}
#pragma mark -
#pragma mark Notification handling
/* Notification wrappers */
- (void)outlineViewSelectionIsChanging:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLSelectionIsChangingNotification object:self];
}
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLSelectionDidChangeNotification object:self];
}
- (void)outlineViewItemWillExpand:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemWillExpandNotification object:self userInfo:[notification userInfo]];
}
- (void)outlineViewItemDidExpand:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemDidExpandNotification object:self userInfo:[notification userInfo]];
}
- (void)outlineViewItemWillCollapse:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemWillCollapseNotification object:self userInfo:[notification userInfo]];
}
- (void)outlineViewItemDidCollapse:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemDidCollapseNotification object:self userInfo:[notification userInfo]];
}
- (void)registerDelegateToReceiveNotification:(NSString*)notification withSelector:(SEL)selector
{
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
//Set the delegate as a receiver of the notification if it implements the notification method
if([_secondaryDelegate respondsToSelector:selector]) {
[defaultCenter addObserver:_secondaryDelegate selector:selector name:notification object:self];
}
}
@end
//
// PXSourceListDataSource.h
// PXViewKit
//
// Created by Alex Rozanski on 17/10/2009.
// Copyright 2009-10 Alex Rozanski http://perspx.com
//
#import <Cocoa/Cocoa.h>
@class PXSourceList;
@protocol PXSourceListDataSource <NSObject>
@required
- (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item;
- (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item;
- (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item;
@optional
- (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item;
- (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item;
- (NSColor*)sourceList:(PXSourceList*)aSourceList badgeTextColorForItem:(id)item;
- (NSColor*)sourceList:(PXSourceList*)aSourceList badgeBackgroundColorForItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item;
- (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item;
//The rest of these methods are basically "wrappers" for the NSOutlineViewDataSource methods
- (id)sourceList:(PXSourceList*)aSourceList itemForPersistentObject:(id)object;
- (id)sourceList:(PXSourceList*)aSourceList persistentObjectForItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard;
- (NSDragOperation)sourceList:(PXSourceList*)sourceList validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index;
- (BOOL)sourceList:(PXSourceList*)aSourceList acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index;
- (NSArray *)sourceList:(PXSourceList*)aSourceList namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedItems:(NSArray *)items;
@end
//
// PXSourceListDelegate.h
// PXViewKit
//
// Created by Alex Rozanski on 17/10/2009.
// Copyright 2009-10 Alex Rozanski http://perspx.com
//
#import <Cocoa/Cocoa.h>
@class PXSourceList;
@protocol PXSourceListDelegate <NSObject>
@optional
//Extra methods
- (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group;
- (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item;
//Basically NSOutlineViewDelegate wrapper methods
- (BOOL)sourceList:(PXSourceList*)aSourceList shouldSelectItem:(id)item;
- (NSIndexSet*)sourceList:(PXSourceList*)aSourceList selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes;
- (BOOL)sourceList:(PXSourceList*)aSourceList shouldEditItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList shouldTrackCell:(NSCell *)cell forItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList shouldExpandItem:(id)item;
- (BOOL)sourceList:(PXSourceList*)aSourceList shouldCollapseItem:(id)item;
- (CGFloat)sourceList:(PXSourceList*)aSourceList heightOfRowByItem:(id)item;
- (NSCell*)sourceList:(PXSourceList*)aSourceList willDisplayCell:(id)cell forItem:(id)item;
- (NSCell*)sourceList:(PXSourceList*)aSourceList dataCellForItem:(id)item;
@end
@interface NSObject (PXSourceListNotifications)
//Selection
- (void)sourceListSelectionIsChanging:(NSNotification *)notification;
- (void)sourceListSelectionDidChange:(NSNotification *)notification;
//Item expanding/collapsing
- (void)sourceListItemWillExpand:(NSNotification *)notification;
- (void)sourceListItemDidExpand:(NSNotification *)notification;
- (void)sourceListItemWillCollapse:(NSNotification *)notification;
- (void)sourceListItemDidCollapse:(NSNotification *)notification;
- (void)sourceListDeleteKeyPressedOnRows:(NSNotification *)notification;
@end
//PXSourceList delegate notifications
extern NSString * const PXSLSelectionIsChangingNotification;
extern NSString * const PXSLSelectionDidChangeNotification;
extern NSString * const PXSLItemWillExpandNotification;
extern NSString * const PXSLItemDidExpandNotification;
extern NSString * const PXSLItemWillCollapseNotification;
extern NSString * const PXSLItemDidCollapseNotification;
extern NSString * const PXSLDeleteKeyPressedOnRowsNotification;
//
// SourceListItem.h
// PXSourceList
//
// Created by Alex Rozanski on 08/01/2010.
// Copyright 2010 Alex Rozanski http://perspx.com
//
// Adapted to VLC media player by Felix Paul Kühne
//
#import <Cocoa/Cocoa.h>
/*An example of a class that could be used to represent a Source List Item
Provides a title, an identifier, and an icon to be shown, as well as a badge value and a property to determine
whether the current item has a badge or not (`badgeValue` is set to -1 if no badge is shown)
Used to form a hierarchical model of SourceListItem instances – similar to the Source List tree structure
and easily accessible by the data source with the "children" property
SourceListItem *parent
- SourceListItem *child1;
- SourceListItem *child2;
- SourceListItem *childOfChild2;
- SourceListItem *anotherChildOfChild2;
- SourceListItem *child3;
*/
@interface SideBarItem : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *identifier;
@property (nonatomic, retain) NSImage *icon;
@property NSInteger badgeValue;
@property NSInteger sdtype;
@property (nonatomic, copy) NSArray *children;
//Convenience methods
+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier;
+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier icon:(NSImage*)anIcon;
- (BOOL)hasBadge;
- (BOOL)hasChildren;
- (BOOL)hasIcon;
@end
//
// SideBarItem.m
// PXSourceList
//
// Created by Alex Rozanski on 08/01/2010.
// Copyright 2010 Alex Rozanski http://perspx.com
//
// GC-enabled code revised by Stefan Vogt http://byteproject.net
//
// Adapted to VLC media player by Felix Paul Kühne
#import "SideBarItem.h"
@implementation SideBarItem
#pragma mark -
#pragma mark Init/Dealloc/Finalize
- (id)init
{
if (self=[super init]) {
_badgeValue = -1; //We don't want a badge value by default
_sdtype = -1; //no sd type set
}
return self;
}
+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier
{
SideBarItem *item = [SideBarItem itemWithTitle:aTitle identifier:anIdentifier icon:nil];
return item;
}
+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier icon:(NSImage*)anIcon
{
SideBarItem *item = [[SideBarItem alloc] init];
[item setTitle:aTitle];
[item setIdentifier:anIdentifier];
[item setIcon:anIcon];
return item;
}
#pragma mark -
#pragma mark Custom Accessors
- (BOOL)hasBadge
{
return _badgeValue!=-1;
}
- (BOOL)hasChildren
{
return [_children count]>0;
}
- (BOOL)hasIcon
{
return _icon!=nil;
}
@end
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="17E139j" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14269.12" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<development version="7000" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14269.12"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="VLCMainMenu">
......@@ -146,7 +147,6 @@
<outlet property="toggleEffectsButton" destination="5537" id="Gg8-nl-gzx"/>
<outlet property="toggleJumpButtons" destination="5240" id="53V-UC-536"/>
<outlet property="togglePlaymodeButtons" destination="5242" id="9TB-F7-ttT"/>
<outlet property="toggleSidebar" destination="5413" id="cz7-Zr-1lC"/>
<outlet property="trackSynchronization" destination="4412" id="BHW-NJ-jbd"/>
<outlet property="videoMenu" destination="334" id="7Ri-Tc-yej"/>
<outlet property="videoeffects" destination="2390" id="fXe-JA-9GI"/>
......@@ -356,11 +356,7 @@
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="K9x-W6-ycv"/>
<menuItem title="Find" keyEquivalent="F" id="6J6-tz-ctn">
<connections>
<action selector="highlightSearchField:" target="-1" id="GlP-7U-XF1"/>
</connections>
</menuItem>
<menuItem title="Find" keyEquivalent="F" id="6J6-tz-ctn"/>
</items>
</menu>
</menuItem>
......@@ -386,12 +382,6 @@
<action selector="toggleEffectsButton:" target="-2" id="QSm-2E-Nlo"/>
</connections>
</menuItem>
<menuItem title="Show Sidebar" id="5413">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSidebar:" target="-2" id="e7y-3l-ZUS"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5250"/>
<menuItem title="Playlist Table Columns" id="5247">
<modifierMask key="keyEquivalentModifierMask"/>
......
This diff is collapsed.
......@@ -184,7 +184,7 @@
p_old_input = p_input;
vlc_object_release(p_input);
[NSApp beginSheet: _editBookmarksWindow modalForWindow: self.window modalDelegate: _editBookmarksWindow didEndSelector: nil contextInfo: nil];
[self.window beginSheet:_editBookmarksWindow completionHandler:nil];
// Clear the bookmark list
for (int i = 0; i < i_bookmarks; i++)
......
......@@ -435,7 +435,7 @@
- (IBAction)customizeProfile:(id)sender
{
[NSApp beginSheet:_customizePanel modalForWindow:self.window modalDelegate:self didEndSelector:NULL contextInfo:nil];
[self.window beginSheet:_customizePanel completionHandler:nil];
}
- (IBAction)closeCustomizationSheet:(id)sender
......@@ -447,8 +447,6 @@
[self updateCurrentProfile];
}
- (IBAction)videoSettingsChanged:(id)sender
{
bool enableSettings = [_customizeVidCheckbox state] == NSOnState && [_customizeVidKeepCheckbox state] == NSOffState;
......@@ -510,7 +508,7 @@
- (IBAction)showStreamPanel:(id)sender
{
[NSApp beginSheet:_streamPanel modalForWindow:self.window modalDelegate:self didEndSelector:NULL contextInfo:nil];
[self.window beginSheet:_streamPanel completionHandler:nil];
}
- (IBAction)closeStreamPanel:(id)sender
......@@ -531,23 +529,32 @@
/* catch obvious errors */
if ([[_streamAddressField stringValue] length] == 0) {
NSBeginInformationalAlertSheet(_NS("No Address given"),
_NS("OK"), @"", @"", _streamPanel, nil, nil, nil, nil,
@"%@", _NS("In order to stream, a valid destination address is required."));
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:_NS("No Address given")];
[alert setInformativeText:_NS("In order to stream, a valid destination address is required.")];
[alert beginSheetModalForWindow:_streamPanel
completionHandler:nil];
return;
}
if ([_streamSAPCheckbox state] && [[_streamChannelField stringValue] length] == 0) {
NSBeginInformationalAlertSheet(_NS("No Channel Name given"),
_NS("OK"), @"", @"", _streamPanel, nil, nil, nil, nil,
@"%@", _NS("SAP stream announcement is enabled. However, no channel name is provided."));
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:_NS("No Channel Name given")];
[alert setInformativeText:_NS("SAP stream announcement is enabled. However, no channel name is provided.")];
[alert beginSheetModalForWindow:_streamPanel
completionHandler:nil];
return;
}
if ([_streamSDPMatrix isEnabled] && [_streamSDPMatrix selectedCell] != [_streamSDPMatrix cellWithTag:0] && [[_streamSDPField stringValue] length] == 0) {
NSBeginInformationalAlertSheet(_NS("No SDP URL given"),
_NS("OK"), @"", @"", _streamPanel, nil, nil, nil, nil,
@"%@", _NS("A SDP export is requested, but no URL is provided."));
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:_NS("No SDP URL given")];
[alert setInformativeText:_NS("A SDP export is requested, but no URL is provided.")];
[alert beginSheetModalForWindow:_streamPanel
completionHandler:nil];
return;
}
......
......@@ -560,7 +560,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
FREENULL(psz_album);
char *psz_track_number = input_item_GetTrackNumber(p_input_item);
currentlyPlayingTrackInfo[MPMediaItemPropertyAlbumTrackNumber] = toNSStr(psz_track_number);
currentlyPlayingTrackInfo[MPMediaItemPropertyAlbumTrackNumber] = @([toNSStr(psz_track_number) intValue]);
FREENULL(psz_track_number);
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = currentlyPlayingTrackInfo;
......
......@@ -96,7 +96,7 @@ int OpenIntf (vlc_object_t *p_this)
[VLCApplication sharedApplication];
[VLCMain sharedInstance];
[NSBundle loadNibNamed:@"MainMenu" owner:[[VLCMain sharedInstance] mainMenu]];
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:[[VLCMain sharedInstance] mainMenu] topLevelObjects:nil];
[[[VLCMain sharedInstance] mainWindow] makeKeyAndOrderFront:nil];
msg_Dbg(p_intf, "Finished loading macosx interface");
......
......@@ -66,7 +66,6 @@
@property (readwrite, weak) IBOutlet NSMenuItem *toggleJumpButtons;
@property (readwrite, weak) IBOutlet NSMenuItem *togglePlaymodeButtons;
@property (readwrite, weak) IBOutlet NSMenuItem *toggleEffectsButton;
@property (readwrite, weak) IBOutlet NSMenuItem *toggleSidebar;
@property (readwrite, weak) IBOutlet NSMenu *playlistTableColumnsMenu;
@property (readwrite, weak) IBOutlet NSMenuItem *playlistTableColumns;
......@@ -214,7 +213,6 @@
- (void)setupMenus;
- (void)setSubmenusEnabled:(BOOL)b_enabled;
- (void)setRateControlsEnabled:(BOOL)b_enabled;
- (void)updateSidebarMenuItem:(BOOL)show;
- (IBAction)openAddonManager:(id)sender;
......@@ -228,7 +226,6 @@
- (IBAction)toggleEffectsButton:(id)sender;
- (IBAction)toggleJumpButtons:(id)sender;
- (IBAction)togglePlaymodeButtons:(id)sender;
- (IBAction)toggleSidebar:(id)sender;
- (IBAction)play:(id)sender;
- (IBAction)stop:(id)sender;
......
......@@ -377,7 +377,6 @@
[_togglePlaymodeButtons setState: var_InheritBool(getIntf(), "macosx-show-playmode-buttons")];
[_toggleEffectsButton setTitle: _NS("Show Audio Effects Button")];
[_toggleEffectsButton setState: var_InheritBool(getIntf(), "macosx-show-effects-button")];
[_toggleSidebar setTitle: _NS("Show Sidebar")];
[_playlistTableColumns setTitle: _NS("Playlist Table Columns")];
[_controlsMenu setTitle: _NS("Playback")];
......@@ -697,16 +696,6 @@
[_togglePlaymodeButtons setState: b_value];
}
- (IBAction)toggleSidebar:(id)sender
{
[[[VLCMain sharedInstance] mainWindow] toggleLeftSubSplitView];
}
- (void)updateSidebarMenuItem:(BOOL)show;
{
[_toggleSidebar setState:show];
}
#pragma mark - Playback
- (IBAction)play:(id)sender
......
/*****************************************************************************
* VLCMainWindow.h: MacOS X interface module
*****************************************************************************
* Copyright (C) 2002-2014 VLC authors and VideoLAN
* Copyright (C) 2002-2018 VLC authors and VideoLAN
* $Id$
*
* Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
......@@ -37,7 +37,6 @@
@class VLCDetachedVideoWindow;
@class VLCMainWindowControlsBar;
@class VLCVoutView;
@class PXSourceList;
typedef enum {
psUserEvent,
......@@ -48,70 +47,17 @@ typedef enum {
@interface VLCMainWindow : VLCVideoWindowCommon
// General MainWindow outlets
@property (readwrite, weak) IBOutlet NSTextField *searchField;
@property (readwrite, weak) IBOutlet NSScrollView *playlistScrollView;
@property (readwrite, weak) IBOutlet NSOutlineView *outlineView;
@property (readwrite, weak) IBOutlet NSSplitView *splitView;
@property (readwrite, weak) IBOutlet NSView *splitViewLeft;
@property (readwrite, weak) IBOutlet NSView *splitViewRight;