Source/BoardView.m
author Jens Alfke <jens@mooseyard.com>
Thu Jul 31 11:18:13 2008 -0700 (2008-07-31)
changeset 22 4cb50131788f
parent 18 ed057f4a72ca
child 23 efe5d4523a23
permissions -rw-r--r--
* Working on 3D rotation of game board.
* Added some colored balls ("drawn" myself using Photoshop glass effect.)
jens@0
     1
/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
jens@0
     2
    http://developer.apple.com/samplecode/GeekGameBoard/
jens@0
     3
    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
jens@0
     4
jens@0
     5
    Redistribution and use in source and binary forms, with or without modification, are permitted
jens@0
     6
    provided that the following conditions are met:
jens@0
     7
jens@0
     8
    * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@0
     9
      and the following disclaimer.
jens@0
    10
    * Redistributions in binary form must reproduce the above copyright notice, this list of
jens@0
    11
      conditions and the following disclaimer in the documentation and/or other materials provided
jens@0
    12
      with the distribution.
jens@0
    13
jens@0
    14
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@0
    15
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@0
    16
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@0
    17
    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@0
    18
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@0
    19
    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@0
    20
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@0
    21
    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@0
    22
*/
jens@0
    23
#import "BoardView.h"
jens@0
    24
#import "Bit.h"
jens@0
    25
#import "BitHolder.h"
jens@22
    26
#import "Game+Protected.h"
jens@12
    27
#import "Turn.h"
jens@10
    28
#import "Player.h"
jens@0
    29
#import "QuartzUtils.h"
jens@0
    30
#import "GGBUtils.h"
jens@0
    31
jens@0
    32
jens@22
    33
#define kMaxPerspective 0.965   // 55 degrees
jens@22
    34
jens@22
    35
jens@3
    36
@interface BoardView ()
jens@3
    37
- (void) _findDropTarget: (NSPoint)pos;
jens@3
    38
@end
jens@3
    39
jens@3
    40
jens@0
    41
@implementation BoardView
jens@0
    42
jens@0
    43
jens@22
    44
@synthesize table=_table, gameBoardInset=_gameBoardInset;
jens@0
    45
jens@0
    46
jens@0
    47
- (void) dealloc
jens@0
    48
{
jens@0
    49
    [_game release];
jens@0
    50
    [super dealloc];
jens@0
    51
}
jens@0
    52
jens@0
    53
jens@22
    54
- (void) _applyPerspective
jens@22
    55
{
jens@22
    56
    CATransform3D t;
jens@22
    57
    if( fabs(_perspective) >= M_PI/180 ) {
jens@22
    58
        CGSize size = self.layer.bounds.size;
jens@22
    59
        t = CATransform3DMakeTranslation(-size.width/2, -size.height/4, 0);
jens@22
    60
        t = CATransform3DConcat(t, CATransform3DMakeRotation(-_perspective, 1,0,0));
jens@22
    61
        
jens@22
    62
        CATransform3D pers = CATransform3DIdentity;
jens@22
    63
        pers.m34 = 1.0/-800;
jens@22
    64
        t = CATransform3DConcat(t, pers);
jens@22
    65
        t = CATransform3DConcat(t, CATransform3DMakeTranslation(size.width/2, 
jens@22
    66
                                                                size.height*(0.25 + 0.05*sin(2*_perspective)),
jens@22
    67
                                                                0));
jens@22
    68
        self.layer.borderWidth = 3;
jens@22
    69
    } else {
jens@22
    70
        t = CATransform3DIdentity;
jens@22
    71
        self.layer.borderWidth = 0;
jens@22
    72
    }
jens@22
    73
    self.layer.transform = t;
jens@22
    74
}    
jens@22
    75
jens@22
    76
- (CGFloat) perspective {return _perspective;}
jens@22
    77
jens@22
    78
- (void) setPerspective: (CGFloat)p
jens@22
    79
{
jens@22
    80
    p = MAX(0.0, MIN(kMaxPerspective, p));
jens@22
    81
    if( p != _perspective ) {
jens@22
    82
        _perspective = p;
jens@22
    83
        [self _applyPerspective];
jens@22
    84
        _game.tablePerspectiveAngle = p;
jens@22
    85
    }
jens@22
    86
}
jens@22
    87
jens@22
    88
jens@10
    89
