2011年5月8日日曜日

Cocoa FileManager Cellのダブルクリック・ディレクトリの場合


画像のような状態で「アプリケーション」をダブルクリックすると、「アプリケーション」ディレクトリに入れるようにする。

OutlineViewではディレクトリのみを選択できる。右側の「FileCellView」では、OutlineViewの選択行が変更されたら(これはdelegateメソッドで通知されるので簡単)、選択ディレクトリ内のファイル一覧を取得するようになっている。

ということは、FileCellViewでディレクトリがダブルクリックされたら、そのディレクトがOutlineViewで選択状態になればいい。FileCellViewに表示されているのは、OutlineViewで選択されたディレクトリ以下のファイル・ディレクトリなので、検索する範囲も非常に限られているから具合がいい。

FileCellViewでディレクトリがダブルクリックされた、NotificationでそれをOutlineViewに通知する。
FileCellViewのmouseDownは今のところこんな風になっている。
-(void)mouseDown:(NSEvent *)theEvent{
    NSRect rect=[self bounds];
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
   
    
    NSInteger cellRow,cellCollunm;
    cellRow=(rect.size.height-point.y)/maxCellSize.height;
    cellCollunm=point.x/maxCellSize.width;
   
    NSInteger max=(rect.size.height/maxCellSize.height);
 
    NSInteger index=cellRow+cellCollunm*max;
    if(index< [contentFileArray count]){
        if(index!=activeCellIndex){
            FileCell*cell=[contentFileArray objectAtIndex:index];
            if(NSPointInRect(point, [cell cellFrameRect])){
                if(activeCellIndex>-1){
                    cell=[contentFileArray objectAtIndex:activeCellIndex];
                    cell.cellState=CELL_STATE_NORMAL;
                }
                cell=[contentFileArray objectAtIndex:index];
                cell.cellState=CELL_STATE_SELECTED;
                activeCellIndex=index;
                [self setNeedsDisplay:YES];
                if([theEvent clickCount]==2){//double click
                    if ([cell isDirectory]) {
                        
                        [[NSNotificationCenter defaultCenter] postNotificationName:@"DirectoryDoubleClickedNotification" object:self];
                    }
                }
            }// else Nothing do            
        }
        else{//TODO FileName Text Edit mode(activeIndex==index)
            if([theEvent clickCount]==2){//double click
                FileCell* cell=[contentFileArray objectAtIndex:index];
             
                if ([cell isDirectory]) {
                
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"DirectoryDoubleClickedNotification" object:self];
                   
                }
            }

        }
        
    }// else Nothing do
    
}
非選択状態のCellがダブルクリックされた時、すでに選択されているCellがダブルクリックされた時、と2か所でNotificationをpostするようになっているが、実際に実行してみると「1度目のクリックで選択」、「2度目のクリックで選択状態のCellをダブルクリック」と判断されるようで、「非選択状態のCellをダブルクリック」は事実上起きないようだ。なるほどなあ。

mouseDownはこの後もっと汚くならざるを得ない運命が待っている。(^^;)どうやって切り分けていこうかなあ。

さて、Notificationを受け取った側は
-(void)directoryDoubleClicked:(id)sender{
    NSString* path= [ (FileCellView*)[sender object] activeIndexCellFullPath];
    if(path!=nil){
        FileSystemItem* item=[outLineView itemAtRow:[outLineView selectedRow]];
        FileSystemItem* newItem=[item chiledItemAtFullPath:path];
     
        NSInteger index=[outLineView rowForItem:newItem];
        NSIndexSet *indexSet=[[[NSIndexSet alloc]initWithIndex:index]autorelease];
        [outLineView selectRowIndexes:indexSet byExtendingSelection:NO];
        [outLineView scrollRowToVisible:index];
    }

}

現在の選択行の下位ディレクトリから、FileCellViewでダブルクリックされたディレクトリを特定して、それを新しい選択行にしている。

とまあ書けば簡単なんだけど、ここに至るまで細かいメソッドをたくさん書いて、それが正常に動いているか確かめて、となんだかとても時間がかかった感じがする。

