One approach I've used is to not try to apply the contextual menu actions to the one specific item that was clicked on but to the selected items. And I make the clicked-on item add itself to the selection.
I used a custom view for the collection item view. The custom view class has an outlet, item
, to its owning collection view item, which I connect in the NIB. It also overrides -rightMouseDown:
to have the item add itself to the selection:
- (void) rightMouseDown:(NSEvent*)event
{
NSCollectionView* parent = self.item.collectionView;
NSUInteger index = NSNotFound;
NSUInteger count = parent.content.count;
for (NSUInteger i = 0; i < count; i++)
{
if ([parent itemAtIndex:i] == self.item)
{
index = i;
break;
}
}
NSMutableIndexSet* selectionIndexes = [[parent.selectionIndexes mutableCopy] autorelease];
if (index != NSNotFound && ![selectionIndexes containsIndex:index])
{
[selectionIndexes addIndex:index];
parent.selectionIndexes = selectionIndexes;
}
return [super rightMouseDown:event];
}
If you prefer, rather than adding the item to the selection, you can check if it's already in the selection. If it is, don't modify the selection. If it's not, replace the selection with just the item (making it the only selected item).
Alternatively, you could set a contextual menu on the item views rather than on the collection view. Then, the menu items could target either the item view or the collection view item.
Lastly, you could subclass NSCollectionView
and override -menuForEvent:
. You would still call through to super
and return the menu it returns, but you could take the opportunity to record the event and/or the item at its location. To determine that, you'd do something like:
- (NSMenu*) menuForEvent:(NSEvent*)event
{
_clickedItemIndex = NSNotFound;
NSPoint point = [self convertPoint:event.locationInWindow fromView:nil];
NSUInteger count = self.content.count;
for (NSUInteger i = 0; i < count; i++)
{
NSRect itemFrame = [self frameForItemAtIndex:i];
if (NSMouseInRect(point, itemFrame, self.isFlipped))
{
_clickedItemIndex = i;
break;
}
}
return [super menuForEvent:event];
}