diff --git a/JNWCollectionView/JNWCollectionViewCell.m b/JNWCollectionView/JNWCollectionViewCell.m index 0722948..6512282 100644 --- a/JNWCollectionView/JNWCollectionViewCell.m +++ b/JNWCollectionView/JNWCollectionViewCell.m @@ -157,15 +157,13 @@ - (NSImage *)backgroundImage { return self.backgroundView.image; } -- (void)mouseDown:(NSEvent *)theEvent { - [super mouseDown:theEvent]; - +- (void)mouseDown:(NSEvent *)theEvent +{ [self.collectionView mouseDownInCollectionViewCell:self withEvent:theEvent]; } -- (void)mouseUp:(NSEvent *)theEvent { - [super mouseUp:theEvent]; - +- (void)mouseUp:(NSEvent *)theEvent +{ [self.collectionView mouseUpInCollectionViewCell:self withEvent:theEvent]; if (theEvent.clickCount == 2) { diff --git a/JNWCollectionView/JNWCollectionViewFramework.h b/JNWCollectionView/JNWCollectionViewFramework.h index 98886ae..0cb40f2 100644 --- a/JNWCollectionView/JNWCollectionViewFramework.h +++ b/JNWCollectionView/JNWCollectionViewFramework.h @@ -114,10 +114,16 @@ typedef NS_ENUM(NSInteger, JNWCollectionViewScrollPosition) { /// Tells the delegate that the specified index path has been scrolled to. - (void)collectionView:(JNWCollectionView *)collectionView didScrollToItemAtIndexPath:(NSIndexPath *)indexPath; +- (void)collectionView:(JNWCollectionView *)collectionView willDisplayCell:(JNWCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath; + /// Tells the delegate that the cell for the specified index path has been put /// back into the reuse queue. - (void)collectionView:(JNWCollectionView *)collectionView didEndDisplayingCell:(JNWCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath; +/// Tells the delegate that the collection view is about to reload the cells, +/// view size has already been calculated, +/// gives the delegate the chance the update the scroll position +- (void)collectionViewWillRelayoutCells:(JNWCollectionView *)collectionView; @end #pragma mark Reloading and customizing @@ -184,18 +190,6 @@ typedef NS_ENUM(NSInteger, JNWCollectionViewScrollPosition) { /// Defaults to nil. @property (nonatomic, strong) JNWCollectionViewLayout *collectionViewLayout; -/// The background color determines what is drawn underneath any cells that might be visible -/// at the time. If this is a repeating pattern image, it will scroll along with the content. -/// -/// Defaults to a white color. -@property (nonatomic, strong) NSColor *backgroundColor; - -/// Whether or not the collection view draws the background color. If the collection view -/// background color needs to be transparent, this should be disabled. -/// -/// Defaults to YES. -@property (nonatomic, assign) BOOL drawsBackground; - #pragma mark - Information /// Returns the total number of sections. @@ -267,6 +261,11 @@ typedef NS_ENUM(NSInteger, JNWCollectionViewScrollPosition) { /// Defaults to YES. @property (nonatomic, assign) BOOL allowsEmptySelection; +/// If set to NO, the collection view will not extend the selection when using command and shift modifier keys +/// +/// Defaults to YES. +@property (nonatomic, assign) BOOL allowsMultipleSelection; + /// Scrolls the collection view to the item at the specified path, optionally animated. The scroll position determines /// where the item is positioned on the screen. - (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(JNWCollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; @@ -276,6 +275,12 @@ typedef NS_ENUM(NSInteger, JNWCollectionViewScrollPosition) { /// desired, pass in JNWCollectionViewScrollPositionNone to prevent the scroll.. - (void)selectItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(JNWCollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; +/// Selects the item at the specified index path, deselecting any other selected items in the process, optionally animated. +/// The collection view will then scroll to that item in the position as determined by scrollPosition. If no scroll is +/// desired, pass in JNWCollectionViewScrollPositionNone to prevent the scroll.. +/// extendSelection: A BOOL value that specifies whether to extend the current selection. Pass YES to extends the selection; NO replaces the current selection. +- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(JNWCollectionViewScrollPosition)scrollPosition byExtendingSelection:(BOOL)extendSelection animated:(BOOL)animated; + /// Selects all items in the collection view. - (void)selectAllItems; diff --git a/JNWCollectionView/JNWCollectionViewFramework.m b/JNWCollectionView/JNWCollectionViewFramework.m index 4692d21..bfcab17 100644 --- a/JNWCollectionView/JNWCollectionViewFramework.m +++ b/JNWCollectionView/JNWCollectionViewFramework.m @@ -31,7 +31,8 @@ typedef NS_ENUM(NSInteger, JNWCollectionViewSelectionType) { JNWCollectionViewSelectionTypeSingle, JNWCollectionViewSelectionTypeExtending, - JNWCollectionViewSelectionTypeMultiple + JNWCollectionViewSelectionTypeMultiple, + JNWCollectionViewSelectionTypeMultipleDontAllowDeselection, }; @interface JNWCollectionView() { @@ -50,6 +51,8 @@ @interface JNWCollectionView() { unsigned int delegateDidDoubleClick:1; unsigned int delegateDidRightClick:1; unsigned int delegateDidEndDisplayingCell:1; + unsigned int delegateWillRelayoutCells:1; + unsigned int delegateWillDisplayCell:1; unsigned int wantsLayout; } _collectionViewFlags; @@ -62,6 +65,7 @@ @interface JNWCollectionView() { // Selection @property (nonatomic, strong) NSMutableArray *selectedIndexes; +@property (nonatomic, strong) NSIndexPath* multipleSelectionSelectedIndexPath; // Cells @property (nonatomic, strong) NSMutableDictionary *reusableCells; // { identifier : (cells) } @@ -75,13 +79,11 @@ @interface JNWCollectionView() { @property (nonatomic, strong) NSMutableDictionary *supplementaryViewClassMap; // { "kind/identifier" : class } @property (nonatomic, strong) NSMutableDictionary *supplementaryViewNibMap; // { "kind/identifier" : nib } -@property (nonatomic, strong) NSView *documentView; +@property (nonatomic, strong) NSView *myDocumentView; @end @implementation JNWCollectionView -@dynamic drawsBackground; -@dynamic backgroundColor; // We're using a static function for the common initialization so that subclassers // don't accidentally override this method in their own common init method. @@ -102,14 +104,15 @@ static void JNWCollectionViewCommonInit(JNWCollectionView *collectionView) { collectionView.wantsLayer = YES; // Set the document view to a custom class that returns YES to -isFlipped. - collectionView.documentView = [[JNWCollectionViewDocumentView alloc] initWithFrame:CGRectZero]; + collectionView.myDocumentView = [[JNWCollectionViewDocumentView alloc] initWithFrame:CGRectZero]; + collectionView.documentView = collectionView.myDocumentView; // We don't want to perform an initial layout pass until the user has called -reloadData. collectionView->_collectionViewFlags.wantsLayout = NO; collectionView.allowsSelection = YES; - collectionView.allowsEmptySelection = YES; + collectionView.allowsMultipleSelection = YES; collectionView.backgroundColor = NSColor.whiteColor; collectionView.drawsBackground = YES; @@ -144,6 +147,8 @@ - (void)setDelegate:(id)delegate { _collectionViewFlags.delegateDidEndDisplayingCell = [delegate respondsToSelector:@selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:)]; _collectionViewFlags.delegateShouldScroll = [delegate respondsToSelector:@selector(collectionView:shouldScrollToItemAtIndexPath:)]; _collectionViewFlags.delegateDidScroll = [delegate respondsToSelector:@selector(collectionView:didScrollToItemAtIndexPath:)]; + _collectionViewFlags.delegateWillRelayoutCells = [delegate respondsToSelector:@selector(collectionViewWillRelayoutCells:)]; + _collectionViewFlags.delegateWillDisplayCell = [delegate respondsToSelector:@selector(collectionView:willDisplayCell:forItemAtIndexPath:)]; } - (void)setDataSource:(id)dataSource { @@ -501,18 +506,19 @@ - (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(JNWCo break; case JNWCollectionViewScrollPositionTop: // make the top of our rect flush with the top of the visible bounds - rect.size.height = CGRectGetHeight(visibleRect); + rect.size.height = NSHeight(visibleRect); //rect.origin.y = self.documentVisibleRect.origin.y + rect.size.height; break; case JNWCollectionViewScrollPositionMiddle: // TODO + + rect.origin.y -= ((NSHeight(visibleRect)-NSHeight(rect)) / 2.f); rect.size.height = self.bounds.size.height; - rect.origin.y += (CGRectGetHeight(visibleRect) / 2.f) - CGRectGetHeight(rect); break; case JNWCollectionViewScrollPositionBottom: // make the bottom of our rect flush with the bottom of the visible bounds - rect.size.height = CGRectGetHeight(visibleRect); - rect.origin.y -= CGRectGetHeight(visibleRect); + rect.size.height = NSHeight(visibleRect); + rect.origin.y -= NSHeight(visibleRect); break; case JNWCollectionViewScrollPositionNone: // no scroll needed @@ -591,7 +597,8 @@ - (void)layout { BOOL shouldInvalidate = [self.collectionViewLayout shouldInvalidateLayoutForBoundsChange:visibleBounds]; [self.data recalculateAndPrepareLayout:shouldInvalidate]; - [self performFullRelayoutForcingSubviewsReset:shouldInvalidate]; +#warning changed for performance reasons, what's the catch? + [self performFullRelayoutForcingSubviewsReset:YES]; } } @@ -599,7 +606,9 @@ - (void)collectionViewLayoutWasInvalidated:(JNWCollectionViewLayout *)layout { // First we prepare the layout. In the future it would possibly be a good idea to coalesce // this call to reduce unnecessary layout preparation calls. [self.data recalculateAndPrepareLayout:YES]; - [self performFullRelayoutForcingSubviewsReset:YES]; + +#warning changed for performance reasons, what's the catch? + [self performFullRelayoutForcingSubviewsReset:NO]; } - (void)performFullRelayoutForcingSubviewsReset:(BOOL)forceReset { @@ -608,6 +617,11 @@ - (void)performFullRelayoutForcingSubviewsReset:(BOOL)forceReset { } [self layoutDocumentView]; + + if (_collectionViewFlags.delegateWillRelayoutCells) { + [self.delegate collectionViewWillRelayoutCells:self]; + } + [self layoutCellsWithRedraw:YES]; [self layoutSupplementaryViewsWithRedraw:YES]; @@ -708,6 +722,10 @@ - (void)layoutCellsWithRedraw:(BOOL)needsVisibleRedraw { JNWCollectionViewLayoutAttributes *attributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath]; [self applyLayoutAttributes:attributes toCell:cell]; + if (_collectionViewFlags.delegateWillDisplayCell) { + [self.delegate collectionView:self willDisplayCell:cell forItemAtIndexPath:indexPath]; + } + if (cell.superview == nil) { [self.documentView addSubview:cell]; } else { @@ -901,8 +919,10 @@ - (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated { JNWCollectionViewCell *cell = [self cellForItemAtIndexPath:indexPath]; [cell setSelected:YES animated:self.animatesSelection]; - if (![self.selectedIndexes containsObject:indexPath]) + if (![self.selectedIndexes containsObject:indexPath]) { [self.selectedIndexes addObject:indexPath]; + [self.selectedIndexes sortUsingSelector:@selector(compare:)]; + } if (_collectionViewFlags.delegateDidSelect) { [self.delegate collectionView:self didSelectItemAtIndexPath:indexPath]; @@ -915,6 +935,15 @@ - (void)selectItemAtIndexPath:(NSIndexPath *)indexPath [self selectItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated selectionType:JNWCollectionViewSelectionTypeSingle]; } +- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(JNWCollectionViewScrollPosition)scrollPosition byExtendingSelection:(BOOL)extendSelection animated:(BOOL)animated +{ + if (!extendSelection) { + [self selectItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated]; + } else { + [self selectItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated selectionType:JNWCollectionViewSelectionTypeMultiple]; + } +} + - (NSIndexPath *)indexPathForNextSelectableItemAfterIndexPath:(NSIndexPath *)indexPath { if (indexPath == nil && [self validateIndexPath:[NSIndexPath jnw_indexPathForItem:0 inSection:0]]) { // Passing `nil` will select the very first index path @@ -960,13 +989,20 @@ - (void)selectItemAtIndexPath:(NSIndexPath *)indexPath } else { [indexesToSelect addObject:indexPath]; } + } else if (selectionType == JNWCollectionViewSelectionTypeMultipleDontAllowDeselection) { + [indexesToSelect addObjectsFromArray:self.selectedIndexes]; + if (![indexesToSelect containsObject:indexPath]) { + [indexesToSelect addObject:indexPath]; + } + } else if (selectionType == JNWCollectionViewSelectionTypeExtending) { // From what I have determined, this behavior should be as follows. // Take the index selected first, and select all items between there and the // last selected item. - NSIndexPath *firstIndex = (self.selectedIndexes.count > 0 ? self.selectedIndexes[0] : nil); + NSIndexPath *firstIndex = [self.selectedIndexes firstObject]; if (firstIndex != nil) { - [indexesToSelect addObject:firstIndex]; + [indexesToSelect addObjectsFromArray:self.selectedIndexes]; + //[indexesToSelect addObject:firstIndex]; if (![firstIndex isEqual:indexPath]) { NSComparisonResult order = [firstIndex compare:indexPath]; @@ -1009,13 +1045,14 @@ - (void)mouseDownInCollectionViewCell:(JNWCollectionViewCell *)cell withEvent:(N // Detect if modifier flags are held down. // We prioritize the command key over the shift key. - if (event.modifierFlags & NSCommandKeyMask) { + if (event.modifierFlags & NSCommandKeyMask && self.allowsMultipleSelection) { [self selectItemAtIndexPath:indexPath atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES selectionType:JNWCollectionViewSelectionTypeMultiple]; - } else if (event.modifierFlags & NSShiftKeyMask) { + } else if (event.modifierFlags & NSShiftKeyMask && self.allowsMultipleSelection) { [self selectItemAtIndexPath:indexPath atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES selectionType:JNWCollectionViewSelectionTypeExtending]; } else { [self selectItemAtIndexPath:indexPath atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES]; } + self.multipleSelectionSelectedIndexPath = nil; } - (void)mouseUpInCollectionViewCell:(JNWCollectionViewCell *)cell withEvent:(NSEvent *)event { @@ -1039,58 +1076,118 @@ - (void)rightClickInCollectionViewCell:(JNWCollectionViewCell *)cell withEvent:( } } -- (void)moveUp:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionUp currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES];} - -- (void)moveUpAndModifySelection:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionUp currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES selectionType:JNWCollectionViewSelectionTypeExtending]; +- (void)selectAll:(id)sender { + [self selectItemsAtIndexPaths:[self allIndexPaths] animated:YES]; } -- (void)moveDown:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionDown currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES]; +- (void)deselectAllItems { + [self deselectItemsAtIndexPaths:[self allIndexPaths] animated:YES]; } -- (void)moveDownAndModifySelection:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionDown currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES selectionType:JNWCollectionViewSelectionTypeExtending]; +- (void)selectAllItems { + [self selectAll:nil]; } -- (void)moveRight:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionRight currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES]; +- (void)mouseDown:(NSEvent *)theEvent +{ + NSEvent* event = [NSApp currentEvent]; + if ((event.modifierFlags >> 16) == 0) { + [self deselectAllItems]; + } } -- (void)moveRightAndModifySelection:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionRight currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES selectionType:JNWCollectionViewSelectionTypeExtending]; + + +#pragma mark - Keyboard Support + +- (void) _selectIndexPathAndAfterKeyPressAccountForMultiSelection:(NSIndexPath*)path animated:(BOOL)animated +{ + NSEvent* event = [NSApp currentEvent]; + JNWCollectionViewSelectionType selectionType = JNWCollectionViewSelectionTypeSingle; + if (event.modifierFlags & NSCommandKeyMask && self.allowsMultipleSelection) { + selectionType = JNWCollectionViewSelectionTypeMultipleDontAllowDeselection; + } + else if (event.modifierFlags & NSShiftKeyMask && self.allowsMultipleSelection) { + selectionType = JNWCollectionViewSelectionTypeExtending; + } + [self selectItemAtIndexPath:path atScrollPosition:JNWCollectionViewScrollPositionNearest animated:animated selectionType:selectionType]; + self.multipleSelectionSelectedIndexPath = path; } -- (void)moveLeft:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionLeft currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES]; +- (void)moveUp:(id)sender +{ + NSIndexPath* currentIndexPath = (self.multipleSelectionSelectedIndexPath) ? self.multipleSelectionSelectedIndexPath : [[self indexPathsForSelectedItems] firstObject]; + + NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionUp currentIndexPath:currentIndexPath]; + + if ([self.selectedIndexes containsObject:toSelect]) { + toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionUp currentIndexPath:[[self indexPathsForSelectedItems] firstObject]]; + } + + [self _selectIndexPathAndAfterKeyPressAccountForMultiSelection:toSelect animated:YES]; } -- (void)moveLeftAndModifySelection:(id)sender { - NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionLeft currentIndexPath:[self indexPathForSelectedItem]]; - [self selectItemAtIndexPath:toSelect atScrollPosition:JNWCollectionViewScrollPositionNearest animated:YES selectionType:JNWCollectionViewSelectionTypeExtending]; +- (void)moveDown:(id)sender +{ + NSIndexPath* currentIndexPath = (self.multipleSelectionSelectedIndexPath) ? self.multipleSelectionSelectedIndexPath : [[self indexPathsForSelectedItems] lastObject]; + + NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionDown currentIndexPath:currentIndexPath]; + + if ([self.selectedIndexes containsObject:toSelect]) { + toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionDown currentIndexPath:[[self indexPathsForSelectedItems] lastObject]]; + } + + [self _selectIndexPathAndAfterKeyPressAccountForMultiSelection:toSelect animated:YES]; } -- (void)selectAll:(id)sender { - [self selectItemsAtIndexPaths:[self allIndexPaths] animated:YES]; +- (void)moveRight:(id)sender +{ + NSIndexPath* currentIndexPath = (self.multipleSelectionSelectedIndexPath) ? self.multipleSelectionSelectedIndexPath : [[self indexPathsForSelectedItems] lastObject]; + + NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionRight currentIndexPath:currentIndexPath]; + + if ([self.selectedIndexes containsObject:toSelect]) { + toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionRight currentIndexPath:[[self indexPathsForSelectedItems] lastObject]]; + } + + [self _selectIndexPathAndAfterKeyPressAccountForMultiSelection:toSelect animated:YES]; } -- (void)deselectAllItems { - [self deselectItemsAtIndexPaths:[self allIndexPaths] animated:YES]; +- (void)moveLeft:(id)sender +{ + NSIndexPath* currentIndexPath = (self.multipleSelectionSelectedIndexPath) ? self.multipleSelectionSelectedIndexPath : [[self indexPathsForSelectedItems] firstObject]; + + NSIndexPath *toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionLeft currentIndexPath:currentIndexPath]; + + if ([self.selectedIndexes containsObject:toSelect]) { + toSelect = [self.collectionViewLayout indexPathForNextItemInDirection:JNWCollectionViewDirectionLeft currentIndexPath:[[self indexPathsForSelectedItems] firstObject]]; + } + + [self _selectIndexPathAndAfterKeyPressAccountForMultiSelection:toSelect animated:YES]; } -- (void)selectAllItems { - [self selectAll:nil]; + +- (BOOL)performKeyEquivalent:(NSEvent *)theEvent +{ + NSString* characters = [theEvent charactersIgnoringModifiers]; + if ([characters length] == 0) { + return NO; + } + + unichar key = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; + if (key == NSHomeFunctionKey && [self respondsToSelector:@selector(scrollToBeginningOfDocument:)]) { + [self scrollToBeginningOfDocument:theEvent]; + return YES; + } + else if (key == NSEndFunctionKey && [self respondsToSelector:@selector(scrollToEndOfDocument:)]) { + [self scrollToEndOfDocument:theEvent]; + return YES; + } + return NO; } -#pragma mark NSObject + +#pragma mark - NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; frame = %@; layer = <%@: %p>; content offset: %@> collection view layout: %@", @@ -1098,4 +1195,18 @@ - (NSString *)description { NSStringFromPoint(self.documentVisibleRect.origin), self.collectionViewLayout]; } +#pragma mark - NSResponder + +// TODO: make these ask the layout for "where's the beginning/end?" in case of non-ltr layouts +- (void)scrollToBeginningOfDocument:(id)sender { + [self.clipView scrollRectToVisible:NSMakeRect(0, 0, 0, 0) animated:self.animatesSelection]; +} + +- (void)scrollToEndOfDocument:(id)sender { + NSSize documentSize = ((JNWCollectionViewDocumentView *)self.clipView.documentView).frame.size; + NSRect scrollToRect = NSMakeRect(documentSize.width, documentSize.height, 0, 0); + [self.clipView scrollRectToVisible:scrollToRect animated:self.animatesSelection]; +} + + @end diff --git a/JNWCollectionView/JNWCollectionViewGridLayout.h b/JNWCollectionView/JNWCollectionViewGridLayout.h index 96e4b5a..0233c12 100644 --- a/JNWCollectionView/JNWCollectionViewGridLayout.h +++ b/JNWCollectionView/JNWCollectionViewGridLayout.h @@ -62,11 +62,6 @@ extern NSString * const JNWCollectionViewGridLayoutFooterKind; /// override any value set here. @property (nonatomic, assign) CGSize itemSize; -/// Choose whether even padding between horizontal items is enabled. -/// -/// Default is YES. -@property (nonatomic, assign) BOOL itemPaddingEnabled; - /// The vertical spacing between rows in the grid. /// /// Defaults to 0. @@ -78,3 +73,12 @@ extern NSString * const JNWCollectionViewGridLayoutFooterKind; @property (nonatomic, assign) CGFloat itemHorizontalMargin; @end + + +@interface JNWCollectionViewGridLayout (Deprecated) +/// Choose whether even padding between horizontal items is enabled. +/// Not used anymore. Please use Flow Layout. +/// +/// Default is YES. +@property (nonatomic, assign) BOOL itemPaddingEnabled; +@end \ No newline at end of file diff --git a/JNWCollectionView/JNWCollectionViewGridLayout.m b/JNWCollectionView/JNWCollectionViewGridLayout.m old mode 100644 new mode 100755 index e540be8..48785a5 --- a/JNWCollectionView/JNWCollectionViewGridLayout.m +++ b/JNWCollectionView/JNWCollectionViewGridLayout.m @@ -72,8 +72,6 @@ - (instancetype)init { self = [super init]; if (self == nil) return nil; self.itemSize = JNWCollectionViewGridLayoutDefaultSize; - self.itemPaddingEnabled = YES; -; return self; } @@ -115,18 +113,15 @@ - (void)prepareLayout { NSUInteger numberOfSections = [self.collectionView numberOfSections]; CGFloat verticalSpacing = self.verticalSpacing; - self.itemPadding = 0; + CGFloat itemPadding = 0; if (numberOfColumns > 0) { - if (self.itemHorizontalMargin == 0 && self.itemPaddingEnabled) { - CGFloat totalPadding = totalWidth - (numberOfColumns * itemSize.width); - self.itemPadding = floorf(totalPadding / (numberOfColumns + 1)); - } else { - self.itemPadding = self.itemHorizontalMargin; - } + CGFloat totalPadding = totalWidth - (numberOfColumns * itemSize.width); + itemPadding = floorf(totalPadding / numberOfColumns); } else { numberOfColumns = 1; } + self.itemPadding = itemPadding; self.numberOfColumns = numberOfColumns; CGFloat totalHeight = 0; @@ -146,7 +141,7 @@ - (void)prepareLayout { for (NSInteger item = 0; item < numberOfItems; item++) { CGPoint origin = CGPointZero; NSInteger column = ((item - (item % numberOfColumns)) / numberOfColumns); - origin.x = sectionInsets.left + self.itemPadding + (item % numberOfColumns) * (itemSize.width + self.itemPadding); + origin.x = sectionInsets.left + self.itemHorizontalMargin/2 + itemPadding/2 + totalWidth/numberOfColumns * (item % numberOfColumns); origin.y = column * itemSize.height + column * verticalSpacing; sectionInfo.itemInfo[item].origin = origin; } @@ -224,13 +219,12 @@ - (NSIndexPath *)indexPathForNextItemInDirection:(JNWCollectionViewDirection)dir } else if (direction == JNWCollectionViewDirectionUp) { CGPoint origin = [self.collectionView rectForItemAtIndexPath:currentIndexPath].origin; // Bump the origin up to the cell directly above this one. - origin.y -= 1; // TODO: Use padding here when implemented. + origin.y -= (self.itemSize.height + self.verticalSpacing); newIndexPath = [self.collectionView indexPathForItemAtPoint:origin]; } else if (direction == JNWCollectionViewDirectionDown) { - CGRect frame = [self.collectionView rectForItemAtIndexPath:currentIndexPath]; - CGPoint origin = frame.origin; + CGPoint origin = [self.collectionView rectForItemAtIndexPath:currentIndexPath].origin; // Bump the origin down to the cell directly below this one. - origin.y += frame.size.height + 1; // TODO: Use padding here when implemented. + origin.y += (self.itemSize.height + self.verticalSpacing); newIndexPath = [self.collectionView indexPathForItemAtPoint:origin]; } diff --git a/demo/JNWCollectionViewDemo/GridDemoViewController.m b/demo/JNWCollectionViewDemo/GridDemoViewController.m index 4b089b0..8aa6855 100644 --- a/demo/JNWCollectionViewDemo/GridDemoViewController.m +++ b/demo/JNWCollectionViewDemo/GridDemoViewController.m @@ -28,6 +28,7 @@ - (void)awakeFromNib { JNWCollectionViewGridLayout *gridLayout = [[JNWCollectionViewGridLayout alloc] init]; gridLayout.delegate = self; gridLayout.verticalSpacing = 10.f; + gridLayout.itemHorizontalMargin = 10.f; self.collectionView.collectionViewLayout = gridLayout; self.collectionView.dataSource = self;