|
HMDT - Special Issue / Sketch BP / Sketch に見るドローオブジェクトの移動、変形 |
- Case Study -
Sketch に見るドローオブジェクトの移動、変形
|
|
Sketch/DocumentMode.subproj/SKTGraphic.m
|
- (void)drawHandleAtPoint:(NSPoint)point inView:(SKTGraphicView *)view {
NSRect handleRect;
handleRect.origin.x = point.x - SKT_HALF_HANDLE_WIDTH + 1.0;
handleRect.origin.y = point.y - SKT_HALF_HANDLE_WIDTH + 1.0;
handleRect.size.width = SKT_HANDLE_WIDTH - 1.0;
handleRect.size.height = SKT_HANDLE_WIDTH - 1.0;
handleRect = [view centerScanRect:handleRect];
[[NSColor controlDarkShadowColor] set];
NSRectFill(handleRect);
handleRect = NSOffsetRect(handleRect, -1.0, -1.0);
[[NSColor knobColor] set];
NSRectFill(handleRect);
}
|
要は、NSRectFill() を使って、2 回四角形を描いてるわけだ。これを、ドローオブジェクトの周りに 8 回繰り返せば、ノブが描かれるってわけだ。
では、コードを最初から見ていこう。スタートポイントは、お約束の SKTGraphicView の mouseDown: だ。
mouseDown: の次は、selectAndTrackMouseWithEvent: に入ることになるんだ。
Sketch/SKTGraphicView.m- (void)mouseDown:(NSEvent *)theEvent { Class theClass = [[SKTToolPaletteController sharedToolPaletteController] currentGraphicClass]; ... if (theClass) { ... } else { [self selectAndTrackMouseWithEvent:theEvent]; } }
では次へ。
このメソッドの中で、移動をするのか、変形をするのか分かれることになるぜ。
Sketch/SKTGraphicView.m- (void)selectAndTrackMouseWithEvent:(NSEvent *)theEvent { ... curPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil]; graphic = [self graphicUnderPoint:curPoint]; isSelected = (graphic ? [self graphicIsSelected:graphic] : NO); ... if (graphic) { // Add or remove this graphic from selection. if (extending) { ... } 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; } ... }
まずは、変形の方からチェックが入る。変形とみなす条件は、
これだけの条件を満たすと、変形の処理が始まるぜ(trackKnob:ofGraphic:wtihEvent:)!
この条件のうち、マウスの下にノブが無い場合は、移動の処理に移るんだ(moveSelectedGraphicsWithEvent:)。
変形するためのメソッドを見てみよう。ノブのトラックをトレースする trackKnob:ofGraphic:withEvent: だ。
Sketch/SKTGraphicView.m- (void)trackKnob:(int)knob ofGraphic:(SKTGraphic *)graphic withEvent:(NSEvent *)theEvent { ... while (1) { theEvent = [[self window] nextEventMatchingMask: (NSLeftMouseDraggedMask | NSLeftMouseUpMask)]; point = [self convertPoint:[theEvent locationInWindow] fromView:nil]; [self invalidateGraphic:graphic]; if (snapsToGrid) { point.x = floor((point.x / spacing) + 0.5) * spacing; point.y = floor((point.y / spacing) + 0.5) * spacing; } knob = [graphic resizeByMovingKnob:knob toPoint:point]; [self invalidateGraphic:graphic]; if (echoToRulers) { [self continueEchoingMoveToRulers:[graphic bounds]]; } if ([theEvent type] == NSLeftMouseUp) { break; } } ... }
もう結構何度も見たような気がする、内部イベントループだ。マウスのドラッグと、ボタンアップを待っているね。マウスがドラッグされたら、ノブの位置と、どの座標に移動したか、という情報を resizeByMovingKnob:toPoint: で SKTGraphic に設定しているんだ。これでオブジェクトの大きさが変わるんだ。
変形するためのメソッドを見てみよう。ノブのトラックをトレースする trackKnob:ofGraphic:withEvent: だ。
Sketch/SKTGraphicView.m- (void)moveSelectedGraphicsWithEvent:(NSEvent *)theEvent { ... while (1) { theEvent = [[self window] nextEventMatchingMask: (NSLeftMouseDraggedMask | NSLeftMouseUpMask)]; curPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil]; if (!isMoving && ((fabs(curPoint.x - lastPoint.x) >= 2.0) || (fabs(curPoint.y - lastPoint.y) >= 2.0))) { isMoving = YES; [selGraphics makeObjectsPerformSelector: @selector(startBoundsManipulation)]; _gvFlags.knobsHidden = YES; } if (isMoving) { ... if (!NSEqualPoints(lastPoint, curPoint)) { for (i=0; i<c; i++) { graphic = [selGraphics objectAtIndex:i]; [self invalidateGraphic:graphic]; [graphic moveBy:NSMakePoint( curPoint.x - lastPoint.x, curPoint.y - lastPoint.y)]; [self invalidateGraphic:graphic]; if (echoToRulers) { [self continueEchoingMoveToRulers: NSMakeRect( curPoint.x - selOriginOffset.x, curPoint.y - selOriginOffset.y, NSWidth(selBounds), NSHeight(selBounds))]; } didMove = YES; } _pasteCascadeDelta.x += (curPoint.x - lastPoint.x); _pasteCascadeDelta.y += (curPoint.y - lastPoint.y); } lastPoint = curPoint; } if ([theEvent type] == NSLeftMouseUp) { break; } } if (echoToRulers) { [self stopEchoingMoveToRulers]; } if (isMoving) { [selGraphics makeObjectsPerformSelector: @selector(stopBoundsManipulation)]; _gvFlags.knobsHidden = NO; ... } }
このメソッド、すげー長いよ。理解するのも一苦労。説明するのは難しすぎ。とりあえず、ポイントだけ押さえておこう。
っていう、こんな感じの流れね。
|
Home | Link | Download | Back Number | Speciall Issue
|