Revision: 15030
          http://sourceforge.net/p/skim-app/code/15030
Author:   hofman
Date:     2025-03-27 16:53:35 +0000 (Thu, 27 Mar 2025)
Log Message:
-----------
Animate color swatch width for autolayout. Always update colors and itemViews 
before animating for insert/remove/move.

Modified Paths:
--------------
    trunk/SKColorSwatch.h
    trunk/SKColorSwatch.m

Modified: trunk/SKColorSwatch.h
===================================================================
--- trunk/SKColorSwatch.h       2025-03-27 10:23:44 UTC (rev 15029)
+++ trunk/SKColorSwatch.h       2025-03-27 16:53:35 UTC (rev 15030)
@@ -49,6 +49,7 @@
     NSMutableArray<SKColorSwatchItemView *> *itemViews;
     NSControl *backgroundView;
     CGFloat bezelHeight;
+    CGFloat bezelWidth;
     
     NSInteger clickedIndex;
     NSInteger selectedIndex;

Modified: trunk/SKColorSwatch.m
===================================================================
--- trunk/SKColorSwatch.m       2025-03-27 10:23:44 UTC (rev 15029)
+++ trunk/SKColorSwatch.m       2025-03-27 16:53:35 UTC (rev 15030)
@@ -108,15 +108,25 @@
 
 @interface SKColorSwatch ()
 @property (nonatomic) NSInteger selectedColorIndex;
-- (NSRect)frameForItemViewAtIndex:(NSInteger)anIndex 
collapsedIndex:(NSInteger)collapsedIndex;
+@property (nonatomic) CGFloat bezelWidth;
+- (NSRect)frameForItemViewAtIndex:(NSInteger)anIndex;
 - (void)setColor:(NSColor *)color atIndex:(NSInteger)i 
fromPanel:(BOOL)fromPanel;
 @end
 
 @implementation SKColorSwatch
 
-@synthesize colors, autoResizes, selects, alternate, 
clickedColorIndex=clickedIndex, selectedColorIndex=selectedIndex;
+@synthesize colors, autoResizes, selects, alternate, 
clickedColorIndex=clickedIndex, selectedColorIndex=selectedIndex, bezelWidth;
 @dynamic color;
 
++ (id)defaultAnimationForKey:(NSAnimatablePropertyKey)key {
+    if ([key isEqualToString:@"bezelWidth"]) {
+        CABasicAnimation *anim = [CABasicAnimation animation];
+        [anim setTimingFunction:[CAMediaTimingFunction 
functionWithName:kCAMediaTimingFunctionDefault]];
+        return anim;
+    } else
+        return [super defaultAnimationForKey:key];
+}
+
 - (Class)valueClassForBinding:(NSString *)binding {
     if ([binding isEqualToString:COLORS_KEY])
         return [NSArray class];
@@ -130,6 +140,8 @@
     selectedIndex = -1;
     draggedIndex = -1;
     
+    bezelWidth = 0.0;
+    
     [self registerForDraggedTypes:[NSColor 
readableTypesForPasteboard:[NSPasteboard 
pasteboardWithName:NSPasteboardNameDrag]]];
 }
 
@@ -154,7 +166,7 @@
         [constraints setValue:@YES forKey:@"shouldBeArchived"];
         [NSLayoutConstraint activateConstraints:constraints];
         
-        SKColorSwatchItemView *itemView = [[SKColorSwatchItemView alloc] 
initWithFrame:[self frameForItemViewAtIndex:0 collapsedIndex:-1]];
+        SKColorSwatchItemView *itemView = [[SKColorSwatchItemView alloc] 
initWithFrame:[self frameForItemViewAtIndex:0]];
         [itemView setColor:[NSColor whiteColor]];
         [self addSubview:itemView];
         itemViews = [[NSMutableArray alloc] initWithObjects:itemView, nil];
@@ -214,16 +226,14 @@
     return rect;
 }
 
