68 unsigned _maxNumberOfRows;
69 unsigned _maxNumberOfColumns;
79 BOOL _allowsMultipleSelection;
80 BOOL _allowsEmptySelection;
85 float _horizontalMargin;
86 float _verticalMargin;
88 unsigned _numberOfRows;
89 unsigned _numberOfColumns;
96 - (id)initWithFrame:(CGRect)aFrame
107 _itemSize = CGSizeMakeZero();
108 _minItemSize = CGSizeMakeZero();
109 _maxItemSize = CGSizeMakeZero();
113 _verticalMargin = 5.0;
117 _allowsEmptySelection = YES;
175 _itemForDragging = nil;
176 _itemPrototype = anItem;
186 return _itemPrototype;
197 if (_cachedItems.length)
198 item = _cachedItems.pop();
209 [item setRepresentedObject:anObject];
210 [[item view] setFrameSize:_itemSize];
219 - (BOOL)acceptsFirstResponder
227 - (BOOL)isFirstResponder
272 - (void)setSelectable:(BOOL)isSelectable
274 if (_isSelectable == isSelectable)
277 _isSelectable = isSelectable;
282 itemCount = [_items count];
285 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !=
CPNotFound && index < itemCount)
286 [_items[index] setSelected:NO];
296 return _isSelectable;
303 - (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
305 _allowsEmptySelection = shouldAllowEmptySelection;
311 - (BOOL)allowsEmptySelection
313 return _allowsEmptySelection;
320 - (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
322 _allowsMultipleSelection = shouldAllowMultipleSelection;
328 - (BOOL)allowsMultipleSelection
330 return _allowsMultipleSelection;
341 if (!_isSelectable || [_selectionIndexes
isEqual:anIndexSet])
345 itemCount = [_items count];
348 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !==
CPNotFound && index < itemCount)
349 [_items[index] setSelected:NO];
351 _selectionIndexes = anIndexSet;
355 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !==
CPNotFound)
356 [_items[index] setSelected:YES];
358 var binderClass = [[
self class] _binderClassForBinding:@"selectionIndexes"];
359 [[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
361 if ([_delegate respondsToSelector:
@selector(collectionViewDidChangeSelection:)])
362 [_delegate collectionViewDidChangeSelection:self];
370 return [_selectionIndexes copy];
374 - (void)reloadContent
377 var count = _items.length;
381 [[_items[count] view] removeFromSuperview];
382 [_items[count] setSelected:NO];
384 _cachedItems.push(_items[count]);
394 count = _content.length;
396 for (; index < count; ++index)
398 _items.push([
self newItemForRepresentedObject:_content[index]]);
405 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !=
CPNotFound && index < count)
406 [_items[index] setSelected:YES];
414 var
width = CGRectGetWidth([
self bounds]);
416 if (
width == _tileWidth)
422 var itemSize = CGSizeMakeCopy(_minItemSize);
424 _numberOfColumns = MAX(1.0, FLOOR(
width / itemSize.width));
426 if (_maxNumberOfColumns > 0)
427 _numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
429 var remaining =
width - _numberOfColumns * itemSize.width,
430 itemsNeedSizeUpdate = NO;
432 if (remaining > 0 && itemSize.width < _maxItemSize.width)
433 itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns));
436 if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width <
width)
437 itemSize.width = MIN(_maxItemSize.width,
width);
439 if (!CGSizeEqualToSize(_itemSize, itemSize))
441 _itemSize = itemSize;
442 itemsNeedSizeUpdate = YES;
446 count = _items.length;
448 if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
449 count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
451 _numberOfRows = CEIL(count / _numberOfColumns);
453 _horizontalMargin = FLOOR((
width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
455 var x = _horizontalMargin,
456 y = -itemSize.height;
458 for (; index < count; ++index)
460 if (index % _numberOfColumns == 0)
462 x = _horizontalMargin;
463 y += _verticalMargin + itemSize.height;
466 var view = [_items[index] view];
468 [view setFrameOrigin:CGPointMake(x, y)];
470 if (itemsNeedSizeUpdate)
471 [view setFrameSize:_itemSize];
473 x += itemSize.width + _horizontalMargin;
477 proposedHeight = y + itemSize.height + _verticalMargin;
479 if ([superview isKindOfClass:[
CPClipView class]])
482 proposedHeight = MAX(superviewSize.height, proposedHeight);
490 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
500 - (void)setMaxNumberOfRows:(
unsigned)aMaxNumberOfRows
502 if (_maxNumberOfRows == aMaxNumberOfRows)
505 _maxNumberOfRows = aMaxNumberOfRows;
513 - (unsigned)maxNumberOfRows
515 return _maxNumberOfRows;
522 - (void)setMaxNumberOfColumns:(
unsigned)aMaxNumberOfColumns
524 if (_maxNumberOfColumns == aMaxNumberOfColumns)
527 _maxNumberOfColumns = aMaxNumberOfColumns;
535 - (unsigned)maxNumberOfColumns
537 return _maxNumberOfColumns;
543 - (unsigned)numberOfRows
545 return _numberOfRows;
552 - (unsigned)numberOfColumns
554 return _numberOfColumns;
561 - (void)setMinItemSize:(CGSize)aSize
563 if (aSize === nil || aSize === undefined)
565 if (CGSizeEqualToSize(_minItemSize, aSize))
568 _minItemSize = CGSizeMakeCopy(aSize);
576 - (CGSize)minItemSize
585 - (void)setMaxItemSize:(CGSize)aSize
587 if (CGSizeEqualToSize(_maxItemSize, aSize))
590 _maxItemSize = CGSizeMakeCopy(aSize);
598 - (CGSize)maxItemSize
603 - (void)setBackgroundColors:(
CPArray)backgroundColors
605 if (_backgroundColors === backgroundColors)
608 _backgroundColors = backgroundColors;
610 if (!_backgroundColors)
613 if ([_backgroundColors count] === 1)
624 return _backgroundColors;
629 if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:
@selector(collectionView:didDoubleClickOnItemAtIndex:)])
630 [_delegate collectionView:self didDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]];
635 _mouseDownEvent = anEvent;
638 index = [
self _indexAtPoint:location];
640 if (index >= 0 && index < _items.length)
646 var indexes = [_selectionIndexes copy];
648 if ([indexes containsIndex:index])
649 [indexes removeIndex:index];
651 [indexes addIndex:index];
653 else if ([anEvent modifierFlags] & CPShiftKeyMask)
656 newSelectedRange = nil;
658 if (index < firstSelectedIndex)
659 newSelectedRange =
CPMakeRange(index, (firstSelectedIndex - index) + 1);
661 newSelectedRange =
CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1);
664 [indexes addIndexesInRange:newSelectedRange];
679 else if (_allowsEmptySelection)
686 if (!_mouseDownEvent)
690 mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
693 if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
694 (ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
697 if (![_delegate respondsToSelector:
@selector(collectionView:dragTypesForItemsAtIndexes:)])
701 if (![_selectionIndexes count])
704 if ([_delegate respondsToSelector:
@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
705 ![_delegate collectionView:
self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
709 var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
713 if (!_itemForDragging)
716 [_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]];
718 var view = [_itemForDragging view];
720 [view setFrameSize:_itemSize];
721 [view setAlphaValue:0.7];
724 at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin
726 event:_mouseDownEvent
739 [aPasteboard
setData:[_delegate collectionView:self dataForItemsAtIndexes:_selectionIndexes forType:aType]
forType:aType];
749 - (void)setVerticalMargin:(
float)aVerticalMargin
751 if (_verticalMargin == aVerticalMargin)
754 _verticalMargin = aVerticalMargin;
763 - (float)verticalMargin
765 return _verticalMargin;
772 - (void)setDelegate:(
id)aDelegate
774 _delegate = aDelegate;
790 if (![[
self delegate] respondsToSelector:
@selector(collectionView:menuForItemAtIndex:)])
794 index = [
self _indexAtPoint:location];
796 return [_delegate collectionView:self menuForItemAtIndex:index];
799 - (int)_indexAtPoint:(CGPoint)thePoint
801 var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
802 column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
804 return row * _numberOfColumns + column;
809 return [_items objectAtIndex:anIndex];
812 - (CGRect)frameForItemAtIndex:(
unsigned)anIndex
825 count = [indexArray count];
827 for (; index < count; ++index)
828 frame = CGRectUnion(
frame, [
self frameForItemAtIndex:indexArray[index]]);
837 - (void)_modifySelectionWithNewIndex:(
int)anIndex direction:(
int)aDirection expand:(BOOL)shouldExpand
839 anIndex = MIN(MAX(anIndex, 0), [[
self items] count] - 1);
841 if (_allowsMultipleSelection && shouldExpand)
843 var indexes = [_selectionIndexes copy],
844 bottomAnchor = [indexes firstIndex],
845 topAnchor = [indexes lastIndex];
848 if (aDirection === -1)
849 [indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)];
851 [indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)];
857 [
self _scrollToSelection];
860 - (void)_scrollToSelection
862 var
frame = [
self frameForItemsAtIndexes:[
self selectionIndexes]];
864 if (!CGRectIsNull(
frame))
865 [
self scrollRectToVisible:frame];
868 - (void)moveLeft:(
id)sender
874 [
self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
877 - (void)moveLeftAndModifySelection:(
id)sender
883 [
self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
886 - (void)moveRight:(
id)sender
891 - (void)moveRightAndModifySelection:(
id)sender
896 - (void)moveDown:(
id)sender
901 - (void)moveDownAndModifySelection:(
id)sender
906 - (void)moveUp:(
id)sender
912 [
self _modifySelectionWithNewIndex:index - [
self numberOfColumns] direction:-1 expand:NO];
915 - (void)moveUpAndModifySelection:(
id)sender
921 [
self _modifySelectionWithNewIndex:index - [
self numberOfColumns] direction:-1 expand:YES];
924 - (void)deleteBackward:(
id)sender
926 if ([[
self delegate] respondsToSelector:
@selector(collectionView:shouldDeleteItemsAtIndexes:)])
931 if (index > [[
self content] count] - 1)
934 [
self _scrollToSelection];
948 - (CGRect)rectForItemAtIndex:(
int)anIndex
950 _CPReportLenientDeprecation([
self class], _cmd,
@selector(frameForItemAtIndex:));
959 _CPReportLenientDeprecation([
self class], _cmd,
@selector(frameForItemsAtIndexes:));
982 var prototypeView = [_itemPrototype view];
983 if (prototypeView && (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())))
985 var item = _itemPrototype;
987 if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
988 _minItemSize = [prototypeView frameSize];
989 else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
990 _maxItemSize = [prototypeView frameSize];
1005 _itemSize = CGSizeMakeZero();
1007 _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey];
1008 _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey];
1010 _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey];
1011 _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey];
1013 _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
1015 _isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
1016 _allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
1018 [
self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
1024 _allowsEmptySelection = YES;
1034 if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
1035 [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
1037 if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
1038 [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
1040 [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
1041 [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
1043 [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
1044 [aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
1046 [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
1048 [aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];