- (void) _removeGameBoard
jens@10
    90
{
jens@16
    91
    if( _table ) {
jens@16
    92
        RemoveImmediately(_table);
jens@16
    93
        _table = nil;
jens@10
    94
    }
jens@10
    95
}
jens@10
    96
jens@10
    97
- (void) createGameBoard
jens@10
    98
{
jens@10
    99
    [self _removeGameBoard];
jens@16
   100
    _table = [[CALayer alloc] init];
jens@16
   101
    _table.frame = [self gameBoardFrame];
jens@16
   102
    _table.autoresizingMask = kCALayerMinXMargin | kCALayerMaxXMargin | kCALayerMinYMargin | kCALayerMaxYMargin;
jens@22
   103
    
jens@10
   104
    // Tell the game to set up the board:
jens@16
   105
    _game.table = _table;
jens@10
   106
jens@16
   107
    [self.layer addSublayer: _table];
jens@16
   108
    [_table release];
jens@10
   109
}
jens@10
   110
jens@10
   111
jens@10
   112
- (Game*) game
jens@10
   113
{
jens@10
   114
    return _game;
jens@10
   115
}
jens@10
   116
jens@10
   117
- (void) setGame: (Game*)game
jens@10
   118
{
jens@10
   119
    if( game!=_game ) {
jens@16
   120
        _game.table = nil;
jens@10
   121
        setObj(&_game,game);
jens@10
   122
        [self createGameBoard];
jens@10
   123
    }
jens@10
   124
}
jens@10
   125
jens@0
   126
- (void) startGameNamed: (NSString*)gameClassName
jens@0
   127
{
jens@10
   128
    Class gameClass = NSClassFromString(gameClassName);
jens@10
   129
    Game *game = [[gameClass alloc] init];
jens@10
   130
    if( game ) {
jens@10
   131
        self.game = game;
jens@10
   132
        [game release];
jens@0
   133
    }
jens@10
   134
}
jens@10
   135
jens@10
   136
jens@0
   137
- (CGRect) gameBoardFrame
jens@0
   138
{
jens@22
   139
    return CGRectInset(self.layer.bounds, _gameBoardInset.width,_gameBoardInset.height);
jens@0
   140
}
jens@0
   141
jens@0
   142
jens@0
   143
- (void)resetCursorRects
jens@0
   144
{
jens@0
   145
    [super resetCursorRects];
jens@15
   146
    if( _game.okToMove )
jens@10
   147
        [self addCursorRect: self.bounds cursor: [NSCursor openHandCursor]];
jens@0
   148
}
jens@0
   149
jens@0
   150
jens@18
   151
- (NSView*) fullScreenView
jens@18
   152
{
jens@18
   153
    return _fullScreenView ?: self;
jens@18
   154
}
jens@18
   155
jens@0
   156
- (IBAction) enterFullScreen: (id)sender
jens@0
   157
{
jens@18
   158
    //[self _removeGameBoard];
jens@18
   159
    if( self.fullScreenView.isInFullScreenMode ) {
jens@18
   160
        [self.fullScreenView exitFullScreenModeWithOptions: nil];
jens@0
   161
    } else {
jens@18
   162
        [self.fullScreenView enterFullScreenMode: self.window.screen 
jens@18
   163
                                     withOptions: nil];
jens@0
   164
    }
jens@18
   165
    //[self createGameBoard];
jens@10
   166
}
jens@10
   167
jens@10
   168
jens@10
   169
- (void)viewWillStartLiveResize
jens@10
   170
{
jens@10
   171
    [super viewWillStartLiveResize];
jens@10
   172
    _oldSize = self.frame.size;
jens@10
   173
}
jens@10
   174
jens@10
   175
- (void)setFrameSize:(NSSize)newSize
jens@10
   176
{
jens@10
   177
    [super setFrameSize: newSize];
jens@10
   178
    if( _oldSize.width > 0.0f ) {
jens@16
   179
        CGAffineTransform xform = _table.affineTransform;
jens@10
   180
        xform.a = xform.d = MIN(newSize.width,newSize.height)/MIN(_oldSize.width,_oldSize.height);
jens@18
   181
        BeginDisableAnimations();
jens@22
   182
        [self _applyPerspective];
jens@16
   183
        _table.affineTransform = xform;
jens@18
   184
        EndDisableAnimations();
jens@10
   185
    } else
jens@10
   186
        [self createGameBoard];
jens@10
   187
}
jens@10
   188
