Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Import changes from external project.

  • Loading branch information...
commit 09ebc2f7a4cd5122b7185bd75739652ffc7faa8b 1 parent 52322a7
@joshaber authored
View
16 JAEdgeInsets.h
@@ -0,0 +1,16 @@
+/*
+ * JAEdgeInsets.h
+ * GitHub
+ *
+ * Created by Josh Abernathy on 1/26/11.
+ * Copyright 2011 Josh Abernathy. All rights reserved.
+ *
+ */
+
+typedef struct {
+ CGFloat top, left, bottom, right;
+} JAEdgeInsets;
+
+static inline JAEdgeInsets JAEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right) {
+ return (JAEdgeInsets) { .top = top, .left = left, .bottom = bottom, .right = right };
+}
View
10 JAListView.h
@@ -7,6 +7,7 @@
//
#import <Cocoa/Cocoa.h>
+#import "JAEdgeInsets.h"
@class JAListView;
@class JAListViewItem;
@@ -35,6 +36,8 @@ extern NSString * const JAListViewDraggingPasteboardType;
- (void)listView:(JAListView *)listView willSelectView:(JAListViewItem *)view;
- (void)listView:(JAListView *)listView didSelectView:(JAListViewItem *)view;
- (void)listView:(JAListView *)listView didDeselectView:(JAListViewItem *)view;
+
+- (void)listView:(JAListView *)listView didRemoveView:(JAListViewItem *)view;
@end
@protocol JAListViewDraggingSourceDelegate <NSObject>
@@ -64,7 +67,6 @@ extern NSString * const JAListViewDraggingPasteboardType;
NSPoint margin;
CGFloat *cachedLocations;
__weak JAListViewItem *viewBeingSelected;
- JAListViewItem *viewBeingUsedForInertialScroll;
NSColor *backgroundColor;
BOOL isResizingManually;
BOOL conditionallyUseLayerBacking;
@@ -116,6 +118,10 @@ extern NSString * const JAListViewDraggingPasteboardType;
*/
- (void)deselectAllViews;
+- (void)markViewBeingUsedForInertialScrolling:(JAListViewItem *)newView;
+- (void)unmarkViewBeingUsedForInertialScrolling:(JAListViewItem *)view;
+- (void)clearViewsBeingUsedForInertialScrolling;
+
@property (nonatomic, readonly) NSScrollView *scrollView;
@property (nonatomic, assign) IBOutlet id<JAListViewDataSource> dataSource;
@property (nonatomic, assign) IBOutlet id<JAListViewDelegate> delegate;
@@ -124,7 +130,7 @@ extern NSString * const JAListViewDraggingPasteboardType;
@property (nonatomic, assign) BOOL canCallDataSourceInParallel;
@property (nonatomic, readonly) NSArray *visibleViews;
@property (nonatomic, assign) NSPoint margin;
-@property (nonatomic, retain) JAListViewItem *viewBeingUsedForInertialScroll;
+@property (nonatomic, assign) JAEdgeInsets padding;
@property (nonatomic, retain) NSColor *backgroundColor;
@property (nonatomic, readonly) CGFloat heightForAllContent;
@property (nonatomic, assign) BOOL conditionallyUseLayerBacking;
View
175 JAListView.m
@@ -42,6 +42,8 @@ - (void)standardLayoutAnimated:(BOOL)animated removeViews:(NSArray *)viewsToRemo
@property (nonatomic, retain) NSMutableArray *currentlySelectedViews;
@property (nonatomic, retain) NSTrackingArea *currentTrackingArea;
@property (nonatomic, copy) void (^currentAnimationBlock)(NSView *newSuperview, NSArray *viewsToAdd, NSArray *viewsToRemove, NSArray *viewsToMove);
+@property (nonatomic, retain) NSMutableArray *viewsBeingUsedForInertialScrolling;
+@property (nonatomic, assign) NSUInteger minIndexForReLayout;
@end
@@ -62,12 +64,12 @@ - (void)dealloc {
cachedLocations = NULL;
}
- self.viewBeingUsedForInertialScroll = nil;
self.backgroundColor = nil;
self.cachedVisibleViews = nil;
self.currentlySelectedViews = nil;
self.currentTrackingArea = nil;
self.currentAnimationBlock = nil;
+ self.viewsBeingUsedForInertialScrolling = nil;
[super dealloc];
}
@@ -122,13 +124,13 @@ - (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[self.backgroundColor set];
- NSRectFill(dirtyRect);
+ NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
}
#pragma mark NSResponder
-- (void)rightMouseUp:(NSEvent *)event {
+- (void)rightMouseDown:(NSEvent *)event {
NSPoint location = [self convertPoint:[event locationInWindow] fromView:nil];
JAListViewItem *view = [self viewAtPoint:location];
@@ -137,9 +139,13 @@ - (void)rightMouseUp:(NSEvent *)event {
}
}
-- (void)mouseDown:(NSEvent *)event {
+- (void)rightMouseUp:(NSEvent *)event {
+ [self rightMouseDown:event];
+}
+
+- (void)mouseDown:(NSEvent *)event {
if(([event modifierFlags] & NSControlKeyMask) != 0 && [event clickCount] == 1) {
- [self rightMouseUp:event];
+ [self rightMouseDown:event];
return;
}
@@ -176,6 +182,11 @@ - (void)mouseDown:(NSEvent *)event {
}
- (void)mouseUp:(NSEvent *)event {
+ // this is to fix a nasty AppKit bug where the event after a contexual menu gets routed oddly and we end up with a mouseUp event that doesn't really belong to us
+ if(!NSPointInRect([self convertPoint:[event locationInWindow] fromView:nil], self.frame)) {
+ return;
+ }
+
[self removeTrackingArea:self.currentTrackingArea];
self.currentTrackingArea = nil;
@@ -191,13 +202,12 @@ - (void)mouseUp:(NSEvent *)event {
self.viewBeingSelected.highlighted = NO;
self.viewBeingSelected = nil;
} else {
- for(JAListViewItem *itemView in [[self.currentlySelectedViews copy] autorelease]) {
- [[itemView retain] autorelease];
- itemView.selected = NO;
- [self.currentlySelectedViews removeObject:itemView];
+ for(JAListViewItem *selectedView in [[self.currentlySelectedViews copy] autorelease]) {
+ selectedView.selected = NO;
+ [self.currentlySelectedViews removeObject:selectedView];
if(respondsToUnSelect) {
- [self.delegate listView:self didDeselectView:itemView];
+ [self.delegate listView:self didDeselectView:selectedView];
}
}
}
@@ -236,11 +246,14 @@ - (void)mouseUp:(NSEvent *)event {
}
} else if([event modifierFlags] & NSShiftKeyMask) {
JAListViewItem *lastSelectedView = [self.currentlySelectedViews lastObject];
- NSUInteger lastIndex = [self indexForView:lastSelectedView];
- NSUInteger indexOfView = [self indexForView:view];
+ NSInteger lastIndex = [self indexForView:lastSelectedView];
+ NSInteger indexOfView = [self indexForView:view];
+
+ if(lastIndex == NSNotFound || indexOfView == NSNotFound) return;
+
if(indexOfView < lastIndex) {
- JAListViewItem *previousView = [self previousSelectableViewFromIndex:lastIndex];
- NSUInteger currentIndex = [self indexForView:previousView];
+ JAListViewItem *previousView = [self previousSelectableViewFromIndex:(NSUInteger) lastIndex];
+ NSInteger currentIndex = [self indexForView:previousView];
while(previousView != nil && currentIndex > indexOfView) {
previousView.selected = YES;
[self.currentlySelectedViews addObject:previousView];
@@ -253,8 +266,8 @@ - (void)mouseUp:(NSEvent *)event {
currentIndex = [self indexForView:previousView];
}
} else {
- JAListViewItem *nextView = [self nextSelectableViewFromIndex:lastIndex];
- NSUInteger currentIndex = [self indexForView:nextView];
+ JAListViewItem *nextView = [self nextSelectableViewFromIndex:(NSUInteger) lastIndex];
+ NSInteger currentIndex = [self indexForView:nextView];
while(nextView != nil && currentIndex < indexOfView) {
nextView.selected = YES;
[self.currentlySelectedViews addObject:nextView];
@@ -275,18 +288,18 @@ - (void)mouseUp:(NSEvent *)event {
[self.delegate listView:self didSelectView:view];
}
} else {
- for(JAListViewItem *itemView in [[self.currentlySelectedViews copy] autorelease]) {
- [[itemView retain] autorelease];
- itemView.selected = NO;
- [self.currentlySelectedViews removeObject:itemView];
+ for(JAListViewItem *selectedView in [[self.currentlySelectedViews copy] autorelease]) {
+ selectedView.selected = NO;
+ [self.currentlySelectedViews removeObject:selectedView];
if(respondsToUnSelect) {
- [self.delegate listView:self didDeselectView:itemView];
+ [self.delegate listView:self didDeselectView:selectedView];
}
}
view.selected = YES;
[self.currentlySelectedViews addObject:view];
+ [self.window makeFirstResponder:view];
if([self.delegate respondsToSelector:@selector(listView:didSelectView:)]) {
[self.delegate listView:self didSelectView:view];
@@ -307,6 +320,41 @@ - (void)mouseExited:(NSEvent *)event {
}
}
+- (void)swipeWithEvent:(NSEvent *)event {
+ JAListViewItem *newView = nil;
+ if([event deltaY] < 0.0f && [self nextSelectableView] != nil) {
+ newView = [self nextSelectableView];
+ } else if([event deltaY] > 0.0f && [self previousSelectableView] != nil) {
+ newView = [self previousSelectableView];
+ } else {
+ [super swipeWithEvent:event];
+ }
+
+ if(newView != nil) {
+ for(JAListViewItem *view in [[self.currentlySelectedViews copy] autorelease]) {
+ [[view retain] autorelease];
+ view.selected = NO;
+ [self.currentlySelectedViews removeObject:view];
+
+ if([self.delegate respondsToSelector:@selector(listView:didDeselectView:)]) {
+ [self.delegate listView:self didDeselectView:view];
+ }
+ }
+
+ newView.selected = YES;
+ [self.window makeFirstResponder:newView];
+ [self.currentlySelectedViews addObject:newView];
+
+ if([self.delegate respondsToSelector:@selector(listView:didSelectView:)]) {
+ [self.delegate listView:self didSelectView:newView];
+ }
+
+ NSRect viewFrame = newView.frame;
+ viewFrame.origin.y = self.cachedLocations[[self indexForView:newView]];
+ [(NSView *) self.scrollView.documentView scrollRectToVisible:viewFrame];
+ }
+}
+
- (void)mouseDragged:(NSEvent *)event {
NSPoint location = [self convertPoint:[event locationInWindow] fromView:nil];
NSView *viewUnderMouse = [self viewAtPoint:location];
@@ -330,7 +378,7 @@ - (void)mouseDragged:(NSEvent *)event {
NSMutableArray *viewsToDrag = [NSMutableArray array];
for(JAListViewItem *view in self.currentlySelectedViews) {
- BOOL shouldDrag = YES;
+ BOOL shouldDrag = NO;
if([self.draggingSourceDelegate respondsToSelector:@selector(listView:shouldDragView:)]) {
shouldDrag = [self.draggingSourceDelegate listView:self shouldDragView:view];
}
@@ -415,6 +463,7 @@ - (void)keyDown:(NSEvent *)event {
if(newView != nil) {
newView.selected = YES;
+ [self.window makeFirstResponder:newView];
[self.currentlySelectedViews addObject:newView];
if([self.delegate respondsToSelector:@selector(listView:didSelectView:)]) {
@@ -511,6 +560,7 @@ - (void)setup {
self.backgroundColor = [NSColor darkGrayColor];
[self registerForDraggedTypes:[NSArray arrayWithObject:JAListViewDraggingPasteboardType]];
self.currentlySelectedViews = [NSMutableArray array];
+ self.viewsBeingUsedForInertialScrolling = [NSMutableArray array];
}
- (void)viewBoundsDidChange:(NSNotification *)notification {
@@ -591,6 +641,10 @@ - (void)reloadAllViews {
[views replaceObjectAtIndex:index withObject:[self viewAtIndex:index]];
}
}
+
+ for(JAListViewItem *viewItem in views) {
+ viewItem.listView = self;
+ }
[self.cachedViews addObjectsFromArray:views];
[self clearCachedLocations];
@@ -615,10 +669,10 @@ - (void)showVisibleViewsAnimated:(BOOL)animated {
[viewsToRemove removeObject:view];
}
}
-
- [viewsToAdd removeObject:self.viewBeingUsedForInertialScroll];
- [viewsToRemove removeObject:self.viewBeingUsedForInertialScroll];
-
+
+ [viewsToAdd removeObjectsInArray:self.viewsBeingUsedForInertialScrolling];
+ [viewsToRemove removeObjectsInArray:self.viewsBeingUsedForInertialScrolling];
+
if(animated) {
CFTimeInterval duration = ([self.window currentEvent].modifierFlags & NSShiftKeyMask) ? 10.0f : defaultAnimationDuration;
@@ -637,7 +691,6 @@ - (void)showVisibleViewsAnimated:(BOOL)animated {
for(NSView *view in [[viewsToRemove copy] autorelease]) {
if([view isKindOfClass:[JAListViewItem class]]) {
minY = MIN(view.frame.origin.y, minY);
- ((JAListViewItem *)view).listView = nil;
} else {
[viewsToRemove removeObject:view];
}
@@ -650,21 +703,23 @@ - (void)showVisibleViewsAnimated:(BOOL)animated {
}
view.autoresizingMask = NSViewWidthSizable | NSViewMaxYMargin;
- view.listView = self;
CGFloat y = self.cachedLocations[[self.cachedViews indexOfObject:view]];
minY = MIN(y, minY);
}
NSMutableArray *viewsToMove = [NSMutableArray array];
+ NSUInteger index = 0;
for(NSView *view in existingViews) {
if([view isKindOfClass:[JAListViewItem class]]) {
JAListViewItem *listItemView = (JAListViewItem *) view;
// only layout views after the first new view
- if(listItemView.frame.origin.y >= minY && !listItemView.ignoreInListViewLayout) {
+ if((listItemView.frame.origin.y >= minY || index >= self.minIndexForReLayout) && !listItemView.ignoreInListViewLayout) {
[viewsToMove addObject:listItemView];
}
}
+
+ index++;
}
if(self.currentAnimationBlock != nil) {
@@ -672,6 +727,14 @@ - (void)showVisibleViewsAnimated:(BOOL)animated {
} else {
[self standardLayoutRemoveViews:viewsToRemove addViews:viewsToAdd moveViews:viewsToMove];
}
+
+ if([self.delegate respondsToSelector:@selector(listView:didRemoveView:)]) {
+ for(JAListViewItem *viewItem in viewsToRemove) {
+ [self.delegate listView:self didRemoveView:viewItem];
+ }
+ }
+
+ self.minIndexForReLayout = NSUIntegerMax;
self.currentAnimationBlock = nil;
@@ -694,14 +757,14 @@ - (void)standardLayoutRemoveViews:(NSArray *)viewsToRemove addViews:(NSArray *)v
}
- (void)standardLayoutAnimated:(BOOL)animated removeViews:(NSArray *)viewsToRemove addViews:(NSArray *)viewsToAdd moveViews:(NSArray *)viewsToMove {
- for(JAListViewItem *view in viewsToRemove) {
+ for(JAListViewItem *view in viewsToRemove) {
id viewOrProxy = animated ? [view animator] : view;
[viewOrProxy removeFromSuperview];
}
for(JAListViewItem *view in viewsToAdd) {
CGFloat y = self.cachedLocations[[self.cachedViews indexOfObject:view]];
- view.frame = NSMakeRect(self.margin.x, y, self.bounds.size.width - self.margin.x*2, view.bounds.size.height);
+ view.frame = NSIntegralRect(NSMakeRect(self.padding.left, y, self.bounds.size.width - (self.padding.left + self.padding.right), view.bounds.size.height));
id viewOrProxy = animated ? [self animator] : self;
[viewOrProxy addSubview:view];
@@ -715,7 +778,7 @@ - (void)standardLayoutAnimated:(BOOL)animated removeViews:(NSArray *)viewsToRemo
CGFloat y = self.cachedLocations[indexOfView]; //!!!: boom - bad access
id viewOrProxy = animated ? [view animator] : view;
- [viewOrProxy setFrameOrigin:NSMakePoint(self.margin.x, y)];
+ [viewOrProxy setFrame:NSMakeRect(self.padding.left, y, view.bounds.size.width, view.bounds.size.height)];
}
}
@@ -748,15 +811,23 @@ - (void)reloadLayoutWithAnimation:(void (^)(NSView *newSuperview, NSArray *views
}
- (void)recacheAllLocations {
- CGFloat currentY = self.margin.y;
+ self.minIndexForReLayout = NSUIntegerMax;
+
+ CGFloat currentY = self.margin.y + self.padding.top;
NSUInteger index = 0;
for(JAListViewItem *view in self.cachedViews) {
- self.cachedLocations[index] = [self yForView:view proposedY:currentY];
+ CGFloat newY = [self yForView:view proposedY:currentY];
+ if(newY != self.cachedLocations[index]) {
+ self.minIndexForReLayout = MIN(self.minIndexForReLayout, index);
+ }
+ self.cachedLocations[index] = newY;
currentY += [self heightForView:view proposedHeight:view.bounds.size.height + self.margin.y];
index++;
}
- heightForAllContent = currentY;
+ heightForAllContent = currentY + self.padding.bottom;
+
+ self.minIndexForReLayout = 0;
}
- (CGFloat)yForView:(JAListViewItem *)view proposedY:(CGFloat)proposedY {
@@ -772,9 +843,6 @@ - (NSUInteger)numberOfViews {
}
- (JAListViewItem *)viewAtIndex:(NSUInteger)index {
- NSUInteger numberOfViews = [self numberOfViews];
- NSAssert2(index < numberOfViews, @"Index (%d) must be less than %d.", index, numberOfViews);
-
JAListViewItem *view = [self.dataSource listView:self viewAtIndex:index];
NSAssert2([view isKindOfClass:[JAListViewItem class]], @"View must be a %@, instead: %@", NSStringFromClass([JAListViewItem class]), view);
return view;
@@ -882,7 +950,7 @@ - (void)getSelectionMinimumIndex:(NSUInteger *)minIndex maximumIndex:(NSUInteger
if(maxIndex != NULL) *maxIndex = 0;
for(JAListViewItem *view in self.currentlySelectedViews) {
- NSUInteger index = [self indexForView:view];
+ NSUInteger index = (NSUInteger) [self indexForView:view];
if(minIndex != NULL) *minIndex = MIN(index, *minIndex);
if(maxIndex != NULL) *maxIndex = MAX(index, *maxIndex);
}
@@ -929,11 +997,11 @@ - (JAListViewItem *)nextSelectableViewFromIndex:(NSUInteger)startingIndex {
- (JAListViewItem *)previousSelectableViewFromIndex:(NSUInteger)startingIndex {
BOOL respondsToShouldSelect = [self.delegate respondsToSelector:@selector(listView:shouldSelectView:)];
JAListViewItem *previousView = nil;
- NSInteger index = startingIndex - 1;
+ NSInteger index = (NSInteger) startingIndex - 1;
while(previousView == nil) {
if(index < 0) break;
- JAListViewItem *potentialView = [self viewAtIndex:index];
+ JAListViewItem *potentialView = [self viewAtIndex:(NSUInteger) index];
if(respondsToShouldSelect) {
if([self.delegate listView:self shouldSelectView:potentialView]) {
previousView = potentialView;
@@ -950,6 +1018,7 @@ - (JAListViewItem *)previousSelectableViewFromIndex:(NSUInteger)startingIndex {
}
- (void)selectView:(JAListViewItem *)view {
+ [self.window makeFirstResponder:view];
view.selected = YES;
[self.currentlySelectedViews addObject:view];
@@ -976,6 +1045,26 @@ - (void)deselectAllViews {
}
}
+- (void)markViewBeingUsedForInertialScrolling:(JAListViewItem *)newView {
+ // This value is fairly arbitrary. I've seen it use 2 different views so we'll go one over that for now.
+ static const NSUInteger maxNumberOfViewsForInertialScrolling = 3;
+
+ NSAssert(newView != nil, @"Cannot mark a nil view as being used for inertial scrolling.");
+
+ [self.viewsBeingUsedForInertialScrolling addObject:newView];
+ while(self.viewsBeingUsedForInertialScrolling.count > maxNumberOfViewsForInertialScrolling) {
+ [self.viewsBeingUsedForInertialScrolling removeObjectAtIndex:0];
+ }
+}
+
+- (void)unmarkViewBeingUsedForInertialScrolling:(JAListViewItem *)view {
+ [self.viewsBeingUsedForInertialScrolling removeObject:view];
+}
+
+- (void)clearViewsBeingUsedForInertialScrolling {
+ [self.viewsBeingUsedForInertialScrolling removeAllObjects];
+}
+
@synthesize dataSource;
@synthesize delegate;
@synthesize draggingSourceDelegate;
@@ -983,13 +1072,15 @@ - (void)deselectAllViews {
@synthesize cachedVisibleViews;
@synthesize canCallDataSourceInParallel;
@synthesize margin;
+@synthesize padding;
@synthesize viewBeingSelected;
-@synthesize viewBeingUsedForInertialScroll;
@synthesize backgroundColor;
@synthesize heightForAllContent;
@synthesize conditionallyUseLayerBacking;
@synthesize currentlySelectedViews;
@synthesize currentTrackingArea;
@synthesize currentAnimationBlock;
+@synthesize viewsBeingUsedForInertialScrolling;
+@synthesize minIndexForReLayout;
@end
View
2  JAListView.xcodeproj/project.pbxproj
@@ -46,6 +46,7 @@
885CF38312A051AD0069C4CF /* NSIndexPath+JAListViewExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexPath+JAListViewExtensions.h"; sourceTree = "<group>"; };
885CF38412A051AD0069C4CF /* NSIndexPath+JAListViewExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexPath+JAListViewExtensions.m"; sourceTree = "<group>"; };
888799BB12B2EB89006A9135 /* Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Demo-Info.plist"; sourceTree = "<group>"; };
+ 88D30AC413249FEC00F32DB2 /* JAEdgeInsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JAEdgeInsets.h; sourceTree = "<group>"; };
88DA16181254594E00A1D5AA /* JAListView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JAListView.h; sourceTree = "<group>"; };
88DA16191254594E00A1D5AA /* JAListView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JAListView.m; sourceTree = "<group>"; };
88DA1678125461A200A1D5AA /* DemoView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoView.h; sourceTree = "<group>"; };
@@ -159,6 +160,7 @@
children = (
88DA16181254594E00A1D5AA /* JAListView.h */,
88DA16191254594E00A1D5AA /* JAListView.m */,
+ 88D30AC413249FEC00F32DB2 /* JAEdgeInsets.h */,
885CF18912A044CC0069C4CF /* JASectionedListView.h */,
885CF18A12A044CC0069C4CF /* JASectionedListView.m */,
8842256812AD686600A4B4D9 /* JAObjectListView.h */,
View
6 JAListView.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace>
+ <FileRef
+ location = "self:JAListView.xcodeproj">
+ </FileRef>
+</Workspace>
View
8 JAListViewItem.h
@@ -7,6 +7,13 @@
#import <Cocoa/Cocoa.h>
+typedef enum {
+ JAListViewPositionTop = 1 << 1,
+ JAListViewPositionMiddle = 1 << 2,
+ JAListViewPositionBottom = 1 << 3,
+ JAListViewPositionNone = 0,
+} JAListViewPosition;
+
@class JAListView;
@@ -18,5 +25,6 @@
@property (nonatomic, assign) BOOL ignoreInListViewLayout;
@property (nonatomic, assign, getter=isSelected) BOOL selected;
@property (nonatomic, assign, getter=isHighlighted) BOOL highlighted;
+@property (nonatomic, readonly) JAListViewPosition listViewPosition;
@end
View
43 JAListViewItem.m
@@ -7,6 +7,7 @@
#import "JAListViewItem.h"
#import "JAListView.h"
+#import "JASectionedListView.h"
@implementation JAListViewItem
@@ -14,19 +15,26 @@ @implementation JAListViewItem
#pragma mark NSView
-- (void)scrollWheel:(NSEvent *)event {
- self.listView.viewBeingUsedForInertialScroll = self;
-
+- (void)scrollWheel:(NSEvent *)event {
+ [self.listView markViewBeingUsedForInertialScrolling:self];
[super scrollWheel:event];
}
+#pragma mark NSResponder
+
+- (BOOL)acceptsFirstResponder {
+ return YES;
+}
+
+
#pragma mark API
@synthesize ignoreInListViewLayout;
@synthesize listView;
@synthesize selected;
@synthesize highlighted;
+@synthesize listViewPosition;
- (NSImage *)draggingImage {
NSBitmapImageRep *bitmap = [self bitmapImageRepForCachingDisplayInRect:self.bounds];
@@ -48,6 +56,35 @@ - (NSImage *)draggingImage {
return result;
}
+- (JAListViewPosition)listViewPosition {
+ JAListViewPosition position = JAListViewPositionNone;
+ NSUInteger index = (NSUInteger) [self.listView indexForView:self];
+ NSUInteger numberOfViews = [self.listView numberOfViews];
+
+ if([self.listView isKindOfClass:[JASectionedListView class]]) {
+ JASectionedListView *sectionedListView = (JASectionedListView *) self.listView;
+ NSUInteger section = 0;
+ NSUInteger newIndex = index;
+ [sectionedListView getSection:&section andIndex:&newIndex fromAbsoluteIndex:index];
+ index = newIndex;
+ numberOfViews = [sectionedListView numberOfViewsInSection:section];
+ }
+
+ if(index == numberOfViews - 1) {
+ position |= JAListViewPositionBottom;
+ }
+
+ if(index == 0) {
+ position |= JAListViewPositionTop;
+ }
+
+ if(position == JAListViewPositionNone) {
+ position = JAListViewPositionMiddle;
+ }
+
+ return position;
+}
+
- (void)setSelected:(BOOL)newValue {
selected = newValue;
View
7 JAObjectListView.h
@@ -21,12 +21,17 @@
- (void)addListViewItem:(JAObjectListViewItem *)view forHeaderForSection:(NSUInteger)section;
- (void)removeListViewItemForHeaderForSection:(NSUInteger)section;
-- (void)removeListViewItem:(JAObjectListViewItem *)view;
+- (void)removeListViewItem:(JAListViewItem *)view;
- (void)removeAllListViewItems;
- (NSArray *)viewsInSection:(NSUInteger)section;
- (NSUInteger)numberOfSections;
+- (JAListViewItem *)headerForSection:(NSUInteger)section;
- (JAObjectListViewItem *)viewItemForObject:(id)object;
- (NSIndexPath *)indexPathForObject:(id)object;
+- (void)removeListViewItemForObject:(id)object;
+- (NSArray *)allObjects;
+
+- (NSString *)debugString;
@end
View
55 JAObjectListView.m
@@ -79,17 +79,15 @@ - (void)reallyAddListViewItem:(JAObjectListViewItem *)view inSection:(NSUInteger
NSMutableArray *sectionViews = nil;
if(section < self.sectionRowViews.count) {
sectionViews = [self.sectionRowViews objectAtIndex:section];
- } else if(section != NSNotFound) { // added NSNotFound check
+ } else if(section != NSNotFound) {
sectionViews = [NSMutableArray array];
- [self.sectionRowViews insertObject:sectionViews atIndex:section]; //!!! boom - bounds
+ [self.sectionRowViews insertObject:sectionViews atIndex:section];
} else {
NSAssert1(NO, @"Tried to insert view into a non-existent section: %@", view);
}
- if(index < sectionViews.count) {
- [sectionViews replaceObjectAtIndex:index withObject:view];
- } else if(index != NSNotFound) { // added NSNotFound check
- [sectionViews insertObject:view atIndex:index]; //!!! boom - bounds
+ if(index != NSNotFound) {
+ [sectionViews insertObject:view atIndex:index];
} else {
NSAssert1(NO, @"Tried to insert view into a non-existent row: %@", view);
}
@@ -104,9 +102,7 @@ - (void)removeListViewItemInSection:(NSUInteger)section atIndex:(NSUInteger)inde
NSUInteger trueIndex = index + 1;
JAObjectListViewItem *view = [sectionViews objectAtIndex:trueIndex];
- if(self.viewBeingUsedForInertialScroll == view) {
- self.viewBeingUsedForInertialScroll = nil;
- }
+ [self unmarkViewBeingUsedForInertialScrolling:view];
[self deselectView:view];
@@ -122,9 +118,7 @@ - (void)addListViewItem:(JAObjectListViewItem *)view forHeaderForSection:(NSUInt
- (void)removeListViewItemForHeaderForSection:(NSUInteger)section {
NSArray *views = [self.sectionRowViews objectAtIndex:section];
for(JAObjectListViewItem *item in views) {
- if(self.viewBeingUsedForInertialScroll == item) {
- self.viewBeingUsedForInertialScroll = nil;
- }
+ [self unmarkViewBeingUsedForInertialScrolling:item];
[self deselectView:item];
}
@@ -132,10 +126,8 @@ - (void)removeListViewItemForHeaderForSection:(NSUInteger)section {
[self.sectionRowViews removeObjectAtIndex:section];
}
-- (void)removeListViewItem:(JAObjectListViewItem *)view {
- if(self.viewBeingUsedForInertialScroll == view) {
- self.viewBeingUsedForInertialScroll = nil;
- }
+- (void)removeListViewItem:(JAListViewItem *)view {
+ [self unmarkViewBeingUsedForInertialScrolling:view];
[self deselectView:view];
@@ -144,7 +136,7 @@ - (void)removeListViewItem:(JAObjectListViewItem *)view {
NSUInteger index = [sectionViews indexOfObject:view];
if(index != NSNotFound) {
if(index == 0) {
- [self.sectionRowViews removeObjectAtIndex:sectionIndex];
+ [self removeListViewItemForHeaderForSection:sectionIndex];
} else {
[sectionViews removeObjectAtIndex:index];
}
@@ -153,13 +145,13 @@ - (void)removeListViewItem:(JAObjectListViewItem *)view {
}
- (void)removeAllListViewItems {
- self.viewBeingUsedForInertialScroll = nil;
+ [self clearViewsBeingUsedForInertialScrolling];
[self deselectAllViews];
[self.sectionRowViews removeAllObjects];
}
- (NSArray *)viewsInSection:(NSUInteger)section {
- if(section >= self.sectionRowViews.count) return nil;
+ NSParameterAssert(section < self.sectionRowViews.count);
NSMutableArray *views = [[[self.sectionRowViews objectAtIndex:section] mutableCopy] autorelease];
if(views.count < 1) return nil;
@@ -185,6 +177,8 @@ - (JAObjectListViewItem *)viewItemForObject:(id)object {
}
- (NSIndexPath *)indexPathForObject:(id)object {
+ NSAssert(object != nil, @"Invalid to look for the index path of a nil object.");
+
NSUInteger section = 0;
for(NSArray *views in self.sectionRowViews) {
@@ -207,4 +201,27 @@ - (NSIndexPath *)indexPathForObject:(id)object {
return nil;
}
+- (JAListViewItem *)headerForSection:(NSUInteger)section {
+ return [[self.sectionRowViews objectAtIndex:section] objectAtIndex:0];
+}
+
+- (void)removeListViewItemForObject:(id)object {
+ [self removeListViewItem:[self viewItemForObject:object]];
+}
+
+- (NSArray *)allObjects {
+ NSMutableArray *objects = [NSMutableArray array];
+ for(NSArray *views in self.sectionRowViews) {
+ for(JAObjectListViewItem *item in views) {
+ if(item.object != nil) [objects addObject:item.object];
+ }
+ }
+
+ return objects;
+}
+
+- (NSString *)debugString {
+ return [NSString stringWithFormat:@"%@", self.sectionRowViews];
+}
+
@end
View
2  JASectionedListView.m
@@ -101,7 +101,7 @@ - (NSUInteger)absoluteIndexFromIndexPath:(NSIndexPath *)indexPath {
}
- (NSIndexPath *)indexPathForView:(JAListViewItem *)view {
- return [self indexPathFromAbsoluteIndex:[self indexForView:view]];
+ return [self indexPathFromAbsoluteIndex:(NSUInteger) [self indexForView:view]];
}
- (BOOL)isViewSectionHeaderView:(JAListViewItem *)view {

0 comments on commit 09ebc2f

Please sign in to comment.
Something went wrong with that request. Please try again.