Revision: 28673
http://sourceforge.net/p/bibdesk/svn/28673
Author: hofman
Date: 2024-01-25 15:11:02 +0000 (Thu, 25 Jan 2024)
Log Message:
-----------
Draw icons and labels in separate subview of file view, so we don't have to
redraw the icons when the selection changes.
Modified Paths:
--------------
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h 2024-01-25
00:04:31 UTC (rev 28672)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h 2024-01-25
15:11:02 UTC (rev 28673)
@@ -221,6 +221,7 @@
NSIndexSet *_selectionIndexes;
CGLayerRef _selectionOverlay;
NSUInteger _lastClickedIndex;
+ NSView *_contentView;
NSView *_rubberBandView;
FVDropHighlightView *_dropHighlightView;
struct __fvFlags {
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m 2024-01-25
00:04:31 UTC (rev 28672)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m 2024-01-25
15:11:02 UTC (rev 28673)
@@ -150,23 +150,29 @@
#pragma mark -
-@protocol FVDropHighlightViewDelegate
-- (void)drawDropHighlightInView:(NSView *)view;
+@protocol FVContentViewDelegate
+- (void)drawRect:(NSRect)rect inView:(NSView *)view;
@end
-@interface FVDropHighlightView : NSView {
+@interface FVContentView : NSView {
+ __weak id<FVContentViewDelegate> _delegate;
+}
+@property (nonatomic, weak) id<FVContentViewDelegate> delegate;
+@end
+
+#pragma mark -
+
+@interface FVDropHighlightView : FVContentView {
NSUInteger _dropIndex;
FVDropOperation _dropOperation;
- __weak id<FVDropHighlightViewDelegate> _delegate;
}
@property (nonatomic) NSUInteger dropIndex;
@property (nonatomic) FVDropOperation dropOperation;
-@property (nonatomic, weak) id<FVDropHighlightViewDelegate> delegate;
@end
#pragma mark -
-@interface FVFileView (FVDelegateDeclarations) <FVDownloadDelegate,
QLPreviewPanelDataSource, QLPreviewPanelDelegate, FVDropHighlightViewDelegate>
+@interface FVFileView (FVDelegateDeclarations) <FVDownloadDelegate,
QLPreviewPanelDataSource, QLPreviewPanelDelegate, FVContentViewDelegate>
@end
#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7
@@ -328,8 +334,15 @@
+ (BOOL)accessInstanceVariablesDirectly { return NO; }
- (void)_commonInit {
- // Icons keyed by URL; may contain icons that are no longer displayed.
Keeping this as primary storage means that
- // rearranging/reloading is relatively cheap, since we don't recreate all
FVIcon instances every time -reload is called.
+ if (_contentView == nil) {
+ _contentView = [[FVContentView alloc] initWithFrame:[self bounds]];
+ [_contentView setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
+ [self addSubview:_contentView];
+ }
+ [(FVContentView *)_contentView setDelegate:self];
+
+ // Icons keyed by URL; may contain icons that are no longer displayed.
Keeping this as primary storage means that
+ // rearranging/reloading is relatively cheap, since we don't recreate all
FVIcon instances every time -reload is called.
_iconCache = [[NSMutableDictionary alloc] init];
// Icons keyed by URL that aren't in the current datasource; this is
purged and repopulated every ZOMBIE_TIMER_INTERVAL
_zombieIconCache = [[NSMutableDictionary alloc] init];
@@ -449,13 +462,23 @@
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
- [self _commonInit];
+ if (self) {
+ [self _commonInit];
+ }
return self;
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
- [self _commonInit];
+ if (self) {
+ for (NSView *view in [self subviews]) {
+ if ([view isMemberOfClass:[FVContentView self]]) {
+ _contentView = view;
+ break;
+ }
+ }
+ [self _commonInit];
+ }
return self;
}
@@ -1068,9 +1091,11 @@
}
- (void)_handleKeyOrMainStateNotification:(NSNotification *)note {
- [self setNeedsDisplay:YES];
+ if (_backgroundView == nil)
+ [self setNeedsDisplay:YES];
+ else
+ [_backgroundView setNeedsDisplay:YES];
[[self enclosingScrollView] setNeedsDisplay:YES];
- [_backgroundView setNeedsDisplay:YES];
}
- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
@@ -1168,7 +1193,7 @@
// extend the icon rect to account for shadow in case text is narrower
than the icon
// extend downward to account for the text area
dirtyRect = NSUnionRect(NSInsetRect(dirtyRect, -ceil(2.0 * [self
iconScale]), -ceil([self iconScale])), [self _rectOfTextForIconRect:dirtyRect]);
- [self setNeedsDisplayInRect:dirtyRect];
+ [_contentView setNeedsDisplayInRect:dirtyRect];
}
#pragma mark Drawing layout
@@ -1702,6 +1727,7 @@
// grid may have changed, so do a full redisplay
[self setNeedsDisplay:YES];
+ [_contentView setNeedsDisplay:YES];
/*
Any time the number of icons or scale changes, cursor rects are garbage
and need to be reset. The approved way to do this is by calling
invalidateCursorRectsForView:, and the docs say to never invoke -[NSView
resetCursorRects] manually. Unfortunately, tracking rects are still active
even though the window isn't key, and we show buttons for non-key windows. As
a consequence, if the number of icons just changed from (say) 3 to 1 in a
non-key view, it can receive mouseEntered: events for the now-missing icons.
Possibly we don't need to reset cursor rects since they only change for the key
window, but we'll reset everything manually just in case. Allow NSWindow to
handle it if the window is key.
@@ -1720,7 +1746,7 @@
- (void)_setViewNeedsDisplay
{
NSAssert(pthread_main_np() != 0, @"main thread required");
- [self setNeedsDisplay:YES];
+ [_contentView setNeedsDisplay:YES];
}
- (void)_recacheIconsWithInfo:(NSDictionary *)info
@@ -1904,7 +1930,7 @@
NSURL *url = [note object];
if ([_infoTable objectForKey:url]) {
[_infoTable removeObjectForKey:url];
- [self setNeedsDisplay:YES];
+ [_contentView setNeedsDisplay:YES];
}
}
@@ -1919,7 +1945,7 @@
// this won't necessarily trigger setNeedsDisplay:, which we need
unconditionally
[self scrollRectToVisible:[self _rectOfIconInRow:r column:c]];
}
- [self setNeedsDisplay:YES];
+ [_contentView setNeedsDisplay:YES];
_fvFlags.isRescaling = NO;
}
@@ -2005,7 +2031,7 @@
// no save/restore needed because of when these are called in -drawRect: (this
is why they're private)
-- (void)drawDropHighlightInView:(NSView *)view;
+- (void)_drawDropHighlight
{
CGFloat lineWidth = 2.0;
NSBezierPath *p;
@@ -2247,7 +2273,7 @@
// redraw at full quality after a resize
- (void)viewDidEndLiveResize
{
- [self setNeedsDisplay:YES];
+ [_contentView setNeedsDisplay:YES];
_fvFlags.scheduledLiveResize = NO;
}
@@ -2362,7 +2388,7 @@
}
}
-enum { FVDrawIcon = 1<<0, FVDrawText = 1<<1, FVDrawHighlight = 1<<2,
FVDrawView = FVDrawIcon | FVDrawText | FVDrawHighlight };
+enum { FVDrawIcon = 1<<0, FVDrawText = 1<<1, FVDrawSelected = 1<<2 };
- (void)_drawIconsInRows:(NSRange)rows columns:(NSRange)columns
drawOption:(NSUInteger)drawOption
{
@@ -2413,7 +2439,7 @@
i = [self _indexForGridRow:r column:c];
// if we're creating a drag image, only draw selected icons
- if (NSNotFound != i && (FVDrawView == drawOption ||
[_selectionIndexes containsIndex:i])) {
+ if (NSNotFound != i && ((FVDrawSelected & drawOption) == 0 ||
[_selectionIndexes containsIndex:i])) {
NSRect fileRect = [self _rectOfIconInRow:r column:c];
@@ -2420,14 +2446,10 @@
// allow some extra for the shadow (-5)
NSRect textRect = [self _rectOfTextForIconRect:fileRect];
// always draw icon and text together, as they may overlap due
to shadow and finder label, and redrawing a part may look odd
- BOOL willDrawIcon = FVDrawView != drawOption || [self
needsToDrawRect:NSUnionRect(NSInsetRect(fileRect, -2.0 * [self iconScale],
-[self iconScale]), textRect)];
+ BOOL willDrawIcon = (FVDrawSelected & drawOption) ||
[_contentView needsToDrawRect:NSUnionRect(NSInsetRect(fileRect, -2.0 * [self
iconScale], -[self iconScale]), textRect)];
if (willDrawIcon) {
- // draw highlight, then draw icon over it, as Finder does
- if ((FVDrawHighlight & drawOption) && [_selectionIndexes
containsIndex:i])
- [self _drawHighlightInRect:NSInsetRect(fileRect,
HIGHLIGHT_INSET, HIGHLIGHT_INSET) inContext:cgContext];
-
if ((FVDrawIcon & drawOption)) {
FVIcon *image = [self iconAtIndex:i];
@@ -2515,66 +2537,8 @@
CGColorRelease(shadowColor);
}
-- (void)_fillBackgroundColorOrGradientInRect:(NSRect)rect
forBounds:(NSRect)bounds
+- (void)_drawIconsInRect:(NSRect)rect;
{
- // any solid color background should override the gradient code
- if ([self backgroundColor]) {
- [[self backgroundColor] setFill];
- NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver);
- }
- else {
- /*
- The NSTableView magic source list color no longer works properly on
10.7, either
- because they changed it from a solid color to a gradient, or just
changed the
- drawing. I couldn't see a reasonable way to subclass NSColor and
draw a gradient
- as Apple does, or to force the color to update properly, so we'll
just cheat and
- do it the easy way. Using 10.5 and later API is okay, since 10.4
gets a solid
- color anyway.
- */
- FVAPIAssert(floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6,
@"gradient background is only available on 10.7 and later");
-
- // otherwise we see a blocky transition, which fades on the redraw
when scrolling stops
- if ([[[self enclosingScrollView] contentView] copiesOnScroll])
- [[[self enclosingScrollView] contentView] setCopiesOnScroll:NO];
-
- // should be RGBA space, since we're drawing to the screen
- CGColorSpaceRef cspace =
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
- const CGFloat locations[] = { 0, 1 };
- CGGradientRef gradient;
-
- // color values from DigitalColor Meter on 10.7, using Generic RGB
space
- if ([[self window] isKeyWindow] || [[self window] isMainWindow]) {
- // ordered as lower/upper
- const CGFloat components[8] = { 198.0 / 255.0, 207.0 / 255.0,
216.0 / 255.0, 1.0, 227.0 / 255.0, 232.0 / 255.0, 238.0 / 255.0, 1.0 };
- gradient = CGGradientCreateWithColorComponents(cspace, components,
locations, 2);
- }
- else {
- // ordered as lower/upper
- const CGFloat components[8] = { 230.0 / 255.0, 230.0 / 255.0,
230.0 / 255.0, 1.0, 246.0 / 255.0, 246.0 / 255.0, 246.0 / 255.0, 1.0 };
- gradient = CGGradientCreateWithColorComponents(cspace, components,
locations, 2);
- }
- CGContextRef ctxt = [[NSGraphicsContext currentContext] graphicsPort];
-
- // only draw the dirty part, but we need to use the full visible
bounds as the gradient extent
- CGContextSaveGState(ctxt);
- CGContextClipToRect(ctxt, NSRectToCGRect(rect));
- CGContextDrawLinearGradient(ctxt, gradient, CGPointMake(0,
NSMaxY(bounds)), CGPointMake(0, NSMinY(bounds)), 0);
- CGContextRestoreGState(ctxt);
-
- CGGradientRelease(gradient);
- CGColorSpaceRelease(cspace);
- }
-}
-
-- (void)drawRect:(NSRect)rect;
-{
- if (_backgroundView == nil && [[NSGraphicsContext currentContext]
isDrawingToScreen]) {
- // otherwise we see a blocky transition, which fades on the redraw
when scrolling stops
- if (_backgroundColor == nil && [[[self enclosingScrollView]
contentView] copiesOnScroll])
- [[[self enclosingScrollView] contentView] setCopiesOnScroll:NO];
- FVFillBackgroundColorOrGradient(_backgroundColor, rect, [self
visibleRect], [self window]);
- }
-
// Only iterate icons in the visible range, since we know the overall
geometry
NSRange rowRange, columnRange;
[self _getRangeOfRows:&rowRange columns:&columnRange inRect:rect];
@@ -2590,7 +2554,7 @@
// only draw icons if we actually have some in this rect
if (iMax > iMin) {
- [self _drawIconsInRows:rowRange columns:columnRange
drawOption:FVDrawView];
+ [self _drawIconsInRows:rowRange columns:columnRange
drawOption:FVDrawIcon | FVDrawText];
// avoid hitting the cache thread while a live resize is in progress,
but allow cache updates while scrolling
// use the same range criteria that we used in iterating icons
@@ -2601,7 +2565,30 @@
[[NSGraphicsContext currentContext] setShouldAntialias:YES];
[self _drawDropMessage];
}
+}
+
+- (void)drawRect:(NSRect)rect;
+{
+ if (_backgroundView == nil && [[NSGraphicsContext currentContext]
isDrawingToScreen]) {
+ // otherwise we see a blocky transition, which fades on the redraw
when scrolling stops
+ if (_backgroundColor == nil && [[[self enclosingScrollView]
contentView] copiesOnScroll])
+ [[[self enclosingScrollView] contentView] setCopiesOnScroll:NO];
+ FVFillBackgroundColorOrGradient(_backgroundColor, rect, [self
visibleRect], [self window]);
+ }
+ if ([_selectionIndexes count] > 0) {
+ CGContextRef context = [[NSGraphicsContext currentContext]
graphicsPort];
+
+ [_selectionIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL
*stop){
+ NSUInteger r, c;
+ if ([self _getGridRow:&r column:&c ofIndex:i]) {
+ NSRect highlightRect = NSInsetRect([self _rectOfIconInRow:r
column:c], HIGHLIGHT_INSET, HIGHLIGHT_INSET);
+ if ([self needsToDrawRect:highlightRect])
+ [self _drawHighlightInRect:highlightRect
inContext:context];
+ }
+ }];
+ }
+
#if DEBUG_GRID
[[NSColor grayColor] set];
NSRect r = NSInsetRect([self bounds], [self _leftMargin], [self
_topMargin]);
@@ -2610,6 +2597,14 @@
#endif
}
+- (void)drawRect:(NSRect)rect inView:(NSView *)view
+{
+ if (view == _contentView)
+ [self _drawIconsInRect:rect];
+ else if (view == _dropHighlightView)
+ [self _drawDropHighlight];
+}
+
#pragma mark Drag source
#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MIN_REQUIRED >=
MAC_OS_X_VERSION_10_7
@@ -2665,7 +2660,7 @@
[image lockFocusFlipped:YES];
[transform concat];
FVRunWithAppearance(self, ^{
- [self _drawIconsInRows:NSMakeRange(r, 1)
columns:NSMakeRange(c, 1) drawOption:FVDrawIcon];
+ [self _drawIconsInRows:NSMakeRange(r, 1)
columns:NSMakeRange(c, 1) drawOption:FVDrawIcon | FVDrawSelected];
});
[image unlockFocus];
@@ -2684,7 +2679,7 @@
[image lockFocusFlipped:YES];
[transform concat];
FVRunWithAppearance(self, ^{
- [self _drawIconsInRows:NSMakeRange(r, 1)
columns:NSMakeRange(c, 1) drawOption:FVDrawText];
+ [self _drawIconsInRows:NSMakeRange(r, 1)
columns:NSMakeRange(c, 1) drawOption:FVDrawText | FVDrawSelected];
});
[image unlockFocus];
@@ -2767,7 +2762,7 @@
NSImage *newImage = [[NSImage alloc] initWithSize:bounds.size];
[newImage lockFocusFlipped:YES];
FVRunWithAppearance(self, ^{
- [self _drawIconsInRows:NSMakeRange(rMin, rMax + 1 - rMin)
columns:NSMakeRange(cMin, cMax + 1 - cMax) drawOption:FVDrawIcon | FVDrawText];
+ [self _drawIconsInRows:NSMakeRange(rMin, rMax + 1 - rMin)
columns:NSMakeRange(cMin, cMax + 1 - cMax) drawOption:FVDrawIcon | FVDrawText |
FVDrawSelected];
});
[newImage unlockFocus];
@@ -2849,9 +2844,9 @@
}
if (_dropHighlightView == nil) {
- _dropHighlightView = [[FVDropHighlightView alloc] initWithFrame:[self
bounds]];
- [(FVDropHighlightView *)_dropHighlightView setDelegate:self];
- [self addSubview:_dropHighlightView];
+ _dropHighlightView = [[FVDropHighlightView alloc]
initWithFrame:[_contentView bounds]];
+ [_dropHighlightView setDelegate:self];
+ [_contentView addSubview:_dropHighlightView];
}
[_dropHighlightView setDropIndex:dropIndex];
[_dropHighlightView setDropOperation:dropOp];
@@ -3089,8 +3084,8 @@
// set enabled states
[self _updateButtonsForIcon:anIcon];
- [self addSubview:_leftArrow];
- [self addSubview:_rightArrow];
+ [_contentView addSubview:_leftArrow];
+ [_contentView addSubview:_rightArrow];
if ([_leftArrow alphaValue] < 1.0) {
[NSAnimationContext runAnimationGroup:^(NSAnimationContext
*context){
@@ -3450,7 +3445,7 @@
#endif
rubberBandRect = [self backingAlignedRect:rubberBandRect
options:NSAlignMinXInward | NSAlignMaxXInward | NSAlignMinYInward |
NSAlignMaxYInward];
[_rubberBandView setFrame:rubberBandRect];
- [self addSubview:_rubberBandView];
+ [_contentView addSubview:_rubberBandView];
[self autoscroll:event];
[super mouseDragged:event];
}
@@ -4209,7 +4204,7 @@
_progressIndicators = [[NSMutableDictionary alloc] init];
[_progressIndicators setObject:progressIndicator forKey:aURL];
[progressIndicator setFrame:[self
_rectOfProgressIndicatorForIconAtIndex:anIndex]];
- [self addSubview:progressIndicator];
+ [_contentView addSubview:progressIndicator];
} else if (anIndex != [progressIndicator indexInView]) {
[progressIndicator setIndexInView:anIndex];
[progressIndicator setFrame:[self
_rectOfProgressIndicatorForIconAtIndex:anIndex]];
@@ -5038,10 +5033,8 @@
#pragma mark -
-@implementation FVDropHighlightView
+@implementation FVContentView
-@synthesize dropIndex=_dropIndex;
-@synthesize dropOperation=_dropOperation;
@synthesize delegate=_delegate;
- (BOOL)isFlipped {
@@ -5049,7 +5042,16 @@
}
- (void)drawRect:(NSRect)dirtyRect {
- [[self delegate] drawDropHighlightInView:self];
+ [[self delegate] drawRect:dirtyRect inView:self];
}
@end
+
+#pragma mark -
+
+@implementation FVDropHighlightView
+
+@synthesize dropIndex=_dropIndex;
+@synthesize dropOperation=_dropOperation;
+
+@end
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit