Source/Grid.m
author Jens Alfke <jens@mooseyard.com>
Wed Mar 12 15:51:32 2008 -0700 (2008-03-12)
changeset 6 af9b2b929b03
parent 1 3eb7be1dd7b6
child 7 428a194e3e59
permissions -rw-r--r--
Fixed: An exception in the Go game if you mouse down on the board but then drag to the captured-pieces area and release the mouse.
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 "Grid.h"
jens@0
    24
#import "Bit.h"
jens@0
    25
#import "Game.h"
jens@0
    26
#import "QuartzUtils.h"
jens@0
    27
jens@0
    28
jens@0
    29
@implementation Grid
jens@0
    30
jens@0
    31
jens@0
    32
- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
jens@0
    33
            spacing: (CGSize)spacing
jens@0
    34
           position: (CGPoint)pos
jens@0
    35
{
jens@0
    36
    NSParameterAssert(nRows>0 && nColumns>0);
jens@0
    37
    self = [super init];
jens@0
    38
    if( self ) {
jens@0
    39
        _nRows = nRows;
jens@0
    40
        _nColumns = nColumns;
jens@0
    41
        _spacing = spacing;
jens@0
    42
        _cellClass = [GridCell class];
jens@1
    43
        self.lineColor = kBlackColor;
jens@0
    44
        _allowsMoves = YES;
jens@0
    45
        _usesDiagonals = YES;
jens@0
    46
jens@0
    47
        self.bounds = CGRectMake(-1, -1, nColumns*spacing.width+2, nRows*spacing.height+2);
jens@0
    48
        self.position = pos;
jens@0
    49
        self.anchorPoint = CGPointMake(0,0);
jens@0
    50
        self.zPosition = kBoardZ;
jens@0
    51
        self.needsDisplayOnBoundsChange = YES;
jens@0
    52
        
jens@0
    53
        unsigned n = nRows*nColumns;
jens@0
    54
        _cells = [[NSMutableArray alloc] initWithCapacity: n];
jens@0
    55
        id null = [NSNull null];
jens@0
    56
        while( n-- > 0 )
jens@0
    57
            [_cells addObject: null];
jens@0
    58
jens@0
    59
        [self setNeedsDisplay];
jens@0
    60
    }
jens@0
    61
    return self;
jens@0
    62
}
jens@0
    63
jens@0
    64
jens@0
    65
- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
jens@0
    66
              frame: (CGRect)frame
jens@0
    67
{
jens@0
    68
    CGFloat spacing = floor(MIN( (frame.size.width -2)/(CGFloat)nColumns,
jens@0
    69
                               (frame.size.height-2)/(CGFloat)nRows) );
jens@3
    70
    CGSize size = CGSizeMake(nColumns*spacing+2, nRows*spacing+2);
jens@3
    71
    CGPoint position = frame.origin;
jens@3
    72
    position.x += round( (frame.size.width -size.width )/2.0 );
jens@3
    73
    position.y += round( (frame.size.height-size.height)/2.0 );
jens@3
    74
jens@0
    75
    return [self initWithRows: nRows columns: nColumns
jens@0
    76
                      spacing: CGSizeMake(spacing,spacing)
jens@3
    77
                     position: position];
jens@0
    78
}
jens@0
    79
jens@0
    80
jens@0
    81
- (void) dealloc
jens@0
    82
{
jens@0
    83
    CGColorRelease(_cellColor);
jens@0
    84
    CGColorRelease(_lineColor);
jens@0
    85
    [_cells release];
jens@0
    86
    [super dealloc];
jens@0
    87
}
jens@0
    88
jens@0
    89
jens@0
    90
static void setcolor( CGColorRef *var, CGColorRef color )
jens@0
    91
{
jens@0
    92
    if( color != *var ) {
jens@0
    93
        CGColorRelease(*var);
jens@0
    94
        *var = CGColorRetain(color);
jens@0
    95
    }
jens@0
    96
}
jens@0
    97
jens@0
    98
