* Improved drag-and-drop (supports CandyBar)
authorJens Alfke <jens@mooseyard.com>
Sat Jul 05 17:46:43 2008 -0700 (2008-07-05)
changeset 11436cbdf56810
parent 10 6c78cc6bd7a6
child 12 4e567e11f45f
* Improved drag-and-drop (supports CandyBar)
* Fixed DiscPiece
* Inheritable layer styles
etc.
Source/Bit.h
Source/Bit.m
Source/Card.m
Source/CheckersGame.m
Source/DemoBoardView.m
Source/DiscPiece.m
Source/Dispenser.m
Source/GGBLayer.h
Source/GGBLayer.m
Source/Grid.h
Source/Grid.m
Source/Piece.m
Source/QuartzUtils.h
Source/QuartzUtils.m
     1.1 --- a/Source/Bit.h	Thu Jul 03 17:44:30 2008 -0700
     1.2 +++ b/Source/Bit.h	Sat Jul 05 17:46:43 2008 -0700
     1.3 @@ -43,6 +43,8 @@
     1.4  {
     1.5      @private
     1.6      int _restingZ;      // Original z position, saved while pickedUp
     1.7 +    float _restingShadowOpacity, _restingShadowRadius;
     1.8 +    CGSize _restingShadowOffset;
     1.9      BOOL _pickedUp;
    1.10      Player *_owner;     // Player that owns this Bit
    1.11  }
     2.1 --- a/Source/Bit.m	Thu Jul 03 17:44:30 2008 -0700
     2.2 +++ b/Source/Bit.m	Sat Jul 05 17:46:43 2008 -0700
     2.3 @@ -100,18 +100,24 @@
     2.4  - (void) setPickedUp: (BOOL)up
     2.5  {
     2.6      if( up != _pickedUp ) {
     2.7 -        CGFloat shadow, offset, radius, opacity, z, scale;
     2.8 +        CGFloat shadow, radius, opacity, z, scale;
     2.9 +        CGSize offset;
    2.10          if( up ) {
    2.11              shadow = 0.8;
    2.12 -            offset = 2;
    2.13 +            offset = CGSizeMake(2,2);
    2.14              radius = 8;
    2.15              opacity = kPickedUpOpacity;
    2.16              scale = kPickedUpScale;
    2.17              z = kPickedUpZ;
    2.18              _restingZ = self.zPosition;
    2.19 +            _restingShadowOpacity = self.shadowOpacity;
    2.20 +            _restingShadowOffset  = self.shadowOffset;
    2.21 +            _restingShadowRadius  = self.shadowRadius;
    2.22          } else {
    2.23 -            shadow = offset = radius = 0.0;
    2.24 -            opacity = 1.0;
    2.25 +            shadow = _restingShadowOpacity;
    2.26 +            offset = _restingShadowOffset;
    2.27 +            radius = _restingShadowRadius;
    2.28 +            opacity = 1;
    2.29              scale = 1.0/kPickedUpScale;
    2.30              z = _restingZ;
    2.31          }
    2.32 @@ -119,7 +125,7 @@
    2.33          //self.zPosition = z;
    2.34  #if !TARGET_OS_IPHONE
    2.35          self.shadowOpacity = shadow;
    2.36 -        self.shadowOffset = CGSizeMake(offset,-offset);
    2.37 +        self.shadowOffset = offset;
    2.38          self.shadowRadius = radius;
    2.39  #endif
    2.40          self.opacity = opacity;
     3.1 --- a/Source/Card.m	Thu Jul 03 17:44:30 2008 -0700
     3.2 +++ b/Source/Card.m	Sat Jul 05 17:46:43 2008 -0700
     3.3 @@ -183,7 +183,7 @@
     3.4  
     3.5  - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
     3.6  {
     3.7 -    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
     3.8 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
     3.9      if( image ) {
    3.10          GGBLayer *face = _faceUp ?_front :_back;
    3.11          face.contents = (id) image;
     4.1 --- a/Source/CheckersGame.m	Thu Jul 03 17:44:30 2008 -0700
     4.2 +++ b/Source/CheckersGame.m	Sat Jul 05 17:46:43 2008 -0700
     4.3 @@ -30,6 +30,25 @@
     4.4  @implementation CheckersGame
     4.5  
     4.6  
     4.7 +static NSMutableDictionary *kPieceStyle1, *kPieceStyle2;
     4.8 +
     4.9 ++ (void) initialize
    4.10 +{
    4.11 +    if( self == [CheckersGame class] ) {
    4.12 +        kPieceStyle1 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
    4.13 +                        (id)GetCGImageNamed(@"Green.png"), @"contents",
    4.14 +                        kCAGravityResizeAspect, @"contentsGravity",
    4.15 +                        kCAFilterLinear, @"minificationFilter",
    4.16 +                        nil];
    4.17 +        kPieceStyle2 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
    4.18 +                        (id)GetCGImageNamed(@"Red.png"), @"contents",
    4.19 +                        kCAGravityResizeAspect, @"contentsGravity",
    4.20 +                        kCAFilterLinear, @"minificationFilter",
    4.21 +                        nil];
    4.22 +    }
    4.23 +}
    4.24 +
    4.25 +
    4.26  - (id) init
    4.27  {
    4.28      self = [super init];
    4.29 @@ -52,8 +71,9 @@
    4.30  
    4.31  - (Piece*) pieceForPlayer: (int)playerNum
    4.32  {
    4.33 -    Piece *p = [[Piece alloc] initWithImageNamed: (playerNum==0 ?@"Green.png" :@"Red.png") 
    4.34 -                                           scale: floor(_grid.spacing.width * 1.0)];
    4.35 +    Piece *p = [[Piece alloc] init];
    4.36 +    p.bounds = CGRectMake(0,0,floor(_grid.spacing.width),floor(_grid.spacing.height));
    4.37 +    p.style = (playerNum ?kPieceStyle2 :kPieceStyle1);
    4.38      p.owner = [self.players objectAtIndex: playerNum];
    4.39      p.name = playerNum ?@"2" :@"1";
    4.40      return [p autorelease];
    4.41 @@ -68,7 +88,7 @@
    4.42  
    4.43  - (void) setUpBoard
    4.44  {
    4.45 -    RectGrid *grid = [[[RectGrid alloc] initWithRows: 8 columns: 8 frame: _board.bounds] autorelease];
    4.46 +    RectGrid *grid = [[RectGrid alloc] initWithRows: 8 columns: 8 frame: _board.bounds];
    4.47      _grid = grid;
    4.48      [_board addSublayer: _grid];
    4.49      CGPoint pos = _grid.position;
     5.1 --- a/Source/DemoBoardView.m	Thu Jul 03 17:44:30 2008 -0700
     5.2 +++ b/Source/DemoBoardView.m	Sat Jul 05 17:46:43 2008 -0700
     5.3 @@ -79,6 +79,7 @@
     5.4  {
     5.5      srandomdev();
     5.6      
     5.7 +    // BoardView supports receiving dragged images, but you have to register for them:
     5.8      [self registerForDraggedTypes: [NSImage imagePasteboardTypes]];
     5.9      [self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]];
    5.10      
     6.1 --- a/Source/DiscPiece.m	Thu Jul 03 17:44:30 2008 -0700
     6.2 +++ b/Source/DiscPiece.m	Sat Jul 05 17:46:43 2008 -0700
     6.3 @@ -27,27 +27,23 @@
     6.4  @implementation DiscPiece
     6.5  
     6.6  
     6.7 -- (void) setImage: (CGImageRef)image scale: (CGFloat)scale
     6.8 +- (void) _setImage: (CGImageRef)image
     6.9  {
    6.10 -    if( scale < 4.0 ) {
    6.11 -        int size = MAX(CGImageGetWidth(image), CGImageGetHeight(image));
    6.12 -        if( scale > 0 )
    6.13 -            scale = ceil( size * scale);
    6.14 -        else
    6.15 -            scale = size;
    6.16 -        scale *= 1.2;
    6.17 -    }
    6.18 -    self.bounds = CGRectMake(0,0,scale,scale);
    6.19 -    
    6.20 +    CGFloat diameter = MAX(CGImageGetWidth(image),CGImageGetHeight(image));
    6.21 +    CGFloat outerDiameter = round(diameter * 1.1);
    6.22 +    self.bounds = CGRectMake(0,0,outerDiameter,outerDiameter);
    6.23 +
    6.24      if( ! _imageLayer ) {
    6.25          _imageLayer = [[CALayer alloc] init];
    6.26          _imageLayer.contentsGravity = @"resizeAspect";
    6.27 +        _imageLayer.masksToBounds = YES;
    6.28          [self addSublayer: _imageLayer];
    6.29          [_imageLayer release];
    6.30      }
    6.31 -    _imageLayer.frame = CGRectInset(self.bounds, scale*.1, scale*.1);
    6.32 +    _imageLayer.frame = CGRectInset(self.bounds, outerDiameter-diameter, outerDiameter-diameter);
    6.33 +    _imageLayer.cornerRadius = diameter/2;
    6.34      _imageLayer.contents = (id) image;
    6.35 -    self.cornerRadius = scale/2;
    6.36 +    self.cornerRadius = outerDiameter/2;
    6.37      self.borderWidth = 3;
    6.38      self.borderColor = kTranslucentLightGrayColor;
    6.39      self.imageName = nil;
     7.1 --- a/Source/Dispenser.m	Thu Jul 03 17:44:30 2008 -0700
     7.2 +++ b/Source/Dispenser.m	Sat Jul 05 17:46:43 2008 -0700
     7.3 @@ -181,7 +181,7 @@
     7.4  {
     7.5      if( ! [_prototype isKindOfClass: [Piece class]] )
     7.6          return NO;
     7.7 -    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
     7.8 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
     7.9      if( image ) {
    7.10          [(Piece*)_prototype setImage: image];
    7.11          self.prototype = _prototype; // recreates _bit
     8.1 --- a/Source/GGBLayer.h	Thu Jul 03 17:44:30 2008 -0700
     8.2 +++ b/Source/GGBLayer.h	Sat Jul 05 17:46:43 2008 -0700
     8.3 @@ -14,9 +14,13 @@
     8.4  #endif
     8.5  
     8.6  
     8.7 +extern NSString* const GGBLayerStyleChangedNotification;
     8.8 +
     8.9 +
    8.10  @interface GGBLayer : CALayer <NSCopying>
    8.11  {
    8.12      CABasicAnimation *_curAnimation;
    8.13 +    NSMutableDictionary *_styleDict;
    8.14  
    8.15  #if ! TARGET_OS_IPHONE
    8.16  }
    8.17 @@ -35,6 +39,10 @@
    8.18  
    8.19  - (void) animateAndBlock: (NSString*)keyPath from: (id)from to: (id)to duration: (NSTimeInterval)duration;
    8.20  
    8.21 +/** Change a property in this layer's 'style' dictionary (if it has one),
    8.22 +    and update every other layer that shares the same style dictionary. */
    8.23 +- (void) setValue: (id)value ofStyleProperty: (NSString*)prop;
    8.24 +
    8.25  @end
    8.26  
    8.27  
     9.1 --- a/Source/GGBLayer.m	Thu Jul 03 17:44:30 2008 -0700
     9.2 +++ b/Source/GGBLayer.m	Sat Jul 05 17:46:43 2008 -0700
     9.3 @@ -8,6 +8,10 @@
     9.4  
     9.5  #import "GGBLayer.h"
     9.6  #import "QuartzUtils.h"
     9.7 +#import "GGBUtils.h"
     9.8 +
     9.9 +
    9.10 +NSString* const GGBLayerStyleChangedNotification = @"GGBLayerStyleChanged";
    9.11  
    9.12  
    9.13  @implementation GGBLayer
    9.14 @@ -67,6 +71,56 @@
    9.15  }
    9.16  
    9.17  
    9.18 +- (void) setStyle: (NSDictionary*)style
    9.19 +{
    9.20 +    if( style != _styleDict ) {
    9.21 +        if( _styleDict )
    9.22 +            [[NSNotificationCenter defaultCenter] removeObserver: self 
    9.23 +                                                            name: GGBLayerStyleChangedNotification
    9.24 +                                                          object: _styleDict];
    9.25 +        if( style )
    9.26 +            [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_styleChanged)
    9.27 +                                                         name: GGBLayerStyleChangedNotification
    9.28 +                                                       object: style];
    9.29 +        setObj(&_styleDict,style);
    9.30 +    }
    9.31 +    [super setStyle: style];
    9.32 +}
    9.33 +
    9.34 +- (void) _styleChanged
    9.35 +{
    9.36 +    // Reapply the style, so any changes in the dict will take effect.
    9.37 +    [super setStyle: _styleDict];
    9.38 +}
    9.39 +
    9.40 +- (void) dealloc
    9.41 +{
    9.42 +    if( _styleDict )
    9.43 +        [[NSNotificationCenter defaultCenter] removeObserver: self
    9.44 +                                                        name: GGBLayerStyleChangedNotification
    9.45 +                                                      object: _styleDict];
    9.46 +    [super dealloc];
    9.47 +}
    9.48 +
    9.49 +
    9.50 +- (void) setValue: (id)value ofStyleProperty: (NSString*)prop
    9.51 +{
    9.52 +    if( _styleDict ) {
    9.53 +        id oldValue = [_styleDict objectForKey: prop];
    9.54 +        if( oldValue != value ) {
    9.55 +            if( value )
    9.56 +                [_styleDict setObject: value forKey: prop];
    9.57 +            else
    9.58 +                [_styleDict removeObjectForKey: prop];
    9.59 +            [[NSNotificationCenter defaultCenter] postNotificationName: GGBLayerStyleChangedNotification
    9.60 +                                                                object: _styleDict];
    9.61 +        }
    9.62 +    } else
    9.63 +        [self setValue: value forKey: prop];
    9.64 +}
    9.65 +
    9.66 +
    9.67 +
    9.68  #if TARGET_OS_IPHONE
    9.69  
    9.70  #pragma mark -
    10.1 --- a/Source/Grid.h	Thu Jul 03 17:44:30 2008 -0700
    10.2 +++ b/Source/Grid.h	Sat Jul 05 17:46:43 2008 -0700
    10.3 @@ -31,6 +31,7 @@
    10.4      CGSize _spacing;                                    
    10.5      Class _cellClass;                                   
    10.6      CGColorRef _cellColor, _lineColor;                  
    10.7 +    CGImageRef _backgroundImage;
    10.8      BOOL _usesDiagonals, _allowsMoves, _allowsCaptures;
    10.9      NSMutableArray *_cells;                             // Really a 2D array, in row-major order.
   10.10  }
   10.11 @@ -51,9 +52,12 @@
   10.12  @property (readonly) unsigned rows, columns;    // Dimensions of the grid
   10.13  @property (readonly) CGSize spacing;            // x,y spacing of GridCells
   10.14  @property CGColorRef cellColor, lineColor;      // Cell background color, line color (or nil)
   10.15 +@property CGImageRef backgroundImage;           // Image drawn in background, behind lines and cells
   10.16  @property BOOL usesDiagonals;                   // Affects GridCell.neighbors, for rect grids
   10.17  @property BOOL allowsMoves, allowsCaptures;     // Can pieces be moved, and can they land on others?
   10.18  
   10.19 +@property (readonly) NSArray *cells;
   10.20 +
   10.21  /** Returns the GridCell at the given coordinates, or nil if there is no cell there.
   10.22      It's OK to call this with off-the-board coordinates; it will just return nil.*/
   10.23  - (GridCell*) cellAtRow: (unsigned)row column: (unsigned)col;
    11.1 --- a/Source/Grid.m	Thu Jul 03 17:44:30 2008 -0700
    11.2 +++ b/Source/Grid.m	Sat Jul 05 17:46:43 2008 -0700
    11.3 @@ -102,8 +102,18 @@
    11.4  - (CGColorRef) lineColor                        {return _lineColor;}
    11.5  - (void) setLineColor: (CGColorRef)lineColor    {setcolor(&_lineColor,lineColor);}
    11.6  
    11.7 +- (CGImageRef) backgroundImage                  {return _backgroundImage;}
    11.8 +- (void) setBackgroundImage: (CGImageRef)image
    11.9 +{
   11.10 +    if( image != _backgroundImage ) {
   11.11 +        CGImageRelease(_backgroundImage);
   11.12 +        _backgroundImage = CGImageRetain(image);
   11.13 +    }
   11.14 +}
   11.15 +
   11.16  @synthesize cellClass=_cellClass, rows=_nRows, columns=_nColumns, spacing=_spacing,
   11.17 -            usesDiagonals=_usesDiagonals, allowsMoves=_allowsMoves, allowsCaptures=_allowsCaptures;
   11.18 +            usesDiagonals=_usesDiagonals, allowsMoves=_allowsMoves, allowsCaptures=_allowsCaptures,
   11.19 +            cells=_cells;
   11.20  
   11.21  
   11.22  #pragma mark -
   11.23 @@ -205,6 +215,10 @@
   11.24      // Custom CALayer drawing implementation. Delegates to the cells to draw themselves
   11.25      // in me; this is more efficient than having each cell have its own drawing.
   11.26      [super drawInContext: ctx];
   11.27 +    
   11.28 +    if( _backgroundImage )
   11.29 +        CGContextDrawImage(ctx, self.bounds, _backgroundImage);
   11.30 +    
   11.31      if( _cellColor ) {
   11.32          CGContextSetFillColorWithColor(ctx, _cellColor);
   11.33          [self drawCellsInContext: ctx fill: YES];
   11.34 @@ -348,13 +362,11 @@
   11.35  
   11.36  #if ! TARGET_OS_IPHONE
   11.37  
   11.38 -// An image from another app can be dragged onto a Dispenser to change the Piece's appearance.
   11.39 -
   11.40 +// An image from another app can be dragged onto a Grid to change its background pattern.
   11.41  
   11.42  - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
   11.43  {
   11.44 -    NSPasteboard *pb = [sender draggingPasteboard];
   11.45 -    if( [NSImage canInitWithPasteboard: pb] )
   11.46 +    if( CanGetCGImageFromPasteboard([sender draggingPasteboard]) )
   11.47          return NSDragOperationCopy;
   11.48      else
   11.49          return NSDragOperationNone;
   11.50 @@ -362,7 +374,7 @@
   11.51  
   11.52  - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
   11.53  {
   11.54 -    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
   11.55 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
   11.56      if( image ) {
   11.57          CGColorRef pattern = CreatePatternColor(image);
   11.58          _grid.cellColor = pattern;
   11.59 @@ -456,7 +468,7 @@
   11.60  
   11.61  - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
   11.62  {
   11.63 -    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
   11.64 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
   11.65      if( image ) {
   11.66          CGColorRef color = CreatePatternColor(image);
   11.67          RectGrid *rectGrid = (RectGrid*)_grid;
    12.1 --- a/Source/Piece.m	Thu Jul 03 17:44:30 2008 -0700
    12.2 +++ b/Source/Piece.m	Sat Jul 05 17:46:43 2008 -0700
    12.3 @@ -27,13 +27,23 @@
    12.4  @implementation Piece
    12.5  
    12.6  
    12.7 +- (id) init
    12.8 +{
    12.9 +    self = [super init];
   12.10 +    if (self != nil) {
   12.11 +        self.zPosition = kPieceZ;
   12.12 +    }
   12.13 +    return self;
   12.14 +}
   12.15 +
   12.16 +
   12.17 +
   12.18  - (id) initWithImageNamed: (NSString*)imageName
   12.19                      scale: (CGFloat)scale
   12.20  {
   12.21 -    self = [super init];
   12.22 +    self = [self init];
   12.23      if (self != nil) {
   12.24          [self setImageNamed: imageName scale: scale];
   12.25 -        self.zPosition = kPieceZ;
   12.26      }
   12.27      return self;
   12.28  }
   12.29 @@ -124,4 +134,29 @@
   12.30  }
   12.31  
   12.32  
   12.33 +#if ! TARGET_OS_IPHONE
   12.34 +
   12.35 +// An image from another app can be dragged onto a Piece to change its background pattern.
   12.36 +
   12.37 +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
   12.38 +{
   12.39 +    if( CanGetCGImageFromPasteboard([sender draggingPasteboard]) )
   12.40 +        return NSDragOperationCopy;
   12.41 +    else
   12.42 +        return NSDragOperationNone;
   12.43 +}
   12.44 +
   12.45 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
   12.46 +{
   12.47 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard],sender);
   12.48 +    if( image ) {
   12.49 +        [self setValue: (id)image ofStyleProperty: @"contents"];
   12.50 +        return YES;
   12.51 +    } else
   12.52 +        return NO;
   12.53 +}
   12.54 +
   12.55 +#endif
   12.56 +
   12.57 +
   12.58  @end
    13.1 --- a/Source/QuartzUtils.h	Thu Jul 03 17:44:30 2008 -0700
    13.2 +++ b/Source/QuartzUtils.h	Sat Jul 05 17:46:43 2008 -0700
    13.3 @@ -50,8 +50,10 @@
    13.4  CGColorRef GetCGPatternNamed( NSString *name );
    13.5  
    13.6  #if ! TARGET_OS_IPHONE
    13.7 +/** Is it possible to read a CGImage from this pasteboard? */
    13.8 +BOOL CanGetCGImageFromPasteboard( NSPasteboard *pb );
    13.9  /** Loads image data from the pasteboard into a CGImage. */
   13.10 -CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb );
   13.11 +CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb, id<NSDraggingInfo>dragInfo );
   13.12  #endif
   13.13  
   13.14  CGImageRef CreateScaledImage( CGImageRef srcImage, CGFloat scale );
    14.1 --- a/Source/QuartzUtils.m	Thu Jul 03 17:44:30 2008 -0700
    14.2 +++ b/Source/QuartzUtils.m	Sat Jul 05 17:46:43 2008 -0700
    14.3 @@ -105,8 +105,12 @@
    14.4          if( [name hasPrefix: @"/"] )
    14.5              path = name;
    14.6          else {
    14.7 -            path = [[NSBundle mainBundle] pathForResource: name ofType: nil];
    14.8 -            NSCAssert1(path,@"Couldn't find bundle image resource '%@'",name);
    14.9 +            NSString *dir = [name stringByDeletingLastPathComponent];
   14.10 +            name = [name lastPathComponent];
   14.11 +            NSString *ext = name.pathExtension;
   14.12 +            name = [name stringByDeletingPathExtension];
   14.13 +            path = [[NSBundle mainBundle] pathForResource: name ofType: ext inDirectory: dir];
   14.14 +            NSCAssert3(path,@"Couldn't find bundle image resource '%@' type '%@' in '%@'",name,ext,dir);
   14.15          }
   14.16          image = CreateCGImageFromFile(path);
   14.17          NSCAssert1(image,@"Failed to load image from %@",path);
   14.18 @@ -136,7 +140,21 @@
   14.19  
   14.20  
   14.21  #if ! TARGET_OS_IPHONE
   14.22 -CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb )
   14.23 +
   14.24 +BOOL CanGetCGImageFromPasteboard( NSPasteboard *pb )
   14.25 +{
   14.26 +    return [NSImage canInitWithPasteboard: pb] 
   14.27 +        || [[pb types] containsObject: @"PixadexIconPathPboardType"];
   14.28 +
   14.29 +    /*if( [[pb types] containsObject: NSFilesPromisePboardType] ) {
   14.30 +     NSArray *fileTypes = [pb propertyListForType: NSFilesPromisePboardType];
   14.31 +     NSLog(@"Got file promise! Types = %@",fileTypes);
   14.32 +     //FIX: Check file types
   14.33 +     return NSDragOperationCopy;
   14.34 +     }*/
   14.35 +}    
   14.36 +
   14.37 +CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb, id<NSDraggingInfo>dragInfo )
   14.38  {
   14.39      CGImageSourceRef src = NULL;
   14.40      NSArray *paths = [pb propertyListForType: NSFilenamesPboardType];
   14.41 @@ -144,6 +162,28 @@
   14.42          // If a file is being dragged, read it:
   14.43          CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: [paths objectAtIndex: 0]];
   14.44          src = CGImageSourceCreateWithURL(url, NULL);
   14.45 +/*
   14.46 +    } else if( dragInfo && [[pb types] containsObject:NSFilesPromisePboardType] ) {
   14.47 +        NSString *dropDir = NSTemporaryDirectory();
   14.48 +        NSArray *filenames = [dragInfo namesOfPromisedFilesDroppedAtDestination: [NSURL fileURLWithPath: dropDir]];
   14.49 +        NSLog(@"promised files are %@ / %@", dropDir,filenames);
   14.50 +        src = nil; */
   14.51 +    } else if( [[pb types] containsObject: @"PixadexIconPathPboardType"] ) {
   14.52 +        // Candybar 3 (nee Pixadex) doesn't drag out icons in any normal image type.
   14.53 +        // It does support file-promises, but I couldn't get those to work using the Cocoa APIs.
   14.54 +        // So instead I'm using its custom type that provides the path(s) to its internal ".pxicon" files.
   14.55 +        // The icon is really easy to get from one of these: it's just file's custom icon.
   14.56 +        NSArray *files = [pb propertyListForType: @"PixadexIconPathPboardType"];
   14.57 +        if( files.count == 1 ) {
   14.58 +            NSString *path = [files objectAtIndex: 0];
   14.59 +            NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
   14.60 +            for( NSImageRep *rep in icon.representations ) {
   14.61 +                if( [rep isKindOfClass: [NSBitmapImageRep class]] ) {
   14.62 +                    [rep retain];   //FIX: This leaks; but if the rep goes away, the CGImage breaks...
   14.63 +                    return [(NSBitmapImageRep*)rep CGImage];
   14.64 +                }
   14.65 +            }
   14.66 +        }
   14.67      } else {
   14.68          // Else look for an image type:
   14.69          NSString *type = [pb availableTypeFromArray: [NSImage imageUnfilteredPasteboardTypes]];
   14.70 @@ -205,6 +245,7 @@
   14.71  
   14.72  float GetPixelAlpha( CGImageRef image, CGSize imageSize, CGPoint pt )
   14.73  {
   14.74 +    NSCParameterAssert(image);
   14.75  #if TARGET_OS_IPHONE
   14.76      // iPhone uses "flipped" (i.e. normal) coords, so images are wrong-way-up
   14.77      pt.y = imageSize.height - pt.y;