|
HMDT - Special Issue / Sketch BP / Sketch に見るドローオブジェクトの選択 |
- Case Study -
Sketch に見るドローオブジェクトの選択
|
|
Sketch/SKTGraphicView.h
|
@interface SKTGraphicView : NSView {
...
NSMutableArray *_selectedGraphics;
|
複数選択することができるから、NSMutableArray 型だぜ。ドローオブジェクトを選択すればこの中に追加して、選択が外れれば消していくんだ。
SKTGraphicView をクリックしたら、その場所にどんなドローオブジェクトがあるか、調べる必要があるよね。それをやるのが graphicUnderPoint: だ。
Sketch/SKTGraphicView.h- (SKTGraphic *)graphicUnderPoint:(NSPoint)point { SKTDrawDocument *document = [self drawDocument]; NSArray *graphics = [document graphics]; unsigned i, c = [graphics count]; SKTGraphic *curGraphic = nil; for (i=0; i<c; i++) { curGraphic = [graphics objectAtIndex:i]; if ([self mouse:point inRect:[curGraphic drawingBounds]] && [curGraphic hitTest:point isSelected:[self graphicIsSelected:curGraphic]]) { break; } } if (i < c) { return curGraphic; } else { return nil; } }
こんな感じで一個ずつ調べていく。クリックしたポイントが、境界の四角の中にあって、ヒットテストで OK が出れば、それがクリックされたことになる。
しかし、この方法だと、ドローオブジェクトが増えたときに時間がかかり過ぎるよな。
次は、マウスクリックに始まる、ドローオブジェクトの選択の様子を見てみよう。中心になるのは、もちろん、SKTGraphicView だ。
処理のエントリは mouseDown: メソッドだ。マウスがクリックされると、ここに入るからね。
Sketch/SKTGraphicView.m- (void)mouseDown:(NSEvent *)theEvent { Class theClass = [[SKTToolPaletteController sharedToolPaletteController] currentGraphicClass]; ... if ([theEvent clickCount] > 1) { ... } if (theClass) { ... } else { [self selectAndTrackMouseWithEvent:theEvent]; } }
まず最初に、SKTToolPaletteController に、いまツールを選択してるかどうか問い合わせるんだ。何も選択してないなら(返り値が nil なら)、オブジェクトを選択することになるんだ。
次にクリックカウントを調べる。ダブルクリック以上なら別の処理になる。
そこまで調べて、次は selectAndTrackMouseWithEvent: に処理が移るんだ。
何もツールを選択してない状態で、ドローオブジェクトを 1 回クリックすると、ここに入る。
Sketch/SKTGraphicView.m- (void)selectAndTrackMouseWithEvent:(NSEvent *)theEvent { NSPoint curPoint; SKTGraphic *graphic = nil; BOOL isSelected; BOOL extending = (([theEvent modifierFlags] & NSShiftKeyMask) ? YES : NO); curPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil]; graphic = [self graphicUnderPoint:curPoint]; isSelected = (graphic ? [self graphicIsSelected:graphic] : NO); if (!extending && !isSelected) { [self clearSelection]; } if (graphic) { // Add or remove this graphic from selection. if (extending) { if (isSelected) { [self deselectGraphic:graphic]; isSelected = NO; } else { [self selectGraphic:graphic]; isSelected = YES; } } else { if (isSelected) { int knobHit = [graphic knobUnderPoint:curPoint]; if (knobHit != NoKnob) { [self trackKnob:knobHit ofGraphic:graphic withEvent:theEvent]; return; } } [self selectGraphic:graphic]; isSelected = YES; } } else { [self rubberbandSelectWithEvent:theEvent]; return; } if (isSelected) { [self moveSelectedGraphicsWithEvent:theEvent]; return; } // If we got here then there must be nothing else to do. // Just track until mouseUp:. while (1) { theEvent = [[self window] nextEventMatchingMask: (NSLeftMouseDraggedMask | NSLeftMouseUpMask)]; if ([theEvent type] == NSLeftMouseUp) { break; } } }
- シフトキーが押されているかどうか調べる
まず、シフトキーがいっしょに押されているかどうか調べるんだ。
Sketch/SKTGraphicView.m ... BOOL extending = (([theEvent modifierFlags] & NSShiftKeyMask) ? YES : NO); ...
NSEvent の modifierFlags を呼び出して、NSShiftKeyMask と論理和を取ることで分かるぜ。その結果は、extending っていう変数に入れておく。
- クリックされたドローオブジェクトを調べる
次に、クリックした先にドローオブジェクトがあるかどうか調べるよ。
Sketch/SKTGraphicView.m ... curPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil]; graphic = [self graphicUnderPoint:curPoint]; isSelected = (graphic ? [self graphicIsSelected:graphic] : NO); ...
まず、クリックした場所を調べる。そして、そこにドローオブジェクトがあるかどうかを、graphicUnderPoint: を使って調べるんだ。その後、そのドローオブジェクトがすでに選択されたものかどうかを調べておくんだ。
- ドローオブジェクトを選択する、または選択を外す
いよいよ選択するぞ!
Sketch/SKTGraphicView.m... if (!extending && !isSelected) { [self clearSelection]; } if (graphic) { // Add or remove this graphic from selection. if (extending) { if (isSelected) { [self deselectGraphic:graphic]; isSelected = NO; } else { [self selectGraphic:graphic]; isSelected = YES; } } else { if (isSelected) { int knobHit = [graphic knobUnderPoint:curPoint]; if (knobHit != NoKnob) { [self trackKnob:knobHit ofGraphic:graphic withEvent:theEvent]; return; } } [self selectGraphic:graphic]; isSelected = YES; } } else { [self rubberbandSelectWithEvent:theEvent]; return; } ...
まず、シフトキーを押さずに、いま選択しているドローオブジェクト「以外」のところをクリックした場合。すべての選択を解除するために clearSelection を呼ぶんだ。
でいよいよ次が、なにかドローオブジェクトをクリックした場合。
ってとこだ。
- 後始末
最後に後始末をする、と。
Sketch/SKTGraphicView.m... if (isSelected) { [self moveSelectedGraphicsWithEvent:theEvent]; return; } // If we got here then there must be nothing else to do. // Just track until mouseUp:. while (1) { theEvent = [[self window] nextEventMatchingMask: (NSLeftMouseDraggedMask | NSLeftMouseUpMask)]; if ([theEvent type] == NSLeftMouseUp) { break; } } }
まだドローオブジェクトが選択されてるなら、今度はドラッグの処理をする。それはまた別のところで解説するよ。
その後は、マウスが放されるまで待つ。nextEventMatchingMask: を呼びながら、ループを回すんだ。これで完了。
|
Home | Link | Download | Back Number | Speciall Issue
|