- (CGColorRef) cellColor                        {return _cellColor;}
jens@0
    99
- (void) setCellColor: (CGColorRef)cellColor    {setcolor(&_cellColor,cellColor);}
jens@0
   100
jens@0
   101
- (CGColorRef) lineColor                        {return _lineColor;}
jens@0
   102
- (void) setLineColor: (CGColorRef)lineColor    {setcolor(&_lineColor,lineColor);}
jens@0
   103
jens@0
   104
@synthesize cellClass=_cellClass, rows=_nRows, columns=_nColumns, spacing=_spacing,
jens@0
   105
            usesDiagonals=_usesDiagonals, allowsMoves=_allowsMoves, allowsCaptures=_allowsCaptures;
jens@0
   106
jens@0
   107
jens@0
   108
#pragma mark -
jens@0
   109
#pragma mark GEOMETRY:
jens@0
   110
jens@0
   111
jens@0
   112
- (GridCell*) cellAtRow: (unsigned)row column: (unsigned)col
jens@0
   113
{
jens@0
   114
    if( row < _nRows && col < _nColumns ) {
jens@0
   115
        id cell = [_cells objectAtIndex: row*_nColumns+col];
jens@0
   116
        if( cell != [NSNull null] )
jens@0
   117
            return cell;
jens@0
   118
    }
jens@0
   119
    return nil;
jens@0
   120
}
jens@0
   121
jens@0
   122
jens@0
   123
/** Subclasses can override this, to change the cell's class or frame. */
jens@0
   124
- (GridCell*) createCellAtRow: (unsigned)row column: (unsigned)col 
jens@0
   125
               suggestedFrame: (CGRect)frame
jens@0
   126
{
jens@0
   127
    return [[[_cellClass alloc] initWithGrid: self 
jens@0
   128
                                        row: row column: col
jens@0
   129
                                      frame: frame]
jens@0
   130
                    autorelease];
jens@0
   131
}
jens@0
   132
jens@0
   133
jens@0
   134
- (GridCell*) addCellAtRow: (unsigned)row column: (unsigned)col
jens@0
   135
{
jens@0
   136
    NSParameterAssert(row<_nRows);
jens@0
   137
    NSParameterAssert(col<_nColumns);
jens@0
   138
    unsigned index = row*_nColumns+col;
jens@0
   139
    GridCell *cell = [_cells objectAtIndex: index];
jens@0
   140
    if( (id)cell == [NSNull null] ) {
jens@0
   141
        CGRect frame = CGRectMake(col*_spacing.width, row*_spacing.height,
jens@0
   142
                                  _spacing.width,_spacing.height);
jens@0
   143
        cell = [self createCellAtRow: row column: col suggestedFrame: frame];
jens@0
   144
        if( cell ) {
jens@0
   145
            [_cells replaceObjectAtIndex: index withObject: cell];
jens@0
   146
            [self addSublayer: cell];
jens@0
   147
            [self setNeedsDisplay];
jens@0
   148
        }
jens@0
   149
    }
jens@0
   150
    return cell;
jens@0
   151
}
jens@0
   152
jens@0
   153
jens@0
   154
- (void) addAllCells
jens@0
   155
{
jens@0
   156
    for( int row=_nRows-1; row>=0; row-- )                // makes 'upper' cells be in 'back'
jens@0
   157
        for( int col=0; col<_nColumns; col++ ) 
jens@0
   158
            [self addCellAtRow: row column: col];
jens@0
   159
}
jens@0
   160
jens@0
   161
jens@0
   162
- (void) removeCellAtRow: (unsigned)row column: (unsigned)col
jens@0
   163
{
jens@0
   164
    NSParameterAssert(row<_nRows);
jens@0
   165
    NSParameterAssert(col<_nColumns);
jens@0
   166
    unsigned index = row*_nColumns+col;
jens@0
   167
    id cell = [_cells objectAtIndex: index];
jens@0
   168
    if( cell != [NSNull null] )
jens@0
   169
        [cell removeFromSuperlayer];
jens@0
   170
    [_cells replaceObjectAtIndex: index withObject: [NSNull null]];
jens@0
   171
    [self setNeedsDisplay];
jens@0
   172
}
jens@0
   173
