Revision: 28656
          http://sourceforge.net/p/bibdesk/svn/28656
Author:   hofman
Date:     2024-01-23 15:28:04 +0000 (Tue, 23 Jan 2024)
Log Message:
-----------
Add progress indicators as subviews. Avoids redrawing the icons. Let the 
progress indicators manage the timer. Animate changing the progress.

Modified Paths:
--------------
    trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h
    trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m
    trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.h
    trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.m

Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h      2024-01-23 
09:38:09 UTC (rev 28655)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.h      2024-01-23 
15:28:04 UTC (rev 28656)
@@ -258,7 +258,6 @@
     NSDictionary                   *_contentBinding;
     NSMutableArray                 *_downloads;
     NSMutableDictionary            *_progressIndicators;
-    CFRunLoopTimerRef               _progressTimer;
     NSMutableArray                 *_accessibilityIcons;
     NSMutableSet                   *_modificationSet;
     NSLock                         *_modificationLock;

Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m      2024-01-23 
09:38:09 UTC (rev 28655)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVFileView.m      2024-01-23 
15:28:04 UTC (rev 28656)
@@ -226,7 +226,6 @@
 - (void)_showArrowsForIconAtIndex:(NSUInteger)anIndex;
 - (void)_hideArrows;
 - (void)_cancelDownloads;
-- (void)_invalidateProgressTimer;
 - (void)_downloadURLAtIndex:(NSUInteger)anIndex replace:(BOOL)replace;
 - (void)_handleFinderLabelChanged:(NSNotification *)note;
 - (void)_updateBinding:(NSString *)binding;
@@ -419,9 +418,6 @@
     // a dictionary of progress indicators
     _progressIndicators = nil;
 
-    // timer to update the view when a download's length is indeterminate
-    _progressTimer = NULL;
-    
     // set of _FVFileKey instances
     _modificationSet = [NSMutableSet new];
     _modificationLock = [NSLock new];
@@ -453,7 +449,6 @@
 
 - (void)dealloc
 {
-    [self _invalidateProgressTimer];
     CFRunLoopTimerInvalidate(_zombieTimer);
     CFRelease(_zombieTimer);
     // this variable is accessed in super's dealloc, so set it to NULL
@@ -1657,6 +1652,31 @@
     [self _resetTrackingRectsAndToolTips];
 }
 
+- (NSRect)_rectOfProgressIndicatorForIconAtIndex:(NSUInteger)anIndex;
+{
+    NSUInteger r, c;
+    NSRect frame = NSZeroRect;
+    if ([self _getGridRow:&r column:&c ofIndex:anIndex]) {
+        frame = [self _rectOfIconInRow:r column:c];
+        NSPoint center = NSMakePoint(NSMidX(frame), NSMidY(frame));
+        
+        CGFloat size = NSHeight(frame) / 2;
+        frame.size.height = size;
+        frame.size.width = size;
+        frame.origin.x = center.x - NSWidth(frame) / 2;
+        frame.origin.y = center.y - NSHeight(frame) / 2;
+    }
+    return frame;
+}
+
+- (void)_updateProgressIndicatorFrames {
+    if ([_progressIndicators count] > 0) {
+        [_progressIndicators enumerateKeysAndObjectsUsingBlock:^(NSURL *url, 
FVProgressIndicator *progressIndicator, BOOL *stop){
+            [progressIndicator setFrame:[self 
_rectOfProgressIndicatorForIconAtIndex:[progressIndicator indexInView]]];
+        }];
+    }
+}
+
 - (void)_resetViewLayout;
 {
     // When the tracking rects are active while the view is layed out, 
mouseEntered may be called even if the mouse does not move.  So we remove them 
before doing the layout.  We will reinstall them at the end of this method.
@@ -1665,6 +1685,9 @@
     // Problem exposed in BibDesk: select all, scroll halfway down in file 
pane, then change selection to a single row.  FVFileView content didn't update 
correctly, even though reloadIcons was called.  Logging drawRect: indicated 
that the wrong region was being updated, but calling _recalculateGridSize here 
fixed it.
     [self _recalculateGridSize];
     
+    // We may have to change the frames of the progress indicators.
+    [self _updateProgressIndicatorFrames];
+    
     // grid may have changed, so do a full redisplay
     [self setNeedsDisplay:YES];
     
@@ -1849,8 +1872,15 @@
     }
     
     for (NSURL *url in [_progressIndicators allKeys]) {
-        if ([_orderedURLs containsObject:url] == NO)
-            [self removeProgressIndicatorForURL:url 
atIndex:[[_progressIndicators objectForKey:url] indexInView]];
+        FVProgressIndicator *progressIndicator = [_progressIndicators 
objectForKey:url];
+        NSUInteger anIndex = [progressIndicator indexInView];
+        if ([_orderedURLs containsObject:url] == NO) {
+            [self removeProgressIndicatorForURL:url atIndex:anIndex];
+        } else if (anIndex >= [self numberOfIcons] || [[self 
URLAtIndex:anIndex] isEqual:url] == NO) {
+            anIndex = [_orderedURLs indexOfObject:url];
+            [progressIndicator setIndexInView:anIndex];
+            [progressIndicator setFrame:[self 
_rectOfProgressIndicatorForIconAtIndex:anIndex]];
+        }
     }
     
     [self _resetViewLayout];