jens@10
   189
- (void)viewDidEndLiveResize
jens@10
   190
{
jens@10
   191
    [super viewDidEndLiveResize];
jens@10
   192
    _oldSize.width = _oldSize.height = 0.0f;
jens@10
   193
    [self createGameBoard];
jens@0
   194
}
jens@0
   195
jens@0
   196
jens@0
   197
#pragma mark -
jens@0
   198
#pragma mark KEY EVENTS:
jens@0
   199
jens@0
   200
jens@18
   201
- (BOOL) performKeyEquivalent: (NSEvent*)ev
jens@0
   202
{
jens@18
   203
    if( [ev.charactersIgnoringModifiers hasPrefix: @"\033"] ) {       // Esc key
jens@18
   204
        if( self.fullScreenView.isInFullScreenMode ) {
jens@18
   205
            [self performSelector: @selector(enterFullScreen:) withObject: nil afterDelay: 0.0];
jens@18
   206
            // without the delayed-perform, NSWindow crashes right after this method returns!
jens@18
   207
            return YES;
jens@18
   208
        }
jens@0
   209
    }
jens@18
   210
    return NO;
jens@0
   211
}
jens@0
   212
jens@0
   213
jens@0
   214
#pragma mark -
jens@0
   215
#pragma mark HIT-TESTING:
jens@0
   216
jens@0
   217
jens@5
   218
/** Converts a point from window coords, to this view's root layer's coords. */
jens@5
   219
- (CGPoint) _convertPointFromWindowToLayer: (NSPoint)locationInWindow
jens@5
   220
{
jens@5
   221
    NSPoint where = [self convertPoint: locationInWindow fromView: nil];    // convert to view coords
jens@22
   222
    where = [self convertPointToBase: where];                               // then to layer base coords
jens@22
   223
    return [self.layer convertPoint: NSPointToCGPoint(where)                // then to transformed layer coords
jens@22
   224
                          fromLayer: self.layer.superlayer];
jens@5
   225
}
jens@5
   226
jens@5
   227
jens@0
   228
// Hit-testing callbacks (to identify which layers caller is interested in):
jens@0
   229
typedef BOOL (*LayerMatchCallback)(CALayer*);
jens@0
   230
jens@0
   231
static BOOL layerIsBit( CALayer* layer )        {return [layer isKindOfClass: [Bit class]];}
jens@0
   232
static BOOL layerIsBitHolder( CALayer* layer )  {return [layer conformsToProtocol: @protocol(BitHolder)];}
jens@0
   233
static BOOL layerIsDropTarget( CALayer* layer ) {return [layer respondsToSelector: @selector(draggingEntered:)];}
jens@0
   234
jens@0
   235
jens@0
   236
/** Locates the layer at a given point in window coords.
jens@0
   237
    If the leaf layer doesn't pass the layer-match callback, the nearest ancestor that does is returned.
jens@0
   238
    If outOffset is provided, the point's position relative to the layer is stored into it. */
jens@0
   239
- (CALayer*) hitTestPoint: (NSPoint)locationInWindow
jens@0
   240
         forLayerMatching: (LayerMatchCallback)match
jens@0
   241
                   offset: (CGPoint*)outOffset
jens@0
   242
{
jens@5
   243
    CGPoint where = [self _convertPointFromWindowToLayer: locationInWindow ];
jens@16
   244
    CALayer *layer = [_table hitTest: where];
jens@0
   245
    while( layer ) {
jens@0
   246
        if( match(layer) ) {
jens@0
   247
            CGPoint bitPos = [self.layer convertPoint: layer.position 
jens@0
   248
                              fromLayer: layer.superlayer];
jens@0
   249
            if( outOffset )
jens@0
   250
                *outOffset = CGPointMake( bitPos.x-where.x, bitPos.y-where.y);
jens@0
   251
            return layer;
jens@0
   252
        } else
jens@0
   253
            layer = layer.superlayer;
jens@0
   254
    }
jens@0
   255
    return nil;
jens@0
   256
}
jens@0
   257
jens@0
   258
jens@0
   259
#pragma mark -
jens@0
   260
#pragma mark MOUSE CLICKS & DRAGS:
jens@0
   261
jens@0
   262
jens@0
   263