で、「アプリケーション」ディレクトリをダブルクリックすると

こんな感じで左右両方のペインのViewで展開できるようになった。

2011年5月7日土曜日

Cocoa FileManager Cellの選択

本日は「クリックしたファイル名が反転表示される」ところまで。


ファイル名その他はNSCellのサブクラスを使って描画している。そりゃNSViewを使えばマウスのイベント処理とか楽なんだけど、おそらく表示する数が多くなると処理が重く、メモリも食うと思われ・・・って試したことないな。今度試すか。(^^;)Tabん時も同じ展開だった気がする。

とりあえず現在はCell。マウスイベントの処理もできるようなんだけど、Cellを乗っけているViewでのmouseDownでもけっこう簡単に処理できるのでそっちからやってみる。

-(void)mouseDown:(NSEvent *)theEvent{
    NSRect rect=[self bounds];
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
   
    
    NSInteger cellRow,cellCollunm;
    cellRow=(rect.size.height-point.y)/maxCellSize.height;
    cellCollunm=point.x/maxCellSize.width;
   
    NSInteger max=(rect.size.height/maxCellSize.height);
 
    NSInteger index=cellRow+cellCollunm*max;
    if(index< [contentFileArray count] && index!=activeCellIndex){
        FileCell*cell=[contentFileArray objectAtIndex:index];
        if(NSPointInRect(point, [cell cellFrameRect])){
            if(activeCellIndex>-1){
                cell=[contentFileArray objectAtIndex:activeCellIndex];
                cell.cellState=CELL_STATE_NORMAL;
            }
            cell=[contentFileArray objectAtIndex:index];
            cell.cellState=CELL_STATE_SELECTED;
            activeCellIndex=index;
            [self setNeedsDisplay:YES];
        }
    }    
}

マウスのポインタの位置からクリックされたCellを判別して、そのcellStateを変えてsetNeedDisplay、というごく簡単な流れ。

Cellは自分のstateによって背景色や文字色を変えているだけ。今の段階ではこれでいいだろう、と。選択された段階でもう1回クリックされたら、今度はファイル名変更、というのがOSXでの一般的な動作だから、それをやってみるか・・・。それともダブルクリックで実行、のほうが簡単かな。

このViewとCellはFileManagerの一番ユーザ側のUIになるから、できるようにしたいことややってみたいことがたくさんあって、ちょっとめまいがする気分。ひとつずつていねいに調べて実現していくしかないなあ。

2011年5月6日金曜日

異星人の郷 読了

異星人の郷 下 (創元SF文庫)
マイクル・フリン
東京創元社
売り上げランキング: 2864

昨日の昼過ぎに読了。いやー、いい作品でした。人物造型がいい。特にエイリアン、それにディートリヒ神父。

現代のパートのオチが、ほほー、そっちできたか、という感動もある。私はシャロンの発見がメインのネタになると思っていたので。

こうなるともっとSFが読みたくなるもので、また明日あたり図書館にいってこようかな。
新刊も旧刊もほとんど買わなくなったケチ体質、というのも理由だが、私が住んでいるような田舎町だと新刊書店より図書館のほうがSFの在庫が豊富だったりするのね。早川の在庫の少なさは悲惨です。

Cocoa FileManager NSURLと日本語

昨夜ビルドしたプロジェクトをなんとなくいじっていて、頻繁にメモリエラーが出る症状を確認。
原因の1つは NSFileManagerのインスタンスを[[NSFileManager alloc]init];から[NSFileManager defaultManager];に変えていたのに、[fileManager release];していたこと。

このあたり、メモリ管理の理解が今イチ弱い。一生懸命
詳解 Objective-C 2.0 改訂版
荻原 剛志
ソフトバンククリエイティブ
売り上げランキング: 15188
この本を読み込むしかないな。ざっとググって調べたところでは、

Cocoa倶楽部(仮称)
このサイトの「Cocoaのメモリ管理(3)」が参考になった。のちのちの自分のために引用しておく。

