home link download back number special issue

HMDT - Special Issue / Sketch BP / ドローオブジェクトに状態調査を追加


- Modification -

ドローオブジェクトに状態調査を追加

ドローオブジェクトの状態調査

ドローオブジェクトは、SKTGraphic っていうルートクラスを持っているんだ。円オブジェクトとか、四角オブジェクトは、こいつから派生している。Sketch にいくつかのツールを追加するために、ベースとなる SKTGraphic も機能強化しよう。

ここでは、いまドローオブジェクトがどういう状態にあるか?、っていうことを調査するためのメソッドを追加してみよう。たとえば、今はオブジェクトを作っている最中なのか?それともオブジェクトを動かしているのか?ということを、調べるためのものだよ。そのために、クリックしてドラッグを開始したときの状況を、もっと詳しく調べておく必要があるんだ。

追加されるのは、

  • オブジェクトの作成中か?
  • オブジェクトを作成しているならば、どちらの方向に向かって作っているのか?
  • オブジェクトのサイズを変更中か?
  • オブジェクトの移動中か?

っていう機能のメソッドだ。

これらのメソッドを追加するには、いまの SKTGraphic のインスタンス変数だけでは、足りないものがあるんだ。それは、

  • ドラッグの開始点(特にオブジェクトを作るとき)

だ。これは、オブジェクトをどっちの方向に作っているのか(右下か?左上か?)、っていうことを調べるのに必要なんだ。これも追加しよう。


インスタンス変数の追加

じゃ、まず、SKTGraphic に 1 個インスタンス変数を追加する。名前は _startPoint。ドラッグの開始点を覚えておくための、NSPoint 型の変数だ。

Sketch/DocumentModel.subproj/SKTGraphic.h
@interface SKTGraphic : NSObject <NSCopying> {
    @private
    SKTDrawDocument *_document;
    NSRect _bounds;
    NSRect _origBounds;
    float _lineWidth;
    NSColor *_fillColor;
    NSColor *_strokeColor;
    struct __gFlags {
        unsigned int drawsFill:1;
        unsigned int drawsStroke:1;
        unsigned int manipulatingBounds:1;
        unsigned int _pad:29;
    } _gFlags;
// By mkino [start]
    NSPoint _startPoint;
// By mkino [end]
}

こんな感じで、最後に 1 個追加する。


メソッドの追加

次にメソッドを追加する。カテゴリを作ってそこに追加しよう。カテゴリの名前は、SKTBoundManipulation だ。

Sketch/DocumentModel.subproj/SKTGraphic.h
// By mkino [start]
@interface SKTGraphic (SKTBoundManipulation)

- (NSRect)originalBounds;
- (NSPoint)startPoint;
- (BOOL)isCreating;
- (BOOL)isSizeChanging;
- (BOOL)isMoving;
- (int)directionOfCreating;

@end
// By mkino [end]

追加されているのは 6 つ。最初の 2 つは、インスタンス変数にアクセスするためのもの。originalBounds は、インスタンス変数 _origBounds を取得するためのもの。この変数は、最初からあるんだけど、アクセッサはなかったんだ。次のは _startPoint のためのアクセッサ。

残りの 4 つは、状態を調べるためのもの。作成中かどうかを調べる isCreating。大きさの変更中かどうかを調べる isSizeChanging。移動中かどうかを調べる isMoving。そして、作成中ならどっちに向かって作っているかを調べる directionOfCreating だ。

directionOfChanging は、方向を表す定数を返すんだ。それも定義しないと。こんな感じで。

Sketch/DocumentModel.subproj/SKTGraphic.h
// By mkino [start]
enum {
    NoneDirection 		= 0, 
    UpperRightDirection	= 1, 
    UpperLeftDirection	= -1, 
    LowerLeftDirection	= -2, 
    LowerRightDirection	= 2, 
};
// By mkino [end]

それぞれ、デフォルト値、右上、左上、左下、右下を表しているんだ。値が中途半端なのは、変換をやりやすくするため。-1 をかけると垂直反転、2 をかけるか 2 で割ると水平反転、になるようにしてるんだ。


_startPoint のための実装

_startPoint を追加したために、必要な実装を見てみよう。

まず、初期化。当然だね。