-- (NSRect)frameForItemViewAtIndex:(NSInteger)anIndex 
collapsedIndex:(NSInteger)collapsedIndex {
-    NSInteger i = anIndex;
-    if (collapsedIndex != -1 && anIndex > collapsedIndex)
-        i--;
-    NSRect rect = NSInsetRect([self frameForColorAtIndex:i], -COLOR_INSET, 
-COLOR_INSET);
-    if (collapsedIndex == anIndex)
-        rect.size.width -= DISTANCE_BETWEEN_COLORS;
-    return rect;
+- (NSRect)frameForItemViewAtIndex:(NSInteger)anIndex {
+    return NSInsetRect([self frameForColorAtIndex:anIndex], -COLOR_INSET, 
-COLOR_INSET);
 }
 
+- (NSRect)frameForCollapsedItemViewAtIndex:(NSInteger)anIndex {
+    return SKShrinkRect([self frameForItemViewAtIndex:anIndex], 
DISTANCE_BETWEEN_COLORS, NSMaxXEdge);
+}
+
 - (NSInteger)colorIndexAtPoint:(NSPoint)point {
     NSRect rect = [self frameForColorAtIndex:0];
     NSInteger i, count = [colors count];
@@ -249,17 +259,21 @@
     return count;
 }
 
-- (NSSize)sizeForNumberOfColors:(NSUInteger)count {
-    NSEdgeInsets insets = [self alignmentRectInsets];
-    return NSMakeSize(COLOR_INSET + count * DISTANCE_BETWEEN_COLORS + 
insets.left + insets.right, bezelHeight + insets.bottom + insets.top);
+- (CGFloat)contentWidth {
+    return COLOR_INSET + [colors count] * DISTANCE_BETWEEN_COLORS;
 }
 
 - (NSSize)intrinsicContentSize {
-    return NSMakeSize(COLOR_INSET + [colors count] * DISTANCE_BETWEEN_COLORS, 
bezelHeight);
+    return NSMakeSize(bezelWidth ?: [self contentWidth], bezelHeight);
 }
 
+- (NSSize)intrinsicFrameSize {
+    NSEdgeInsets insets = [self alignmentRectInsets];
+    return NSMakeSize([self contentWidth] + insets.left + insets.right, 
bezelHeight + insets.bottom + insets.top);
+}
+
 - (void)sizeToFit {
-    [self setFrameSize:[self sizeForNumberOfColors:[colors count]]];
+    [self setFrameSize:[self intrinsicFrameSize]];
 }
 
 - (NSEdgeInsets)alignmentRectInsets {
@@ -269,7 +283,7 @@
 - (void)updateItemViewFrames {
     NSUInteger i, iMax = [itemViews count];
     for (i = 0; i < iMax; i++)
-        [[itemViews objectAtIndex:i] setFrame:[self frameForItemViewAtIndex:i 
collapsedIndex:-1]];
+        [[itemViews objectAtIndex:i] setFrame:[self 
frameForItemViewAtIndex:i]];
 }
 
 - (void)updateBezelHeight {
@@ -492,6 +506,11 @@
     [super setEnabled:enabled];
 }
 
+- (void)setBezelWidth:(CGFloat)width {
+    bezelWidth = width;
+    [self invalidateIntrinsicContentSize];
+}
+
 #pragma mark Modification
 
 - (void)selectColorAtIndex:(NSInteger)idx {
@@ -585,9 +604,9 @@
     [self setColor:color atIndex:i fromPanel:NO];
 }
 
-- (void)animateItemViewsCollapsing:(NSInteger)collapsedIndex {
+- (void)animateItemViewFrames {
     [itemViews enumerateObjectsUsingBlock:^(SKColorSwatchItemView *itemView, 
NSUInteger i, BOOL *stop){
-        NSRect frame = [self frameForItemViewAtIndex:i 
collapsedIndex:collapsedIndex];
+        NSRect frame = [self frameForItemViewAtIndex:i];
         if (NSEqualRects(frame, [itemView frame]) == NO)
             [[itemView animator] setFrame:frame];
     }];
@@ -597,9 +616,9 @@
     if (color && i >= 0 && i <= (NSInteger)[colors count]) {
         [self deactivate];
         [self willChangeColors];
+        bezelWidth = [self contentWidth];
         [colors insertObject:color atIndex:i];
-        [self invalidateIntrinsicContentSize];
-        SKColorSwatchItemView *itemView = [[SKColorSwatchItemView alloc] 
initWithFrame:[self frameForItemViewAtIndex:i collapsedIndex:i]];
+        SKColorSwatchItemView *itemView = [[SKColorSwatchItemView alloc] 
initWithFrame:[self frameForCollapsedItemViewAtIndex:i]];
         [itemView setColor:color];
         if (i < (NSInteger)[itemViews count])
             [self addSubview:itemView positioned:NSWindowBelow 
relativeTo:[itemViews objectAtIndex:i]];
@@ -606,19 +625,20 @@
         else
             [self addSubview:itemView positioned:NSWindowAbove relativeTo:nil];
         [itemViews insertObject:itemView atIndex:i];
-        NSSize size = [self sizeForNumberOfColors:[colors count]];
+        [self didChangeColors];
         [self noteFocusRingMaskChanged];
         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
-                [self animateItemViewsCollapsing:-1];
+                [self animateItemViewFrames];
+                [[self animator] setBezelWidth:[self contentWidth]];
                 if (autoResizes)
-                    [[self animator] setFrameSize:size];
+                    [[self animator] setFrameSize:[self intrinsicFrameSize]];
             }
             completionHandler:^{
+                [self setBezelWidth:0.0];
                 if (autoResizes)
                     [self sizeToFit];
                 [self noteFocusRingMaskChanged];
             }];
-        [self didChangeColors];
     }
 }
 
@@ -625,22 +645,25 @@
 - (void)removeColorAtIndex:(NSInteger)i {
     if (i >= 0 && i < (NSInteger)[colors count] && [colors count] > 1) {
         [self deactivate];
-        NSSize size = [self sizeForNumberOfColors:[colors count] - 1];
+        [self willChangeColors];
+        bezelWidth = [self contentWidth];
+        [colors removeObjectAtIndex:i];
+        SKColorSwatchItemView *itemView = [itemViews objectAtIndex:i];
+        [itemViews removeObjectAtIndex:i];
+        [self didChangeColors];
         [self noteFocusRingMaskChanged];
         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
-                [self animateItemViewsCollapsing:i];
+                [[itemView animator] setFrame:[self 
frameForCollapsedItemViewAtIndex:i]];
+                [self animateItemViewFrames];
+                [[self animator] setBezelWidth:[self contentWidth]];
                 if (autoResizes)
-                    [[self animator] setFrameSize:size];
+                    [[self animator] setFrameSize:[self intrinsicFrameSize]];
             }
             completionHandler:^{
-                [self willChangeColors];
-                [colors removeObjectAtIndex:i];
-                [[itemViews objectAtIndex:i] removeFromSuperview];
-                [itemViews removeObjectAtIndex:i];
-                [self didChangeColors];
+                [itemView removeFromSuperview];
+                [self setBezelWidth:0.0];
                 if (autoResizes)
                     [self sizeToFit];
-                [self invalidateIntrinsicContentSize];
                 [self noteFocusRingMaskChanged];
             }];
     }
@@ -658,9 +681,10 @@
         [itemViews insertObject:itemView atIndex:to];
         if (to > from)
             [self addSubview:itemView positioned:NSWindowAbove 
relativeTo:[itemViews objectAtIndex:to - 1]];
+        [self didChangeColors];
         [self noteFocusRingMaskChanged];
         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
-                [self animateItemViewsCollapsing:-1];
+                [self animateItemViewFrames];
             }
             completionHandler:^{
                 if (to < from)
@@ -667,7 +691,6 @@
                     [self addSubview:itemView positioned:NSWindowBelow 
relativeTo:[itemViews objectAtIndex:to + 1]];
                 [self noteFocusRingMaskChanged];
             }];
-        [self didChangeColors];
     }
 }
 

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

Reply via email to