基本としてオブジェクトのオーナシップを意識する。すなわち、以下の鉄則を厳守する。

【鉄則1】自分で生成したオブジェクトは、自分で解放する
【鉄則2】他人が生成したオブジェクトは、気に留めない
【鉄則3】他人が生成したオブジェクトが必要なら、必ず保持(retain)して、必要にならなくなった時点で、必ず解除(release or autorelease)する

可能な限り alloc-init系の生成メソッドは使わない。【鉄則2からの派生】
なるほど。自分の作ったクラスでも「コンビニエンスメソッド」をつくりなさい、ということなので心がけるようにしよう。

もうひとつ、特定のディレクトリにアクセスしようとすると確実にアプリが落ちる現象があって、日本語ディレクトリがだめみたい。これも「NSURL 日本語」でググルとある程度の情報が手に入る。UTF8にしないといけない、みたい。ただ、現在のところ、
valid = [fileManager fileExistsAtPath:path isDirectory:&isDir];
    if (valid && isDir) {
        NSURL* url=[[NSURL alloc]initFileURLWithPath:path isDirectory:YES];

とやっておくと日本語でも全然OKであることが判明。むー、理由がよくわからないので明日以降研究しよう。[NSURL alloc]initFileURLWithPath:path isDirectory:YESならOKというのが・・・。

OutlineViewのほうはpath関係は全部NSStringでやっているので、これのNSURLへの書き換えもしたいので、ここはていねいに調べながらやっていきたいところ。いい加減な知識でプログラミングを進めていくと結局痛い目にあうのは自分なので、先をあせらず勉強。(と自分を戒める(^^;))

早いところ「Ese開発開始」といきたいところなんだけど。

2011年5月5日木曜日

Cocoa FileManager 右側のペイン 独自View 考え中

本日の収穫。
NSScrollViewの上に独自Viewをはりつけて、[scrollView setDocumentView:独自View]とすれば、独自Viewのframeの大きさによってNSScrollViewがスクロールの面倒を自動でみてくれる、ということがわかった。なるほど。

NSURLでファイルの更新日時やファイルサイズを取得できるようになったので、こんどはそれを表示する。表示専用の独自Cellを用意してあるので、そこでdrawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlViewを書けばいいわけだが・・・。「ファイル名+サイズ+更新日時」を1セットにしたい。これだと目視でだいたい350くらい必要。(・・・350の単位はピクセルでいいのか?(^^;)そんなこともわかっていないという)Cellのwidthを固定にしてしまえば描画はかなり楽になりそう。あとは表示すべきファイルの数によって、Cellを乗せるViewのframeの大きさを変えてやればいい、と。Cellの大きさは表示する項目の数によって変えてやればいいだろう。

しかしそうなると、Windowがリサイズされた時に独自Viewのリサイズをどうするのか。現在のコードでいうと、リサイズされたらdrawRect:(NSRect)dirtyRectが呼ばれるわけで、そこで必ずCellの大きさに基づいた表示数を計算する仕様だから大丈夫か。

また、アクティブなCell(の表示にはまだ手をつけてないけど)を動かしたときのスクロールはどうなるか。これはキー入力に対応してみないとわからないな。

とかなんとか考えながら、本日はこんな感じで終了。


その一方でNSTableViewでの表示もやりたいし、いろいろと迷い中。FinderのGrid表示みたいなのもやりたいしなあ。

右側のペインは
1,独自描画のFDclone風View
2,NSTableView
3,Grid表示
の3つでだいたい決定か。

2011年5月4日水曜日

休日

午前中はずっと読書。

異星人の郷 下 (創元SF文庫)
マイクル・フリン
東京創元社
売り上げランキング: 33694

下巻に突入。
午後からはプログラミングをしたり読書をしたり、のんびり過ごす。いいお休みだった。

「異星人の郷」、大変おもしろい。エイリアンに布教するあたり、踏み絵の国に住んでいる人間としては若干違和感があるけど。

Cocoa FileManager NSURL

そこで初めてファイルの属性を取得する方法を勉強する。すごく泥縄だなあ。いつもだけど。
改めて
Low-Level File Management Programming Topics

を読んでみたら・・・10.6以降はファイル関係はNSStringではなくてNSURLを使え、と書いてあった。がちょーん。これまでのところ、全部path関係はNSStringで作ってしまった。

NSURLは全然使ったことがなかったが、ドキュメントを読むとファイル属性を簡単に取得できるようだ。というわけで実験開始。
OutlineViewから渡ってくるのはディレクトリを表す文字列path。これをURLにして、
 NSURL* url=[[NSURL alloc]initWithString:path];
        NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey,
                               NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey,NSURLFileAllocatedSizeKey, nil];
        
        NSArray *array = [fileManager contentsOfDirectoryAtURL:url includingPropertiesForKeys:properties options:0 error:nil];
