![]() |
API 0.9.5
|
00001 /* 00002 * CPCollectionView.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 00025 00059 @implementation CPCollectionView : CPView 00060 { 00061 CPArray _content; 00062 CPArray _items; 00063 00064 CPData _itemData; 00065 CPCollectionViewItem _itemPrototype; 00066 CPCollectionViewItem _itemForDragging; 00067 CPMutableArray _cachedItems; 00068 00069 unsigned _maxNumberOfRows; 00070 unsigned _maxNumberOfColumns; 00071 00072 CGSize _minItemSize; 00073 CGSize _maxItemSize; 00074 00075 CPArray _backgroundColors; 00076 00077 float _tileWidth; 00078 00079 BOOL _isSelectable; 00080 BOOL _allowsMultipleSelection; 00081 BOOL _allowsEmptySelection; 00082 CPIndexSet _selectionIndexes; 00083 00084 CGSize _itemSize; 00085 00086 float _horizontalMargin; 00087 float _verticalMargin; 00088 00089 unsigned _numberOfRows; 00090 unsigned _numberOfColumns; 00091 00092 id _delegate; 00093 00094 CPEvent _mouseDownEvent; 00095 } 00096 00097 - (id)initWithFrame:(CGRect)aFrame 00098 { 00099 self = [super initWithFrame:aFrame]; 00100 00101 if (self) 00102 { 00103 _items = []; 00104 _content = []; 00105 00106 _cachedItems = []; 00107 00108 _itemSize = CGSizeMakeZero(); 00109 _minItemSize = CGSizeMakeZero(); 00110 _maxItemSize = CGSizeMakeZero(); 00111 00112 [self setBackgroundColors:nil]; 00113 00114 _verticalMargin = 5.0; 00115 _tileWidth = -1.0; 00116 00117 _selectionIndexes = [CPIndexSet indexSet]; 00118 _allowsEmptySelection = YES; 00119 _isSelectable = YES; 00120 } 00121 00122 return self; 00123 } 00124 00172 - (void)setItemPrototype:(CPCollectionViewItem)anItem 00173 { 00174 _cachedItems = []; 00175 _itemData = nil; 00176 _itemForDragging = nil; 00177 _itemPrototype = anItem; 00178 00179 [self reloadContent]; 00180 } 00181 00185 - (CPCollectionViewItem)itemPrototype 00186 { 00187 return _itemPrototype; 00188 } 00189 00194 - (CPCollectionViewItem)newItemForRepresentedObject:(id)anObject 00195 { 00196 var item = nil; 00197 00198 if (_cachedItems.length) 00199 item = _cachedItems.pop(); 00200 00201 else 00202 { 00203 if (!_itemData) 00204 if (_itemPrototype) 00205 _itemData = [CPKeyedArchiver archivedDataWithRootObject:_itemPrototype]; 00206 00207 item = [CPKeyedUnarchiver unarchiveObjectWithData:_itemData]; 00208 } 00209 00210 [item setRepresentedObject:anObject]; 00211 [[item view] setFrameSize:_itemSize]; 00212 00213 return item; 00214 } 00215 00216 // Working with the Responder Chain 00220 - (BOOL)acceptsFirstResponder 00221 { 00222 return YES; 00223 } 00224 00228 - (BOOL)isFirstResponder 00229 { 00230 return [[self window] firstResponder] === self; 00231 } 00232 00233 // Setting the Content 00240 - (void)setContent:(CPArray)anArray 00241 { 00242 // reset the _selectionIndexes 00243 [self setSelectionIndexes:[CPIndexSet indexSet]]; 00244 00245 _content = anArray; 00246 00247 [self reloadContent]; 00248 } 00249 00253 - (CPArray)content 00254 { 00255 return _content; 00256 } 00257 00261 - (CPArray)items 00262 { 00263 return _items; 00264 } 00265 00266 // Setting the Selection Mode 00271 - (void)setSelectable:(BOOL)isSelectable 00272 { 00273 if (_isSelectable == isSelectable) 00274 return; 00275 00276 _isSelectable = isSelectable; 00277 00278 if (!_isSelectable) 00279 { 00280 var index = CPNotFound; 00281 00282 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) 00283 [_items[index] setSelected:NO]; 00284 } 00285 } 00286 00291 - (BOOL)isSelectable 00292 { 00293 return _isSelectable; 00294 } 00295 00300 - (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection 00301 { 00302 _allowsEmptySelection = shouldAllowEmptySelection; 00303 } 00304 00308 - (BOOL)allowsEmptySelection 00309 { 00310 return _allowsEmptySelection; 00311 } 00312 00317 - (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection 00318 { 00319 _allowsMultipleSelection = shouldAllowMultipleSelection; 00320 } 00321 00325 - (BOOL)allowsMultipleSelection 00326 { 00327 return _allowsMultipleSelection; 00328 } 00329 00334 - (void)setSelectionIndexes:(CPIndexSet)anIndexSet 00335 { 00336 if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable) 00337 return; 00338 00339 var index = CPNotFound; 00340 00341 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) 00342 [_items[index] setSelected:NO]; 00343 00344 _selectionIndexes = anIndexSet; 00345 00346 var index = CPNotFound; 00347 00348 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) 00349 [_items[index] setSelected:YES]; 00350 00351 var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"]; 00352 [[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"]; 00353 00354 if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) 00355 [_delegate collectionViewDidChangeSelection:self]; 00356 } 00357 00361 - (CPIndexSet)selectionIndexes 00362 { 00363 return [_selectionIndexes copy]; 00364 } 00365 00366 /* @ignore */ 00367 - (void)reloadContent 00368 { 00369 // Remove current views 00370 var count = _items.length; 00371 00372 while (count--) 00373 { 00374 [[_items[count] view] removeFromSuperview]; 00375 [_items[count] setSelected:NO]; 00376 00377 _cachedItems.push(_items[count]); 00378 } 00379 00380 _items = []; 00381 00382 if (!_itemPrototype) 00383 return; 00384 00385 var index = 0; 00386 00387 count = _content.length; 00388 00389 for (; index < count; ++index) 00390 { 00391 _items.push([self newItemForRepresentedObject:_content[index]]); 00392 00393 [self addSubview:[_items[index] view]]; 00394 } 00395 00396 index = CPNotFound; 00397 while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) 00398 [_items[index] setSelected:YES]; 00399 00400 [self tile]; 00401 } 00402 00403 /* @ignore */ 00404 - (void)tile 00405 { 00406 var width = CGRectGetWidth([self bounds]); 00407 00408 if (width == _tileWidth) 00409 return; 00410 00411 // We try to fit as many views per row as possible. Any remaining space is then 00412 // either proportioned out to the views (if their minSize != maxSize) or used as 00413 // margin 00414 var itemSize = CGSizeMakeCopy(_minItemSize); 00415 00416 _numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width)); 00417 00418 if (_maxNumberOfColumns > 0) 00419 _numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns); 00420 00421 var remaining = width - _numberOfColumns * itemSize.width, 00422 itemsNeedSizeUpdate = NO; 00423 00424 if (remaining > 0 && itemSize.width < _maxItemSize.width) 00425 itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns)); 00426 00427 // When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width. 00428 if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width) 00429 itemSize.width = MIN(_maxItemSize.width, width); 00430 00431 if (!CGSizeEqualToSize(_itemSize, itemSize)) 00432 { 00433 _itemSize = itemSize; 00434 itemsNeedSizeUpdate = YES; 00435 } 00436 00437 var index = 0, 00438 count = _items.length; 00439 00440 if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0) 00441 count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows); 00442 00443 _numberOfRows = CEIL(count / _numberOfColumns); 00444 00445 _horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1)); 00446 00447 var x = _horizontalMargin, 00448 y = -itemSize.height; 00449 00450 for (; index < count; ++index) 00451 { 00452 if (index % _numberOfColumns == 0) 00453 { 00454 x = _horizontalMargin; 00455 y += _verticalMargin + itemSize.height; 00456 } 00457 00458 var view = [_items[index] view]; 00459 00460 [view setFrameOrigin:CGPointMake(x, y)]; 00461 00462 if (itemsNeedSizeUpdate) 00463 [view setFrameSize:_itemSize]; 00464 00465 x += itemSize.width + _horizontalMargin; 00466 } 00467 00468 var superview = [self superview], 00469 proposedHeight = y + itemSize.height + _verticalMargin; 00470 00471 if ([superview isKindOfClass:[CPClipView class]]) 00472 { 00473 var superviewSize = [superview bounds].size; 00474 proposedHeight = MAX(superviewSize.height, proposedHeight); 00475 } 00476 00477 _tileWidth = width; 00478 [self setFrameSize:CGSizeMake(width, proposedHeight)]; 00479 _tileWidth = -1.0; 00480 } 00481 00482 - (void)resizeSubviewsWithOldSize:(CGSize)aSize 00483 { 00484 [self tile]; 00485 } 00486 00487 // Laying Out the Collection View 00492 - (void)setMaxNumberOfRows:(unsigned)aMaxNumberOfRows 00493 { 00494 if (_maxNumberOfRows == aMaxNumberOfRows) 00495 return; 00496 00497 _maxNumberOfRows = aMaxNumberOfRows; 00498 00499 [self tile]; 00500 } 00501 00505 - (unsigned)maxNumberOfRows 00506 { 00507 return _maxNumberOfRows; 00508 } 00509 00514 - (void)setMaxNumberOfColumns:(unsigned)aMaxNumberOfColumns 00515 { 00516 if (_maxNumberOfColumns == aMaxNumberOfColumns) 00517 return; 00518 00519 _maxNumberOfColumns = aMaxNumberOfColumns; 00520 00521 [self tile]; 00522 } 00523 00527 - (unsigned)maxNumberOfColumns 00528 { 00529 return _maxNumberOfColumns; 00530 } 00531 00535 - (unsigned)numberOfRows 00536 { 00537 return _numberOfRows; 00538 } 00539 00544 - (unsigned)numberOfColumns 00545 { 00546 return _numberOfColumns; 00547 } 00548 00553 - (void)setMinItemSize:(CGSize)aSize 00554 { 00555 if (CGSizeEqualToSize(_minItemSize, aSize)) 00556 return; 00557 00558 _minItemSize = CGSizeMakeCopy(aSize); 00559 00560 [self tile]; 00561 } 00562 00566 - (CGSize)minItemSize 00567 { 00568 return _minItemSize; 00569 } 00570 00575 - (void)setMaxItemSize:(CGSize)aSize 00576 { 00577 if (CGSizeEqualToSize(_maxItemSize, aSize)) 00578 return; 00579 00580 _maxItemSize = CGSizeMakeCopy(aSize); 00581 00582 [self tile]; 00583 } 00584 00588 - (CGSize)maxItemSize 00589 { 00590 return _maxItemSize; 00591 } 00592 00593 - (void)setBackgroundColors:(CPArray)backgroundColors 00594 { 00595 if (_backgroundColors === backgroundColors) 00596 return; 00597 00598 _backgroundColors = backgroundColors; 00599 00600 if (!_backgroundColors) 00601 _backgroundColors = [CPColor whiteColor]; 00602 00603 if ([_backgroundColors count] === 1) 00604 [self setBackgroundColor:_backgroundColors[0]]; 00605 00606 else 00607 [self setBackgroundColor:nil]; 00608 00609 [self setNeedsDisplay:YES]; 00610 } 00611 00612 - (CPArray)backgroundColors 00613 { 00614 return _backgroundColors; 00615 } 00616 00617 - (void)mouseUp:(CPEvent)anEvent 00618 { 00619 if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)]) 00620 [_delegate collectionView:self didDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]]; 00621 } 00622 00623 - (void)mouseDown:(CPEvent)anEvent 00624 { 00625 _mouseDownEvent = anEvent; 00626 00627 var location = [self convertPoint:[anEvent locationInWindow] fromView:nil], 00628 index = [self _indexAtPoint:location]; 00629 00630 if (index >= 0 && index < _items.length) 00631 { 00632 if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPCommandKeyMask || [anEvent modifierFlags] & CPShiftKeyMask)) 00633 { 00634 if ([anEvent modifierFlags] & CPCommandKeyMask) 00635 { 00636 var indexes = [_selectionIndexes copy]; 00637 00638 if ([indexes containsIndex:index]) 00639 [indexes removeIndex:index]; 00640 else 00641 [indexes addIndex:index]; 00642 } 00643 else if ([anEvent modifierFlags] & CPShiftKeyMask) 00644 { 00645 var firstSelectedIndex = [[self selectionIndexes] firstIndex], 00646 newSelectedRange = nil; 00647 00648 if (index < firstSelectedIndex) 00649 newSelectedRange = CPMakeRange(index, (firstSelectedIndex - index) + 1); 00650 else 00651 newSelectedRange = CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1); 00652 00653 indexes = [[self selectionIndexes] copy]; 00654 [indexes addIndexesInRange:newSelectedRange]; 00655 } 00656 } 00657 else 00658 indexes = [CPIndexSet indexSetWithIndex:index]; 00659 00660 [self setSelectionIndexes:indexes]; 00661 } 00662 else if (_allowsEmptySelection) 00663 [self setSelectionIndexes:[CPIndexSet indexSet]]; 00664 } 00665 00666 - (void)mouseDragged:(CPEvent)anEvent 00667 { 00668 var locationInWindow = [anEvent locationInWindow], 00669 mouseDownLocationInWindow = [_mouseDownEvent locationInWindow]; 00670 00671 // FIXME: This is because Safari's drag hysteresis is 3px x 3px 00672 if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) && 00673 (ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3)) 00674 return; 00675 00676 if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)]) 00677 return; 00678 00679 // If we don't have any selected items, we've clicked away, and thus the drag is meaningless. 00680 if (![_selectionIndexes count]) 00681 return; 00682 00683 if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] && 00684 ![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent]) 00685 return; 00686 00687 // Set up the pasteboard 00688 var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes]; 00689 00690 [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self]; 00691 00692 if (!_itemForDragging) 00693 _itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]]; 00694 else 00695 [_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]]; 00696 00697 var view = [_itemForDragging view]; 00698 00699 [view setFrameSize:_itemSize]; 00700 [view setAlphaValue:0.7]; 00701 00702 [self dragView:view 00703 at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin 00704 offset:CGSizeMakeZero() 00705 event:_mouseDownEvent 00706 pasteboard:nil 00707 source:self 00708 slideBack:YES]; 00709 } 00710 00716 - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType 00717 { 00718 [aPasteboard setData:[_delegate collectionView:self dataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType]; 00719 } 00720 00721 // Cappuccino Additions 00722 00728 - (void)setVerticalMargin:(float)aVerticalMargin 00729 { 00730 if (_verticalMargin == aVerticalMargin) 00731 return; 00732 00733 _verticalMargin = aVerticalMargin; 00734 00735 [self tile]; 00736 } 00737 00742 - (float)verticalMargin 00743 { 00744 return _verticalMargin; 00745 } 00746 00751 - (void)setDelegate:(id)aDelegate 00752 { 00753 _delegate = aDelegate; 00754 } 00755 00759 - (id)delegate 00760 { 00761 return _delegate; 00762 } 00763 00767 - (CPMenu)menuForEvent:(CPEvent)theEvent 00768 { 00769 if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)]) 00770 return [super menuForEvent:theEvent]; 00771 00772 var location = [self convertPoint:[theEvent locationInWindow] fromView:nil], 00773 index = [self _indexAtPoint:location]; 00774 00775 return [_delegate collectionView:self menuForItemAtIndex:index]; 00776 } 00777 00778 - (int)_indexAtPoint:(CGPoint)thePoint 00779 { 00780 var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)), 00781 column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin)); 00782 00783 return row * _numberOfColumns + column; 00784 } 00785 00786 - (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex 00787 { 00788 return [_items objectAtIndex:anIndex]; 00789 } 00790 00791 - (CGRect)frameForItemAtIndex:(unsigned)anIndex 00792 { 00793 return [[[self itemAtIndex:anIndex] view] frame]; 00794 } 00795 00796 - (CGRect)frameForItemsAtIndexes:(CPIndexSet)anIndexSet 00797 { 00798 var indexArray = [], 00799 frame = CGRectNull; 00800 00801 [anIndexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil]; 00802 00803 var index = 0, 00804 count = [indexArray count]; 00805 00806 for (; index < count; ++index) 00807 frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]); 00808 00809 return frame; 00810 } 00811 00812 @end 00813 00814 @implementation CPCollectionView (KeyboardInteraction) 00815 00816 - (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand 00817 { 00818 anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1); 00819 00820 if (_allowsMultipleSelection && shouldExpand) 00821 { 00822 var indexes = [_selectionIndexes copy], 00823 bottomAnchor = [indexes firstIndex], 00824 topAnchor = [indexes lastIndex]; 00825 00826 // if the direction is backward (-1) check with the bottom anchor 00827 if (aDirection === -1) 00828 [indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)]; 00829 else 00830 [indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)]; 00831 } 00832 else 00833 indexes = [CPIndexSet indexSetWithIndex:anIndex]; 00834 00835 [self setSelectionIndexes:indexes]; 00836 [self _scrollToSelection]; 00837 } 00838 00839 - (void)_scrollToSelection 00840 { 00841 var frame = [self frameForItemsAtIndexes:[self selectionIndexes]]; 00842 00843 if (!CGRectIsNull(frame)) 00844 [self scrollRectToVisible:frame]; 00845 } 00846 00847 - (void)moveLeft:(id)sender 00848 { 00849 var index = [[self selectionIndexes] firstIndex]; 00850 if (index === CPNotFound) 00851 index = [[self items] count]; 00852 00853 [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO]; 00854 } 00855 00856 - (void)moveLeftAndModifySelection:(id)sender 00857 { 00858 var index = [[self selectionIndexes] firstIndex]; 00859 if (index === CPNotFound) 00860 index = [[self items] count]; 00861 00862 [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES]; 00863 } 00864 00865 - (void)moveRight:(id)sender 00866 { 00867 [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO]; 00868 } 00869 00870 - (void)moveRightAndModifySelection:(id)sender 00871 { 00872 [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES]; 00873 } 00874 00875 - (void)moveDown:(id)sender 00876 { 00877 [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO]; 00878 } 00879 00880 - (void)moveDownAndModifySelection:(id)sender 00881 { 00882 [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES]; 00883 } 00884 00885 - (void)moveUp:(id)sender 00886 { 00887 var index = [[self selectionIndexes] firstIndex]; 00888 if (index == CPNotFound) 00889 index = [[self items] count]; 00890 00891 [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO]; 00892 } 00893 00894 - (void)moveUpAndModifySelection:(id)sender 00895 { 00896 var index = [[self selectionIndexes] firstIndex]; 00897 if (index == CPNotFound) 00898 index = [[self items] count]; 00899 00900 [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES]; 00901 } 00902 00903 - (void)deleteBackward:(id)sender 00904 { 00905 if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)]) 00906 { 00907 [[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]]; 00908 00909 var index = [[self selectionIndexes] firstIndex]; 00910 if (index > [[self content] count] - 1) 00911 [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]]; 00912 00913 [self _scrollToSelection]; 00914 [self setNeedsDisplay:YES]; 00915 } 00916 } 00917 00918 - (void)keyDown:(CPEvent)anEvent 00919 { 00920 [self interpretKeyEvents:[anEvent]]; 00921 } 00922 00923 @end 00924 00925 @implementation CPCollectionView (Deprecated) 00926 00927 - (CGRect)rectForItemAtIndex:(int)anIndex 00928 { 00929 _CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemAtIndex:)); 00930 00931 // Don't re-compute anything just grab the current frame 00932 // This allows subclasses to override tile without messing this up. 00933 return [self frameForItemAtIndex:anIndex]; 00934 } 00935 00936 - (CGRect)rectForItemsAtIndexes:(CPIndexSet)anIndexSet 00937 { 00938 _CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemsAtIndexes:)); 00939 00940 return [self frameForItemsAtIndexes:anIndexSet]; 00941 } 00942 00943 @end 00944 00945 var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", 00946 CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", 00947 CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", 00948 CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey", 00949 CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey", 00950 CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey", 00951 CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey", 00952 CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey"; 00953 00954 00955 @implementation CPCollectionView (CPCoding) 00956 00957 - (void)awakeFromCib 00958 { 00959 [super awakeFromCib]; 00960 00961 if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) 00962 { 00963 var item = _itemPrototype; 00964 00965 if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero())) 00966 _minItemSize = [[item view] frameSize]; 00967 else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) 00968 _maxItemSize = [[item view] frameSize]; 00969 } 00970 } 00971 00972 - (id)initWithCoder:(CPCoder)aCoder 00973 { 00974 self = [super initWithCoder:aCoder]; 00975 00976 if (self) 00977 { 00978 _items = []; 00979 _content = []; 00980 00981 _cachedItems = []; 00982 00983 _itemSize = CGSizeMakeZero(); 00984 00985 _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); 00986 _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); 00987 00988 _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0; 00989 _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0; 00990 00991 _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey]; 00992 00993 _isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey]; 00994 _allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey]; 00995 00996 [self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]]; 00997 00998 _tileWidth = -1.0; 00999 01000 _selectionIndexes = [CPIndexSet indexSet]; 01001 01002 _allowsEmptySelection = YES; 01003 } 01004 01005 return self; 01006 } 01007 01008 - (void)encodeWithCoder:(CPCoder)aCoder 01009 { 01010 [super encodeWithCoder:aCoder]; 01011 01012 if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero())) 01013 [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey]; 01014 01015 if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) 01016 [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey]; 01017 01018 [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey]; 01019 [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey]; 01020 01021 [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; 01022 [aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey]; 01023 01024 [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; 01025 01026 [aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey]; 01027 } 01028 01029 @end