Permalink
Browse files

Proper mouse-drag selection, improved drag-drop and support for conte…

…xtual menus
  • Loading branch information...
1 parent 6b427fc commit b4655879f65688e0fc8f0da59b35d2e1ff270afe @pieteromvlee pieteromvlee committed Jan 28, 2011
Showing with 110 additions and 37 deletions.
  1. +19 −4 BCCollectionView+Dragging.m
  2. +11 −0 BCCollectionView+Keyboard.m
  3. +29 −11 BCCollectionView+Mouse.m
  4. +1 −0 BCCollectionView.h
  5. +39 −22 BCCollectionView.m
  6. +11 −0 BCCollectionViewDelegate.h
@@ -12,16 +12,20 @@ @implementation BCCollectionView (BCCollectionView_Dragging)
- (void)initiateDraggingSessionWithEvent:(NSEvent *)anEvent
{
- NSUInteger index = [self indexOfItemAtPoint:mouseDownLocation];
+ NSUInteger index = [self indexOfItemAtPoint:mouseDownLocation];
+ [self selectItemAtIndex:index];
+
NSRect itemRect = [self rectOfItemAtIndex:index];
NSView *currentView = [[self viewControllerForItemAtIndex:index] view];
NSData *imageData = [currentView dataWithPDFInsideRect:NSMakeRect(0,0,NSWidth(itemRect),NSHeight(itemRect))];
NSImage *pdfImage = [[[NSImage alloc] initWithData:imageData] autorelease];
NSImage *dragImage = [[NSImage alloc] initWithSize:[pdfImage size]];
- [dragImage lockFocus];
- [pdfImage drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:0.5];
- [dragImage unlockFocus];
+ if ([dragImage size].width > 0 && [dragImage size].height > 0) {
+ [dragImage lockFocus];
+ [pdfImage drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:0.5];
+ [dragImage unlockFocus];
+ }
NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[self delegateWriteIndexes:selectionIndexes toPasteboard:pasteboard];
@@ -69,6 +73,17 @@ - (void)draggingEnded:(id <NSDraggingInfo>)sender
[delegate collectionView:self draggingEnded:sender];
}
+- (void)draggingExited:(id<NSDraggingInfo>)sender
+{
+ if (dragHoverIndex != NSNotFound) {
+ [self setNeedsDisplayInRect:[self rectOfItemAtIndex:dragHoverIndex]];
+ [self setDragHoverIndex:NSNotFound];
+ }
+
+ if ([delegate respondsToSelector:@selector(collectionView:draggingExited:)])
+ [delegate collectionView:self draggingExited:sender];
+}
+
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
if ([delegate respondsToSelector:@selector(collectionView:performDragOperation:onViewController:forItem:)])
@@ -117,4 +117,15 @@ - (void)moveDownAndModifySelection:(id)sender
}
}
+- (void)deleteBackward:(id)sender
+{
+ if ([delegate respondsToSelector:@selector(collectionView:deleteItemsAtIndexes:)])
+ [delegate collectionView:self deleteItemsAtIndexes:selectionIndexes];
+}
+
+- (void)deleteForward:(id)sender
+{
+ [self deleteBackward:sender];
+}
+
@end
View
@@ -21,17 +21,21 @@ - (void)mouseDown:(NSEvent *)theEvent
{
[[self window] makeFirstResponder:self];
+ isDragging = YES;
mouseDownLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
mouseDraggedLocation = mouseDownLocation;
NSUInteger index = [self indexOfItemContentRectAtPoint:mouseDownLocation];
+ if (index != NSNotFound && [delegate respondsToSelector:@selector(collectionView:didClickItem:withViewController:)])
+ [delegate collectionView:self didClickItem:[contentArray objectAtIndex:index] withViewController:[visibleViewControllers objectForKey:[NSNumber numberWithInt:index]]];
+
if (![self shiftOrCommandKeyPressed] && ![selectionIndexes containsIndex:index])
[self deselectAllItems];
self.originalSelectionIndexes = [[selectionIndexes copy] autorelease];
if ([theEvent clickCount] == 2 && [delegate respondsToSelector:@selector(collectionView:didDoubleClickViewControllerAtIndex:)])
- [delegate collectionView:self didDoubleClickViewControllerAtIndex:[visibleViewControllers objectForKey:[NSNumber numberWithInt:[self indexOfItemAtPoint:mouseDownLocation]]]];
+ [delegate collectionView:self didDoubleClickViewControllerAtIndex:[visibleViewControllers objectForKey:[NSNumber numberWithInt:index]]];
if ([self shiftOrCommandKeyPressed] && [self.originalSelectionIndexes containsIndex:index])
[self deselectItemAtIndex:index];
@@ -52,24 +56,37 @@ - (void)regularMouseDragged:(NSEvent *)anEvent
[self setNeedsDisplayInRect:BCRectFromTwoPoints(mouseDownLocation, mouseDraggedLocation)];
mouseDraggedLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
+ NSIndexSet *suggestedIndexes = [self indexesOfItemContentRectsInRect:BCRectFromTwoPoints(mouseDownLocation, mouseDraggedLocation)];
- NSIndexSet *newIndexes = [self indexesOfItemContentRectsInRect:BCRectFromTwoPoints(mouseDownLocation, mouseDraggedLocation)];
- [newIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
- if ([self.originalSelectionIndexes containsIndex:idx])
- [self deselectItemAtIndex:idx];
- else
+ if (![self shiftOrCommandKeyPressed]) {
+ NSMutableIndexSet *oldIndexes = [[selectionIndexes mutableCopy] autorelease];
+ [oldIndexes removeIndexes:suggestedIndexes];
+ [self deselectItemsAtIndexes:oldIndexes];
+ }
+
+ [suggestedIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
+ if ([self shiftOrCommandKeyPressed]) {
+ if ([originalSelectionIndexes containsIndex:idx])
+ [self deselectItemAtIndex:idx];
+ else
+ [self selectItemAtIndex:idx];
+ } else
[self selectItemAtIndex:idx];
}];
+
[self setNeedsDisplayInRect:BCRectFromTwoPoints(mouseDownLocation, mouseDraggedLocation)];
}
- (void)mouseDragged:(NSEvent *)theEvent
{
- if (firstDrag && [selectionIndexes count] > 0 && [self delegateSupportsDragForItemsAtIndexes:selectionIndexes])
- [self initiateDraggingSessionWithEvent:theEvent];
- else
- [self regularMouseDragged:theEvent];
- firstDrag = NO;
+ if (isDragging) {
+ NSUInteger index = [self indexOfItemContentRectAtPoint:mouseDownLocation];
+ if (firstDrag && index != NSNotFound && [selectionIndexes count] > 0 && [self delegateSupportsDragForItemsAtIndexes:selectionIndexes])
+ [self initiateDraggingSessionWithEvent:theEvent];
+ else
+ [self regularMouseDragged:theEvent];
+ firstDrag = NO;
+ }
}
- (void)mouseUp:(NSEvent *)theEvent
@@ -79,6 +96,7 @@ - (void)mouseUp:(NSEvent *)theEvent
mouseDownLocation = NSZeroPoint;
mouseDraggedLocation = NSZeroPoint;
+ isDragging = NO;
self.originalSelectionIndexes = nil;
}
View
@@ -30,6 +30,7 @@
NSIndexSet *originalSelectionIndexes;
NSInteger dragHoverIndex;
+ BOOL isDragging;
BOOL firstDrag;
}
@property (nonatomic, assign) id<BCCollectionViewDelegate> delegate;
View
@@ -30,7 +30,7 @@ - (id)initWithCoder:(NSCoder *)aDecoder
[enclosingClipView setPostsBoundsChangedNotifications:YES];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(scrollViewDidScroll:) name:NSViewBoundsDidChangeNotification object:enclosingClipView];
- [center addObserver:self selector:@selector(viewDidResize) name:NSViewFrameDidChangeNotification object:nil];
+ [center addObserver:self selector:@selector(viewDidResize) name:NSViewFrameDidChangeNotification object:self];
}
return self;
}
@@ -49,7 +49,7 @@ - (void)dealloc
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:NSViewBoundsDidChangeNotification object:[[self enclosingScrollView] contentView]];
- [center removeObserver:self name:NSViewFrameDidChangeNotification object:nil];
+ [center removeObserver:self name:NSViewFrameDidChangeNotification object:self];
[reusableViewControllers release];
[visibleViewControllers release];
@@ -131,6 +131,9 @@ - (void)delegateDidSelectItemAtIndex:(NSUInteger)index
[delegate collectionView:self
didSelectItem:[contentArray objectAtIndex:index]
withViewController:[self viewControllerForItemAtIndex:index]];
+
+ if ([delegate respondsToSelector:@selector(collectionViewSelectionDidChange:)])
+ [delegate collectionViewSelectionDidChange:self];
}
- (void)delegateDidDeselectItemAtIndex:(NSUInteger)index
@@ -139,6 +142,9 @@ - (void)delegateDidDeselectItemAtIndex:(NSUInteger)index
[delegate collectionView:self
didDeselectItem:[contentArray objectAtIndex:index]
withViewController:[self viewControllerForItemAtIndex:index]];
+
+ if ([delegate respondsToSelector:@selector(collectionViewSelectionDidChange:)])
+ [delegate collectionViewSelectionDidChange:self];
}
- (void)delegateViewControllerBecameInvisibleAtIndex:(NSUInteger)index
@@ -151,7 +157,7 @@ - (void)delegateViewControllerBecameInvisibleAtIndex:(NSUInteger)index
- (NSUInteger)numberOfRows
{
- return ceil((float)[contentArray count]/(float)[self numberOfItemsPerRow]);
+ return MAX(1, ceil((float)[contentArray count]/(float)[self numberOfItemsPerRow]));
}
- (NSUInteger)numberOfItemsPerRow
@@ -313,25 +319,23 @@ - (NSViewController *)emptyViewControllerForInsertion
- (void)addMissingViewControllersToView
{
- [[NSIndexSet indexSetWithIndexesInRange:[self rangeOfVisibleItems]] enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
- NSNumber *key = [NSNumber numberWithInteger:idx];
- if (![visibleViewControllers objectForKey:key]) {
- NSViewController *viewController = [self emptyViewControllerForInsertion];
- [visibleViewControllers setObject:viewController forKey:key];
- [[viewController view] setFrame:[self rectOfItemAtIndex:idx]];
- [[viewController view] setAutoresizingMask:NSViewMaxXMargin | NSViewMaxYMargin];
-
- id itemToLoad = [contentArray objectAtIndex:idx];
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [[NSIndexSet indexSetWithIndexesInRange:[self rangeOfVisibleItems]] enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
+ NSNumber *key = [NSNumber numberWithInteger:idx];
+ if (![visibleViewControllers objectForKey:key]) {
+ NSViewController *viewController = [self emptyViewControllerForInsertion];
+ [visibleViewControllers setObject:viewController forKey:key];
+ [[viewController view] setFrame:[self rectOfItemAtIndex:idx]];
+ [[viewController view] setAutoresizingMask:NSViewMaxXMargin | NSViewMaxYMargin];
+
+ id itemToLoad = [contentArray objectAtIndex:idx];
[delegate collectionView:self willShowViewController:viewController forItem:itemToLoad];
- dispatch_async(dispatch_get_main_queue(), ^{
- [self addSubview:[viewController view]];
- if ([selectionIndexes containsIndex:idx])
- [self delegateUpdateSelectionForItemAtIndex:idx];
- });
- });
- }
- }];
+ [self addSubview:[viewController view]];
+ if ([selectionIndexes containsIndex:idx])
+ [self delegateUpdateSelectionForItemAtIndex:idx];
+ }
+ }];
+ });
}
- (void)moveViewControllersToProperPosition
@@ -462,15 +466,20 @@ - (void)resizeFrameToFitContents
- (void)reloadDataWithItems:(NSArray *)newContent emptyCaches:(BOOL)shouldEmptyCaches
{
+ [self deselectAllItems];
+
if (!delegate)
return;
self.contentArray = newContent;
[self resizeFrameToFitContents];
if (shouldEmptyCaches) {
- for (NSViewController *viewController in [visibleViewControllers allValues])
+ for (NSViewController *viewController in [visibleViewControllers allValues]) {
[[viewController view] removeFromSuperview];
+ if ([delegate respondsToSelector:@selector(collectionView:viewControllerBecameInvisible:)])
+ [delegate collectionView:self viewControllerBecameInvisible:viewController];
+ }
[reusableViewControllers removeAllObjects];
[visibleViewControllers removeAllObjects];
@@ -509,4 +518,12 @@ - (void)viewDidResize
});
}
+- (NSMenu *)menuForEvent:(NSEvent *)anEvent
+{
+ if ([delegate respondsToSelector:@selector(collectionView:menuForItemsAtIndexes:)])
+ return [delegate collectionView:self menuForItemsAtIndexes:[self selectionIndexes]];
+ else
+ return nil;
+}
+
@end
View
@@ -37,6 +37,9 @@ enum {
- (BOOL)collectionView:(BCCollectionView *)collectionView shouldSelectItem:(id)anItem withViewController:(NSViewController *)viewController;
- (void)collectionView:(BCCollectionView *)collectionView didSelectItem:(id)anItem withViewController:(NSViewController *)viewController;
- (void)collectionView:(BCCollectionView *)collectionView didDeselectItem:(id)anItem withViewController:(NSViewController *)viewController;
+- (void)collectionViewSelectionDidChange:(BCCollectionView *)collectionView;
+
+- (void)collectionView:(BCCollectionView *)collectionView didClickItem:(id)anItem withViewController:(NSViewController *)viewController;
- (void)collectionViewDidScroll:(BCCollectionView *)collectionView inDirection:(NSUInteger)scrollDirection;
- (void)collectionView:(BCCollectionView *)collectionView didDoubleClickViewControllerAtIndex:(NSViewController *)viewController;
@@ -57,4 +60,12 @@ enum {
onViewController:(NSViewController *)viewController
forItem:(id)item;
- (void)collectionView:(BCCollectionView *)collectionView draggingEnded:(id <NSDraggingInfo>)draggingInfo;
+- (void)collectionView:(BCCollectionView *)collectionView draggingExited:(id <NSDraggingInfo>)draggingInfo;
+
+//key events
+- (void)collectionView:(BCCollectionView *)collectionView deleteItemsAtIndexes:(NSIndexSet *)indexSet;
+
+//contextual menu
+- (NSMenu *)collectionView:(BCCollectionView *)collectionView menuForItemsAtIndexes:(NSIndexSet *)indexSet
+;
@end

0 comments on commit b465587

Please sign in to comment.