Revision: 29171
          http://sourceforge.net/p/bibdesk/svn/29171
Author:   hofman
Date:     2025-04-23 09:34:04 +0000 (Wed, 23 Apr 2025)
Log Message:
-----------
Always use a separate view to draw the selection highlights. Needed to make the 
possible visual effect view invisible for mouse events.

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      2025-04-22 
15:49:17 UTC (rev 29170)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h      2025-04-23 
09:34:04 UTC (rev 29171)
@@ -194,7 +194,7 @@
 @end
 
 
-@class FVSliderWindow, FVOperationQueue, FVBackgroundView, FVArrowButton, 
FVDropHighlightView;
+@class FVSliderWindow, FVOperationQueue, FVBackgroundView, FVHighlightView, 
FVArrowButton, FVDropHighlightView;
 
 /**
  FVFileView is the primary class in the framework.  
@@ -223,7 +223,7 @@
     NSUInteger                      _lastClickedIndex;
     NSView                         *_contentView;
     NSView                         *_rubberBandView;
-    NSView                         *_highlightView;
+    FVHighlightView                *_highlightView;
     FVDropHighlightView            *_dropHighlightView;
     struct __fvFlags {
         unsigned int displayMode:2;

Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m      2025-04-22 
15:49:17 UTC (rev 29170)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m      2025-04-23 
09:34:04 UTC (rev 29171)
@@ -109,6 +109,12 @@
 #define NSEventModifierFlagOption NSAlternateKeyMask
 #endif
 
+typedef NS_ENUM(NSUInteger, FVHighlightStyle) {
+    FVHighlightStyleBordered,
+    FVHighlightStyleUnbordered,
+    FVHighlightStyleTranslucent
+};
+
 @interface _FVURLInfo : NSObject
 {
 @public;
@@ -147,6 +153,17 @@
 
 #pragma mark -
 
+@interface FVHighlightView : NSView {
+    NSArray *_highlightRects;
+    FVHighlightStyle _highlightStyle;
+    CGLayerRef _layer;
+}
+@property (nonatomic, copy) NSArray *highlightRects;
+@property (nonatomic) FVHighlightStyle highlightStyle;
+@end
+
+#pragma mark -
+
 @interface FVRubberBandView : NSView
 @end
 
@@ -244,6 +261,8 @@
 
 @property (nonatomic, copy) NSArray *iconURLs;
 
+@property (nonatomic, readonly) FVHighlightStyle highlightStyle;
+
 // only declare methods here to shut the compiler up if we can't rearrange
 - (FVIcon *)iconAtIndex:(NSUInteger)anIndex;
 - (FVIcon *)_cachedIconForURL:(NSURL *)aURL;
@@ -268,8 +287,8 @@
 - (void)handlePreviewerWillClose:(NSNotification *)aNote;
 - (void)_registerForKeyOrMainStateNotifications;
 - (void)_unregisterForKeyOrMainStateNotifications;
-- (void)_addHighlightView;
-- (void)_updateHighlightViewMask;
+- (void)_updateHighlightRects;
+- (void)_updateHighlightStyle;
 
 @end
 
@@ -342,6 +361,11 @@
 + (BOOL)accessInstanceVariablesDirectly { return NO; }
 
 - (void)_commonInit {
+    _highlightView = [[FVHighlightView alloc] initWithFrame:[self bounds]];
+    [_highlightView setHighlightStyle:floor(NSAppKitVersionNumber) > 
NSAppKitVersionNumber10_9 ? FVHighlightStyleUnbordered : 
FVHighlightStyleBordered];
+    [_highlightView setAutoresizingMask:NSViewWidthSizable | 
NSViewHeightSizable];
+    [self addSubview:_highlightView];
+    
     _contentView = [[FVDisplayView alloc] initWithFrame:[self bounds] 
delegate:self];
     [_contentView setAutoresizingMask:NSViewWidthSizable | 
NSViewHeightSizable];
     [self addSubview:_contentView];
@@ -497,16 +521,6 @@
 
 #pragma mark API
 
-static inline BOOL _allowsUnborderedHighlight(NSColor *color) {
-    if (color == nil)
-        return YES;
-    if ([[color colorSpaceName] isEqualToString:NSNamedColorSpace] == NO || 
[[color catalogNameComponent] isEqualToString:@"System"] == NO)
-        return NO;
-    if ([[color colorNameComponent] hasSuffix:@"BackgroundColor"] || [[color 
colorNameComponent] hasSuffix:@"RowColor"])
-        return floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_15 || 
[[color colorNameComponent] isEqualToString:@"underPageBackgroundColor"] == NO;
-    return NO;
-}
-
 - (void)setBackgroundColor:(NSColor *)aColor;
 {
     if (_backgroundColor != aColor) {
@@ -518,19 +532,7 @@
         }
         _backgroundColor = [aColor copy];
         [_backgroundView setBackgroundColor:_backgroundColor];
-        if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_9) {
-            _fvFlags.unborderedHighlight = 
_allowsUnborderedHighlight(_backgroundColor);
-            CGLayerRelease(_selectionOverlay);
-            _selectionOverlay = NULL;
-            if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_15) {
-                if (_backgroundColor == nil && _backgroundView) {
-                    [self _addHighlightView];
-                } else if (_highlightView) {
-                    [_highlightView removeFromSuperview];
-                    _highlightView = nil;
-                }
-            }
-        }
+        [self _updateHighlightStyle];
     }
 }
 
@@ -850,10 +852,7 @@
     if (indexSet != _selectionIndexes) {
         _selectionIndexes = [[NSIndexSet alloc] initWithIndexSet:indexSet];
         
-        if (_highlightView)
-            [self _updateHighlightViewMask];
-        else
-            [self setNeedsDisplay:YES];
+        [self _updateHighlightRects];
         
         
NSAccessibilityPostNotification(NSAccessibilityUnignoredAncestor(self), 
NSAccessibilityFocusedUIElementChangedNotification);
         
@@ -1114,10 +1113,7 @@
     if (_backgroundView) {
         [_backgroundView removeFromSuperview];
         _backgroundView = nil;
-        if (_highlightView) {
-            [_highlightView removeFromSuperview];
-            _highlightView = nil;
-        }
+        [self _updateHighlightStyle];
     }
     
     [[NSNotificationCenter defaultCenter] removeObserver:self 
name:NSViewFrameDidChangeNotification object:nil];
@@ -1143,15 +1139,8 @@
                 [_backgroundView setBackgroundColor:_backgroundColor];
                 [scrollView addSubview:_backgroundView 
positioned:NSWindowBelow relativeTo:nil];
                 [scrollView setDrawsBackground:NO];
-                if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_15) 
{
-                    if (_backgroundColor == nil) {
-                        [self _addHighlightView];
-                    } else if (_highlightView) {
-                        [_highlightView removeFromSuperview];
-                        _highlightView = nil;
-                    }
-                }
             }
+            [self _updateHighlightStyle];
         }
     }
 }
@@ -1493,7 +1482,7 @@
             }
         }
         
-        [self _updateHighlightViewMask];
+        [self _updateHighlightRects];
    }
     
 }
@@ -2034,40 +2023,47 @@
     }
 }
 
-#pragma mark Highlight view layout
+#pragma mark Highlight view updates
 
-- (void)_updateHighlightViewMask {
-    if (_highlightView) {
-        NSImage *image = nil;
-        NSRect bounds = [self bounds];
-        if (NSIsEmptyRect(bounds) == NO) {
-            image = [[NSImage alloc] initWithSize:bounds.size];
-            if ([_selectionIndexes count]) {
-                [image lockFocusFlipped:YES];
-                [[NSColor blackColor] setFill];
-                [_selectionIndexes enumerateIndexesUsingBlock:^(NSUInteger i, 
BOOL *stop){
-                    NSRect highlightRect = [self _rectOfIconAtIndex:i];
-                    if (NSIsEmptyRect(highlightRect) == NO) {
-                        highlightRect = NSInsetRect(highlightRect, 
HIGHLIGHT_INSET, HIGHLIGHT_INSET);
-                        [[NSBezierPath bezierPathWithRoundedRect:highlightRect 
xRadius:6.0 yRadius:6.0] fill];
-                    }
-                }];
-                [image unlockFocus];
+- (void)_updateHighlightRects {
+    NSMutableArray *highlightRects = nil;
+    
+    if ([_selectionIndexes count]) {
+        highlightRects = [NSMutableArray array];
+        [_selectionIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL 
*stop){
+            NSRect highlightRect = [self _rectOfIconAtIndex:i];
+            if (NSIsEmptyRect(highlightRect) == NO) {
+                highlightRect = NSInsetRect(highlightRect, HIGHLIGHT_INSET, 
HIGHLIGHT_INSET);
+                [highlightRects addObject:[NSValue 
valueWithRect:highlightRect]];
             }
-            [image setTemplate:YES];
-        }
-        [_highlightView setValue:image forKey:@"maskImage"];
+        }];
     }
+    
+    [_highlightView setHighlightRects:highlightRects];
 }
 
-- (void)_addHighlightView {
-    if (_highlightView == nil) {
-        _highlightView = [[NSClassFromString(@"NSVisualEffectView") alloc] 
initWithFrame:[self bounds]];
-        [_highlightView setValue:[NSNumber numberWithInteger:4] 
forKey:@"material"];
-        [_highlightView setAutoresizingMask:NSViewWidthSizable | 
NSViewHeightSizable];
-        [self _updateHighlightViewMask];
-        [self addSubview:_highlightView positioned:NSWindowBelow 
relativeTo:nil];
+- (void)_updateHighlightStyle {
+    // for generic colors we want a border so always either the fill or the 
stroke contrasts
+    FVHighlightStyle highlightStyle = FVHighlightStyleBordered;
+    
+    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_9) {
+        if (_backgroundColor == nil) {
+            // with a sidebar visual effect background we want a selection 
visual effect highlight
+            if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_15 && 
_backgroundView)
+                highlightStyle = FVHighlightStyleTranslucent;
+            else
+                highlightStyle = FVHighlightStyleUnbordered;
+        } else if ([[_backgroundColor colorSpaceName] 
isEqualToString:NSNamedColorSpace] && [[_backgroundColor catalogNameComponent] 
isEqualToString:@"System"]) {
+            // for system background colors we can use a highlight without 
border
+            // except on 10.5- underPageBackgroundColor is very dark (or light 
in dark mode)
+            NSString *colorName = [_backgroundColor colorNameComponent];
+            if (([colorName hasSuffix:@"BackgroundColor"] || [colorName 
hasSuffix:@"RowColor"]) &&
+                (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_15 || 
[colorName isEqualToString:@"underPageBackgroundColor"] == NO))
+                highlightStyle = FVHighlightStyleUnbordered;
+        }
     }
+    
+    [_highlightView setHighlightStyle:highlightStyle];
 }
 
 #pragma mark Cache thread
@@ -2237,52 +2233,6 @@
     }
 }
 
-- (void)_drawHighlightInRect:(NSRect)aRect 
inContext:(CGContextRef)drawingContext;
-{
-    // drawing into a CGImage and then overlaying it keeps the rubber band 
highlight much more responsive
-    if (NULL == _selectionOverlay) {
-        
-        _selectionOverlay = CGLayerCreateWithContext(drawingContext, 
CGSizeMake(NSWidth(aRect), NSHeight(aRect)), NULL);
-        CGContextRef layerContext = CGLayerGetContext(_selectionOverlay);
-        NSRect imageRect = NSZeroRect;
-        CGSize layerSize = CGLayerGetSize(_selectionOverlay);
-        imageRect.size.height = layerSize.height;
-        imageRect.size.width = layerSize.width;
-        CGContextClearRect(layerContext, NSRectToCGRect(imageRect));
-        
-        NSGraphicsContext *nsContext = [NSGraphicsContext 
graphicsContextWithGraphicsPort:layerContext flipped:YES];
-        [NSGraphicsContext saveGraphicsState];
-        [NSGraphicsContext setCurrentContext:nsContext];
-        [nsContext saveGraphicsState];
-        
-        // @@ Dark mode
-        if (_fvFlags.unborderedHighlight) {
-            // [NSAppearance currentAppearance] should alwaye be [self 
effectiveAppearance] here
-            NSColor *fillColor = [[NSColor textColor] 
colorWithAlphaComponent:32.0 / 255.0];
-            NSBezierPath *p = [NSBezierPath 
bezierPathWithRoundedRect:imageRect xRadius:6.0 yRadius:6.0];
-            [fillColor setFill];
-            [p fill];
-        } else {
-            NSColor *strokeColor = [NSColor colorWithCalibratedWhite:224.0 / 
255.0 alpha:124.0 / 255.0];
-            NSColor *fillColor = [NSColor colorWithCalibratedWhite:0.0 
alpha:32.0 / 255.0];
-            [strokeColor setStroke];
-            [fillColor setFill];
-            imageRect = NSInsetRect(imageRect, 1.0, 1.0);
-            NSBezierPath *p = [NSBezierPath 
bezierPathWithRoundedRect:imageRect xRadius:5.0 yRadius:5.0];
-            [p setLineWidth:2.0];
-            [p stroke];
-            imageRect = NSInsetRect(imageRect, 1.0, 1.0);
-            p = [NSBezierPath bezierPathWithRoundedRect:imageRect xRadius:4.0 
yRadius:4.0];
-            [p fill];
-            [p setLineWidth:1.0];
-        }
-        
-        [NSGraphicsContext restoreGraphicsState];
-    }
-    
-    CGContextDrawLayerInRect(drawingContext, NSRectToCGRect(aRect), 
_selectionOverlay);
-}
-
 #define DROP_MESSAGE_MIN_FONTSIZE ((CGFloat) 8.0)
 #define DROP_MESSAGE_MAX_INSET    ((CGFloat) 20.0)
 
@@ -2705,24 +2655,6 @@
         FVFillBackgroundColorOrGradient(_backgroundColor, rect, [self 
visibleRect], [self window]);
     }
     
-    if ([_selectionIndexes count] > 0 && _highlightView == nil) {
-        CGContextRef context = [[NSGraphicsContext currentContext] 
graphicsPort];
-        
-        CGContextSaveGState(context);
-        CGContextSetBlendMode(context, kCGBlendModeNormal);
-        
-        [_selectionIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL 
*stop){
-            NSRect highlightRect = [self _rectOfIconAtIndex:i];
-            if (NSIsEmptyRect(highlightRect) == NO) {
-                highlightRect = NSInsetRect(highlightRect, HIGHLIGHT_INSET, 
HIGHLIGHT_INSET);
-                if ([self needsToDrawRect:highlightRect])
-                    [self _drawHighlightInRect:highlightRect 
inContext:context];
-            }
-        }];
-        
-        CGContextRestoreGState(context);
-    }
-    
 #if DEBUG_GRID
     [[NSColor grayColor] set];
     NSRect r = NSInsetRect([self bounds], [self _leftMargin], [self 
_topMargin]);
@@ -5191,6 +5123,150 @@
     }
 }
 
+#pragma mark -
+
+@implementation FVHighlightView
+
+@synthesize highlightRects=_highlightRects;
+@synthesize highlightStyle=_highlightStyle;
+
+- (BOOL)isFlipped { return YES; }
+
+- (NSView *)hitTest:(NSPoint)point { return nil; }
+
+- (void)viewDidChangeEffectiveAppearance {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpartial-availability"
+    [super viewDidChangeEffectiveAppearance];
+#pragma clang diagnostic pop
+    CGLayerRelease(_layer);
+    _layer = NULL;
+}
+
+- (void)_updateMaskImage {
+    if ([[self subviews] count]) {
+        NSImage *image = nil;
+        NSRect bounds = [self bounds];
+        if (NSIsEmptyRect(bounds) == NO) {
+            image = [[NSImage alloc] initWithSize:bounds.size];
+            if ([_highlightRects count]) {
+                [image lockFocusFlipped:YES];
+                [[NSColor blackColor] setFill];
+                for (NSValue *value in _highlightRects) {
+                    NSRect highlightRect = [value rectValue];
+                    [[NSBezierPath bezierPathWithRoundedRect:highlightRect 
xRadius:6.0 yRadius:6.0] fill];
+                }
+                [image unlockFocus];
+            }
+            [image setTemplate:YES];
+        }
+        [[[self subviews] objectAtIndex:0] setValue:image forKey:@"maskImage"];
+    }
+}
+
+- (void)setHighlightRects:(NSArray *)array
+{
+    if (array != _highlightRects) {
+        _highlightRects = [array copy];
+        if (_highlightStyle == FVHighlightStyleTranslucent)
+            [self _updateMaskImage];
+        else
+            [self setNeedsDisplay:YES];
+    }
+}
+
+- (void)setHighlightStyle:(FVHighlightStyle)style
+{
+    if (style != _highlightStyle) {
+        _highlightStyle = style;
+        
+        CGLayerRelease(_layer);
+        _layer = NULL;
+        
+        if (_highlightStyle == FVHighlightStyleTranslucent) {
+            if ([[self subviews] count] == 0) {
+                NSView *view = [[NSClassFromString(@"NSVisualEffectView") 
alloc] initWithFrame:[self bounds]];
+                [view setValue:[NSNumber numberWithInteger:4] 
forKey:@"material"];
+                [view setAutoresizingMask:NSViewWidthSizable | 
NSViewHeightSizable];
+                [self addSubview:view];
+                [self _updateMaskImage];
+            }
+        } else if ([[self subviews] count]) {
+            [[[self subviews] objectAtIndex:0] removeFromSuperview];
+        }
+    }
+}
+
+- (void)_drawHighlightInRect:(NSRect)aRect 
inContext:(CGContextRef)drawingContext;
+{
+    if (NULL == _layer) {
+        
+        _layer = CGLayerCreateWithContext(drawingContext, 
CGSizeMake(NSWidth(aRect), NSHeight(aRect)), NULL);
+        CGContextRef layerContext = CGLayerGetContext(_layer);
+        NSRect imageRect = NSZeroRect;
+        CGSize layerSize = CGLayerGetSize(_layer);
+        imageRect.size.height = layerSize.height;
+        imageRect.size.width = layerSize.width;
+        CGContextClearRect(layerContext, NSRectToCGRect(imageRect));
+        
+        NSGraphicsContext *nsContext = [NSGraphicsContext 
graphicsContextWithGraphicsPort:layerContext flipped:YES];
+        [NSGraphicsContext saveGraphicsState];
+        [NSGraphicsContext setCurrentContext:nsContext];
+        [nsContext saveGraphicsState];
+        
+        // @@ Dark mode
+        if (_highlightStyle == FVHighlightStyleUnbordered) {
+            // [NSAppearance currentAppearance] should alwaye be [self 
effectiveAppearance] here
+            NSColor *fillColor = [[NSColor textColor] 
colorWithAlphaComponent:32.0 / 255.0];
+            NSBezierPath *p = [NSBezierPath 
bezierPathWithRoundedRect:imageRect xRadius:6.0 yRadius:6.0];
+            [fillColor setFill];
+            [p fill];
+        } else if (_highlightStyle == FVHighlightStyleBordered) {
+            NSColor *strokeColor = [NSColor colorWithCalibratedWhite:224.0 / 
255.0 alpha:124.0 / 255.0];
+            NSColor *fillColor = [NSColor colorWithCalibratedWhite:0.0 
alpha:32.0 / 255.0];
+            [strokeColor setStroke];
+            [fillColor setFill];
+            imageRect = NSInsetRect(imageRect, 1.0, 1.0);
+            NSBezierPath *p = [NSBezierPath 
bezierPathWithRoundedRect:imageRect xRadius:5.0 yRadius:5.0];
+            [p setLineWidth:2.0];
+            [p stroke];
+            imageRect = NSInsetRect(imageRect, 1.0, 1.0);
+            p = [NSBezierPath bezierPathWithRoundedRect:imageRect xRadius:4.0 
yRadius:4.0];
+            [p fill];
+            [p setLineWidth:1.0];
+        }
+        
+        [NSGraphicsContext restoreGraphicsState];
+    }
+    
+    CGContextDrawLayerInRect(drawingContext, NSRectToCGRect(aRect), _layer);
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+    if ([_highlightRects count] && _highlightStyle != 
FVHighlightStyleTranslucent) {
+        if (_layer && NSEqualSizes(NSSizeFromCGSize(CGLayerGetSize(_layer)), 
[[_highlightRects objectAtIndex:0] rectValue].size) == NO) {
+            CGLayerRelease(_layer);
+            _layer = NULL;
+        }
+        
+        CGContextRef context = [[NSGraphicsContext currentContext] 
graphicsPort];
+        
+        CGContextSaveGState(context);
+        CGContextSetBlendMode(context, kCGBlendModeNormal);
+        
+        for (NSValue *value in _highlightRects) {
+            NSRect highlightRect = [value rectValue];
+            if ([self needsToDrawRect:highlightRect])
+                [self _drawHighlightInRect:highlightRect inContext:context];
+        }
+        
+        CGContextRestoreGState(context);
+    }
+}
+
+@end
+
 #pragma mark
 
 @implementation FVRubberBandView

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Bibdesk-commit mailing list
Bibdesk-commit@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit

Reply via email to