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