Revision: 15024 http://sourceforge.net/p/skim-app/code/15024 Author: hofman Date: 2025-03-26 16:44:37 +0000 (Wed, 26 Mar 2025) Log Message: ----------- Use segmented control and auto layout fo background of color swatch control. Its alignment rect should always be the bezel rect.
Modified Paths: -------------- trunk/SKColorSwatch.h trunk/SKColorSwatch.m Modified: trunk/SKColorSwatch.h =================================================================== --- trunk/SKColorSwatch.h 2025-03-25 22:56:08 UTC (rev 15023) +++ trunk/SKColorSwatch.h 2025-03-26 16:44:37 UTC (rev 15024) @@ -42,12 +42,12 @@ extern NSString *SKColorSwatchColorsChangedNotification; -@class SKColorSwatchBackgroundView, SKColorSwatchItemView; +@class SKColorSwatchItemView; @interface SKColorSwatch : NSControl <NSDraggingSource, NSAccessibilityGroup> { NSMutableArray<NSColor *> *colors; NSMutableArray<SKColorSwatchItemView *> *itemViews; - SKColorSwatchBackgroundView *backgroundView; + NSControl *backgroundView; CGFloat bezelHeight; NSInteger clickedIndex; Modified: trunk/SKColorSwatch.m =================================================================== --- trunk/SKColorSwatch.m 2025-03-25 22:56:08 UTC (rev 15023) +++ trunk/SKColorSwatch.m 2025-03-26 16:44:37 UTC (rev 15024) @@ -64,12 +64,7 @@ #define BEZEL_INSET_BOTTOM 2.0 #define COLOR_INSET 2.0 -#define LARGE_SIZE_HEIGHT_OUTSET 4.5 -#define LARGE_SIZE_WIDTH_OUTSET 5.0 - -#define SKControlSizeLarge 3 - -static inline CGFloat swatchRadius(NSControlSize controlSize) { +static inline CGFloat cornerRadius(NSControlSize controlSize) { if (@available(macOS 11.0, *)) { switch (controlSize) { case NSControlSizeRegular: return 3.0; @@ -76,30 +71,13 @@ case NSControlSizeSmall: return 2.0; case NSControlSizeMini: return 1.0; case NSControlSizeLarge: return 4.0; - default: return 3.0; } } else { - switch (controlSize) { - case NSControlSizeRegular: return 2.0; - case NSControlSizeSmall: return 1.0; - case NSControlSizeMini: return 0.5; - default: return 2.0; - } + return controlSize == NSControlSizeRegular ? 2.0 : 1.0; } } -static inline CGFloat bezelWidthOffset(NSControlSize controlSize) { - switch (controlSize) { - case NSControlSizeRegular: return 4.0; - case NSControlSizeSmall: return 0.0; - case NSControlSizeMini: return 0.0; - case SKControlSizeLarge: return 2.0; - default: return 4.0; - } -} - -@interface SKColorSwatchBackgroundView : NSControl -@property (nonatomic) CGFloat bezelWidth; +@interface SKColorSwatchBackgroundView : NSSegmentedControl @end typedef NS_ENUM(NSUInteger, SKColorSwatchDropLocation) { @@ -169,11 +147,16 @@ [self commonInit]; - SKColorSwatchBackgroundView *view = [[SKColorSwatchBackgroundView alloc] initWithFrame:[self bounds]]; - [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [view setBezelWidth:[self intrinsicContentSize].width]; - [self addSubview:view]; - backgroundView = view; + backgroundView = [[SKColorSwatchBackgroundView alloc] initWithFrame:[self bounds]]; + [backgroundView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [self addSubview:backgroundView]; + NSArray *constraints = @[ + [[backgroundView leadingAnchor] constraintEqualToAnchor:[self leadingAnchor]], + [[self trailingAnchor] constraintEqualToAnchor:[backgroundView trailingAnchor]], + [[backgroundView topAnchor] constraintEqualToAnchor:[self topAnchor]], + [[self bottomAnchor] constraintEqualToAnchor:[backgroundView bottomAnchor]]]; + [constraints setValue:@YES forKey:@"shouldBeArchived"]; + [NSLayoutConstraint activateConstraints:constraints]; SKColorSwatchItemView *itemView = [[SKColorSwatchItemView alloc] initWithFrame:[self frameForItemViewAtIndex:0 collapsedIndex:-1]]; [itemView setColor:[NSColor whiteColor]]; @@ -291,20 +274,17 @@ return NSEdgeInsetsMake(BEZEL_INSET_TOP, BEZEL_INSET_LEFT, BEZEL_INSET_BOTTOM, BEZEL_INSET_RIGHT); } -- (void)updateSubviewLayout { +- (void)updateItemViewFrames { NSUInteger i, iMax = [itemViews count]; for (i = 0; i < iMax; i++) [[itemViews objectAtIndex:i] setFrame:[self frameForItemViewAtIndex:i collapsedIndex:-1]]; - [backgroundView setBezelWidth:[self intrinsicContentSize].width]; } - (void)updateBezelHeight { - CGFloat height = [[backgroundView cell] cellSize].height - BEZEL_INSET_TOP - BEZEL_INSET_BOTTOM; - if ([backgroundView controlSize] == SKControlSizeLarge) - height -= 2.0 * LARGE_SIZE_HEIGHT_OUTSET; + CGFloat height = [backgroundView intrinsicContentSize].height; if (fabs(height - bezelHeight) > 0.0) { bezelHeight = height; - [self updateSubviewLayout]; + [self updateItemViewFrames]; [self invalidateIntrinsicContentSize]; if (autoResizes) [self sizeToFit]; @@ -312,15 +292,9 @@ } - (void)setControlSize:(NSControlSize)controlSize { - if (controlSize != [self controlSize]) { - [super setControlSize:controlSize]; + [super setControlSize:controlSize]; + if (controlSize != [backgroundView controlSize]) { [backgroundView setControlSize:controlSize]; - NSRect bgFrame = [self bounds]; - if (controlSize == SKControlSizeLarge) { - bgFrame = NSInsetRect(bgFrame, -LARGE_SIZE_WIDTH_OUTSET, -LARGE_SIZE_HEIGHT_OUTSET); - bgFrame.origin.y = ceil(bgFrame.origin.y); - } - [backgroundView setFrame:bgFrame]; [self updateBezelHeight]; } } @@ -336,7 +310,7 @@ - (void)drawFocusRingMask { NSRect rect = [self focusRingMaskBounds]; if (NSIsEmptyRect(rect) == NO) { - CGFloat r = swatchRadius([self controlSize]); + CGFloat r = cornerRadius([self controlSize]); [[NSBezierPath bezierPathWithRoundedRect:rect xRadius:r yRadius:r] fill]; } } @@ -357,19 +331,20 @@ - (void)handleKeyOrMainStateChanged:(NSNotification *)note { if ([[note name] isEqualToString:NSWindowDidResignMainNotification]) [self deactivate]; - [[self subviews] setValue:[NSNumber numberWithInt:YES] forKey:@"needsDisplay"]; + [[self subviews] setValue:@YES forKey:@"needsDisplay"]; } - (void)viewWillMoveToWindow:(NSWindow *)newWindow { NSWindow *oldWindow = [self window]; NSArray *names = @[NSWindowDidBecomeMainNotification, NSWindowDidResignMainNotification, NSWindowDidBecomeKeyNotification, NSWindowDidResignKeyNotification]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; if (oldWindow) { for (NSString *name in names) - [[NSNotificationCenter defaultCenter] removeObserver:self name:name object:oldWindow]; + [nc removeObserver:self name:name object:oldWindow]; } if (newWindow) { for (NSString *name in names) - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyOrMainStateChanged:) name:name object:newWindow]; + [nc addObserver:self selector:@selector(handleKeyOrMainStateChanged:) name:name object:newWindow]; } [self deactivate]; [super viewWillMoveToWindow:newWindow]; @@ -405,7 +380,7 @@ NSColor *color = [colors objectAtIndex:i]; - CGFloat r = swatchRadius(NSControlSizeRegular) - 0.5; + CGFloat r = cornerRadius(NSControlSizeRegular) - 0.5; NSImage *image = [NSImage bitmapImageWithSize:NSMakeSize(12.0, 12.0) forView:self drawingHandler:^(NSRect rect){ [color drawSwatchInRect:NSInsetRect(rect, 1.0, 1.0)]; @@ -518,7 +493,7 @@ [[itemViews objectAtIndex:iMax] removeFromSuperview]; [itemViews removeObjectAtIndex:iMax]; } - [self updateSubviewLayout]; + [self updateItemViewFrames]; [self invalidateIntrinsicContentSize]; [[NSNotificationCenter defaultCenter] postNotificationName:SKColorSwatchColorsChangedNotification object:self]; } @@ -630,11 +605,8 @@ NSUInteger i = 0; for (SKColorSwatchItemView *itemView in itemViews) [[itemView animator] setFrame:[self frameForItemViewAtIndex:i++ collapsedIndex:collapsedIndex]]; - if (NSEqualSizes(size, NSZeroSize) == NO) { - [[backgroundView animator] setBezelWidth:size.width - BEZEL_INSET_LEFT - BEZEL_INSET_RIGHT]; - if (autoResizes) - [[self animator] setFrameSize:size]; - } + if (NSEqualSizes(size, NSZeroSize) == NO && autoResizes) + [[self animator] setFrameSize:size]; } - (void)insertColor:(NSColor *)color atIndex:(NSInteger)i { @@ -888,25 +860,17 @@ @implementation SKColorSwatchBackgroundView -@dynamic bezelWidth; - -+ (id)defaultAnimationForKey:(NSString *)key { - if ([key isEqualToString:@"bezelWidth"]) { - CABasicAnimation *anim = [CABasicAnimation animation]; - [anim setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]]; - return anim; - } else - return [super defaultAnimationForKey:key]; -} - - (instancetype)initWithFrame:(NSRect)frameRect { self = [super initWithFrame:frameRect]; if (self) { - NSSegmentedCell *cell = [[NSSegmentedCell alloc] init]; - [cell setSegmentCount:1]; - [cell setSegmentStyle:NSSegmentStyleTexturedSquare]; - [cell setWidth:fmax(0.0, NSWidth(frameRect) - bezelWidthOffset(NSControlSizeRegular) - BEZEL_INSET_LEFT - BEZEL_INSET_RIGHT) forSegment:0]; - [self setCell:cell]; + [self setSegmentCount:1]; + [self setWidth:0.0 forSegment:0]; + [self setSegmentDistribution:NSSegmentDistributionFill]; + [self setSegmentStyle:NSSegmentStyleTexturedSquare]; + [self setContentHuggingPriority:1 forOrientation:NSLayoutConstraintOrientationHorizontal]; + [self setContentHuggingPriority:1 forOrientation:NSLayoutConstraintOrientationVertical]; + [self setContentCompressionResistancePriority:1 forOrientation:NSLayoutConstraintOrientationHorizontal]; + [self setContentCompressionResistancePriority:1 forOrientation:NSLayoutConstraintOrientationVertical]; } return self; } @@ -913,23 +877,20 @@ - (BOOL)canBecomeKeyView { return NO; } -- (CGFloat)bezelWidth { - return [[self cell] widthForSegment:0] + bezelWidthOffset([self controlSize]); +- (void)mouseDown:(NSEvent *)event { + [[self superview] mouseDown:event]; } -- (void)setBezelWidth:(CGFloat)width { - [[self cell] setWidth:width - bezelWidthOffset([self controlSize]) forSegment:0]; - [self setNeedsDisplay:YES]; +- (void)rightMouseDown:(NSEvent *)event { + [[self superview] rightMouseDown:event]; } -- (void)mouseDown:(NSEvent *)event { - [[self superview] mouseDown:event]; -} - - (void)keyDown:(NSEvent *)event { [[self superview] keyDown:event]; } +- (void)performClick:(id)sender {} + - (BOOL)isAccessibilityElement { return NO; } @@ -992,7 +953,7 @@ if (NSWidth(rect) < 5.0) return; rect = NSInsetRect(rect, COLOR_INSET, COLOR_INSET); - CGFloat r = swatchRadius([(SKColorSwatch *)[self superview] controlSize]); + CGFloat r = cornerRadius([(SKColorSwatch *)[self superview] controlSize]); BOOL disabled = NO; if (@available(macOS 10.14, *)) disabled = [[self window] isMainWindow] == NO && [[self window] isKeyWindow] == NO && ([self isDescendantOf:[[self window] contentView]] == NO || [[self window] isKindOfClass:NSClassFromString(@"NSToolbarSnapshotWindow")]); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ Skim-app-commit mailing list Skim-app-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/skim-app-commit