Sketch/DocumentModel.subproj/SKTGraphic.m
- (id)init {
    self = [super init];
    if (self) {
        ...

// By mkino [start]
        _startPoint = NSZeroPoint;
// By mkino [end]
    }
    return self;
}

init の中で、NSZeroPoint に初期化してやるんだ。

そして、値を代入してやるのは、ここ。createWithEvent:inView: の中だ。

Sketch/DocumentModel.subproj/SKTGraphic.m
- (BOOL)createWithEvent:(NSEvent *)theEvent inView:(SKTGraphicView *)view {
    NSPoint point = 
        [view convertPoint:[theEvent locationInWindow] fromView:nil];
    ...

// By mkino [start]
    _startPoint = point;
// By mkino [end]

最初にクリックされたポイントを保存しておくんだ。以上。


_origBounds のための実装

_origBounds は、もともと実装されているんだけど、1 つだけ修正をしておく。サイズの変更とかが終わった後で、_origBounds の値も、新しくなった境界の値にしておく。

Sketch/DocumentModel.subproj/SKTGraphic.m
- (void)stopBoundsManipulation {
    if (_gFlags.manipulatingBounds) {
        // Restore the original bounds, the set the new bounds.
        if (!NSEqualRects(_origBounds, _bounds)) {
            NSRect tmp;

            _gFlags.manipulatingBounds = NO;
            tmp = _bounds;
            _bounds = _origBounds;
            [self setBounds:tmp];
// mkino [start]
            _origBounds = tmp;
// mkino [stop]
        } else {
            _gFlags.manipulatingBounds = NO;
        }
    }
}

_origBounds が、名前の通りの、もとの境界の大きさを表すのは、ドラッグをしている最中だけ、ということね。


メソッドの実装

いよいよメソッドの実装だ。一気にいくよ!

まず、最初の 2 つ、originalBoundsstartPoint は簡単。

Sketch/DocumentModel.subproj/SKTGraphic.m
- (NSRect)originalBounds {
    return _origBounds;
}

- (NSPoint)startPoint {
    return _startPoint;
}

普通のアクセッサだね。

続いて、状況調査のためのメソッド、最初の 3 つ。

Sketch/DocumentModel.subproj/SKTGraphic.m
- (BOOL)isCreating
{
    return NSEqualRects(_origBounds, NSMakeRect(0.0, 0.0, 1.0, 1.0));
}

- (BOOL)isSizeChanging
{
    return !NSEqualSizes(_bounds.size, _origBounds.size);
}

- (BOOL)isMoving
{
    return NSEqualSizes(_bounds.size, _origBounds.size) && 
           !NSEqualPoints(_bounds.origin, _origBounds.origin);
}

isCreating は、_origBounds をデフォルト値と比較してやることで判別してる。デフォルト値が { 0.0, 0.0, 1.0, 1.0 } なんだ。

isSizeChanging は、_bounds_origBounds のサイズを比較することで分かる。

それに対して isMoving は、_bounds_origBounds の、サイズが変わっていなくて、起点が変わっていることで、判別してるんだ。

そして、最後の 1 つ。directionOfCreating

Sketch/DocumentModel.subproj/SKTGraphic.m
- (int)directionOfCreating
{
    if (_startPoint.x == _bounds.origin.x && 
        _startPoint.y > _bounds.origin.y) 
    {
        // Upper right
        return UpperRightDirection;
    }
    else if (_startPoint.x == _bounds.origin.x && 
             _startPoint.y == _bounds.origin.y) 
    {
        // Lower right
        return LowerRightDirection;
    }
    else if (_startPoint.x > _bounds.origin.x && 
             _startPoint.y > _bounds.origin.y) 
    {
        // Upper left
        return UpperLeftDirection;
    }
    else if (_startPoint.x > _bounds.origin.x && 
             _startPoint.y == _bounds.origin.y) 
    {
        // Lower left
        return LowerLeftDirection;
    }
    
    return NoneDirection;
}

ドラッグの開始点である _startPoint と、現在の領域である _bounds を比べることで、どっちにドラッグしているかを調べているんだ。もっとスマートなやり方もあるのかもしれないけど、とりあえず力業でやってみた。


- ソースコードのダウンロード -

HMDT - Download / Sketch BP


Home | Link | Download | Back Number | Speciall Issue

Sketch BP

mailto: mkino@xd5.so-net.ne.jp

HMDT