@@ -2482,23 +2512,6 @@
     CGColorRelease(shadowColor);
 }
 
-- (NSRect)_rectOfProgressIndicatorForIconAtIndex:(NSUInteger)anIndex;
-{
-    NSUInteger r, c;
-    NSRect frame = NSZeroRect;
-    if ([self _getGridRow:&r column:&c ofIndex:anIndex]) {    
-        frame = [self _rectOfIconInRow:r column:c];
-        NSPoint center = NSMakePoint(NSMidX(frame), NSMidY(frame));
-        
-        CGFloat size = NSHeight(frame) / 2;
-        frame.size.height = size;
-        frame.size.width = size;
-        frame.origin.x = center.x - NSWidth(frame) / 2;
-        frame.origin.y = center.y - NSHeight(frame) / 2;
-    }
-    return frame;
-}
-
 - (void)_fillBackgroundColorOrGradientInRect:(NSRect)rect 
forBounds:(NSRect)bounds
 {
     // any solid color background should override the gradient code
@@ -2604,15 +2617,6 @@
         else if (NSIsEmptyRect(_rubberBandRect) == NO) {
             [self _drawRubberbandRect];
         }
-        
-        if ([_progressIndicators count]) {
-            [_progressIndicators enumerateKeysAndObjectsUsingBlock:^(NSURL 
*url, FVProgressIndicator *progressIndicator, BOOL *stop){
-                NSUInteger anIndex = [progressIndicator indexInView];
-                // we only draw a if there's an active download for this 
URL/index pair
-                if (anIndex < [self numberOfIcons] && [[self 
URLAtIndex:anIndex] isEqual:url])
-                    [progressIndicator drawWithFrame:[self 
_rectOfProgressIndicatorForIconAtIndex:anIndex]];
-            }];
-        }
     }
 #if DEBUG_GRID 
     [[NSColor grayColor] set];
@@ -4095,27 +4099,6 @@
 
 #pragma mark Download support
 
