Skip to content

Commit

Permalink
CollectionView supports grouping
Browse files Browse the repository at this point in the history
  • Loading branch information
pieteromvlee committed Mar 1, 2011
1 parent cebff4a commit 5247718
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 91 deletions.
1 change: 1 addition & 0 deletions BCCollectionView.h
Expand Up @@ -46,6 +46,7 @@
@property (nonatomic, copy) NSString *zoomValueObserverKey, *accumulatedKeyStrokes; @property (nonatomic, copy) NSString *zoomValueObserverKey, *accumulatedKeyStrokes;


@property (readonly) NSArray *visibleViewControllerArray; @property (readonly) NSArray *visibleViewControllerArray;
@property (readonly) BCCollectionViewLayoutManager *layoutManager;


//designated way to load BCCollectionView //designated way to load BCCollectionView
- (void)reloadDataWithItems:(NSArray *)newContent emptyCaches:(BOOL)shouldEmptyCaches; - (void)reloadDataWithItems:(NSArray *)newContent emptyCaches:(BOOL)shouldEmptyCaches;
Expand Down
89 changes: 57 additions & 32 deletions BCCollectionView.m
Expand Up @@ -4,9 +4,10 @@
#import "BCCollectionView.h" #import "BCCollectionView.h"
#import "BCGeometryExtensions.h" #import "BCGeometryExtensions.h"
#import "BCCollectionViewLayoutManager.h" #import "BCCollectionViewLayoutManager.h"
#import "BCCollectionViewGroup.h"


@implementation BCCollectionView @implementation BCCollectionView
@synthesize delegate, contentArray, backgroundColor, originalSelectionIndexes, zoomValueObserverKey, accumulatedKeyStrokes, numberOfPreRenderedRows; @synthesize delegate, contentArray, backgroundColor, originalSelectionIndexes, zoomValueObserverKey, accumulatedKeyStrokes, numberOfPreRenderedRows, layoutManager;
@dynamic visibleViewControllerArray; @dynamic visibleViewControllerArray;


- (id)initWithCoder:(NSCoder *)aDecoder - (id)initWithCoder:(NSCoder *)aDecoder
Expand Down Expand Up @@ -112,6 +113,14 @@ - (void)drawRect:(NSRect)dirtyRect


if (dragHoverIndex != NSNotFound && [self shoulDrawHover]) if (dragHoverIndex != NSNotFound && [self shoulDrawHover])
[self drawItemSelectionForInRect:[[[visibleViewControllers objectForKey:[NSNumber numberWithInteger:dragHoverIndex]] view] frame]]; [self drawItemSelectionForInRect:[[[visibleViewControllers objectForKey:[NSNumber numberWithInteger:dragHoverIndex]] view] frame]];

if ([delegate respondsToSelector:@selector(collectionView:drawGroupSeparator:inRect:)]) {
NSRect groupRect = NSMakeRect(0, 0, NSWidth([self visibleRect]), BCCollectionViewGroupHeight);
for (BCCollectionViewGroup *group in [layoutManager groups]) {
groupRect.origin.y = [layoutManager rectOfItemAtIndex:[group itemRange].location].origin.y-BCCollectionViewGroupHeight;
[delegate collectionView:self drawGroupSeparator:group inRect:groupRect];
}
}
} }


#pragma mark Delegate Call Wrappers #pragma mark Delegate Call Wrappers
Expand Down Expand Up @@ -208,10 +217,25 @@ - (NSIndexSet *)indexesOfItemContentRectsInRect:(NSRect)aRect
- (NSRange)rangeOfVisibleItems - (NSRange)rangeOfVisibleItems
{ {
NSRect visibleRect = [self visibleRect]; NSRect visibleRect = [self visibleRect];
NSUInteger firstIndex = [layoutManager indexOfItemAtPointOrClosestGuess:NSMakePoint(NSMinX(visibleRect), NSMinY(visibleRect))]; NSInteger numberOfRows = [layoutManager numberOfRows];
NSUInteger lastIndex = [layoutManager indexOfItemAtPointOrClosestGuess:NSMakePoint(NSMaxX(visibleRect), NSMaxY(visibleRect))]; NSInteger indexOfFirstItemAtRow = 0;
return NSIntersectionRange(NSMakeRange(firstIndex, lastIndex-firstIndex), NSInteger firstIndex = NSNotFound;
NSMakeRange(0, [contentArray count])); NSInteger lastIndex = NSNotFound;

for (NSInteger i=0; i<numberOfRows; i++) {
NSRect r = [layoutManager rectOfItemAtIndex:indexOfFirstItemAtRow];
BOOL rowIsVisible = NSIntersectionRange(NSMakeRange(r.origin.y, r.size.height), NSMakeRange(visibleRect.origin.y, visibleRect.size.height)).length != 0;

if (firstIndex == NSNotFound && rowIsVisible)
firstIndex = indexOfFirstItemAtRow;
if (firstIndex != NSNotFound && !rowIsVisible)
lastIndex = indexOfFirstItemAtRow-1;
if (firstIndex != NSNotFound && lastIndex != NSNotFound)
return NSMakeRange(firstIndex, lastIndex-firstIndex);

indexOfFirstItemAtRow += [layoutManager numberOfItemsAtRow:i];
}
return NSMakeRange(firstIndex, lastIndex-firstIndex);
} }


