レイヤーをドラッグ&ドロップで移動できるようにします。レイヤーの上で右クリックするとコンテキストメニュー[レイヤー○○を移動させる]が表示されます。これをクリックすると左クリック ⇒ ドラッグ&ドロップでレイヤーの位置を変更できます。変更したあとであってもレイヤーの外側をクリックするまではドラッグで位置を変更することができます。

まずコンテキストメニューに[レイヤー○○を移動させる]を表示させます。

コンテキストメニューをクリックしたらフィールド変数 Form1.contextMenuEx1のIsMovingが変化します。左クリックされたときにForm1.ContextMenuEx.IsMovingを調べることで移動のための処理を開始すべきかどうか判断できます。処理を開始しなければならない場合は LayerMoveStart(Layer layer, Point clickPoint)メソッドが実行されます。

LayerMoveStart(Layer layer, Point clickPoint)メソッドではクリックされた場所がレイヤーの内部かどうかを調べます。レイヤーの外部がクリックされたのであれば移動させる処理はしなくてよいということになります。

では移動処理が必要な場合はどうするか? マウスキャプチャをすることでForm1にMouseUpイベントとMouseMoveイベントを捕捉できるようにします。それと同時に移動するレイヤーを枠で囲って視覚的にもわかりやすくします。このときは新たに作成した ShowLayers(Layer selectedLayer)メソッドで編集中の画像を表示させます。

ただしこの処理をするときはBitmapの生成が高速でおこなわれます。そこで毎回Bitmapを生成してScroolPictureBox.Bitmapにセットするようなことはしません。これをやると画像がカクカクしてしまいます。処理が追いつかないのです。そこで別の方法(後述)をとります。

それからLayerMoveクラスは以下のようになっています。どのレイヤーを動かすのか、レイヤーの元の位置、レイヤーを動かすためにクリックされた部分の座標(MouseUpのときの座標と比較すればどれだけ移動するのかがわかる)を格納し、実際にレイヤーを移動させるメソッドをもちます。

LayerMoveStartメソッド内でマウスキャプチャをしているのでマウスの移動やマウスボタンが離されたときの通知はForm1クラスに届きます。そこでマウスの移動やマウスボタンが離されたときの処理を書きます。

ShowLayers(Layer selectedLayer)メソッドについて

まずScroolPictureBoxクラスを改良します。やっていることはこのクラスのなかにあるPictureBoxのPaintイベントに対して処理をすることができるようになったことと、PictureBoxのPaintイベントを引き起こすことができるようにPictureBoxInvalidate()メソッドを追加したことです。

そしてForm1クラスでイベントハンドラ scroolPictureBox1.PicturePaintを追加。ShowLayers(Layer selectedLayer)メソッドが実行されたらフィールド変数に引数をコピーしてPictureBoxInvalidate()を呼び出します。するとBitmapがつくられるのは1回だけ。マウスがうごくたびにBitmapに複数のレイヤーのデータを書き込んで、これをscroolPictureBox1>Bitmap = bitmap;なんてする時間がかかる処理は行なわれなくなります。

これでレイヤーを移動させるときに動作がカクカクすることはなくなります。またコンテキストメニュー [レイヤーXXXを移動させる]を選択するとともに対象のレイヤーに枠が表示されます。そして移動が終わっても枠は消えません。右クリックをしたり、レイヤーのない部分をクリックすると枠は消えます。