API  0.9.9
CPCollectionView.j
Go to the documentation of this file.
1 /*
2  * CPCollectionView.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
35 
36 
38 
39 @optional
40 - (BOOL)collectionView:(CPCollectionView)collectionView acceptDrop:(id)draggingInfo index:(CPInteger)index dropOperation:(CPCollectionViewDropOperation)dropOperation;
41 - (BOOL)collectionView:(CPCollectionView)collectionView canDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event;
42 - (BOOL)collectionView:(CPCollectionView)collectionView writeItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pasteboard;
43 - (CPArray)collectionView:(CPCollectionView)collectionView dragTypesForItemsAtIndexes:(CPIndexSet)indexes;
44 - (CPData)collectionView:(CPCollectionView)collectionView dataForItemsAtIndexes:(CPIndexSet)indices forType:(CPString)aType;
45 - (CPDragOperation)collectionView:(CPCollectionView)collectionView validateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation;
46 - (CPMenu)collectionView:(CPCollectionView)collectionView menuForItemAtIndex:(CPInteger)anIndex;
47 - (CPView)collectionView:(CPCollectionView)collectionView dragginViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
48 - (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
49 
50 @end
51 
53 
81 @implementation CPCollectionView : CPView
82 {
83  CPArray _content;
84  CPArray _items;
85 
86  CPData _itemData;
87  CPCollectionViewItem _itemPrototype;
88  CPCollectionViewItem _itemForDragging;
89  CPMutableArray _cachedItems;
90 
91  unsigned _maxNumberOfRows;
92  unsigned _maxNumberOfColumns;
93 
94  CGSize _minItemSize;
95  CGSize _maxItemSize;
96 
97  CPArray _backgroundColors;
98 
99  float _tileWidth;
100 
101  BOOL _isSelectable;
102  BOOL _allowsMultipleSelection;
103  BOOL _allowsEmptySelection;
104  CPIndexSet _selectionIndexes;
105 
106  CGSize _itemSize;
107 
108  float _horizontalMargin;
109  float _verticalMargin;
110 
111  unsigned _numberOfRows;
112  unsigned _numberOfColumns;
113 
114  id <CPCollectionViewDelegate> _delegate;
115  unsigned _implementedDelegateMethods;
116 
117  CPEvent _mouseDownEvent;
118 
119  BOOL _needsMinMaxItemSizeUpdate;
120  CGSize _storedFrameSize;
121 
122  BOOL _uniformSubviewsResizing;
123  BOOL _lockResizing;
124 
125  CPInteger _currentDropIndex;
126  CPDragOperation _currentDragOperation;
127 
128  _CPCollectionViewDropIndicator _dropView;
129 }
130 
131 - (id)initWithFrame:(CGRect)aFrame
132 {
133  self = [super initWithFrame:aFrame];
134 
135  if (self)
136  {
137  _maxNumberOfRows = 0;
138  _maxNumberOfColumns = 0;
139 
140  _minItemSize = CGSizeMakeZero();
141  _maxItemSize = CGSizeMakeZero();
142 
143  [self setBackgroundColors:nil];
144 
145  _verticalMargin = 5.0;
146  _isSelectable = YES;
147  _allowsEmptySelection = YES;
148 
149  [self _init];
150  }
151 
152  return self;
153 }
154 
155 - (void)_init
156 {
157  _content = [];
158 
159  _items = [];
160  _cachedItems = [];
161 
162  _numberOfColumns = CPNotFound;
163  _numberOfRows = CPNotFound;
164 
165  _itemSize = CGSizeMakeZero();
166 
167  _selectionIndexes = [CPIndexSet indexSet];
168 
169  _storedFrameSize = CGSizeMakeZero();
170 
171  _needsMinMaxItemSizeUpdate = YES;
172  _uniformSubviewsResizing = NO;
173  _lockResizing = NO;
174 
175  _currentDropIndex = -1;
176  _currentDragOperation = CPDragOperationNone;
177  _dropView = nil;
178 
179  [self setAutoresizesSubviews:NO];
180  [self setAutoresizingMask:0];
181 }
182 
183 
184 
185 #pragma mark -
186 #pragma mark Delegate
187 
192 - (void)setDelegate:(id <CPCollectionViewDelegate>)aDelegate
193 {
194  if (_delegate === aDelegate)
195  return;
196 
197  _delegate = aDelegate;
198  _implementedDelegateMethods = 0;
199 
200  if ([_delegate respondsToSelector:@selector(collectionView:acceptDrop:index:dropOperation:)])
202 
203  if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)])
205 
206  if ([_delegate respondsToSelector:@selector(collectionView:writeItemsAtIndexes:toPasteboard:)])
208 
209  if ([_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
211 
212  if ([_delegate respondsToSelector:@selector(collectionView:dataForItemsAtIndexes:forType:)])
214 
215  if ([_delegate respondsToSelector:@selector(collectionView:validateDrop:proposedIndex:dropOperation:)])
217 
218  if ([_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
220 
221  if ([_delegate respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
223 
224  if ([_delegate respondsToSelector:@selector(collectionView:draggingViewForItemsAtIndexes:withEvent:offset:)])
226 }
227 
272 - (void)setItemPrototype:(CPCollectionViewItem)anItem
273 {
274  _cachedItems = [];
275  _itemData = nil;
276  _itemForDragging = nil;
277  _itemPrototype = anItem;
278 
279  [self _reloadContentCachingRemovedItems:NO];
280 }
281 
286 {
287  return _itemPrototype;
288 }
289 
294 - (CPCollectionViewItem)newItemForRepresentedObject:(id)anObject
295 {
296  var item = nil;
297 
298  if (_cachedItems.length)
299  item = _cachedItems.pop();
300 
301  else
302  item = [_itemPrototype copy];
303 
304  [item setRepresentedObject:anObject];
305  [[item view] setFrameSize:_itemSize];
306 
307  return item;
308 }
309 
310 // Working with the Responder Chain
315 {
316  return YES;
317 }
318 
323 {
324  return [[self window] firstResponder] === self;
325 }
326 
327 // Setting the Content
339 - (void)setContent:(CPArray)anArray
340 {
341  _content = anArray;
342 
343  [self reloadContent];
344 }
345 
349 - (CPArray)content
350 {
351  return _content;
352 }
353 
357 - (CPArray)items
358 {
359  return _items;
360 }
361 
362 // Setting the Selection Mode
367 - (void)setSelectable:(BOOL)isSelectable
368 {
369  if (_isSelectable == isSelectable)
370  return;
371 
372  _isSelectable = isSelectable;
373 
374  if (!_isSelectable)
375  {
376  var index = CPNotFound,
377  itemCount = [_items count];
378 
379  // Be wary of invalid selection ranges since setContent: does not clear selection indexes.
380  while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < itemCount)
381  [_items[index] setSelected:NO];
382  }
383 }
384 
390 {
391  return _isSelectable;
392 }
393 
398 - (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
399 {
400  _allowsEmptySelection = shouldAllowEmptySelection;
401 }
402 
407 {
408  return _allowsEmptySelection;
409 }
410 
415 - (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
416 {
417  _allowsMultipleSelection = shouldAllowMultipleSelection;
418 }
419 
424 {
425  return _allowsMultipleSelection;
426 }
427 
432 - (void)setSelectionIndexes:(CPIndexSet)anIndexSet
433 {
434  if (!anIndexSet)
435  anIndexSet = [CPIndexSet indexSet];
436  if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet])
437  return;
438 
439  var index = CPNotFound,
440  itemCount = [_items count];
441 
442  // Be wary of invalid selection ranges since setContent: does not clear selection indexes.
443  while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound && index < itemCount)
444  [_items[index] setSelected:NO];
445 
446  _selectionIndexes = anIndexSet;
447 
448  var index = CPNotFound;
449 
450  while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound)
451  [_items[index] setSelected:YES];
452 
453  var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
454  [[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
455 }
456 
461 {
462  return [_selectionIndexes copy];
463 }
464 
466 {
467  [self _reloadContentCachingRemovedItems:YES];
468 }
469 
470 /* @ignore */
471 - (void)_reloadContentCachingRemovedItems:(BOOL)shouldCache
472 {
473  // Remove current views
474  var count = _items.length;
475 
476  while (count--)
477  {
478  [[_items[count] view] removeFromSuperview];
479  [_items[count] setSelected:NO];
480 
481  if (shouldCache)
482  _cachedItems.push(_items[count]);
483  }
484 
485  _items = [];
486 
487  if (!_itemPrototype)
488  return;
489 
490  var index = 0;
491 
492  count = _content.length;
493 
494  for (; index < count; ++index)
495  {
496  _items.push([self newItemForRepresentedObject:_content[index]]);
497 
498  [self addSubview:[_items[index] view]];
499  }
500 
501  index = CPNotFound;
502  // Be wary of invalid selection ranges since setContent: does not clear selection indexes.
503  while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < count)
504  [_items[index] setSelected:YES];
505 
506  [self tileIfNeeded:NO];
507 }
508 
509 - (void)resizeSubviewsWithOldSize:(CGSize)oldBoundsSize
510 {
511  // Desactivate subviews autoresizing
512 }
513 
514 - (void)resizeWithOldSuperviewSize:(CGSize)oldBoundsSize
515 {
516  if (_lockResizing)
517  return;
518 
519  _lockResizing = YES;
520 
521  [self tile];
522 
523  _lockResizing = NO;
524 }
525 
526 - (void)tile
527 {
528  [self tileIfNeeded:!_uniformSubviewsResizing];
529 }
530 
531 - (void)tileIfNeeded:(BOOL)lazyFlag
532 {
533  var frameSize = [[self superview] frameSize],
534  count = _items.length,
535  oldNumberOfColumns = _numberOfColumns,
536  oldNumberOfRows = _numberOfRows,
537  oldItemSize = _itemSize,
538  storedFrameSize = _storedFrameSize;
539 
540  // No need to tile if we are not yet placed in the view hierarchy.
541  if (!frameSize)
542  return;
543 
544  [self _updateMinMaxItemSizeIfNeeded];
545 
546  [self _computeGridWithSize:frameSize count:@ref(count)];
547 
548  //CPLog.debug("frameSize="+CPStringFromSize(frameSize) + "itemSize="+CPStringFromSize(itemSize) + " ncols=" + colsRowsCount[0] +" nrows="+ colsRowsCount[1]+" displayCount="+ colsRowsCount[2]);
549 
550  [self setFrameSize:_storedFrameSize];
551 
552  //CPLog.debug("OLD " + oldNumberOfColumns + " NEW " + _numberOfColumns);
553  if (!lazyFlag ||
554  _numberOfColumns !== oldNumberOfColumns ||
555  _numberOfRows !== oldNumberOfRows ||
556  !CGSizeEqualToSize(_itemSize, oldItemSize))
557 
558  [self displayItems:_items frameSize:_storedFrameSize itemSize:_itemSize columns:_numberOfColumns rows:_numberOfRows count:count];
559 }
560 
561 - (void)_computeGridWithSize:(CGSize)aSuperviewSize count:(Function)countRef
562 {
563  var width = aSuperviewSize.width,
564  height = aSuperviewSize.height,
565  itemSize = CGSizeMakeCopy(_minItemSize),
566  maxItemSizeWidth = _maxItemSize.width,
567  maxItemSizeHeight = _maxItemSize.height,
568  itemsCount = [_items count],
569  numberOfRows,
571 
572  numberOfColumns = FLOOR(width / itemSize.width);
573 
574  if (maxItemSizeWidth == 0)
575  numberOfColumns = MIN(numberOfColumns, _maxNumberOfColumns);
576 
577  if (_maxNumberOfColumns > 0)
578  numberOfColumns = MIN(MIN(_maxNumberOfColumns, itemsCount), numberOfColumns);
579 
580  numberOfColumns = MAX(1.0, numberOfColumns);
581 
582  itemSize.width = FLOOR(width / numberOfColumns);
583 
584  if (maxItemSizeWidth > 0)
585  {
586  itemSize.width = MIN(maxItemSizeWidth, itemSize.width);
587 
588  if (numberOfColumns == 1)
589  itemSize.width = MIN(maxItemSizeWidth, width);
590  }
591 
592  numberOfRows = CEIL(itemsCount / numberOfColumns);
593 
594  if (_maxNumberOfRows > 0)
595  numberOfRows = MIN(numberOfRows, _maxNumberOfRows);
596 
597  height = MAX(height, numberOfRows * (_minItemSize.height + _verticalMargin));
598 
599  var itemSizeHeight = FLOOR(height / numberOfRows) - _verticalMargin;
600 
601  if (maxItemSizeHeight > 0)
602  itemSizeHeight = MIN(itemSizeHeight, maxItemSizeHeight);
603 
604  _itemSize = CGSizeMake(MAX(_minItemSize.width, itemSize.width), MAX(_minItemSize.height, itemSizeHeight));
605  _storedFrameSize = CGSizeMake(MAX(width, _minItemSize.width), height);
606  _numberOfColumns = numberOfColumns;
607  _numberOfRows = numberOfRows;
608  countRef(MIN(itemsCount, numberOfColumns * numberOfRows));
609 }
610 
611 - (void)displayItems:(CPArray)displayItems frameSize:(CGSize)aFrameSize itemSize:(CGSize)anItemSize columns:(CPInteger)numberOfColumns rows:(CPInteger)numberOfRows count:(CPInteger)displayCount
612 {
613 // CPLog.debug("DISPLAY ITEMS " + numberOfColumns + " " + numberOfRows);
614 
615  _horizontalMargin = _uniformSubviewsResizing ? FLOOR((aFrameSize.width - numberOfColumns * anItemSize.width) / (numberOfColumns + 1)) : HORIZONTAL_MARGIN;
616 
617  var x = _horizontalMargin,
618  y = -anItemSize.height;
619 
620  [displayItems enumerateObjectsUsingBlock:function(item, idx, stop)
621  {
622  var view = [item view];
623 
624  if (idx >= displayCount)
625  {
626  [view setFrameOrigin:CGPointMake(-anItemSize.width, -anItemSize.height)];
627  return;
628  }
629 
630  if (idx % numberOfColumns == 0)
631  {
632  x = _horizontalMargin;
633  y += _verticalMargin + anItemSize.height;
634  }
635 
636  [view setFrameOrigin:CGPointMake(x, y)];
637  [view setFrameSize:anItemSize];
638 
639  x += anItemSize.width + _horizontalMargin;
640  }];
641 }
642 
643 - (void)_updateMinMaxItemSizeIfNeeded
644 {
645  if (!_needsMinMaxItemSizeUpdate)
646  return;
647 
648  var prototypeView;
649 
650  if (_itemPrototype && (prototypeView = [_itemPrototype view]))
651  {
652  if (_minItemSize.width == 0)
653  _minItemSize.width = [prototypeView frameSize].width;
654 
655  if (_minItemSize.height == 0)
656  _minItemSize.height = [prototypeView frameSize].height;
657 
658  if (_maxItemSize.height == 0 && !([prototypeView autoresizingMask] & CPViewHeightSizable))
659  _maxItemSize.height = [prototypeView frameSize].height;
660 
661  if (_maxItemSize.width == 0 && !([prototypeView autoresizingMask] & CPViewWidthSizable))
662  _maxItemSize.width = [prototypeView frameSize].width;
663 
664  _needsMinMaxItemSizeUpdate = NO;
665  }
666 }
667 
668 // Laying Out the Collection View
673 - (void)setMaxNumberOfRows:(unsigned)aMaxNumberOfRows
674 {
675  if (_maxNumberOfRows == aMaxNumberOfRows)
676  return;
677 
678  _maxNumberOfRows = aMaxNumberOfRows;
679 
680  [self tile];
681 }
682 
686 - (unsigned)maxNumberOfRows
687 {
688  return _maxNumberOfRows;
689 }
690 
695 - (void)setMaxNumberOfColumns:(unsigned)aMaxNumberOfColumns
696 {
697  if (_maxNumberOfColumns == aMaxNumberOfColumns)
698  return;
699 
700  _maxNumberOfColumns = aMaxNumberOfColumns;
701 
702  [self tile];
703 }
704 
709 {
710  return _maxNumberOfColumns;
711 }
712 
716 - (unsigned)numberOfRows
717 {
718  return _numberOfRows;
719 }
720 
725 - (unsigned)numberOfColumns
726 {
727  return _numberOfColumns;
728 }
729 
734 - (void)setMinItemSize:(CGSize)aSize
735 {
736  if (aSize === nil || aSize === undefined)
737  [CPException raise:CPInvalidArgumentException reason:"Invalid value provided for minimum size"];
738 
739  if (CGSizeEqualToSize(_minItemSize, aSize))
740  return;
741 
742  _minItemSize = CGSizeMakeCopy(aSize);
743 
744  if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
745  _needsMinMaxItemSizeUpdate = YES;
746 
747  [self tile];
748 }
749 
753 - (CGSize)minItemSize
754 {
755  return _minItemSize;
756 }
757 
762 - (void)setMaxItemSize:(CGSize)aSize
763 {
764  if (CGSizeEqualToSize(_maxItemSize, aSize))
765  return;
766 
767  _maxItemSize = CGSizeMakeCopy(aSize);
768 
769 // if (_maxItemSize.width == 0 || _maxItemSize.height == 0)
770 // _needsMinMaxItemSizeUpdate = YES;
771 
772  [self tile];
773 }
774 
778 - (CGSize)maxItemSize
779 {
780  return _maxItemSize;
781 }
782 
783 - (void)setBackgroundColors:(CPArray)backgroundColors
784 {
785  if (_backgroundColors === backgroundColors)
786  return;
787 
788  _backgroundColors = backgroundColors;
789 
790  if (!_backgroundColors)
791  _backgroundColors = [[CPColor whiteColor]];
792 
793  if ([_backgroundColors count] === 1)
794  [self setBackgroundColor:_backgroundColors[0]];
795 
796  else
797  [self setBackgroundColor:nil];
798 
799  [self setNeedsDisplay:YES];
800 }
801 
803 {
804  return _backgroundColors;
805 }
806 
807 - (void)mouseUp:(CPEvent)anEvent
808 {
809  if ([_selectionIndexes count] && [anEvent clickCount] == 2)
810  [self _sendDelegateDidDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]];
811 }
812 
813 - (void)mouseDown:(CPEvent)anEvent
814 {
815  _mouseDownEvent = anEvent;
816 
817  var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
818  index = [self _indexAtPoint:location];
819 
820  if (index >= 0 && index < _items.length)
821  {
822  if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPPlatformActionKeyMask || [anEvent modifierFlags] & CPShiftKeyMask))
823  {
824  if ([anEvent modifierFlags] & CPPlatformActionKeyMask)
825  {
826  var indexes = [_selectionIndexes copy];
827 
828  if ([indexes containsIndex:index])
829  [indexes removeIndex:index];
830  else
831  [indexes addIndex:index];
832  }
833  else if ([anEvent modifierFlags] & CPShiftKeyMask)
834  {
835  var firstSelectedIndex = [[self selectionIndexes] firstIndex],
836  newSelectedRange = nil;
837 
838  // This catches the case where the shift key is held down for the first selection.
839  if (firstSelectedIndex === CPNotFound)
840  firstSelectedIndex = index;
841 
842  if (index < firstSelectedIndex)
843  newSelectedRange = CPMakeRange(index, (firstSelectedIndex - index) + 1);
844  else
845  newSelectedRange = CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1);
846 
847  indexes = [[self selectionIndexes] copy];
848  [indexes addIndexesInRange:newSelectedRange];
849  }
850  }
851  else
852  indexes = [CPIndexSet indexSetWithIndex:index];
853 
854  [self setSelectionIndexes:indexes];
855 
856  // TODO Is it allowable for collection view items to become the first responder? In that case they
857  // may have become that at this point by virtue of CPWindow's sendEvent: mouse down handling, and
858  // the following line will rudely snatch it away from them. For most cases though, clicking on an
859  // item should naturally make the collection view the first responder so that keyboard navigation
860  // is enabled.
861  [[self window] makeFirstResponder:self];
862  }
863  else if (_allowsEmptySelection)
865 }
866 
867 // Cappuccino Additions
868 
874 - (void)setVerticalMargin:(float)aVerticalMargin
875 {
876  if (_verticalMargin == aVerticalMargin)
877  return;
878 
879  _verticalMargin = aVerticalMargin;
880 
881  [self tile];
882 }
883 
884 - (void)setUniformSubviewsResizing:(BOOL)flag
885 {
886  _uniformSubviewsResizing = flag;
887  [self tileIfNeeded:NO];
888 }
889 
890 
896 {
897  return _verticalMargin;
898 }
899 
903 - (id)delegate
904 {
905  return _delegate;
906 }
907 
911 - (CPMenu)menuForEvent:(CPEvent)theEvent
912 {
913  if (![self _delegateRespondsToCollectionViewMenuForItemAtIndex])
914  return [super menuForEvent:theEvent];
915 
916  var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
917  index = [self _indexAtPoint:location];
918 
919  return [self _sendDelegateMenuForItemAtIndex:index];
920 }
921 
922 - (int)_indexAtPoint:(CGPoint)thePoint
923 {
924  var column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
925 
926  if (column < _numberOfColumns)
927  {
928  var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin));
929 
930  if (row < _numberOfRows)
931  return (row * _numberOfColumns + column);
932  }
933 
934  return CPNotFound;
935 }
936 
937 - (CPCollectionViewItem)itemAtIndex:(CPUInteger)anIndex
938 {
939  return [_items objectAtIndex:anIndex];
940 }
941 
942 - (CGRect)frameForItemAtIndex:(CPUInteger)anIndex
943 {
944  return [[[self itemAtIndex:anIndex] view] frame];
945 }
946 
947 - (CGRect)frameForItemsAtIndexes:(CPIndexSet)anIndexSet
948 {
949  var indexArray = [],
950  frame = CGRectNull;
951 
952  [anIndexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
953 
954  var index = 0,
955  count = [indexArray count];
956 
957  for (; index < count; ++index)
958  frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]);
959 
960  return frame;
961 }
962 
963 @end
964 
966 /*
967  TODO: dropOperation is not supported yet. The visible drop operation is like CPCollectionViewDropBefore.
968 */
969 
975 - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
976 {
977  [aPasteboard setData:[self _sendDelegateDataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
978 }
979 
980 - (void)_createDropIndicatorIfNeeded
981 {
982  // Create and position the drop indicator view.
983 
984  if (!_dropView)
985  _dropView = [[_CPCollectionViewDropIndicator alloc] initWithFrame:CGRectMake(-8, -8, 0, 0)];
986 
987  [_dropView setFrameSize:CGSizeMake(10, _itemSize.height + _verticalMargin)];
988  [self addSubview:_dropView];
989 }
990 
991 - (void)mouseDragged:(CPEvent)anEvent
992 {
993  // Don't crash if we never registered the intial click.
994  if (!_mouseDownEvent)
995  return;
996 
997  [self _createDropIndicatorIfNeeded];
998 
999  var locationInWindow = [anEvent locationInWindow],
1000  mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
1001 
1002  // FIXME: This is because Safari's drag hysteresis is 3px x 3px
1003  if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
1004  (ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
1005  return;
1006 
1007  if (![self _delegateRespondsToCollectionViewDragTypesForItemsAtIndexes])
1008  return;
1009 
1010  // If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
1011  if (![_selectionIndexes count])
1012  return;
1013 
1014  if (![self _sendDelegateCanDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
1015  return;
1016 
1017  // Set up the pasteboard
1018  var dragTypes = [self _sendDelegateDragTypesForItemsAtIndexes:_selectionIndexes];
1019 
1020  [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
1021 
1022  var dragImageOffset = CGSizeMakeZero(),
1023  view = [self _sendDelegateDraggingViewForItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent offset:dragImageOffset];
1024 
1025  [view setFrameSize:_itemSize];
1026  [view setAlphaValue:0.7];
1027 
1028  var dragLocation = [self convertPoint:locationInWindow fromView:nil],
1029  dragPoint = CGPointMake(dragLocation.x - _itemSize.width / 2 , dragLocation.y - _itemSize.height / 2);
1030 
1031  [self dragView:view
1032  at:dragPoint
1033  offset:dragImageOffset
1034  event:_mouseDownEvent
1035  pasteboard:nil
1036  source:self
1037  slideBack:YES];
1038 }
1039 
1040 - (CPView)draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset
1041 {
1042  var idx = _content[[indexes firstIndex]];
1043 
1044  if (!_itemForDragging)
1045  _itemForDragging = [self newItemForRepresentedObject:idx];
1046  else
1047  [_itemForDragging setRepresentedObject:idx];
1048 
1049  return [_itemForDragging view];
1050 }
1051 
1052 - (CPDragOperation)draggingEntered:(id)draggingInfo
1053 {
1054  var dropIndex = -1,
1055  dropIndexRef = @ref(dropIndex),
1056  dragOp = [self _validateDragWithInfo:draggingInfo dropIndex:dropIndexRef dropOperation:1];
1057 
1058  dropIndex = dropIndexRef();
1059 
1060  [self _createDropIndicatorIfNeeded];
1061 
1062  [self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:dragOp newDropIndex:dropIndex newDropOperation:1];
1063 
1064  return _currentDragOperation;
1065 }
1066 
1067 - (CPDragOperation)draggingUpdated:(id)draggingInfo
1068 {
1069  if (![self _dropIndexDidChange:draggingInfo])
1070  return _currentDragOperation;
1071 
1072  var dropIndex,
1073  dropIndexRef = @ref(dropIndex);
1074 
1075  var dragOperation = [self _validateDragWithInfo:draggingInfo dropIndex:dropIndexRef dropOperation:1];
1076 
1077  dropIndex = dropIndexRef();
1078 
1079  [self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:dragOperation newDropIndex:dropIndex newDropOperation:1];
1080 
1081  return dragOperation;
1082 }
1083 
1084 - (CPDragOperation)_validateDragWithInfo:(id)draggingInfo dropIndex:(Function)dropIndexRef dropOperation:(int)dropOperation
1085 {
1086  var result = CPDragOperationMove,
1087  dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:dropOperation];
1088 
1089  if ([self _delegateRespondsToCollectionViewValidateDropProposedIndexDropOperation])
1090  {
1091  var dropIndexRef2 = @ref(dropIndex);
1092 
1093  result = [self _sendDelegateValidateDrop:draggingInfo proposedIndex:dropIndexRef2 dropOperation:dropOperation];
1094 
1095  if (result !== CPDragOperationNone)
1096  dropIndex = dropIndexRef2();
1097  }
1098 
1099  dropIndexRef(dropIndex);
1100 
1101  return result;
1102 }
1103 
1104 - (void)draggingExited:(id)draggingInfo
1105 {
1106  [self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:0 newDropIndex:-1 newDropOperation:1];
1107 }
1108 
1109 - (void)draggingEnded:(id)draggingInfo
1110 {
1111  [self _updateDragAndDropStateWithDraggingInfo:draggingInfo newDragOperation:0 newDropIndex:-1 newDropOperation:1];
1112 }
1113 
1114 /*
1115 Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
1116 - (BOOL)_writeItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pboard
1117 {
1118  if ([self respondsToSelector:@selector(collectionView:writeItemsAtIndexes:toPasteboard:)])
1119  return [_delegate collectionView:self writeItemsAtIndexes:indexes toPasteboard:pboard];
1120 
1121  return NO;
1122 }
1123 */
1124 
1125 - (BOOL)performDragOperation:(id)draggingInfo
1126 {
1127  var result = NO;
1128 
1129  if (_currentDragOperation && _currentDropIndex !== -1)
1130  result = [self _sendDelegateAcceptDrop:draggingInfo index:_currentDropIndex dropOperation:1];
1131 
1132  [self draggingEnded:draggingInfo]; // Is this correct ?
1133 
1134  return result;
1135 }
1136 
1137 - (void)_updateDragAndDropStateWithDraggingInfo:(id)draggingInfo newDragOperation:(CPDragOperation)dragOperation newDropIndex:(CPInteger)dropIndex newDropOperation:(CPInteger)dropOperation
1138 {
1139  _currentDropIndex = dropIndex;
1140  _currentDragOperation = dragOperation;
1141 
1142  var frameOrigin,
1143  dropviewFrameWidth = CGRectGetWidth([_dropView frame]);
1144 
1145  if (_currentDropIndex == -1 || _currentDragOperation == CPDragOperationNone)
1146  frameOrigin = CGPointMake(-dropviewFrameWidth, 0);
1147  else if (_currentDropIndex == 0)
1148  frameOrigin = CGPointMake(0, 0);
1149  else
1150  {
1151  var offset;
1152 
1153  if ((_currentDropIndex % _numberOfColumns) !== 0 || _currentDropIndex == [_items count])
1154  {
1155  dropIndex = _currentDropIndex - 1;
1156  offset = (_horizontalMargin - dropviewFrameWidth) / 2;
1157  }
1158  else
1159  {
1160  offset = - _itemSize.width - dropviewFrameWidth - (_horizontalMargin - dropviewFrameWidth) / 2;
1161  }
1162 
1163  var rect = [self frameForItemAtIndex:dropIndex];
1164 
1165  frameOrigin = CGPointMake(CGRectGetMaxX(rect) + offset, rect.origin.y - _verticalMargin);
1166  }
1167 
1168  [_dropView setFrameOrigin:frameOrigin];
1169 }
1170 
1171 - (BOOL)_dropIndexDidChange:(id)draggingInfo
1172 {
1173  var dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:1];
1174 
1175  if (dropIndex == CPNotFound)
1176  dropIndex = [[self content] count];
1177 
1178  return (_currentDropIndex !== dropIndex)
1179 }
1180 
1181 - (CPInteger)_dropIndexForDraggingInfo:(id)draggingInfo proposedDropOperation:(int)dropOperation
1182 {
1183  var location = [self convertPoint:[draggingInfo draggingLocation] fromView:nil],
1184  locationX = location.x + _itemSize.width / 2;
1185 
1186  var column = MIN(FLOOR(locationX / (_itemSize.width + _horizontalMargin)), _numberOfColumns),
1187  row = FLOOR(location.y / (_itemSize.height + _verticalMargin));
1188 
1189  if (row >= _numberOfRows - 1)
1190  {
1191  if (row >= _numberOfRows)
1192  {
1193  row = _numberOfRows - 1;
1194  column = _numberOfColumns;
1195  }
1196 
1197  return MIN((row * _numberOfColumns + column), [_items count]);
1198  }
1199 
1200  return (row * _numberOfColumns + column);
1201 }
1202 
1203 @end
1204 @implementation _CPCollectionViewDropIndicator : CPView
1205 {
1206  id __doxygen__;
1207 }
1208 
1209 - (void)drawRect:(CGRect)aRect
1210 {
1211  var context = [[CPGraphicsContext currentContext] graphicsPort],
1212  width = CGRectGetWidth(aRect),
1213  circleRect = CGRectMake(1, 1, width - 2, width - 2);
1214 
1215  CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"4886ca"]);
1216  CGContextSetFillColor(context, [CPColor whiteColor]);
1217  CGContextSetLineWidth(context, 3);
1218 
1219  //draw white under the circle thing
1220  CGContextFillRect(context, circleRect);
1221 
1222  //draw the circle thing
1223  CGContextStrokeEllipseInRect(context, circleRect);
1224 
1225  //then draw the line
1226  CGContextBeginPath(context);
1227  CGContextMoveToPoint(context, FLOOR(width / 2), CGRectGetMinY(aRect) + width);
1228  CGContextAddLineToPoint(context, FLOOR(width / 2), CGRectGetHeight(aRect));
1229  CGContextStrokePath(context);
1230 }
1231 
1232 @end
1233 
1235 
1236 - (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
1237 {
1238  var count = [[self items] count];
1239 
1240  if (count === 0)
1241  return;
1242 
1243  anIndex = MIN(MAX(anIndex, 0), count - 1);
1244 
1245  if (_allowsMultipleSelection && shouldExpand)
1246  {
1247  var indexes = [_selectionIndexes copy],
1248  bottomAnchor = [indexes firstIndex],
1249  topAnchor = [indexes lastIndex];
1250 
1251  // if the direction is backward (-1) check with the bottom anchor
1252  if (aDirection === -1)
1253  [indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)];
1254  else
1255  [indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)];
1256  }
1257  else
1258  indexes = [CPIndexSet indexSetWithIndex:anIndex];
1259 
1260  [self setSelectionIndexes:indexes];
1261  [self _scrollToSelection];
1262 }
1263 
1264 - (void)_scrollToSelection
1265 {
1266  var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
1267 
1268  if (!CGRectIsEmpty(frame))
1269  [self scrollRectToVisible:frame];
1270 }
1271 
1272 - (void)moveLeft:(id)sender
1273 {
1274  var index = [[self selectionIndexes] firstIndex];
1275  if (index === CPNotFound)
1276  index = [[self items] count];
1277 
1278  [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
1279 }
1280 
1281 - (void)moveLeftAndModifySelection:(id)sender
1282 {
1283  var index = [[self selectionIndexes] firstIndex];
1284  if (index === CPNotFound)
1285  index = [[self items] count];
1286 
1287  [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
1288 }
1289 
1290 - (void)moveRight:(id)sender
1291 {
1292  [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
1293 }
1294 
1295 - (void)moveRightAndModifySelection:(id)sender
1296 {
1297  [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
1298 }
1299 
1300 - (void)moveDown:(id)sender
1301 {
1302  [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
1303 }
1304 
1305 - (void)moveDownAndModifySelection:(id)sender
1306 {
1307  [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
1308 }
1309 
1310 - (void)moveUp:(id)sender
1311 {
1312  var index = [[self selectionIndexes] firstIndex];
1313  if (index == CPNotFound)
1314  index = [[self items] count];
1315 
1316  [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
1317 }
1318 
1319 - (void)moveUpAndModifySelection:(id)sender
1320 {
1321  var index = [[self selectionIndexes] firstIndex];
1322  if (index == CPNotFound)
1323  index = [[self items] count];
1324 
1325  [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES];
1326 }
1327 
1328 - (void)deleteBackward:(id)sender
1329 {
1330  if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
1331  {
1332  [[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
1333 
1334  var index = [[self selectionIndexes] firstIndex];
1335  if (index > [[self content] count] - 1)
1336  [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]];
1337 
1338  [self _scrollToSelection];
1339  [self setNeedsDisplay:YES];
1340  }
1341 }
1342 
1343 - (void)keyDown:(CPEvent)anEvent
1344 {
1345  [self interpretKeyEvents:[anEvent]];
1346 }
1347 
1348 - (void)setAutoresizingMask:(unsigned)aMask
1349 {
1350  [super setAutoresizingMask:0];
1351 }
1352 
1353 @end
1354 
1355 
1357 
1358 - (CGRect)rectForItemAtIndex:(int)anIndex
1359 {
1360  _CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemAtIndex:));
1361 
1362  // Don't re-compute anything just grab the current frame
1363  // This allows subclasses to override tile without messing this up.
1364  return [self frameForItemAtIndex:anIndex];
1365 }
1366 
1367 - (CGRect)rectForItemsAtIndexes:(CPIndexSet)anIndexSet
1368 {
1369  _CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemsAtIndexes:));
1370 
1371  return [self frameForItemsAtIndexes:anIndexSet];
1372 }
1373 
1374 @end
1375 
1376 
1378 
1379 /*
1380  @ignore
1381  Return YES if the delegate implements collectionView:validateDrop:proposedIndex:dropOperation:
1382 */
1383 - (BOOL)_delegateRespondsToCollectionViewValidateDropProposedIndexDropOperation
1384 {
1386 }
1387 
1388 /*
1389  @ignore
1390  Return YES if the delegate implements collectionView:menuForItemAtIndex:
1391 */
1392 - (BOOL)_delegateRespondsToCollectionViewMenuForItemAtIndex
1393 {
1394  return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_menuForItemAtIndex_;
1395 }
1396 
1397 /*
1398  @ignore
1399  Return YES if the delegate implements collectionView:dragTypesForItemsAtIndexes:
1400 */
1401 - (BOOL)_delegateRespondsToCollectionViewDragTypesForItemsAtIndexes
1402 {
1403  return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_;
1404 }
1405 
1410 - (BOOL)_sendDelegateAcceptDrop:(id)draggingInfo index:(CPInteger)index dropOperation:(CPCollectionViewDropOperation)dropOperation
1411 {
1413  return NO;
1414 
1415  return [_delegate collectionView:self acceptDrop:draggingInfo index:index dropOperation:dropOperation];
1416 }
1417 
1422 - (BOOL)_sendDelegateCanDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent
1423 {
1425  return YES;
1426 
1427  return [_delegate collectionView:self canDragItemsAtIndexes:indexes withEvent:anEvent];
1428 }
1429 
1434 - (BOOL)_sendDelegateWriteItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pasteboard
1435 {
1437  return NO;
1438 
1439  return [_delegate collectionView:self writeItemsAtIndexes:indexes toPasteboard:pasteboard];
1440 }
1441 
1446 - (CPArray)_sendDelegateDragTypesForItemsAtIndexes:(CPIndexSet)indexes
1447 {
1448  if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_))
1449  return [];
1450 
1451  return [_delegate collectionView:self dragTypesForItemsAtIndexes:indexes];
1452 }
1453 
1458 - (CPData)_sendDelegateDataForItemsAtIndexes:(CPIndexSet)indexes forType:(CPString)aType
1459 {
1461  return nil;
1462 
1463  return [_delegate collectionView:self dataForItemsAtIndexes:indexes forType:aType];
1464 }
1465 
1470 - (CPDragOperation)_sendDelegateValidateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation
1471 {
1473  return CPDragOperationNone;
1474 
1475  return [_delegate collectionView:self validateDrop:draggingInfo proposedIndex:proposedDropIndex dropOperation:proposedDropOperation];
1476 }
1477 
1482 - (void)_sendDelegateDidDoubleClickOnItemAtIndex:(int)index
1483 {
1484  if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_))
1485  return;
1486 
1487  return [_delegate collectionView:self didDoubleClickOnItemAtIndex:index];
1488 }
1489 
1490 
1495 - (void)_sendDelegateMenuForItemAtIndex:(CPInteger)anIndex
1496 {
1497  if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_menuForItemAtIndex_))
1498  return nil;
1499 
1500  return [_delegate collectionView:self menuForItemAtIndex:anIndex];
1501 }
1502 
1507 - (CPView)_sendDelegateDraggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent offset:(CGPoint)dragImageOffset
1508 {
1510  return [self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:dragImageOffset];
1511 
1512  return [_delegate collectionView:self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:dragImageOffset];
1513 }
1514 
1515 @end
1516 
1517 
1518 var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
1519  CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
1520  CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
1521  CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
1522  CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
1523  CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
1524  CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
1525  CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
1526 
1527 
1529 
1530 - (id)initWithCoder:(CPCoder)aCoder
1531 {
1532  self = [super initWithCoder:aCoder];
1533 
1534  if (self)
1535  {
1536  _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey];
1537  _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey];
1538 
1539  _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey];
1540  _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey];
1541 
1542  _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
1543 
1544  _isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
1545  _allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
1546 
1547  [self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
1548 
1549  [self _init];
1550  }
1551 
1552  return self;
1553 }
1554 
1555 - (void)encodeWithCoder:(CPCoder)aCoder
1556 {
1557  [super encodeWithCoder:aCoder];
1558 
1559  if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
1560  [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
1561 
1562  if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
1563  [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
1564 
1565  [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
1566  [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
1567 
1568  [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
1569  [aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
1570 
1571  [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
1572 
1573  [aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
1574 }
1575 
1576 @end
1577 
1579 
1584 {
1585  return _uniformSubviewsResizing;
1586 }
1587 
1591 - (void)setUniformSubviewsResizing:(BOOL)aValue
1592 {
1593  _uniformSubviewsResizing = aValue;
1594 }
1595 
1596 @end
id initWithFrame:(CGRect aFrame)
Definition: CPView.j:323
Used to implement exception handling (creating & raising).
Definition: CPException.h:2
BOOL makeFirstResponder:(CPResponder aResponder)
Definition: CPWindow.j:1618
function CGContextStrokeEllipseInRect(aContext, aRect)
Definition: CGContext.j:606
Definition: CPMenu.h:2
CPInteger lastIndex()
Definition: CPIndexSet.j:289
void addSubview:(CPView aSubview)
Definition: CPView.j:495
void dragView:at:offset:event:pasteboard:source:slideBack:(CPView aView, [at] CGPoint aLocation, [offset] CGSize mouseOffset, [event] CPEvent anEvent, [pasteboard] CPPasteboard aPasteboard, [source] id aSourceObject, [slideBack] BOOL slideBack)
Definition: CPView.j:2348
A CALayer is similar to a CPView
Definition: CALayer.j:46
var CPCollectionViewMaxNumberOfColumnsKey
unsigned numberOfColumns()
CGPoint frameOrigin()
Definition: CPView.j:1016
var CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_
void tileIfNeeded:(BOOL lazyFlag)
var isEqual
CPGraphicsContext currentContext()
id initWithCoder:(CPCoder aCoder)
Definition: CPView.j:3596
CPViewWidthSizable
Definition: CPView.j:67
CPDragOperation CPDragOperationNone
var CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_
function CGContextSetStrokeColor(aContext, aColor)
Definition: CGContext.j:675
BOOL setData:forType:(CPData aData, [forType] CPString aType)
Definition: CPPasteboard.j:216
CPResponder firstResponder()
Definition: CPWindow.j:1643
CGPoint locationInWindow()
Definition: CPEvent.j:287
CPCollectionViewItem newItemForRepresentedObject:(id anObject)
CPInteger getIndexes:maxCount:inIndexRange:(CPArray anArray, [maxCount] CPInteger aMaxCount, [inIndexRange] CPRange aRange)
Definition: CPIndexSet.j:386
CPColor whiteColor()
Definition: CPColor.j:358
void displayItems:frameSize:itemSize:columns:rows:count:(CPArray displayItems, [frameSize] CGSize aFrameSize, [itemSize] CGSize anItemSize, [columns] CPInteger numberOfColumns, [rows] CPInteger numberOfRows, [count] CPInteger displayCount)
int width
A Cappuccino wrapper for any data type.
Definition: CPData.h:2
void raise:reason:(CPString aName, [reason] CPString aReason)
Definition: CPException.j:66
A collection of unique integers.
Definition: CPIndexSet.h:2
CPDragOperationMove
CPInteger firstIndex()
Definition: CPIndexSet.j:278
function CGContextAddLineToPoint(aContext, x, y)
Definition: CGContext.j:247
function CGContextStrokePath(aContext)
Definition: CGContext.j:619
var CPCollectionViewDelegate_collectionView_menuForItemAtIndex_
function CGContextSetLineWidth(aContext, aLineWidth)
Definition: CGContext.j:177
var CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_
CPWindow window()
Definition: CPView.j:486
CGSize frameSize()
Definition: CPView.j:1021
var CPCollectionViewMinItemSizeKey
var CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset
void setAutoresizingMask:(unsigned aMask)
CPIndexSet selectionIndexes()
An immutable string (collection of characters).
Definition: CPString.h:2
CGPoint convertPoint:fromView:(CGPoint aPoint, [fromView] CPView aView)
Definition: CPView.j:2142
unsigned maxNumberOfColumns()
if(CPFeatureIsCompatible(CPHTMLCanvasFeature))
var CPCollectionViewVerticalMarginKey
CGRect frameForItemAtIndex:(CPUInteger anIndex)
var CPCollectionViewSelectableKey
function CGContextSetFillColor(aContext, aColor)
Definition: CGContext.j:663
void setAutoresizingMask:(unsigned aMask)
Definition: CPView.j:1472
void setNeedsDisplay:(BOOL aFlag)
Definition: CPView.j:2490
CPMenu menuForEvent:(CPEvent anEvent)
Definition: CPView.j:1850
void encodeWithCoder:(CPCoder aCoder)
Definition: CPView.j:3704
function CGContextBeginPath(aContext)
Definition: CGContext.j:311
CPShiftKeyMask
var CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_
var CPCollectionViewMaxItemSizeKey
void setAutoresizesSubviews:(BOOL aFlag)
Definition: CPView.j:1454
void setBackgroundColors:(CPArray backgroundColors)
var CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_
var CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_
CPPlatformActionKeyMask
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
CPNotFound
Definition: CPObjJRuntime.j:62
unsigned declareTypes:owner:(CPArray types, [owner] id anOwner)
Definition: CPPasteboard.j:177
CPCollectionViewItem itemPrototype()
var CPCollectionViewBackgroundColorsKey
CPViewHeightSizable
Definition: CPView.j:85
void setBackgroundColor:(CPColor aColor)
Definition: CPView.j:1859
var CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_
var CPCollectionViewMaxNumberOfRowsKey
void setFrameSize:(CGSize aSize)
Definition: CPView.j:1086
void addIndexesInRange:(CPRange aRange)
Definition: CPIndexSet.j:732
function CGContextFillRect(aContext, aRect)
Definition: CGContext.j:358
Definition: CPEvent.h:2
CPView superview()
Definition: CPView.j:469
unsigned autoresizingMask()
Definition: CPView.j:1480
CGRect frame()
Definition: CPView.j:1011
void draggingEnded:(id draggingInfo)
id indexSetWithIndex:(int anIndex)
Definition: CPIndexSet.j:51
function CGContextMoveToPoint(aContext, x, y)
Definition: CGContext.j:344
CGRect frameForItemsAtIndexes:(CPIndexSet anIndexSet)
var CPCollectionViewAllowsMultipleSelectionKey
CPRange function CPMakeRange(location, length)
Definition: CPRange.j:37
void setSelectionIndexes:(CPIndexSet anIndexSet)
id indexSet()
Definition: CPIndexSet.j:43
var HORIZONTAL_MARGIN
id pasteboardWithName:(CPString aName)
Definition: CPPasteboard.j:97
unsigned maxNumberOfRows()
Definition: CPView.j:131
CPCollectionViewItem itemAtIndex:(CPUInteger anIndex)