-- (void)_invalidateProgressTimer
-{
-    if (_progressTimer) {
-        CFRunLoopTimerInvalidate(_progressTimer);
-        CFRelease(_progressTimer);
-        _progressTimer = NULL;
-    }
-}
-
-- (void)_progressTimerFired:(CFRunLoopTimerRef)timer
-{
-    NSUInteger r, c;
-    for (FVProgressIndicator *progressIndicator in [_progressIndicators 
allValues]) {
-        if ([progressIndicator style] == FVProgressIndicatorIndeterminate) {
-            [progressIndicator animate];
-            if ([self _getGridRow:&r column:&c ofIndex:[progressIndicator 
indexInView]])
-                [self _setNeedsDisplayForIconInRow:r column:c];
-        }
-    }
-}
-
 - (void)downloadUpdated:(FVDownload *)download
 {    
     [self updateProgressIndicator:[download currentProgress] forURL:[download 
downloadURL] atIndex:[download indexInView]];
@@ -4221,7 +4204,6 @@
 
 - (void)updateProgressIndicator:(double)progress forURL:(NSURL *)aURL 
atIndex:(NSUInteger)anIndex {
     FVProgressIndicator *progressIndicator = [_progressIndicators 
objectForKey:aURL];
-    NSUInteger r, c;
     if (progressIndicator == nil) {
         progressIndicator = [[FVProgressIndicator alloc] init];
         [progressIndicator setIndexInView:anIndex];
@@ -4228,41 +4210,29 @@
         if (_progressIndicators == nil)
             _progressIndicators = [[NSMutableDictionary alloc] init];
         [_progressIndicators setObject:progressIndicator forKey:aURL];
+        [progressIndicator setFrame:[self 
_rectOfProgressIndicatorForIconAtIndex:anIndex]];
+        [self addSubview:progressIndicator];
     } else if (anIndex != [progressIndicator indexInView]) {
-        NSUInteger oldIndex = [progressIndicator indexInView];
         [progressIndicator setIndexInView:anIndex];
-        if (oldIndex < [self numberOfIcons] && [self _getGridRow:&r column:&c 
ofIndex:oldIndex])
-            [self _setNeedsDisplayForIconInRow:r column:c];
+        [progressIndicator setFrame:[self 
_rectOfProgressIndicatorForIconAtIndex:anIndex]];
     }
     if (progress < 0.0) {
         [progressIndicator setStyle:FVProgressIndicatorIndeterminate];
-        if (_progressTimer == NULL) {
-            // runloop will retain this timer, but we'll retain it too and 
release in -dealloc
-            _progressTimer = 
FVCreateWeakTimerWithTimeInterval(PROGRESS_TIMER_INTERVAL, 
CFAbsoluteTimeGetCurrent() + PROGRESS_TIMER_INTERVAL, self, 
@selector(_progressTimerFired:));
-            CFRunLoopAddTimer(CFRunLoopGetCurrent(), _progressTimer, 
kCFRunLoopDefaultMode);
-        }
     } else {
         [progressIndicator setStyle:FVProgressIndicatorDeterminate];
-        [progressIndicator setCurrentProgress:progress];
+        [[progressIndicator animator] setCurrentProgress:progress];
     }
-    if ([self _getGridRow:&r column:&c ofIndex:anIndex])
-        [self _setNeedsDisplayForIconInRow:r column:c];
 }
 
 - (void)removeProgressIndicatorForURL:(NSURL *)aURL 
atIndex:(NSUInteger)anIndex {
+    [[_progressIndicators objectForKey:aURL] removeFromSuperview];
     [_progressIndicators removeObjectForKey:aURL];
-    if ([_progressIndicators count] == 0 || [[[_progressIndicators allValues] 
valueForKey:@"style"] containsObject:[NSNumber 
numberWithInteger:FVProgressIndicatorIndeterminate]] == NO)
-        [self _invalidateProgressTimer];
-    NSUInteger r, c;
-    if ([self _getGridRow:&r column:&c ofIndex:anIndex])
-        [self _setNeedsDisplayForIconInRow:r column:c];
 }
 
 - (void)resetProgressIndicators {
     if ([_progressIndicators count] > 0) {
+        [[_progressIndicators allValues] 
makeObjectsPerformSelector:@selector(removeFromSuperview)];
         [_progressIndicators removeAllObjects];
-        [self _invalidateProgressTimer];
-        [self setNeedsDisplay:YES];
     }
     for (FVDownload *download in _downloads) {
         [self updateProgressIndicator:[download currentProgress] 
forURL:[download downloadURL] atIndex:[download indexInView]];

Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.h
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.h     
2024-01-23 09:38:09 UTC (rev 28655)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.h     
2024-01-23 15:28:04 UTC (rev 28656)
@@ -51,7 +51,7 @@
     FVProgressIndicatorDeterminate   = 0
 };
 
-@interface FVProgressIndicator : NSObject
+@interface FVProgressIndicator : NSView
 {
 @private
     CGFloat                  _currentProgress;
@@ -58,6 +58,7 @@
     NSInteger                _currentStep;
     FVProgressIndicatorStyle _style;
     NSUInteger               _indexInView;
+    CFRunLoopTimerRef        _progressTimer;
 }
 
 @property (nonatomic) CGFloat currentProgress;
@@ -67,8 +68,4 @@
 
 @property (nonatomic) NSUInteger indexInView;
 
-- (void)animate;
-
-- (void)drawWithFrame:(NSRect)aRect;
-
 @end

Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.m     
2024-01-23 09:38:09 UTC (rev 28655)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVProgressIndicator.m     
2024-01-23 15:28:04 UTC (rev 28656)
@@ -37,8 +37,15 @@
  */
 
 #import "FVProgressIndicator.h"
+#import <QuartzCore/QuartzCore.h>
+#import "FVUtilities.h"
 
 
+@interface FVProgressIndicator ()
+- (void)_startProgressTimer;
+- (void)_invalidateProgressTimer;
+@end
+
 @implementation FVProgressIndicator
 
 @synthesize currentProgress=_currentProgress;
@@ -45,17 +52,25 @@
 @synthesize style=_style;
 @synthesize indexInView=_indexInView;
 
-static NSInteger numSteps = 8;
++ (id)defaultAnimationForKey:(NSString *)key {
+    if ([key isEqualToString:@"currentProgress"])
+        return [CABasicAnimation animation];
+    return [super defaultAnimationForKey:key];
+}
 
+static NSInteger _numSteps = 8;
+static CGFloat _progressTimeInterval = 0.1;
+
 + (void)initialize {
     FVINITIALIZE(FVProgressIndicator);
     
-    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_15)
-        numSteps = 12;
+    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_15) {
+        _numSteps = 12;
+        _progressTimeInterval = 1.0/24.0;
+    }
 }
 
