Photoshop プラグインでwxWidgetsを使用する方法

個人的なメモ。
wxWidgetsを使う理由。
Windows/Mac両用のGUIが必要。
Adobe Dialog ManagerがPhotoshop CS5 Mac(64bit)で使えなくなった。
Qtは高額なロイヤリティを払わないとソースを配布するか(スタティックリンクの場合)、リバースエンジニアリングを許可しないといけない(動的リンクでも)LGPLライセンスしか選べない。

wxWidgetsの注意点。
現在MacOS Cocoa(64bit)対応は完全ではない。
実行ファイルのサイズがどえらく肥大化する。
単一アーキテクチャ向けでビルドして5〜6MB、32/64bitユニバーサルバイナリにすると10MBオーバー。

Photoshopプラグインの基礎知識
エントリポイントで条件分岐。通常サンプルに習って、DoUI()関数を書いてそこでUIを作成。そこから先のやりかた。

wxWidgetsを使うためにはwxApp(のサブクラス)のインスタンスを作る必要がある。

class MyApp : public wxApp
{
public:
  virtual bool OnInit();
};

こんな感じの簡単なのでOK。wxAppには本格的なアプリケーションを作成するための機能が色々あるけど、モーダルダイアログを表示するだけならOnInit()で完結しちゃってかまわないと思う。

同時にダイアログもwxDiaogのサブクラスで作成しておくが、このへんは適当にwxFormBuilderとかで作っちゃえばいい。以下の例ではwxDialogのサブクラスとしてmyDialogというクラスを用意してあるものとして記述。

んで、MyAppのOnInit()メソッドで

intptr_t psParentWindow=NULL;
bool MyApp::OnInit()
{
	wxWindow* hostWindow = new wxWindow();
#ifdef __WXMSW __
	hostWindow->SetHWND((WXHWND)psParentWindow);
#endif
	myDialog *frame = new myDialog(hostWindow);


	if (frame->ShowModal()==wxID_OK){
		
	}
	if (!frame->isOK()){
		gResult = userCanceledErr;
	}
	frame->Destroy();
  

  // success
  return true;
}

モーダルダイアログがちゃんと動作するためには少なくともWindows版ではPhotoshop側のメインウィンドウを親ウィンドウとして設定してやる必要がある。これをやらないとフィルターのダイアログが出ているのにメニューや他の書類ウィンドウが操作できてしまい、フィルターダイアログが後ろに行ってしまったりして不都合が生じる。スマートではないが、グローバル変数 psParentWindow を定義し、他の場所であらかじめPhotoshopのドキュメントウィンドウへのハンドルを取得しておく。
なお、wxWindow::SetHWNDはWindows版のみのメソッドで、Mac版にはないので#ifdefで囲っておく。MacOS(Cocoa)ではこれがなくても問題ないようだ。

ここまでがwxWidgetsで書いておくべき内容。Photoshopのプラグインでこれをどう使うかというのはまあ

void DoUI(globals)
{
	PSUIHooksSuite3 *sPSUIHooks;
	sSPBasic->AcquireSuite(kPSUIHooksSuite,
                                 kPSUIHooksSuiteVersion3,     
                                 (const void **)&sPSUIHooks);
	psParentWindow = sPSUIHooks->MainAppWindow(); //親ウィンドウを取得(Photoshop内部API)

	wxChar *argv=NULL;
	int argc =0;
	wxApp::SetInstance( new MyApp() );
	wxEntryStart( argc, (char **)NULL );
	wxTheApp->OnInit();
	wxTheApp->OnExit();
	wxEntryCleanup();
}

こんな感じw
普通のwxWidgetsアプリケーションではDECLARE_APP(MyApp);とかIMPLEMENT_APP(MyApp);のマクロで初期化するのだけど、プラグインを書く場合はマクロ使わない方がよけいなことをされなくていいかも。wxAppが細かくイベント制御する必要はなくて、ダイアログのShowModal()がフィルターのUIに必要なイベント処理をうけもってくれるので。