- 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 つ、originalBounds と startPoint は簡単。
|
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 を比べることで、どっちにドラッグしているかを調べているんだ。もっとスマートなやり方もあるのかもしれないけど、とりあえず力業でやってみた。
|