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

Reply via email to