jens@0
   174
jens@0
   175
#pragma mark -
jens@0
   176
#pragma mark DRAWING:
jens@0
   177
jens@0
   178
jens@0
   179
- (void) drawCellsInContext: (CGContextRef)ctx fill: (BOOL)fill
jens@0
   180
{
jens@0
   181
    // Subroutine of -drawInContext:. Draws all the cells, with or without a fill.
jens@0
   182
    for( unsigned row=0; row<_nRows; row++ )
jens@0
   183
        for( unsigned col=0; col<_nColumns; col++ ) {
jens@0
   184
            GridCell *cell = [self cellAtRow: row column: col];
jens@0
   185
            if( cell )
jens@0
   186
                [cell drawInParentContext: ctx fill: fill];
jens@0
   187
        }
jens@0
   188
}
jens@0
   189
jens@0
   190
jens@0
   191
- (void)drawInContext:(CGContextRef)ctx
jens@0
   192
{
jens@0
   193
    // Custom CALayer drawing implementation. Delegates to the cells to draw themselves
jens@0
   194
    // in me; this is more efficient than having each cell have its own drawing.
jens@3
   195
    [super drawInContext: ctx];
jens@0
   196
    if( _cellColor ) {
jens@0
   197
        CGContextSetFillColorWithColor(ctx, _cellColor);
jens@0
   198
        [self drawCellsInContext: ctx fill: YES];
jens@0
   199
    }
jens@0
   200
    if( _lineColor ) {
jens@0
   201
        CGContextSetStrokeColorWithColor(ctx,_lineColor);
jens@0
   202
        [self drawCellsInContext:ctx fill: NO];
jens@0
   203
    }
jens@0
   204
}
jens@0
   205
jens@0
   206
jens@0
   207
@end
jens@0
   208
jens@0
   209
jens@0
   210
jens@0
   211
#pragma mark -
jens@0
   212
jens@0
   213
@implementation GridCell
jens@0
   214
jens@0
   215
jens@0
   216
- (id) initWithGrid: (Grid*)grid 
jens@0
   217
                row: (unsigned)row column: (unsigned)col
jens@0
   218
              frame: (CGRect)frame
jens@0
   219
{
jens@0
   220
    self = [super init];
jens@0
   221
    if (self != nil) {
jens@0
   222
        _grid = grid;
jens@0
   223
        _row = row;
jens@0
   224
        _column = col;
jens@0
   225
        self.position = frame.origin;
jens@0
   226
        CGRect bounds = frame;
jens@0
   227
        bounds.origin.x -= floor(bounds.origin.x);  // make sure my coords fall on pixel boundaries
jens@0
   228
        bounds.origin.y -= floor(bounds.origin.y);
jens@0
   229
        self.bounds = bounds;
jens@0
   230
        self.anchorPoint = CGPointMake(0,0);
jens@0
   231
        self.borderColor = kHighlightColor;         // Used when highlighting (see -setHighlighted:)
jens@0
   232
    }
jens@0
   233
    return self;
jens@0
   234
}
jens@0
   235
jens@0
   236
- (NSString*) description
jens@0
   237
{
jens@0
   238
    return [NSString stringWithFormat: @"%@(%u,%u)", [self class],_column,_row];
jens@0
   239
}
jens@0
   240
jens@0
   241
@synthesize grid=_grid, row=_row, column=_column;
jens@0
   242
jens@0
   243
jens@0
   244
- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
jens@0
   245
{
jens@0
   246
    // Default implementation just fills or outlines the cell.
jens@0
   247
    CGRect frame = self.frame;
jens@0
   248
    if( fill )
jens@0
   249
        CGContextFillRect(ctx,frame);
jens@0
   250
    else
jens@0
   251
        CGContextStrokeRect(ctx, frame);
jens@0
   252
}
jens@0
   253
jens@0
   254