-- (id)init
-{
+- (id)init {
     self = [super init];
     if (self) {
         _currentProgress = 0;
@@ -65,36 +80,72 @@
     return self;
 }
 
-- (void)animate
-{
-    if (_style == FVProgressIndicatorIndeterminate)
-        _currentStep = (_currentStep + 1) % numSteps;
+- (void)dealloc {
+    [self _invalidateProgressTimer];
 }
 
-- (void)drawWithFrame:(NSRect)aRect
-{
+- (void)setStyle:(FVProgressIndicatorStyle)style {
+    if (style != _style) {
+        _style = style;
+        [self setNeedsDisplay:YES];
+        if (_style == FVProgressIndicatorIndeterminate)
+            [self _startProgressTimer];
+        else
+            [self _invalidateProgressTimer];
+    }
+}
+
+- (void)setCurrentProgress:(CGFloat)currentProgress {
+    _currentProgress = currentProgress;
+    [self setNeedsDisplay:YES];
+}
+
+- (void)_progressTimerFired:(CFRunLoopTimerRef)timer {
+    if (_style == FVProgressIndicatorIndeterminate) {
+        _currentStep = (_currentStep + 1) % _numSteps;
+        [self setNeedsDisplay:YES];
+    }
+}
+
+- (void)_startProgressTimer {
+    if (_progressTimer == NULL && [self window]) {
+        // runloop will retain this timer, but we'll retain it too and release 
in -dealloc
+        _progressTimer = 
FVCreateWeakTimerWithTimeInterval(_progressTimeInterval, _progressTimeInterval 
* floor(CFAbsoluteTimeGetCurrent() / _progressTimeInterval + 1.0), self, 
@selector(_progressTimerFired:));
+        CFRunLoopAddTimer(CFRunLoopGetCurrent(), _progressTimer, 
kCFRunLoopDefaultMode);
+    }
+}
+
+- (void)_invalidateProgressTimer {
+    if (_progressTimer) {
+        CFRunLoopTimerInvalidate(_progressTimer);
+        CFRelease(_progressTimer);
+        _progressTimer = NULL;
+    }
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
     CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
     CGContextSaveGState(context);
-    CGRect progressRect = NSRectToCGRect(aRect);    
+    CGRect progressRect = NSRectToCGRect([self bounds]);
     CGPoint ctr = CGPointMake(CGRectGetMidX(progressRect), 
CGRectGetMidY(progressRect));
     CGFloat h = CGRectGetHeight(progressRect) / 64.0;
     
     if (_style == FVProgressIndicatorIndeterminate) {
         // indeterminate download length
-        CGFloat angle = M_PI * 2.0 / numSteps;
+        CGFloat angle = M_PI * 2.0 / _numSteps;
         CGContextTranslateCTM(context, ctr.x, ctr.y);
         CGContextRotateCTM(context, _currentStep * angle);
         CGContextTranslateCTM(context, -ctr.x, -ctr.y);
         NSInteger i;
-        for (i = 0; i < numSteps; i++) {
-            CGColorRef strokeColor = CGColorCreateGenericGray(0.0, (1.0 - 
(CGFloat)i / numSteps) * (numSteps - 4.0) / 8.0);
+        for (i = 0; i < _numSteps; i++) {
+            CGColorRef strokeColor = CGColorCreateGenericGray(0.0, (1.0 - 
(CGFloat)i / _numSteps) * (_numSteps - 4.0) / 8.0);
             CGContextSetStrokeColorWithColor(context, strokeColor);
             CGColorRelease(strokeColor);
-            CGContextSetLineWidth(context, (12.0 - numSteps / 2.0) * h);
+            CGContextSetLineWidth(context, (12.0 - _numSteps / 2.0) * h);
             CGContextSetLineCap(context, kCGLineCapRound);
             CGContextBeginPath(context);
-            CGContextMoveToPoint(context, ctr.x, ctr.y - (14.0 + numSteps / 
4.0) * h);
-            CGContextAddLineToPoint(context, ctr.x, ctr.y - (26.0 + numSteps / 
4.0) * h);
+            CGContextMoveToPoint(context, ctr.x, ctr.y - (14.0 + _numSteps / 
4.0) * h);
+            CGContextAddLineToPoint(context, ctr.x, ctr.y - (26.0 + _numSteps 
/ 4.0) * h);
             CGContextStrokePath(context);
             CGContextTranslateCTM(context, ctr.x, ctr.y);
             CGContextRotateCTM(context, -angle);
@@ -139,4 +190,16 @@
     CGContextRestoreGState(context);
 }
 
+- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
+    [super viewWillMoveToWindow:newWindow];
+    if (newWindow == nil)
+        [self _invalidateProgressTimer];
+}
+
+- (void)viewDidMoveToWindow {
+    [super viewDidMoveToWindow];
+    if (_style == FVProgressIndicatorIndeterminate)
+        [self _startProgressTimer];
+}
+
 @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

Reply via email to