こんな感じでファイル名やら属性やらを取得できる。ファイルの属性は
NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey,
NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey,NSURLFileAllocatedSizeKey, nil];
という配列で「取得したい属性」を指定する。fileManager contentsOfDirectoryAtURL:で返ってくるNSArrayに収められたNSURLのオブジェクトに、この属性もちゃんと収めれていて、
NSString *str=nil;
[myURL getResourceValue:&str forKey:NSURLLocalizedNameKey error:nil];
こんな感じでNSURLから取り出すことができる。

で、試しにローカライズされたファイル・ディレクトリ名があればそれを表示するようにしたのが下の画像。


うむ、こっちのほうがいいかな。ただ、OutlineViewではNSStringで全部やっているので、左側のペインと右側のペインで整合性がなくなっているのがつらいところ。

これもおいおい手をつけていこう。とりあえずはファイルの取り扱いを始められるように、ファイルサイズや更新日時を表示できるようにしてみる、と。

Cocoa FileManager 右側のペイン 独自View

NSCellなどはそのままに、ViewだけNSMatrixからカスタムNSViewに変える。
Cellの描画関係はいつぞやダウンロードした木下誠氏のNSOutlineViewのサンプルからいただいたもの。
#define ICON_SIZE_WIDTH 16
#define ICON_SIZE_HEIGHT 16
#define MARGIN_X 2
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    DirectoryFile* entry = [self objectValue];
    NSString* path;
    NSRect pathRect;
    
    NSImage* iconImage;
    NSSize iconSize;
    NSPoint iconPoint;
    
    // Draw Image
    
    iconImage = [entry icon];
    iconSize = NSZeroSize;
    iconPoint.x = cellFrame.origin.x;
    iconPoint.y = cellFrame.origin.y;
    
    if(iconImage) {
        iconSize.width = ICON_SIZE_WIDTH;
        iconSize.height = ICON_SIZE_HEIGHT;
        iconPoint.x += MARGIN_X;
        
        if([controlView isFlipped]) {
            iconPoint.y += iconSize.height;
        }
        
        [iconImage setSize:iconSize];
        [iconImage compositeToPoint:iconPoint operation:NSCompositeSourceOver];
    }
    
    // Draw text
    path = [entry name];
    pathRect.origin.x = cellFrame.origin.x + MARGIN_X;
    if(iconSize.width > 0) {
        pathRect.origin.x += iconSize.width + MARGIN_X;
    }
    pathRect.origin.y = cellFrame.origin.y;
    pathRect.size.width = cellFrame.size.width - (pathRect.origin.x - cellFrame.origin.x);
    pathRect.size.height = cellFrame.size.height;
    
    if(path) {
        [path drawAtPoint:pathRect.origin withAttributes:nil];
    }

}
このメソッドをNSView側から呼び出せばCellがファイルのアイコンとファイル名を描画してくれる。
カスタムNSViewの描画関連。

}
#define CONTENT_CELL_HEIGHT 24
#define CONTENT_CELL_WIDTH 200
#define CONTENT_CELL_LEFT_MARGINE 4
- (void)drawRect:(NSRect)dirtyRect
{
    // Drawing code here.
   
    NSRect rect=[self bounds];
    NSPoint point;
    NSSize size;
    point=NSMakePoint(CONTENT_CELL_LEFT_MARGINE, rect.size.height-CONTENT_CELL_HEIGHT);
    size=NSMakeSize(CONTENT_CELL_WIDTH, CONTENT_CELL_HEIGHT);
    for (NSInteger i=0; i<[contentFileArray count]; i++) {
        FileCell* cell=[contentFileArray objectAtIndex:i];
        NSRect cellFrameRect=NSMakeRect(point.x, point.y,size.width,size.height);
        [cell drawWithFrame:cellFrameRect inView:self];
        point.y-=CONTENT_CELL_HEIGHT;
        if (point.y<0) {
            point.y=rect.size.height-CONTENT_CELL_HEIGHT;
            point.x+=CONTENT_CELL_WIDTH+CONTENT_CELL_LEFT_MARGINE;
        }
    }
}