- (NSRange)rangeOfVisibleItemsWithOverflow - (NSRange)rangeOfVisibleItemsWithOverflow
Expand Down Expand Up @@ -428,7 +452,7 @@ - (void)softReloadVisibleViewControllers
- (void)resizeFrameToFitContents - (void)resizeFrameToFitContents
{ {
NSRect frame = [self frame]; NSRect frame = [self frame];
frame.size.height = MAX([self visibleRect].size.height, [layoutManager numberOfRows] * [self cellSize].height); frame.size.height = MAX([self visibleRect].size.height, NSMaxY([layoutManager rectOfItemAtIndex:[contentArray count]-1]));
[self setFrame:frame]; [self setFrame:frame];
} }


Expand All @@ -440,26 +464,27 @@ - (void)reloadDataWithItems:(NSArray *)newContent emptyCaches:(BOOL)shouldEmptyC
return; return;


self.contentArray = newContent; self.contentArray = newContent;
[layoutManager willReload]; [layoutManager reloadWithCompletionBlock:^{
[self resizeFrameToFitContents]; [self resizeFrameToFitContents];

if (shouldEmptyCaches) {
for (NSViewController *viewController in [visibleViewControllers allValues]) {
[[viewController view] removeFromSuperview];
if ([delegate respondsToSelector:@selector(collectionView:viewControllerBecameInvisible:)])
[delegate collectionView:self viewControllerBecameInvisible:viewController];
}


[reusableViewControllers removeAllObjects]; if (shouldEmptyCaches) {
[visibleViewControllers removeAllObjects]; for (NSViewController *viewController in [visibleViewControllers allValues]) {
} else [[viewController view] removeFromSuperview];
[self softReloadVisibleViewControllers]; if ([delegate respondsToSelector:@selector(collectionView:viewControllerBecameInvisible:)])

[delegate collectionView:self viewControllerBecameInvisible:viewController];
[selectionIndexes removeAllIndexes]; }


dispatch_async(dispatch_get_main_queue(), ^{ [reusableViewControllers removeAllObjects];
[self addMissingViewControllersToView]; [visibleViewControllers removeAllObjects];
}); } else
[self softReloadVisibleViewControllers];

[selectionIndexes removeAllIndexes];

dispatch_async(dispatch_get_main_queue(), ^{
[self addMissingViewControllersToView];
});
}];
} }


- (void)scrollViewDidScroll:(NSNotification *)note - (void)scrollViewDidScroll:(NSNotification *)note
Expand All @@ -480,13 +505,13 @@ - (void)scrollViewDidScroll:(NSNotification *)note


- (void)viewDidResize - (void)viewDidResize
{ {
[layoutManager willReload]; [layoutManager reloadWithCompletionBlock:^{
[self resizeFrameToFitContents]; [self resizeFrameToFitContents];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[layoutManager willReload]; [self moveViewControllersToProperPosition];
[self moveViewControllersToProperPosition]; [self addMissingViewControllersToView];
[self addMissingViewControllersToView]; });
}); }];
} }


- (NSMenu *)menuForEvent:(NSEvent *)anEvent - (NSMenu *)menuForEvent:(NSEvent *)anEvent
Expand Down
4 changes: 3 additions & 1 deletion BCCollectionViewDelegate.h
Expand Up @@ -3,7 +3,7 @@


#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>


@class BCCollectionView; @class BCCollectionView, BCCollectionViewGroup;


