Revision: 25848 http://sourceforge.net/p/bibdesk/svn/25848 Author: hofman Date: 2021-05-03 17:10:00 +0000 (Mon, 03 May 2021) Log Message: ----------- Move preference icon view code to preference controller, it is built up from standard views
Modified Paths: -------------- trunk/bibdesk/BDSKPreferenceController.h trunk/bibdesk/BDSKPreferenceController.m Modified: trunk/bibdesk/BDSKPreferenceController.h =================================================================== --- trunk/bibdesk/BDSKPreferenceController.h 2021-05-03 16:44:38 UTC (rev 25847) +++ trunk/bibdesk/BDSKPreferenceController.h 2021-05-03 17:10:00 UTC (rev 25848) @@ -39,7 +39,6 @@ #import <Cocoa/Cocoa.h> #import "NSTouchBar_BDSKForwardDeclarations.h" -@class BDSKPreferenceIconView; @interface BDSKPreferenceController : NSWindowController <NSToolbarDelegate, NSWindowDelegate, NSTouchBarDelegate> { NSView *controlView; @@ -52,7 +51,8 @@ NSTextField *titleField; NSButton *tbRevertButton; NSButton *tbRevertAllButton; - BDSKPreferenceIconView *iconView; + NSView *iconView; + CALayer *spotlightLayer; NSMutableArray *categories; NSMutableDictionary *categoryDicts; NSMutableDictionary *records; @@ -61,6 +61,7 @@ NSMutableDictionary *toolbarItems; NSString *helpBookName; NSMutableDictionary *identifierSearchTerms; + NSMutableDictionary *iconButtons; } + (id)sharedPreferenceController; Modified: trunk/bibdesk/BDSKPreferenceController.m =================================================================== --- trunk/bibdesk/BDSKPreferenceController.m 2021-05-03 16:44:38 UTC (rev 25847) +++ trunk/bibdesk/BDSKPreferenceController.m 2021-05-03 17:10:00 UTC (rev 25848) @@ -39,9 +39,11 @@ #import "BDSKPreferenceController.h" #import "BDSKPreferenceRecord.h" #import "BDSKPreferencePane.h" -#import "BDSKPreferenceIconView.h" +#import "BDSKColoredView.h" #import <Sparkle/Sparkle.h> #import "NSAnimationContext_BDSKExtensions.h" +#import "NSColor_BDSKExtensions.h" +#import <Quartz/Quartz.h> #define BDSKPreferencesWindowFrameAutosaveName @"BDSKPreferencesWindow" @@ -67,6 +69,30 @@ } #endif +#define MINIMUM_ICON_WIDTH 0.0 +#define MINIMUM_ICON_HEIGHT 0.0 +#define MAXIMUM_ICON_WIDTH 100.0 +#define MAXIMUM_ICON_HEIGHT 200.0 +#define TOP_MARGIN 1.0 +#define BOTTOM_MARGIN 0.0 +#define TOP_CAPTION_MARGIN 4.0 +#define SIDE_CAPTION_MARGIN 12.0 +#define SIDE_ICON_MARGIN 16.0 +#define COLLAPSE_SIDE_ICON_MARGIN YES +#define ICON_SPACING 2.0 +#define COLLAPSE_ICON_SPACING YES +#define TOP_ICON_MARGIN 8.0 +#define BOTTOM_ICON_MARGIN 12.0 +#define DIVIDER_HEIGHT 1.0 +#define MASK_ALPHA 0.3 +#define MAXIMUM_BLUR 10 + +#if SDK_BEFORE(10_14) +@interface NSColor (BDSKMojaveDeclarations) ++ (NSColor *)separatorColor; +@end +#endif + @interface BDSKPreferenceController (BDSKPrivate) + (void)makeImages; - (void)iconViewShowPane:(id)sender; @@ -74,9 +100,9 @@ - (void)setupToolbar; - (void)loadPreferences; - (void)loadPanes; -- (BDSKPreferenceIconView *)iconView; +- (NSView *)iconView; +- (void)showSpotlightsForIdentifiers:(NSArray *)identifiers; - (void)changeContentView:(NSView *)view from:(NSView *)oldView display:(BOOL)display; -- (NSArray *)identifiersForSearchTerm:(NSString *)searchTerm; @end @@ -151,10 +177,6 @@ [[window contentView] setWantsLayer:YES]; - iconView = [[BDSKPreferenceIconView alloc] initWithPreferenceController:self]; - [iconView setAction:@selector(iconViewShowPane:)]; - [iconView setTarget:self]; - CGFloat width = [iconView fittingSize].width; for (BDSKPreferencePane *pane in [panes objectEnumerator]) width = fmax(width, [[pane view] fittingSize].width); @@ -162,7 +184,7 @@ frame.size.width = width; [window setFrame:frame display:NO]; - [self changeContentView:iconView from:nil display:NO]; + [self changeContentView:[self iconView] from:nil display:NO]; [self setSelectedPaneIdentifier:@""]; @@ -255,7 +277,7 @@ } - (void)iconViewShowPane:(id)sender { - [self selectPaneWithIdentifier:[sender clickedIdentifier]]; + [self selectPaneWithIdentifier:[[sender cell] representedObject]]; } - (IBAction)showNextPreviousPane:(id)sender { @@ -280,11 +302,16 @@ - (IBAction)search:(id)sender { NSString *searchTerm = [searchField stringValue]; if ([searchTerm length] > 0) { - [iconView showSpotlightsForIdentifiers:[self identifiersForSearchTerm:searchTerm]]; + NSMutableArray *identifiers = [NSMutableArray array]; + [identifierSearchTerms enumerateKeysAndObjectsUsingBlock:^(NSString *identifier, NSString *string, BOOL *stop){ + if ([string rangeOfString:searchTerm options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch].location != NSNotFound) + [identifiers addObject:identifier]; + }]; + [self showSpotlightsForIdentifiers:identifiers]; if ([[self selectedPaneIdentifier] isEqualToString:@""] == NO) [self selectPaneWithIdentifier:@""]; } else { - [iconView showSpotlightsForIdentifiers:nil]; + [self showSpotlightsForIdentifiers:nil]; } } @@ -473,6 +500,57 @@ return identifiers; } +#pragma mark Touch Bar + +- (NSTouchBar *)makeTouchBar { + NSTouchBar *touchBar = [[[NSClassFromString(@"NSTouchBar") alloc] init] autorelease]; + [touchBar setDelegate:self]; + [touchBar setDefaultItemIdentifiers:[NSArray arrayWithObjects:BDSKTouchBarItemIdentifierPreviousNext, BDSKTouchBarItemIdentifierShowAll, @"NSTouchBarItemIdentifierFixedSpaceSmall", BDSKTouchBarItemIdentifierReset, BDSKTouchBarItemIdentifierResetAll, nil]]; + return touchBar; +} + +- (NSTouchBarItem *)touchBar:(NSTouchBar *)aTouchBar makeItemForIdentifier:(NSString *)identifier { + NSTouchBarItem *item = nil; + if ([identifier isEqualToString:BDSKTouchBarItemIdentifierPreviousNext]) { + NSArray *images = [NSArray arrayWithObjects:[NSImage imageNamed:NSImageNameTouchBarGoBackTemplate], [NSImage imageNamed:NSImageNameTouchBarGoForwardTemplate], nil]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + NSSegmentedControl *button = [NSSegmentedControl segmentedControlWithImages:images trackingMode:NSSegmentSwitchTrackingMomentary target:self action:@selector(showNextPreviousPane:)]; + if (RUNNING_AFTER(10_9)) + [button setSegmentStyle:NSSegmentStyleSeparated]; +#pragma clang diagnostic pop + item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; + [(NSCustomTouchBarItem *)item setView:button]; + } else if ([identifier isEqualToString:BDSKTouchBarItemIdentifierShowAll]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + NSButton *button = [NSButton buttonWithImage:[NSImage imageNamed:@"NSTouchBarIconViewTemplate"] target:self action:@selector(showAll:)]; +#pragma clang diagnostic pop + item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; + [(NSCustomTouchBarItem *)item setView:button]; + } else if ([identifier isEqualToString:BDSKTouchBarItemIdentifierReset]) { + if (tbRevertButton == nil) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + tbRevertButton = [[NSButton buttonWithTitle:NSLocalizedString(@"Reset", @"Button title") target:self action:@selector(revertPaneDefaults:)] retain]; +#pragma clang diagnostic pop + [tbRevertButton setEnabled:[[[self selectedPane] initialValues] count] > 0]; + } + item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; + [(NSCustomTouchBarItem *)item setView:tbRevertButton]; + } else if ([identifier isEqualToString:BDSKTouchBarItemIdentifierResetAll]) { + if (tbRevertAllButton == nil) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + tbRevertAllButton = [[NSButton buttonWithTitle:NSLocalizedString(@"Reset All", @"Button title") target:self action:@selector(revertAllDefaults:)] retain]; +#pragma clang diagnostic pop + } + item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; + [(NSCustomTouchBarItem *)item setView:tbRevertAllButton]; + } + return item; +} + #pragma mark Private // we redraw the images for Files and Templates using the doc icon for the user system @@ -569,12 +647,6 @@ } } -- (BDSKPreferenceIconView *)iconView { - if (iconView == nil) - [self window]; - return iconView; -} - - (void)changeContentView:(NSView *)view from:(NSView *)oldView display:(BOOL)display { NSWindow *window = [self window]; NSView *contentView = [window contentView]; @@ -650,64 +722,189 @@ } } -#pragma mark Touch Bar +#pragma mark Icon View -- (NSArray *)identifiersForSearchTerm:(NSString *)searchTerm { - NSMutableArray *identifiers = [NSMutableArray array]; - [identifierSearchTerms enumerateKeysAndObjectsUsingBlock:^(NSString *identifier, NSString *string, BOOL *stop){ - if ([string rangeOfString:searchTerm options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch].location != NSNotFound) - [identifiers addObject:identifier]; - }]; - return identifiers; -} +// @@ Dark Mode -- (NSTouchBar *)makeTouchBar { - NSTouchBar *touchBar = [[[NSClassFromString(@"NSTouchBar") alloc] init] autorelease]; - [touchBar setDelegate:self]; - [touchBar setDefaultItemIdentifiers:[NSArray arrayWithObjects:BDSKTouchBarItemIdentifierPreviousNext, BDSKTouchBarItemIdentifierShowAll, @"NSTouchBarItemIdentifierFixedSpaceSmall", BDSKTouchBarItemIdentifierReset, BDSKTouchBarItemIdentifierResetAll, nil]]; - return touchBar; -} - -- (NSTouchBarItem *)touchBar:(NSTouchBar *)aTouchBar makeItemForIdentifier:(NSString *)identifier { - NSTouchBarItem *item = nil; - if ([identifier isEqualToString:BDSKTouchBarItemIdentifierPreviousNext]) { - NSArray *images = [NSArray arrayWithObjects:[NSImage imageNamed:NSImageNameTouchBarGoBackTemplate], [NSImage imageNamed:NSImageNameTouchBarGoForwardTemplate], nil]; +- (void)setupIconView { + iconButtons = [[NSMutableDictionary alloc] init]; + + iconView = [[NSView alloc] init]; + + NSButton *firstButton = nil; + BDSKColoredView *prevBgView = nil; + NSMutableArray *constraints = [NSMutableArray array]; + NSColor *backgroundColor = [NSColor colorWithCalibratedAquaWhite:0.0 alpha:0.03 darkAquaWhite:1.0 alpha:0.03]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpartial-availability" - NSSegmentedControl *button = [NSSegmentedControl segmentedControlWithImages:images trackingMode:NSSegmentSwitchTrackingMomentary target:self action:@selector(showNextPreviousPane:)]; - if (RUNNING_AFTER(10_9)) - [button setSegmentStyle:NSSegmentStyleSeparated]; + NSColor *dividerColor = [NSColor respondsToSelector:@selector(separatorColor)] ? [NSColor separatorColor] : [[NSColor controlTextColor] colorWithAlphaComponent:0.1]; #pragma clang diagnostic pop - item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; - [(NSCustomTouchBarItem *)item setView:button]; - } else if ([identifier isEqualToString:BDSKTouchBarItemIdentifierShowAll]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpartial-availability" - NSButton *button = [NSButton buttonWithImage:[NSImage imageNamed:@"NSTouchBarIconViewTemplate"] target:self action:@selector(showAll:)]; -#pragma clang diagnostic pop - item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; - [(NSCustomTouchBarItem *)item setView:button]; - } else if ([identifier isEqualToString:BDSKTouchBarItemIdentifierReset]) { - if (tbRevertButton == nil) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpartial-availability" - tbRevertButton = [[NSButton buttonWithTitle:NSLocalizedString(@"Reset", @"Button title") target:self action:@selector(revertPaneDefaults:)] retain]; -#pragma clang diagnostic pop - [tbRevertButton setEnabled:[[[self selectedPane] initialValues] count] > 0]; + BOOL drawsBackground = NO; + + for (NSString *category in [self categories]) { + BDSKColoredView *bgView = [[[BDSKColoredView alloc] init] autorelease]; + if (drawsBackground) + [bgView setBackgroundColor:backgroundColor]; + drawsBackground = NO == drawsBackground; + [bgView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [iconView addSubview:bgView]; + + NSMutableArray *constraints2 = [NSMutableArray array]; + + [constraints addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:iconView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]]; + [constraints addObject:[NSLayoutConstraint constraintWithItem:iconView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:bgView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]]; + + if (prevBgView) { + BDSKColoredView *dividerView = nil; + dividerView = [[[BDSKColoredView alloc] init] autorelease]; + [dividerView setBackgroundColor:dividerColor]; + [dividerView addConstraint:[NSLayoutConstraint constraintWithItem:dividerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:DIVIDER_HEIGHT]]; + [dividerView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [iconView addSubview:dividerView]; + + [constraints addObject:[NSLayoutConstraint constraintWithItem:dividerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:iconView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]]; + [constraints addObject:[NSLayoutConstraint constraintWithItem:iconView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:dividerView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]]; + [constraints addObject:[NSLayoutConstraint constraintWithItem:dividerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prevBgView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]]; + [constraints addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:dividerView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]]; + } else { + [constraints addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:iconView attribute:NSLayoutAttributeTop multiplier:1.0 constant:TOP_MARGIN]]; } - item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; - [(NSCustomTouchBarItem *)item setView:tbRevertButton]; - } else if ([identifier isEqualToString:BDSKTouchBarItemIdentifierResetAll]) { - if (tbRevertAllButton == nil) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpartial-availability" - tbRevertAllButton = [[NSButton buttonWithTitle:NSLocalizedString(@"Reset All", @"Button title") target:self action:@selector(revertAllDefaults:)] retain]; -#pragma clang diagnostic pop + + NSTextField *captionField = [[[NSTextField alloc] init] autorelease]; + [captionField setBordered:NO]; + [captionField setEditable:NO]; + [captionField setDrawsBackground:NO]; + [captionField setFont:[NSFont boldSystemFontOfSize:0.0]]; + [captionField setStringValue:[self localizedTitleForCategory:category] ?: @""]; + [captionField setTranslatesAutoresizingMaskIntoConstraints:NO]; + [bgView addSubview:captionField]; + + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:captionField attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:bgView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:SIDE_CAPTION_MARGIN]]; + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:captionField attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:SIDE_CAPTION_MARGIN]]; + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:captionField attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:bgView attribute:NSLayoutAttributeTop multiplier:1.0 constant:TOP_CAPTION_MARGIN]]; + + NSButton *prevButton = nil; + for (NSString *identifier in [self panesForCategory:category]) { + + NSButton *button = [[NSButton alloc] init]; + [button setImage:[self iconForIdentifier:identifier]]; + [button setTitle:[self localizedLabelForIdentifier:identifier]]; + [button setToolTip:[self localizedToolTipForIdentifier:identifier]]; + [button setFont:[NSFont labelFontOfSize:12.0]]; + [button setImagePosition:NSImageAbove]; + [button setBordered:NO]; + [button setButtonType:NSMomentaryChangeButton]; + [button setTarget:self]; + [button setAction:@selector(iconViewShowPane:)]; + [[button cell] setRepresentedObject:identifier]; + [iconButtons setObject:button forKey:identifier]; + [button setTranslatesAutoresizingMaskIntoConstraints:NO]; + [bgView addSubview:button]; + [button release]; + + if (firstButton) { + NSMutableArray *constraints3 = bgView == [firstButton superview] ? constraints2 : constraints; + [constraints3 addObject:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:firstButton attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]]; + [constraints3 addObject:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:firstButton attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]]; + } else { + firstButton = button; + } + if (prevButton) { + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:prevButton attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:ICON_SPACING]]; + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:prevButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]]; + } else { + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:bgView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:SIDE_ICON_MARGIN]]; + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:captionField attribute:NSLayoutAttributeBottom multiplier:1.0 constant:TOP_ICON_MARGIN]]; + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeBottom multiplier:1.0 constant:BOTTOM_ICON_MARGIN]]; + } + + prevButton = button; } - item = [[[NSClassFromString(@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier] autorelease]; - [(NSCustomTouchBarItem *)item setView:tbRevertAllButton]; + + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:prevButton attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:SIDE_ICON_MARGIN]]; + [constraints2 addObject:[NSLayoutConstraint constraintWithItem:bgView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:prevButton attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:SIDE_ICON_MARGIN]]; + [[constraints2 lastObject] setPriority:99.0]; + + [bgView addConstraints:constraints2]; + + prevBgView = bgView; } - return item; + [constraints addObject:[NSLayoutConstraint constraintWithItem:iconView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:prevBgView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:BOTTOM_MARGIN]]; + [iconView addConstraints:constraints]; + [iconView setTranslatesAutoresizingMaskIntoConstraints:NO]; } +- (NSView *)iconView { + if (iconView == nil) + [self setupIconView]; + return iconView; +} + +- (CGImageRef)createSpotlightImageForIdentifiers:(NSArray *)identifiers { + CGFloat blurPadding = MAXIMUM_BLUR * 2.0; + CGFloat scale = [iconView convertSizeToBacking:NSMakeSize(1.0, 1.0)].width; + CGAffineTransform t = CGAffineTransformTranslate(CGAffineTransformMakeScale(scale, scale), blurPadding, blurPadding); + CGRect bounds = NSRectToCGRect([iconView bounds]); + // we make the bounds larger so the blurred edges will fall outside the view + CGRect maskRect = CGRectInset(bounds, -blurPadding, -blurPadding); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGContextRef context = CGBitmapContextCreate(NULL, CGRectGetWidth(maskRect) * scale, CGRectGetHeight(maskRect) * scale, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast); + CGColorSpaceRelease(colorSpace); + CGColorRef color = CGColorCreateGenericRGB(0.0, 0.0, 0.0, MASK_ALPHA); + CGContextSetFillColorWithColor(context, color); + CGColorRelease(color); + + // we need to scale and shift because canvas of the image is at positive values in backing space + CGContextConcatCTM(context, t); + CGContextAddRect(context, maskRect); + for (NSString *identifier in identifiers) { + NSButton *button = [iconButtons objectForKey:identifier]; + NSRect rect = [iconView convertRect:[button bounds] fromView:button]; + CGFloat diameter = fmax(NSHeight(rect), NSWidth(rect)); + CGRect circleRect = CGRectMake(NSMidX(rect) - 0.5 * diameter, NSMidY(rect) - 0.5 * diameter, diameter, diameter); + CGContextAddEllipseInRect(context, circleRect); + } + CGContextEOFillPath(context); + + CGImageRef cgImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + + CIImage *ciImage = [CIImage imageWithCGImage:cgImage]; + CGImageRelease(cgImage); + // apply the blur filter to soften the edges of the circles + CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; + // sys prefs uses fuzzier circles for more matches; filter range 0 -- 100, values 0 -- 10 are reasonable? + [gaussianBlurFilter setValue:[NSNumber numberWithDouble:MIN([identifiers count], MAXIMUM_BLUR) * scale] forKey:kCIInputRadiusKey]; + // see NSCIImageRep.h for this and other useful methods that aren't documented + [gaussianBlurFilter setValue:ciImage forKey:kCIInputImageKey]; + ciImage = [gaussianBlurFilter valueForKey:kCIOutputImageKey]; + + return [[CIContext context] createCGImage:ciImage fromRect:CGRectApplyAffineTransform(bounds, t)]; +} + +- (void)showSpotlightsForIdentifiers:(NSArray *)identifiers { + if (identifiers == nil) { + + [spotlightLayer setContents:nil]; + + } else { + + if (spotlightLayer == nil) { + spotlightLayer = [[CALayer alloc] init]; + [spotlightLayer setFrame:[iconView bounds]]; + [spotlightLayer setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable]; + [spotlightLayer setZPosition:1.0]; + [iconView setWantsLayer:YES]; + [iconView displayIfNeeded]; + [[iconView layer] addSublayer:spotlightLayer]; + } + + CGImageRef image = [self createSpotlightImageForIdentifiers:identifiers]; + [spotlightLayer setContents:(id)image]; + CGImageRelease(image); + + } +} + @end 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