jens@0
   255
- (void) setBit: (Bit*)bit
jens@0
   256
{
jens@0
   257
    if( bit != self.bit ) {
jens@0
   258
        [super setBit: bit];
jens@0
   259
        if( bit ) {
jens@0
   260
            // Center it:
jens@0
   261
            CGSize size = self.bounds.size;
jens@0
   262
            bit.position = CGPointMake(floor(size.width/2.0),
jens@0
   263
                                       floor(size.height/2.0));
jens@0
   264
        }
jens@0
   265
    }
jens@0
   266
}
jens@0
   267
jens@0
   268
- (Bit*) canDragBit: (Bit*)bit
jens@0
   269
{
jens@0
   270
    if( _grid.allowsMoves && bit==self.bit )
jens@0
   271
        return [super canDragBit: bit];
jens@0
   272
    else
jens@0
   273
        return nil;
jens@0
   274
}
jens@0
   275
jens@0
   276
- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
jens@0
   277
{
jens@0
   278
    return self.bit == nil || _grid.allowsCaptures;
jens@0
   279
}
jens@0
   280
jens@0
   281
jens@0
   282
- (BOOL) fwdIsN 
jens@0
   283
{
jens@0
   284
    return self.game.currentPlayer.index == 0;
jens@0
   285
}
jens@0
   286
jens@0
   287
jens@0
   288
- (NSArray*) neighbors
jens@0
   289
{
jens@0
   290
    BOOL orthogonal = ! _grid.usesDiagonals;
jens@0
   291
    NSMutableArray *neighbors = [NSMutableArray arrayWithCapacity: 8];
jens@0
   292
    for( int dy=-1; dy<=1; dy++ )
jens@0
   293
        for( int dx=-1; dx<=1; dx++ )
jens@0
   294
            if( (dx || dy) && !(orthogonal && dx && dy) ) {
jens@0
   295
                GridCell *cell = [_grid cellAtRow: _row+dy column: _column+dx];
jens@0
   296
                if( cell )
jens@0
   297
                    [neighbors addObject: cell];
jens@0
   298
            }
jens@0
   299
    return neighbors;
jens@0
   300
}
jens@0
   301
jens@0
   302
jens@0
   303
// Recursive subroutine used by getGroup:.
jens@0
   304
- (void) x_addToGroup: (NSMutableSet*)group liberties: (NSMutableSet*)liberties owner: (Player*)owner
jens@0
   305
{
jens@0
   306
    Bit *bit = self.bit;
jens@0
   307
    if( bit == nil ) {
jens@0
   308
        if( [liberties containsObject: self] )
jens@0
   309
            return; // already traversed
jens@0
   310
        [liberties addObject: self];
jens@0
   311
    } else if( bit.owner==owner ) {
jens@0
   312
        if( [group containsObject: self] )
jens@0
   313
            return; // already traversed
jens@0
   314
        [group addObject: self];
jens@0
   315
        for( GridCell *c in self.neighbors )
jens@0
   316
            [c x_addToGroup: group liberties: liberties owner: owner];
jens@0
   317
    }
jens@0
   318
}
jens@0
   319
jens@0
   320
jens@0
   321
- (NSSet*) getGroup: (int*)outLiberties
jens@0
   322
{
jens@0
   323
    NSMutableSet *group=[NSMutableSet set], *liberties=nil;
jens@0
   324
    if( outLiberties )
jens@0
   325
        liberties = [NSMutableSet set];
jens@0
   326
    [self x_addToGroup: group liberties: liberties owner: self.bit.owner];
jens@0
   327
    if( outLiberties )
jens@0
   328
        *outLiberties = liberties.count;
jens@0
   329
    return group;
jens@0
   330
}
jens@0
   331
jens@0
   332
jens@0
   333
#pragma mark -
jens@0
   334
#pragma mark DRAG-AND-DROP:
jens@0
   335
jens@0
   336
jens@1
   337
#if ! TARGET_OS_ASPEN
jens@1
   338
jens@0
   339
