diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-09-04 11:11:37 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-09-04 11:11:37 +0200 |
| commit | bb5daa2e90623691a5259700b9d388d2d21f46d3 (patch) | |
| tree | f5629e81bedc6cdd35ee9a79628997c5e14ffa7c /Liquid Glass Bezel/BBObjectCell.m | |
| parent | 3dfeb86c5c3b72acc59919c7a198fcf76a54c35c (diff) | |
Rename to Liquid Glass Bezel, add preferences
Diffstat (limited to 'Liquid Glass Bezel/BBObjectCell.m')
| -rw-r--r-- | Liquid Glass Bezel/BBObjectCell.m | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/Liquid Glass Bezel/BBObjectCell.m b/Liquid Glass Bezel/BBObjectCell.m new file mode 100644 index 0000000..7bf1b3c --- /dev/null +++ b/Liquid Glass Bezel/BBObjectCell.m @@ -0,0 +1,211 @@ +#import "BBObjectCell.h" + +@implementation BBObjectCell + +- (NSCellImagePosition)preferredImagePosition { + return NSImageAbove; +} + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { + BOOL isFirstResponder = [[controlView window] firstResponder] == controlView && ![controlView isKindOfClass:[NSTableView class]]; + BOOL dropTarget = ([self isHighlighted] && ([self highlightsBy] & NSChangeBackgroundCellMask) && ![self isBezeled]); + + NSColor *fillColor; + NSColor *strokeColor = [NSColor clearColor]; + + if (isFirstResponder) { + fillColor = [NSColor selectedTextBackgroundColor]; + } else { + fillColor = [NSColor clearColor]; + } + + if (dropTarget) { + fillColor = [NSColor controlAccentColor]; + } + + [fillColor setFill]; + [strokeColor setStroke]; + + NSBezierPath *roundRect = [NSBezierPath bezierPath]; + [roundRect appendBezierPathWithRoundedRectangle:cellFrame withRadius:NSHeight(cellFrame)/cellRadiusFactor]; + [roundRect fill]; + + [self drawInteriorWithFrame:[self drawingRectForBounds:cellFrame] inView:controlView]; +} + +- (NSRect)titleRectForBounds:(NSRect)theRect +{ + NSRect rect = theRect; + rect = NSOffsetRect(rect, 0, -4); + return [super titleRectForBounds: rect]; +} + +- (void)drawTextForObject:(QSObject *)drawObject withFrame:(NSRect)cellFrame inView:(NSView *)controlView { + if ([self imagePosition] == NSImageOnly) return; + + NSString *abbrString = nil; + if ([controlView respondsToSelector:@selector(matchedString)]) + abbrString = [(QSSearchObjectView *)controlView matchedString]; + + NSString *nameString = nil; + NSIndexSet *hitMask = nil; + + id ranker = [drawObject ranker]; + if (ranker && abbrString) + nameString = [ranker matchedStringForAbbreviation:abbrString hitmask:&hitMask inContext:nil]; + + if (!nameString) + nameString = [drawObject displayName]; + + BOOL rankedStringIsName = [nameString isEqualToString:[drawObject displayName]] || nameString == nil; + if (!nameString) { + // fall back to the identifier if no reasonable name can be found + nameString = [drawObject identifier]; + } + if (!nameString) { + // Couldn't find anything sensible to use for the name, fallback to avoid a crash + nameString = @"Unknown"; + } + + BOOL useAlternateColor = [controlView isKindOfClass:[NSTableView class]] && [(NSTableView *)controlView isRowSelected:[(NSTableView *)controlView rowAtPoint:cellFrame.origin]]; + NSColor *mainColor = (textColor ? textColor : (useAlternateColor ? [NSColor alternateSelectedControlTextColor] : [NSColor controlTextColor])); + NSColor *fadedColor = [mainColor colorWithAlphaComponent:0.50]; + NSRect textDrawRect = [self titleRectForBounds:cellFrame]; + + NSMutableAttributedString *titleString = [[[NSMutableAttributedString alloc] initWithString:nameString] autorelease]; + [titleString setAttributes:rankedStringIsName ? nameAttributes : detailsAttributes range:NSMakeRange(0, [titleString length])]; + + // Bring out the matched letters + if (abbrString && ![abbrString hasPrefix:@"QSActionMnemonic"]) { + [titleString addAttribute:NSForegroundColorAttributeName value:rankedStringIsName ? fadedColor : [fadedColor colorWithAlphaComponent:0.8] range:NSMakeRange(0, [titleString length])]; + + NSUInteger i = 0; + NSUInteger j = 0; + NSUInteger hits[[titleString length]]; + NSUInteger count = [hitMask getIndexes:(NSUInteger *)&hits maxCount:[titleString length] inIndexRange:nil]; + NSDictionary *attributes = @{ + NSForegroundColorAttributeName: rankedStringIsName ? mainColor : fadedColor + }; + for(i = 0; i<count; i += j) { + for (j = 1; i+j<count && hits[i+j-1] +1 == hits[i+j]; j++); + [titleString addAttributes:attributes range:NSMakeRange(hits[i], j)]; + } + } else { + [titleString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithDouble:-1.0] range:NSMakeRange(0, [titleString length])]; + } +// +// // Ranked string and nameString aren't the same. Show 'nameString ⟷ rankedString' in the UI +// if (!rankedStringIsName && [drawObject displayName].length) { +// [titleString addAttribute:NSFontAttributeName value:detailsFont range:NSMakeRange(0,[titleString length])]; +// NSMutableAttributedString *attributedNameString = [[NSMutableAttributedString alloc] initWithString:[drawObject displayName]]; +// [attributedNameString setAttributes:nameAttributes range:NSMakeRange(0, [[drawObject displayName] length])]; +// +// [attributedNameString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" ⟷ " attributes:rankedNameAttributes] autorelease]]; +// // the replaceCharacters... method inserts the new string into the receiver at the start of the work (range.location and range.length are 0) +// [titleString replaceCharactersInRange:NSMakeRange(0,0) withAttributedString:attributedNameString]; +// [attributedNameString release]; +// } + + if (showDetails) { + NSString *detailsString = [drawObject details]; + + NSRange returnRange = [detailsString rangeOfString:@"\n"]; + if (returnRange.location != NSNotFound) { + detailsString = [detailsString substringToIndex:returnRange.location]; + } + + detailsAttributes = [detailsAttributes mutableCopy]; + [detailsAttributes setValue:[NSColor grayColor] forKey:NSForegroundColorAttributeName]; + + if (detailsString && detailsString.length && ![detailsString isEqualToString:nameString]) { + [titleString appendAttributedString:[[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"\n%@",detailsString] attributes:detailsAttributes] autorelease]]; + } + } + + NSRect centerRect = rectFromSize([titleString size]); + centerRect.size.width = NSWidth(textDrawRect); + centerRect.size.height = MIN(NSHeight(textDrawRect), centerRect.size.height); + [titleString drawInRect:centerRectInRect(centerRect, textDrawRect)]; +} + +- (void)drawSearchPlaceholderWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { + NSString *defaultText = NSLocalizedStringWithDefaultValue(@"Type to search", nil, [NSBundle mainBundle], @"Type to search", @"Hint that appears in the first pane of the QS interface when it's empty."); + NSSize textSize = [defaultText sizeWithAttributes:nameAttributes]; + NSRect textRect = centerRectInRect(rectFromSize(textSize), cellFrame); + BOOL isFirstResponder = [[controlView window] firstResponder] == controlView && ![controlView isKindOfClass:[NSTableView class]]; + + if (isFirstResponder && [controlView isKindOfClass:[QSSearchObjectView class]]) { + NSImage *find = [NSImage imageWithSystemSymbolName:@"magnifyingglass.circle.fill" accessibilityDescription:nil]; + + + [find setSize:QSSize16]; + NSRect findImageRect = expelRectFromRectOnEdge(centerRectInRect(rectFromSize([find size]), cellFrame), textRect, NSRectEdgeMinX, -2); + + + NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; + [graphicsContext saveGraphicsState]; + CGContextRef context = [graphicsContext CGContext]; + CGContextBeginTransparencyLayerWithRect(context, findImageRect, nil); + CGContextSetBlendMode(context, kCGBlendModeNormal); + [find drawInRect:findImageRect fromRect:rectFromSize([find size]) operation:NSCompositingOperationSourceOver fraction:1]; + CGContextSetBlendMode(context, kCGBlendModeSourceIn); + CGContextSetFillColorWithColor(context, [[NSColor textColor] CGColor]); + CGContextFillRect(context, findImageRect); + CGContextEndTransparencyLayer(context); + + [defaultText drawInRect:textRect withAttributes:nameAttributes]; + } +} + +- (void)drawIconForObject:(QSObject *)object withFrame:(NSRect)cellFrame inView:(NSView *)controlView { + NSImage *image = [object icon]; + NSString *iconName = nil; + NSImageSymbolConfiguration *iconConfig = nil; + if ([[image name] isEqualToString: @"defaultAction"]) { + iconName = @"gearshape.circle"; + } + else if ([[image name] isEqualToString: @"Find"]) { + iconName = @"magnifyingglass"; + } + else if ([[image name] isEqualToString: @"Object"]) { + iconName = @"cube.transparent"; + iconConfig = [NSImageSymbolConfiguration configurationWithHierarchicalColor:[NSColor controlAccentColor]]; + } + else if ([[image name] isEqualToString: @"ContactAddress"]) { + iconName = @"mappin.circle"; + } + else if ([[image name] isEqualToString: @"ContactEmail"]) { + iconName = @"envelope.circle"; + } + else if ([[image name] isEqualToString: @"ContactPhone"]) { + iconName = @"phone.circle"; + } + else if ([[image name] isEqualToString: @"DefaultBookmarkIcon"]) { + iconName = @"link.circle"; + } + else if ([[image name] isEqualToString: @"Catalog"]) { + iconName = @"sparkles.rectangle.stack"; + } + else if ([[image name] isEqualToString: @"Triggers"]) { + iconName = @"bolt.fill"; + } + + + if (iconName != nil) { + NSImage *newIcon = [NSImage imageWithSystemSymbolName:iconName accessibilityDescription:[image name]]; + + if (iconConfig == nil) { + NSArray *colors = [NSArray arrayWithObjects:[NSColor textColor], [NSColor controlAccentColor], nil]; + iconConfig = [NSImageSymbolConfiguration configurationWithPaletteColors:colors]; + } + + QSObject *newObject = [QSObject objectWithName:[object name]]; + [newObject setIcon:[newIcon imageWithSymbolConfiguration:iconConfig]]; + [newObject setIconLoaded:[object iconLoaded]]; + return [super drawIconForObject: newObject withFrame:cellFrame inView:controlView]; + } + + [super drawIconForObject: object withFrame:cellFrame inView:controlView]; +} + +@end |