要は「yが0になったらxをCONTENT_CELL_WIDTH+CONTENT_CELL_LEFT_MARGINE分だけずらせ、という簡単なもの。まずはちゃんと描画することを確かめるためのコードなんでこの程度。 これがこうなる、と。

ふむふむ、これをこんどはFDcloneのような「1行・2行・3行・5行」切り替えの表示方式にしていく。
そのためにはファイルの属性を取得しなければ・・・。

2011年5月3日火曜日

図書館で借りる

1日じゅうXcode4の中にいると、ものすごく疲れることを発見。(^^;)1日くらいならいいけれど、連休中ずっと、となるとさすがに腰や右手(マウス派なので・・)が痛くなる。

この連休中は本を読みながらためにプログラミングをする、という体制で行くことに決めて、本日は図書館に出かけた。

うっしっし、あったあった。
異星人の郷 上 (創元SF文庫)
マイクル・フリン
東京創元社
売り上げランキング: 10553
借りてきました上下で。

さっそく読み始めて100ページ、いよいよエイリアンが出てきた。ワクワクする。いやー、SF読みたかったからちょうどいいや。

年数だけは筋金入りのSF者なんで、時々無性に読みたくなるんだなあ、SFが。しかし手当たり次第に読む、ということも年齢のためかできなくなっていて、評価の定まった安全牌をついつい選んでしまう。たとえば

どれだけ読めば、気がすむの?
豊崎 由美
アスペクト
売り上げランキング: 224022
こういう楽しい書評集を読むと、いろんなジャンルの小説を読みたくなるんだけど・・・ノリのいいエンタメ以外はほとんど読みきれなくなっている。今日も本当は「異星人の郷」の上巻読みきるつもりだったのに、NSMatrixをいじり始めたらあっという間に夜が更けていた。

1日が48時間くらいで、勤務時間4時間くらいにならないかな。(^^;)

Cocoa FileManager 右側のペイン NSMatrix微妙

NSMatrixで1列だけファイルを表示してみた。


左側のOutlineViewで表示するディレクトリが指定されるので、そのなかのファイルとディレクトリの各種情報を収めるクラス、そのクラスをもとに1ファイル分の表示を担当するCellクラス、と作っていって、最後はNSMatrixに [matrixView addRowWithCells:array];で1行ずつ渡している。

NSMatrixの行と列の数の指定がけっこう不自由で、addRowWithCellsでファイルの配列を渡すと、「その行(Row)の中に配列の中のファイルを横に並べていく」という動作をする。しかし横に並べるときは、あらかじめaddColumnで並べる分だけのColumnを作っておかないといけない、ようだ。

もっと柔軟に追加とか削除とかできないと面倒かも、と感じている。ウィンドウのサイズを変えると自動的に並べ替えてくれる、とか、そういうものではなさそうだ。そういう機能がほしい時はNSCollectionViewを使え、ということか。しかしNSCollectionViewはひとつのファイルを表示するのに、NSViewとNSViewControllerを使うという贅沢仕様だし。