// An image from another app can be dragged onto a Dispenser to change the Piece's appearance.
jens@0
   340
jens@0
   341
jens@0
   342
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
jens@0
   343
{
jens@0
   344
    NSPasteboard *pb = [sender draggingPasteboard];
jens@0
   345
    if( [NSImage canInitWithPasteboard: pb] )
jens@0
   346
        return NSDragOperationCopy;
jens@0
   347
    else
jens@0
   348
        return NSDragOperationNone;
jens@0
   349
}
jens@0
   350
jens@0
   351
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
jens@0
   352
{
jens@0
   353
    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
jens@0
   354
    if( image ) {
jens@0
   355
        CGColorRef pattern = CreatePatternColor(image);
jens@0
   356
        _grid.cellColor = pattern;
jens@0
   357
        CGColorRelease(pattern);
jens@0
   358
        [_grid setNeedsDisplay];
jens@0
   359
        return YES;
jens@0
   360
    } else
jens@0
   361
        return NO;
jens@0
   362
}
jens@0
   363
jens@1
   364
#endif
jens@0
   365
jens@0
   366
@end
jens@0
   367
jens@0
   368
jens@0
   369
jens@0
   370
jens@0
   371
#pragma mark -
jens@0
   372
jens@0
   373
@implementation RectGrid
jens@0
   374
jens@0
   375
jens@0
   376
- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
jens@0
   377
            spacing: (CGSize)spacing
jens@0
   378
           position: (CGPoint)pos
jens@0
   379
{
jens@0
   380
    self = [super initWithRows: nRows columns: nColumns spacing: spacing position: pos];
jens@0
   381
    if( self ) {
jens@0
   382
        _cellClass = [Square class];
jens@0
   383
    }
jens@0
   384
    return self;
jens@0
   385
}
jens@0
   386
jens@0
   387
jens@0
   388
- (CGColorRef) altCellColor                         {return _altCellColor;}
jens@0
   389
- (void) setAltCellColor: (CGColorRef)altCellColor  {setcolor(&_altCellColor,altCellColor);}
jens@0
   390
jens@0
   391
jens@0
   392
@end
jens@0
   393
jens@0
   394
jens@0
   395
jens@0
   396
#pragma mark -
jens@0
   397
jens@0
   398
@implementation Square
jens@0
   399
jens@0
   400
jens@0
   401
- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
jens@0
   402
{
jens@0
   403
    if( fill ) {
jens@0
   404
        CGColorRef c = ((RectGrid*)_grid).altCellColor;
jens@0
   405
        if( c ) {
jens@0
   406
            if( ! ((_row+_column) & 1) )
jens@0
   407
                c = _grid.cellColor;
jens@0
   408
            CGContextSetFillColorWithColor(ctx, c);
jens@0
   409
        }
jens@0
   410
    }
jens@0
   411
    [super drawInParentContext: ctx fill: fill];
jens@0
   412
}
jens@0
   413
jens@0
   414
jens@0
   415
- (void) setHighlighted: (BOOL)highlighted
jens@0
   416
{
jens@0
   417
    [super setHighlighted: highlighted];
jens@3
   418
    self.cornerRadius = self.bounds.size.width/2.0;
jens@0
   419
    self.borderWidth = (highlighted ?6 :0);
jens@0
   420
}
jens@0
   421
jens@0
   422
jens@0
   423
- (Square*) nw     {return (Square*)[_grid cellAtRow: _row+1 column: _column-1];}
jens@0
   424
- (Square*) n      {return (Square*)[_grid cellAtRow: _row+1 column: _column  ];}
jens@0
   425
- (Square*) ne     {return (Square*)[_grid cellAtRow: _row+1 column: _column+1];}
jens@0
   426
- (Square*) e      {return (Square*)[_grid cellAtRow: _row   column: _column+1];}
jens@0
   427
- (Square*) se     {return (Square*)[_grid cellAtRow: _row-1 column: _column+1];}
jens@0
   428
- (Square*) s      {return (Square*)[_grid cellAtRow: _row-1 column: _column  ];}
jens@0
   429