- (void) mouseDown: (NSEvent*)ev
jens@0
   264
{
jens@15
   265
    if( ! _game.okToMove ) {
jens@10
   266
        NSBeep();
jens@10
   267
        return;
jens@10
   268
    }
jens@10
   269
    
jens@3
   270
    BOOL placing = NO;
jens@0
   271
    _dragStartPos = ev.locationInWindow;
jens@0
   272
    _dragBit = (Bit*) [self hitTestPoint: _dragStartPos
jens@0
   273
                        forLayerMatching: layerIsBit 
jens@0
   274
                                  offset: &_dragOffset];
jens@3
   275
    
jens@3
   276
    if( ! _dragBit ) {
jens@3
   277
        // If no bit was clicked, see if it's a BitHolder the game will let the user add a Bit to:
jens@3
   278
        id<BitHolder> holder = (id<BitHolder>) [self hitTestPoint: _dragStartPos
jens@3
   279
                                                 forLayerMatching: layerIsBitHolder
jens@3
   280
                                                           offset: NULL];
jens@3
   281
        if( holder ) {
jens@3
   282
            _dragBit = [_game bitToPlaceInHolder: holder];
jens@3
   283
            if( _dragBit ) {
jens@3
   284
                _dragOffset.x = _dragOffset.y = 0;
jens@3
   285
                if( _dragBit.superlayer==nil )
jens@5
   286
                    _dragBit.position = [self _convertPointFromWindowToLayer: _dragStartPos];
jens@3
   287
                placing = YES;
jens@3
   288
            }
jens@3
   289
        }
jens@3
   290
    }
jens@3
   291
    
jens@3
   292
    if( ! _dragBit ) {
jens@3
   293
        Beep();
jens@3
   294
        return;
jens@3
   295
    }
jens@3
   296
    
jens@3
   297
    // Clicked on a Bit:
jens@3
   298
    _dragMoved = NO;
jens@3
   299
    _dropTarget = nil;
jens@3
   300
    _oldHolder = _dragBit.holder;
jens@3
   301
    // Ask holder's and game's permission before dragging:
jens@3
   302
    if( _oldHolder ) {
jens@3
   303
        _dragBit = [_oldHolder canDragBit: _dragBit];
jens@0
   304
        if( _dragBit && ! [_game canBit: _dragBit moveFrom: _oldHolder] ) {
jens@0
   305
            [_oldHolder cancelDragBit: _dragBit];
jens@0
   306
            _dragBit = nil;
jens@0
   307
        }
jens@0
   308
        if( ! _dragBit ) {
jens@0
   309
            _oldHolder = nil;
jens@0
   310
            NSBeep();
jens@0
   311
            return;
jens@0
   312
        }
jens@3
   313
    }
jens@3
   314
    
jens@3
   315
    // Start dragging:
jens@3
   316
    _oldSuperlayer = _dragBit.superlayer;
jens@3
   317
    _oldLayerIndex = [_oldSuperlayer.sublayers indexOfObjectIdenticalTo: _dragBit];
jens@3
   318
    _oldPos = _dragBit.position;
jens@3
   319
    ChangeSuperlayer(_dragBit, self.layer, self.layer.sublayers.count);
jens@3
   320
    _dragBit.pickedUp = YES;
jens@3
   321
    [[NSCursor closedHandCursor] push];
jens@3
   322
    
jens@3
   323
    if( placing ) {
jens@3
   324
        if( _oldSuperlayer )
jens@5
   325
            _dragBit.position = [self _convertPointFromWindowToLayer: _dragStartPos];
jens@3
   326
        _dragMoved = YES;
jens@3
   327
        [self _findDropTarget: _dragStartPos];
jens@3
   328
    }
jens@0
   329
}
jens@0
   330
jens@3
   331
jens@0
   332