やはり自分でNSViewとNSCellを使って地道に作ったほうが、結局は好きなようにできる感じがするなあ。どうしよう。明日以降だなあ。

2011年5月2日月曜日

Smart Cover到着(^^;)

やはり本日届きました、Smart Cover。仕方ないので一応箱から出して触ってみる。

・・・けっこう重くね?という感じ。ま、本体も来ていないうちからあれこれ騒いでもしょうがない。

あとは本体の発送メールを待つばかり。とりあえず今日はメール、まだ来ておりません。早くて今週末、と踏んでいるが・・・。予定通り2週間後かもしれないし。

Cocoa FileManager 右側のペイン

えーと、tabbedInterfaceの自分用FileManagerを作ろうとしている、とやっと書いてもいい状態になってきたかな。tabの話題から久しぶりに離れることができそう。

tabの中にNSSplitViewをおいて、左側のペインにNSOutlineViewを置いた。これはディレクトリ表示用。おおまかにはすでに出来上がっている。

で、今度は右側のペイン。

なにも表示はしていないが、scrollerをAutoHideにしたNSScrollViewを置いてある。この上に、NSMatrixを入れてみようと考えている。

右側のペインは当然「とあるフォルダの中の、フォルダとファイル」を表示するためにある。どのように表示させるべきか。Finderのまねをしても仕方がない。Finderでできることをひと通りなぞってみる、という方法はあるが、とりあえずそれはやらない。まず自分が一番やってみたいこと、から始めようと考えている。

右側のペインはFileManagerの心臓部にあたるので、これを「FDclone」風に表示できるか試してみようかな、と思っている。つまりこれ。


これはいわゆる「2列表示」、1列にも3列にも5列にもできるんだけど一番好きなのが2列。まずはこの状態にできるかがんばってみる。ファイルを表示するのに「アイコン+ファイル名+ファイルサイズ+更新日時」をワンパックにしてNSCellに描画して、それを並べるという計画。

うーん、うまくいくかなあ。NSMatrixはけっこう鬼門だからなあ。だからこそ再挑戦、という意味もある。

2011年5月1日日曜日

Art Text 2 Lite

MacStoreでたまたま見かけてインストールしてみたArt Text 2 Lite。


あはは、これはいい。MacStoreのコメントにあるとおり、ワードアートみたいな感じで文字加工ができて、それを画像に落とせる、というツール。ホームページビルダーにも似たようなツールがついていたような記憶が。

10分ほどで作ってみたのがこの画像。

文字主体のICONが簡単に作れそう。いいツールを発見した。
ちなみ開発元はここでした。
BeLight Software

Cocoa Tabbed Interface KVOとバインディング

Tab関連ほぼ完成。見た目がアレなのはおいおいなんとかしたいところ。いやこれ、本当に大事なところで、見た目がしょぼいと作る気がなくなってしまうので、もう少しCoolにしたいですな。

TabBarの下に、tablessなNSTabViewをくっつけて、この2つをTabBarControllerで管理する構成にしてみた。xibファイルはこんな感じ。


tabが追加されるときにNSTabViewItemも同時に挿入する。tabの現在のアクティブなindexをkeyにして、キー値監視でNSTabViewのselectionと同期をとっている。

NSTabViewItemにoutlineViewをのっけたViewを載せて、今日のところはここまで。




キー値監視、KVOはあちこちで解説を読んでよくわからなかったが、実際に使ってみれば「なーんだ」というほど簡単でウルトラ便利であることがわかった。
「他のクラスのオブジェクトの、メンバ変数の変更をいつでも通知してもらえる」、という感じでありましょうか。これがNotificationを使うとなると、メンバ変数の値を変更するたびにNotificationをPostしなければいけないが、KVOなら一度addObserverしておけばOK、と。

これをInterfaceBuilderだけでやってしまおう、というのがつまりCocoaバインディングだったのね。
もちろん、
詳解 Objective-C 2.0 改訂版
荻原 剛志
ソフトバンククリエイティブ
売り上げランキング: 15847
この本の解説がなければかなり苦労したであろうと思われる。必読書ですな、荻原本は。欲をいえばもうちょっと詳しくひとつひとつのAPIの用例とかもあると・・・ってそれじゃあ倍の厚さになってしまうか。