- (Square*) sw     {return (Square*)[_grid cellAtRow: _row-1 column: _column-1];}
jens@0
   430
- (Square*) w      {return (Square*)[_grid cellAtRow: _row   column: _column-1];}
jens@0
   431
jens@0
   432
// Directions relative to the current player:
jens@0
   433
- (Square*) fl     {return self.fwdIsN ?self.nw :self.se;}
jens@0
   434
- (Square*) f      {return self.fwdIsN ?self.n  :self.s;}
jens@0
   435
- (Square*) fr     {return self.fwdIsN ?self.ne :self.sw;}
jens@0
   436
- (Square*) r      {return self.fwdIsN ?self.e  :self.w;}
jens@0
   437
- (Square*) br     {return self.fwdIsN ?self.se :self.nw;}
jens@0
   438
- (Square*) b      {return self.fwdIsN ?self.s  :self.n;}
jens@0
   439
- (Square*) bl     {return self.fwdIsN ?self.sw :self.ne;}
jens@0
   440
- (Square*) l      {return self.fwdIsN ?self.w  :self.e;}
jens@0
   441
jens@0
   442
jens@1
   443
#if ! TARGET_OS_ASPEN
jens@1
   444
jens@0
   445
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
jens@0
   446
{
jens@0
   447
    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
jens@0
   448
    if( image ) {
jens@0
   449
        CGColorRef color = CreatePatternColor(image);
jens@0
   450
        RectGrid *rectGrid = (RectGrid*)_grid;
jens@0
   451
        if( rectGrid.altCellColor && ((_row+_column) & 1) )
jens@0
   452
            rectGrid.altCellColor = color;
jens@0
   453
        else
jens@0
   454
            rectGrid.cellColor = color;
jens@0
   455
        CGColorRelease(color);
jens@0
   456
        [rectGrid setNeedsDisplay];
jens@0
   457
        return YES;
jens@0
   458
    } else
jens@0
   459
        return NO;
jens@0
   460
}
jens@0
   461
jens@1
   462
#endif
jens@1
   463
jens@0
   464
@end
jens@0
   465
jens@0
   466
jens@0
   467
jens@0
   468
#pragma mark -
jens@0
   469
jens@0
   470
@implementation GoSquare
jens@0
   471
jens@0
   472
@synthesize dotted=_dotted;
jens@0
   473
jens@0
   474
- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
jens@0
   475
{
jens@0
   476
    if( fill )
jens@0
   477
        [super drawInParentContext: ctx fill: fill];
jens@0
   478
    else {
jens@0
   479
        CGRect frame = self.frame;
jens@0
   480
        const CGFloat midx=floor(CGRectGetMidX(frame))+0.5, 
jens@0
   481
                    midy=floor(CGRectGetMidY(frame))+0.5;
jens@0
   482
        CGPoint p[4] = {{CGRectGetMinX(frame),midy},
jens@0
   483
                        {CGRectGetMaxX(frame),midy},
jens@0
   484
                        {midx,CGRectGetMinY(frame)},
jens@0
   485
                        {midx,CGRectGetMaxY(frame)}};
jens@0
   486
        if( ! self.s )  p[2].y = midy;
jens@0
   487
        if( ! self.n )  p[3].y = midy;
jens@0
   488
        if( ! self.w )  p[0].x = midx;
jens@0
   489
        if( ! self.e )  p[1].x = midx;
jens@0
   490
        CGContextStrokeLineSegments(ctx, p, 4);
jens@0
   491
        
jens@0
   492
        if( _dotted ) {
jens@0
   493
            CGContextSetFillColorWithColor(ctx,_grid.lineColor);
jens@0
   494
            CGRect dot = CGRectMake(midx-2.5, midy-2.5, 5, 5);
jens@0
   495
            CGContextFillEllipseInRect(ctx, dot);
jens@0
   496
        }
jens@0
   497
    }
jens@0
   498
}
jens@0
   499
jens@1
   500
jens@0
   501
@end