2011年6月12日日曜日

Cocoa NSTableView サブクラス化

デフォルトのNSTableViewだと、Drag時に選択行の全部がDragImageになる。ファイル名、ファイルサイズ、更新日時が1行になるので、やたらと横に長いDragImageになってしまう。

Finderの場合はファイル名のみがDragImageになる。Finder並の動作にするためには、NSTableViewをサブクラス化するしかないようだ。delegateではできない動作となる。

どうせrightMouseDownも書きたいところだったので、本格的にサブクラス化することにした。本格的に、というのは、以前TBBOY'S ROOMさんのSimpleLyricsPlayer その31(NSTableViewでひとつのセルだけをD&Dする#2)のコードを拝借して、ファイル名のみのDragImageを作るようにしていたからだが、「ひとつのセルだけ」というタイトルからもわかるとおり、複数行を選択してもカーソル直下の1行分だけをDragImageにする方法だったわけで、これを改造するところから始める。

TBBOY'S ROOMさんのコードをよく読むと、NSImage上にNSCellのdrawInteriorWithFrameで描画をしているらしい。これをカーソル直下の1行分から、

- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent *)dragEvent offset:(NSPointPointer)dragImageOffset

で渡ってくる(NSIndexSet *)dragRows分描画するようにすればいいようだ、と見当がつく。

で、いろいろ試行錯誤の上に書いたコードがこれ。

- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent *)dragEvent offset:(NSPointPointer)dragImageOffset
{
   
    NSInteger col =0;

    if ([dragRows count]<1) {
        return nil;
    }
    NSUInteger index=[dragRows firstIndex];

    NSRect cellFrame = [self frameOfCellAtColumn:col row:index];
    
    CGFloat cellWidth=[[self tableColumnWithIdentifier:@"fileName"] width];
    CGFloat cellHeight=[self rowHeight];
    
    //NSLog(@"image size h:%f w:%f",cellHeight,cellWidth);
    
    NSSize imageSize=NSMakeSize(cellWidth,cellHeight*[dragRows count]);
  
    NSImage *dragImage = [[[NSImage alloc] initWithSize:imageSize] autorelease];
    //NSLog(@"image size w:%f h%f",[dragImage size].width,[dragImage size].height);
    [dragImage lockFocus];
    
    NSRect waku = cellFrame;
    waku.origin.x=0;
    waku.origin.y=imageSize.height-cellHeight;
    
    while (index!=NSNotFound) {
        NSCell *dragCell = [self preparedCellAtColumn:col row:index];
        [dragCell drawInteriorWithFrame:waku inView:self];
        //NSLog(@"waku origin x:%f y:%f",waku.origin.x,waku.origin.y);
        
        waku.origin.y-=cellHeight;
        index=[dragRows indexGreaterThanIndex: index];
    }
       
    [dragImage unlockFocus];
    
    *dragImageOffset=NSZeroPoint;
    //NSLog(@"offset %f %f",dragImageOffset->x,dragImageOffset->y);
    return dragImage;
}
一番調べるの時間がかかったのがNSIndexSetから、どうやってindexを順次取り出すか、というところ。これはデベロッパドキュメントにちゃんと載っていた。


で、無事DragImageが思った通りに描画された。

次は右クリックのコンテキストメニューでファイルの削除(「ごみ箱に移動」)を実装する予定。とか書いても、その日の思いつきであれこれやるので未定ではあるな。

0 件のコメント:

コメントを投稿