Finderからアプリケーションへのアイコン(ファイルやフォルダ)のドラッグ&ドロップは、もうひとつのファイルのオープン方法として、Macユーザの間ではすっかりお馴染みです。今回から数回に分けて、こうしたドラッグ&ドロップ処理のアプリケーションへの実装について解説したいと思います。
ウィンドウ上へドラッグ&ドロップされたアイコンから情報を得て、そのファイルをオープンするといった処理は、数多くのアプリケーションで採用されています。こうした処理は、Drag ManagerのAPIを使うことで実現します。本サンプルアプリケーションでも、画像ファイルやフォルダ(Finderのアイコン)を直接カタログウィンドウのブラウザ上にドロップすることで、その情報を登録することが可能です。以前、「コールバックルーチンの初期化」を紹介した時にもお話しましたが、ドラッグ&ドロップを利用するには、まずは2つのコールバックルーチン(Callback Routine)をシステムに登録(インストール)する必要があります。それを実行しているのがsetupDrag()ルーチンです。

コールバックルーチンとは、システムに制御が渡っている間、一時的に制御をアプリ側に戻すためにシステム側から実行されるルーチンのことです。setupDrag()では2つのコールバックルーチンを登録しています。そのうち、InstallTrackingHandler()で登録されているmyTrackDrag()ルーチンは、アイコンをドラッグしている間に継続して呼ばれます。また、InstallReceiveHandler()で登録されているmyReciveDrag()ルーチンは、アイコンをドロップした瞬間に呼ばれます。
各コールバックルーチンに渡される引数や返り値は、Universal InterfacesのDrag.hに定義されていますので、そちらを参照してください。Mac OS X 10.1から「DragActions」に関係するAPIがいくつか追加されましたが、それ以外の仕組みはMac OS 9の時代からからほとんど変更ありません。以前にも言及しましたが、setupDrag()でコールバックルーチン名の先頭に付けている(DragTrackingHandlerProcPtr)や(DragReceiveHandlerProcPtr)といったキャストは、Mac OS Xネイティブアプリケーションであれば不必要なはずです。しかし、Drag.hの定義内容にミスがあるのか、キャストを記述しないとコンパイルエラーが発生しますので注意してください。
通常、Drag Managerを利用する場合には、次の3つの処理を実装する必要があります。まずは、ドラッグ最中の処理(Tracking処理)、そしてドロップされたデータを受け取る処理(Receive処理)、最後に自分のデータをドラッグして相手に渡す処理(Send処理)です。本サンプルアプリケーションでは、アプリケーション側のデータを別アプリ(Finderなど)に渡す機能はありませんので、Tracking処理とReceive処理のみを実装します。まずは、Tracking処理の方を見てみることにします。Tracking処理の目的は、ユーザにドロップ可能なターゲット領域(通常は矩形枠)を知らせるために、その領域を強調色(ハイライト色)で表示し直すことにあります。そのためには、ドラッグされているデータ(PICTとかファイル保存場所)が受け取り可なのか不可なのかを判断する必要もあります。以下が、InstallTrackingHandler()でシステムへ登録されたmyTrackDrag()ルーチンです。

myTrackDrag()では、ドラッグデータの状態が引数で渡されるDragTrackingMessageの値によって判断できる仕組みになっています。メッセージには、kDragTrackingEnterWindow、kDragTrackingInWindow、kDragTrackingLeaveWindowの3種類があり、それぞれドラッグされているデータ(例えばアイコン)がウィンドウ領域へ入った時、ウィンドウ領域内を移動している時、ウィンドウ領域から外れた時に伝達されます。まずは、ドラッグがウィンドウ領域へ入った時に、そのデータが受け取り可能かどうかをtrackDragAcceptType()ルーチンで判断します。

今回はターゲット領域となるウィンドウはカタログウィンドウのみで、それ以外のウィンドウ(画像表示ウィンドウなど)はアイコンドロップのターゲット領域とはなりません。その判断は、GetWRefCon()で得たウィンドウタイプで判断します。ターゲットがカタログウィンドウであれば、GetFlavorFlags()を使いドラッグされているデータの種類が受け取り可能かどうかを判断します。今回はドラッグされているデータタイプが'hfs 'の場合にのみ受け取ることができます。もし、受け取れると判断されれば、trackDragInWindow()により、ターゲット領域を特定します。

ドラッグ&ドロップ処理ではウィンドウ全領域がターゲット領域となる場合が多いのですが(Finderなどがそう)、今回はウィンドウ内のブラウザコントロールの矩形枠が唯一のターゲット領域となります。もし、ウィンドウ内に複数のターゲット領域が存在しているとすれば、外部変数のd_cnbにその識別番号(1から始まる)を記録して強調枠を描いたり削除したりする場合の判断に用います。以下が、ターゲット領域の矩形枠を強調色で描画するtrackDragDrawHilite()ルーチンです。

もし、ターゲット領域をウィンドウ枠ひとつだけに限定すれば、このルーチンはずっと簡単な処理となります。現在のDrag Managerではウィンドウのテーマ(背景)が「しましま」であると、何故だかShowDragHilite()を実行しても強調色で矩形が描画されません(涙)。背景が真っ白なドキュメントウィンドウならOKなのですが、「しましま」テーマであっても何らかの強調を行うのが、ユーザインターフェースガイドライン的には正しいと思うのですが....。
次回は、Finderからドラッグされてきたアイコンがターゲット領域(ブラウザ)へドロップされた瞬間の処理、つまりInstallReceiveHandler()で登録されているmyReciveDrag()について解説したいと思います。
copyright 2005 Ottimo, Inc. All rights reserved
無断転載・引用禁止
Contact us: koike@ottimo.co.jp