2011年4月30日土曜日

Smart Cover発送される

本日、Smart Coverを発送した、というメールが届く。到着予定が5月4日とな。

順当なら月曜日あたりで届くはずだけど、震災の影響を加味している、ということかな。
iPad2本体はいつになることやら。Smart Coverだけで何をして遊ぼうかなあ(^^;)。

Cocoa Tabbed Interface Notification

overflowボタンを押した、という通知はNotificationでやってみる。これにはメニュー表示を伴うため、NSEventが必要になる。KVOでもNSDictionaryをつけることができるからNotificationにしなければいけない必然性はない。ま、なんでもやってみるということで。

-(void)mouseDown:(NSEvent *)theEvent{
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    if(buttonState!=OV_DISABLE){
        if (NSPointInRect(point, buttonImageRect)){
            if(buttonState==OV_HOVER){
                buttonState=OV_PUSHED;
                isPress=YES;
            }
            [self setNeedsDisplay:YES];
        }
    }
}
-(void)mouseUp:(NSEvent *)theEvent{
    NSPoint point = [self convertPointFromBase:[theEvent locationInWindow]];
    if(buttonState!=OV_DISABLE){
        if (NSPointInRect(point, buttonImageRect)){
            if(buttonState==OV_PUSHED){
                
                buttonState=OV_HOVER;
                isPress=NO;
                NSDictionary* userInfo=[NSDictionary dictionaryWithObject:theEvent forKey:@"buttonEvent" ];
              
                [[NSNotificationCenter defaultCenter]postNotificationName:@"OverflowButtonIsPressed" object:self userInfo:userInfo];
                //[self tabScroll:OV_LEFT :theEvent];                
            }
        }
        else buttonState=OV_NORMAL;
        [self setNeedsDisplay:YES];
    }
}

isPressってのがKVO用に用意していたメンバなわけだが、結局使ってないな。こんな感じでNSEventをNSDictionaryに収めてNotificationを飛ばし、これをTabBarControllerで受ける、と。

だいたいこれでTab関係の書き直しが終了したので、本日は新しいプロジェクトを作ってtab関連のファイルをコピーして使えるか試してもみた。

実はこれですごい苦労をした。.xibファイルのコピーって鬼門なのかな。TabBarControllerの- (id)initWithNibName:でKVOのaddObserverが有効にならないし、nib上のViewのメンバを書き換えられなくなった。うーん、と腕を組んだけど- (id)initWithNibName:以外ならIBOutletでつながれたViewにちゃんとアクセスできたのでそれでよしとする。要調査。

2011年4月29日金曜日

iPad2発注

本日からiPad2がオンラインストアでも注文できるということなので、Apple Storeを覗いてみたら発送は1〜2週かかるとある。

ふむ、いちおうSoftBankの店頭の状況を確認しようと、近所の大型家電店のSoftBankコーナーで聞いてみたら、「白の16G、3Gモデルなら若干の在庫あり。Wifiモデルはすでに売り切れ、再入荷は早くて3週間後」というお答え。

それならもうApple Storeで買ってしまえということで「黒・16G・Wifiモデル+Smart Coverポリウレタン青」を注文した。

発送予定はきっちり2週間後。しかしSmart Coverだけは1週間後に届く予定。ちょっと悲しいな。

今回はお母ちゃんもけっこう乗り気なので、届くのが楽しみだ。

Cocoa Tabbed Interface NSViewControllerで作り直し(2) キー値監視

TabbedInterfaceを実現するために、現在作っているのは
・Tab・・tabそのものの描画とイベント処理をするクラス
・TabBar・・tabをsubViewとして管理するクラス、tabのoverflowなどの処理をする
・OverflowButton・・tabがoverflowした時に表示される>>みたいなボタン
・TabbarController・・以上のクラスのインスタンスを管理するクラス