- (void) mouseDragged: (NSEvent*)ev
jens@0
   333
{
jens@0
   334
    if( _dragBit ) {
jens@0
   335
        // Get the mouse position, and see if we've moved 3 pixels since the mouseDown:
jens@0
   336
        NSPoint pos = ev.locationInWindow;
jens@0
   337
        if( fabs(pos.x-_dragStartPos.x)>=3 || fabs(pos.y-_dragStartPos.y)>=3 )
jens@0
   338
            _dragMoved = YES;
jens@0
   339
        
jens@0
   340
        // Move the _dragBit (without animation -- it's unnecessary and slows down responsiveness):
jens@5
   341
        CGPoint where = [self _convertPointFromWindowToLayer: pos];
jens@0
   342
        where.x += _dragOffset.x;
jens@0
   343
        where.y += _dragOffset.y;
jens@0
   344
        
jens@5
   345
        CGPoint newPos = [_dragBit.superlayer convertPoint: where fromLayer: self.layer];
jens@0
   346
jens@0
   347
        [CATransaction flush];
jens@0
   348
        [CATransaction begin];
jens@0
   349
        [CATransaction setValue:(id)kCFBooleanTrue
jens@0
   350
                         forKey:kCATransactionDisableActions];
jens@0
   351
        _dragBit.position = newPos;
jens@0
   352
        [CATransaction commit];
jens@0
   353
jens@0
   354
        // Find what it's over:
jens@3
   355
        [self _findDropTarget: pos];
jens@3
   356
    }
jens@3
   357
}
jens@3
   358
jens@3
   359
jens@3
   360
- (void) _findDropTarget: (NSPoint)locationInWindow
jens@3
   361
{
jens@3
   362
    locationInWindow.x += _dragOffset.x;
jens@3
   363
    locationInWindow.y += _dragOffset.y;
jens@3
   364
    id<BitHolder> target = (id<BitHolder>) [self hitTestPoint: locationInWindow
jens@3
   365
                                             forLayerMatching: layerIsBitHolder
jens@3
   366
                                                       offset: NULL];
jens@3
   367
    if( target == _oldHolder )
jens@3
   368
        target = nil;
jens@3
   369
    if( target != _dropTarget ) {
jens@3
   370
        [_dropTarget willNotDropBit: _dragBit];
jens@3
   371
        _dropTarget.highlighted = NO;
jens@3
   372
        _dropTarget = nil;
jens@3
   373
    }
jens@3
   374
    if( target ) {
jens@3
   375
        CGPoint targetPos = [(CALayer*)target convertPoint: _dragBit.position
jens@3
   376
                                                 fromLayer: _dragBit.superlayer];
jens@3
   377
        if( [target canDropBit: _dragBit atPoint: targetPos]
jens@3
   378
           && [_game canBit: _dragBit moveFrom: _oldHolder to: target] ) {
jens@3
   379
            _dropTarget = target;
jens@3
   380
            _dropTarget.highlighted = YES;
jens@0
   381
        }
jens@0
   382
    }
jens@0
   383
}
jens@0
   384
jens@3
   385
jens@0
   386
- (void) mouseUp: (NSEvent*)ev
jens@0
   387
{
jens@0
   388
    if( _dragBit ) {
jens@0
   389
        if( _dragMoved ) {
jens@0
   390
            // Update the drag tracking to the final mouse position:
jens@0
   391
            [self mouseDragged: ev];
jens@0
   392
            _dropTarget.highlighted = NO;
jens@0
   393
            _dragBit.pickedUp = NO;
jens@0
   394
jens@0
   395
            // Is the move legal?
jens@0
   396
            if( _dropTarget && [_dropTarget dropBit: _dragBit
jens@0
   397
                                            atPoint: [(CALayer*)_dropTarget convertPoint: _dragBit.position 
jens@0
   398
                                                                            fromLayer: _dragBit.superlayer]] ) {
jens@0
   399
                // Yes, notify the interested parties:
jens@0
   400
                [_oldHolder draggedBit: _dragBit to: _dropTarget];
jens@0
   401
                [_game bit: _dragBit movedFrom: _oldHolder to: _dropTarget];
jens@0
   402
            } else {
jens@0
   403
                // Nope, cancel:
jens@0
   404
                [_dropTarget willNotDropBit: _dragBit];
jens@3
   405
                if( _oldSuperlayer ) {
jens@3
   406
                    ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
jens@3
   407
                    _dragBit.position = _oldPos;
jens@3
   408
                    [_oldHolder cancelDragBit: _dragBit];
jens@3
   409
                } else {
jens@3
   410
                    [_dragBit removeFromSuperlayer];
jens@3
   411
                }
jens@0
   412
            }
jens@0
   413
        } else {
jens@0
   414
            // Just a click, without a drag:
jens@0
   415
            _dropTarget.highlighted = NO;
jens@0
   416
            _dragBit.pickedUp = NO;
jens@0
   417
            ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
jens@0
   418
            [_oldHolder cancelDragBit: _dragBit];
jens@0
   419
            if( ! [_game clickedBit: _dragBit] )
jens@0
   420
                NSBeep();
jens@0
   421
        }
jens@9
   422
jens@0
   423
        _dropTarget = nil;
jens@0
   424
        _dragBit = nil;
jens@0
   425
        [NSCursor pop];
jens@0
   426
    }
jens@0
   427
}
jens@0
   428