enum { enum {
BCCollectionViewScrollDirectionUp = 0, BCCollectionViewScrollDirectionUp = 0,
Expand Down Expand Up @@ -44,6 +44,8 @@ enum {
- (BOOL)collectionViewShouldDrawSelections:(BCCollectionView *)collectionView; - (BOOL)collectionViewShouldDrawSelections:(BCCollectionView *)collectionView;
- (BOOL)collectionViewShouldDrawHover:(BCCollectionView *)collectionView; - (BOOL)collectionViewShouldDrawHover:(BCCollectionView *)collectionView;


- (void)collectionView:(BCCollectionView *)collectionView drawGroupSeparator:(BCCollectionViewGroup *)group inRect:(NSRect)rect;

//managing Drag & Drop (in order of occurence) //managing Drag & Drop (in order of occurence)
- (BOOL)collectionView:(BCCollectionView *)collectionView canDragItemsAtIndexes:(NSIndexSet *)indexSet; - (BOOL)collectionView:(BCCollectionView *)collectionView canDragItemsAtIndexes:(NSIndexSet *)indexSet;
- (void)collectionView:(BCCollectionView *)collectionView writeItemsAtIndexes:(NSIndexSet *)indexSet toPasteboard:(NSPasteboard *)pboard; - (void)collectionView:(BCCollectionView *)collectionView writeItemsAtIndexes:(NSIndexSet *)indexSet toPasteboard:(NSPasteboard *)pboard;
Expand Down
19 changes: 19 additions & 0 deletions BCCollectionViewGroup.h
@@ -0,0 +1,19 @@
// Created by Pieter Omvlee on 01/03/2011.
// Copyright 2011 Bohemian Coding. All rights reserved.

#import <Foundation/Foundation.h>

#define BCCollectionViewGroupHeight 30

@interface BCCollectionViewGroup : NSObject
{
NSString *title;
NSRange itemRange;
BOOL isCollapsed;
}
+ (id)groupWithTitle:(NSString *)title range:(NSRange)range;
@property (copy) NSString *title;
@property NSRange itemRange;
@property (setter=setCollapsed:) BOOL isCollapsed;

@end
23 changes: 23 additions & 0 deletions BCCollectionViewGroup.m
@@ -0,0 +1,23 @@
// Created by Pieter Omvlee on 01/03/2011.
// Copyright 2011 Bohemian Coding. All rights reserved.

#import "BCCollectionViewGroup.h"

@implementation BCCollectionViewGroup
@synthesize title, itemRange, isCollapsed;

+ (id)groupWithTitle:(NSString *)title range:(NSRange)range
{
BCCollectionViewGroup *group = [[BCCollectionViewGroup alloc] init];
[group setTitle:title];
[group setItemRange:range];
return [group autorelease];
}

- (void)dealloc
{
[title release];
[super dealloc];
}

@end
14 changes: 14 additions & 0 deletions BCCollectionViewItemLayout.h
@@ -0,0 +1,14 @@
// Created by Pieter Omvlee on 01/03/2011.
// Copyright 2011 Bohemian Coding. All rights reserved.

#import <Foundation/Foundation.h>

@interface BCCollectionViewItemLayout : NSObject
{
NSInteger rowIndex, columnIndex, itemIndex;
NSRect itemRect;
}
@property NSInteger rowIndex, columnIndex, itemIndex;
@property NSRect itemRect;
+ (id)layoutItem;
@end
14 changes: 14 additions & 0 deletions BCCollectionViewItemLayout.m
@@ -0,0 +1,14 @@
// Created by Pieter Omvlee on 01/03/2011.
// Copyright 2011 Bohemian Coding. All rights reserved.

#import "BCCollectionViewItemLayout.h"

@implementation BCCollectionViewItemLayout
@synthesize rowIndex, columnIndex, itemRect, itemIndex;

+ (id)layoutItem
{
return [[[self alloc] init] autorelease];
}

@end
18 changes: 12 additions & 6 deletions BCCollectionViewLayoutManager.h
Expand Up @@ -8,19 +8,25 @@
{ {
BCCollectionView *collectionView; BCCollectionView *collectionView;
NSInteger numberOfRows; NSInteger numberOfRows;
NSArray *groups;
NSMutableArray *itemLayouts;

NSOperationQueue *queue;
} }
@property (copy) NSArray *groups;
- (id)initWithCollectionView:(BCCollectionView *)collectionView; //assigned - (id)initWithCollectionView:(BCCollectionView *)collectionView; //assigned
- (void)reloadWithCompletionBlock:(dispatch_block_t)completionBlock;


- (void)willReload; #pragma mark Primitives
- (NSUInteger)numberOfRows; - (NSUInteger)numberOfRows;
- (NSUInteger)numberOfItemsAtRow:(NSInteger)rowIndex; - (NSUInteger)numberOfItemsAtRow:(NSInteger)rowIndex;
- (NSUInteger)rowOfItemAtIndex:(NSInteger)anIndex;
- (NSSize)cellSize; - (NSSize)cellSize;
- (NSUInteger)indexOfItemAtPointOrClosestGuess:(NSPoint)p;

- (NSRect)rectOfItemAtIndex:(NSUInteger)anIndex;
- (NSRect)contentRectOfItemAtIndex:(NSUInteger)anIndex;


#pragma mark From Point to Index
- (NSUInteger)indexOfItemAtPoint:(NSPoint)p; - (NSUInteger)indexOfItemAtPoint:(NSPoint)p;
- (NSUInteger)indexOfItemContentRectAtPoint:(NSPoint)p; - (NSUInteger)indexOfItemContentRectAtPoint:(NSPoint)p;

#pragma mark From Index to Rect
- (NSRect)rectOfItemAtIndex:(NSUInteger)anIndex;
- (NSRect)contentRectOfItemAtIndex:(NSUInteger)anIndex;
@end @end

0 comments on commit 5247718

Please sign in to comment.