以上4つ。このうちOverflowButtonを新しく作ったので、けっこう苦労している。TabとTabBarだけの時は実質ひとつのView(TabBar)でユーザー入力を処理していたので、コードがごちゃごちゃになった点を除けば[self 〜]でほとんどの処理ができたが、現在は複数のViewを同期させる必要ある。・・・といっても実質2つか(^^;)。

TabBar上でtabが描画しきれなくなったのでOverflowButtonを表示させたい、という場合、どうやってインスタンス同士が連携するのか本日勉強。

ま、一番わかりやすいのはNotificationですわな。その他、キー値監視という仕組みを使えばいいらしいことは知っていた。というわけでKVOを初めて使ってみた。苦労しましたわ、理解するまで。

TabBar上のstartIndexという数値が変化したら、その値を調べてOverflowButtonの動作を変更したい、というのがやりたい処理。どちらのクラスについても「知っている」必要があるので、結局TabbarController上で(Controllerなのでnib上のIBOutletでTabBar、OverflowButton両方をメンバとして持っているわけですな)
 [tabBar addObserver:self forKeyPath:@"startIndex" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)  context:NULL];
とした上で、
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    
    if([keyPath isEqualToString:@"startIndex"]){
     
        if (tabBar.startIndex>0) {
            leftOverFlowButton.buttonState=OV_NORMAL;
            
        }

とかなんとかやればいい、ということがわかった。しかしobserveValueForKeyPath:の引数を全然つかっていないので、Notification使ったほうがスマートな感じがするなあ。

[監視されるクラス addObserver:監視するクラス forKeyPath:監視されるクラスのメンバ]という関係がわかるまでけっこう時間がかかってしまった。さらに forKeyPathで指定されたメンバの変更は、[self set〜]形式で変更されたものでないと通知されない、と。やっぱNotificationのほうが便利なような気がする・・・(^^;)

自分のクラスのプロパティが、外部のクラスで変更された時に使うのが便利なのか。

というわけで、「OverflowButtonが押された時の処理」はNotificationでやってみることにする。これは明日。

2011年4月28日木曜日

Cocoa Tabbed Interface NSViewControllerで作ってみる

これまでつくってきたTab、TabBarに、OverflowButtonを新しく作りなおして、この3つのViewを管理するTabBarControllerを作ってみる。

一応NSViewContrllerのサブクラスにしてみたが(controller1つで1つのnibファイルを管理する形にできるので・・)果たしてそれで正解なのかどうかはまだわからない。NSViewContrllerの働きをわかっていないので練習のつもり。

とりあえず今日はここまで。


見た目はほとんど変わらないが、TabBarの両端にあるOverflowButtonは新しくNSViewをサブクラス化したもの。TabBarから独立させた分、表示の管理は楽になると思われる。

ただ、ControllerがTabのデータ(model?)を所持するとして、複数のViewの連携がうまくできるのかはかなり心もとない。大丈夫なのかいな、と思いつつ以降は明日。

2011年4月27日水曜日

Cocoa Tabbed Interface SplitViewをのせてみる

ある程度tabが出来上がってきたの、試しにsplitViewをのせ、さらにoutLineView、TableViewをのせて表示してみた。


なんとなくそれらしい見た目にはなった。そこで、前に作りかけたOutLineViewのプロジェクトをのぞいてみたところ、わお、課題がたくさん。全部のクラスを、ひとつずつ書きなおして(というか1から作り上げて)いかないければならないことがわかった。相当時間がかかるなあ。

当面はまずTabBarControllerから手をつけていこう。
とか書きながら、さっきまでtabの見た目をちょいちょいいじっていた。とりあえず角を丸める。

bezierPathWithRoundedRect:xRadius:yRadius:とcurveToPoint:controlPoint1:controlPoint2:の組み合わせでせこせこ描いてみた。こんなんでいいのか、という汚いソースになっている・・・。おそらくこれに「白い線」を書き加えていくともう少し立体感が出ると思われる。あるいは影か。