jens@0
   429
jens@22
   430
- (void)scrollWheel:(NSEvent *)e
jens@22
   431
{
jens@22
   432
    self.perspective += e.deltaY * M_PI/180;
jens@22
   433
    //Log(@"Perspective = %2.0f degrees (%5.3f radians)", self.perspective*180/M_PI, self.perspective);
jens@22
   434
}
jens@22
   435
jens@22
   436
jens@0
   437
#pragma mark -
jens@0
   438
#pragma mark INCOMING DRAGS:
jens@0
   439
jens@0
   440
jens@0
   441
// subroutine to call the target
jens@0
   442
static int tell( id target, SEL selector, id arg, int defaultValue )
jens@0
   443
{
jens@0
   444
    if( target && [target respondsToSelector: selector] )
jens@0
   445
        return (ssize_t) [target performSelector: selector withObject: arg];
jens@0
   446
    else
jens@0
   447
        return defaultValue;
jens@0
   448
}
jens@0
   449
jens@0
   450
jens@0
   451
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
jens@0
   452
{
jens@0
   453
    _viewDropTarget = [self hitTestPoint: [sender draggingLocation]
jens@0
   454
                        forLayerMatching: layerIsDropTarget
jens@0
   455
                                  offset: NULL];
jens@0
   456
    _viewDropOp = _viewDropTarget ?[_viewDropTarget draggingEntered: sender] :NSDragOperationNone;
jens@0
   457
    return _viewDropOp;
jens@0
   458
}
jens@0
   459
jens@0
   460
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
jens@0
   461
{
jens@0
   462
    CALayer *target = [self hitTestPoint: [sender draggingLocation]
jens@0
   463
                        forLayerMatching: layerIsDropTarget 
jens@0
   464
                                  offset: NULL];
jens@0
   465
    if( target == _viewDropTarget ) {
jens@0
   466
        if( _viewDropTarget )
jens@0
   467
            _viewDropOp = tell(_viewDropTarget,@selector(draggingUpdated:),sender,_viewDropOp);
jens@0
   468
    } else {
jens@0
   469
        tell(_viewDropTarget,@selector(draggingExited:),sender,0);
jens@0
   470
        _viewDropTarget = target;
jens@0
   471
        if( _viewDropTarget )
jens@0
   472
            _viewDropOp = [_viewDropTarget draggingEntered: sender];
jens@0
   473
        else
jens@0
   474
            _viewDropOp = NSDragOperationNone;
jens@0
   475
    }
jens@0
   476
    return _viewDropOp;
jens@0
   477
}
jens@0
   478
jens@0
   479
- (BOOL)wantsPeriodicDraggingUpdates
jens@0
   480
{
jens@0
   481
    return (_viewDropTarget!=nil);
jens@0
   482
}
jens@0
   483
jens@0
   484
- (void)draggingExited:(id <NSDraggingInfo>)sender
jens@0
   485
{
jens@0
   486
    tell(_viewDropTarget,@selector(draggingExited:),sender,0);
jens@0
   487
    _viewDropTarget = nil;
jens@0
   488
}
jens@0
   489
jens@0
   490
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
jens@0
   491
{
jens@0
   492
    return tell(_viewDropTarget,@selector(prepareForDragOperation:),sender,YES);
jens@0
   493
}
jens@0
   494
jens@0
   495
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
jens@0
   496
{
jens@0
   497
    return [_viewDropTarget performDragOperation: sender];
jens@0
   498
}
jens@0
   499
jens@0
   500
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
jens@0
   501
{
jens@0
   502
    tell(_viewDropTarget,@selector(concludeDragOperation:),sender,0);
jens@0
   503
}
jens@0
   504
jens@0
   505
- (void)draggingEnded:(id <NSDraggingInfo>)sender
jens@0
   506
{
jens@0
   507
    tell(_viewDropTarget,@selector(draggingEnded:),sender,0);
jens@0
   508
}
jens@0
   509
jens@0
   510
@end