FireworksのイベントをFlashパネルで監視(Extension習作)

FireworksのFlashパネル開発用AS3ライブラリFireworksEventのテストを兼ねた習作Event Viewerです。Event Viewerは、デザイン制作のお供ではなく、Flashパネルはことでどんなときにどんなイベント(処理)を受け取るのかを視覚化するのに作成しました。

Fireworks Event VIEWERスクリーンショットclearとclicpboard表示

Extension開発時にどんなタイミングでどのようにイベントが発生するかを確認するというのが主な用途です。ただ、Fireworksがどういう処理をしているのか見るのも面白いかもしれません。個人的にはドキュメントのサイズ変更のイベント発生回数に驚きました。

Extensionとして配布しませんので見てみたいという方は書きかけで申し訳ないのですが、こちらのURLを参考にCommand PanelsフォルダにFlashパネルのswfを設置してみてください。イベントはFlashパネルだけが受け取れます。そのため、コマンドではなく、パネルとして設置しないと正常に動作しないのでお気をつけください。また、全イベントを補足しているので大変パフォーマンスが落ちやすく、Fireworksの内部エラーを引き起こしかねません。大事なデータを開いているときには利用しないようにしてください。

FireworksがFlashに伝搬するイベント

FireworksはいろいろなタイミングでFlashにイベントとして状態を知らせます。

そのイベントを受け取って処理を行うにはActionScript 3.0の場合、2つの設定をする必要があります。

  • イベントを受け取るためのcallbackを設定すること
  • Fireworksにそのイベントを受け取るcallbackが存在することを示すこと

どちらも、ExternalInterface.addCallbackを使用します。解説は、Fireworksデベロッパーセンターの「ActionScript 3.0でのFireworksイベントの処理」を読んでください。ここでは簡単にコード例を示します。

ExternalInterface.addCallback("onStartMovie",startMovieHandler);
ExternalInterface.addCallback("IsFwCallbackInstalled", IsFwCallbackInstalled);

//Fireworksが叩くcallback
function startMovieHandler():void {
  MMExecute('alert("パネルが開きました")');
}
//Fireworksがイベントに対応するcallbackがあるかどうか確認するためのcallback
//trueが返ってきたときだけ、対応するcallbackを叩く仕組み
function IsFwCallbackInstalled(functionName:String ):Boolean {
  switch (functionName) {
    case "onStartMovie":
      return true;
  }
  return false;
}

ただ、毎回IsFwCallbackInstalledを登録したり、そのcallback用メソッドを用意するのは大変面倒なのと、イベント名が覚えきれないのでそれをサポートするライブラリを作成しました。それがFireworksEventクラスです。

/*
   FireworksEvent Class
   version 0.1.1

   Risa Yugucchi <risa.yuguchi@gmail.com>
   Twitter: http://twitter.com/risay
   
   history
   0.1.1	add debugMode
   0.1		created

The MIT License

Copyright (c) 2009 Risa Yuguchi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/
package jp.rstudio.extension.fw 
{
	import flash.errors.IllegalOperationError;
	import flash.external.ExternalInterface;
	import flash.utils.Dictionary;
	
	/**
	 * Fireworks APIをActionScriptから実行するためのユーティティクラス
	 * FireworksがFlashパネルに送出するイベントを登録したり削除したりする
	 * @author Risa Yuguchi <info@r-studio.jp>
	 */
	public class FireworksEvent extends Object
	{
		/**
		 * swfパネルが開いたとき、Fw起動時にワークスペースにswfパネルがあるとき。MacとWindowsで挙動が違う場合があるので検証に注意すべきイベント
		 */
		public static const START_MOVIE:String="onFwStartMovie";
		/**
		 * swfパネルが閉じられたとき。MacとWindowsで挙動が違う場合があるので検証に注意すべきイベント
		 */
		public static const STOP_MOVIE:String="onFwStopMovie";
		/**
		 * 情報パネルの単位が変更されたとき
		 */
		public static const UNITS_CHANGE:String="onFwUnitsChange";
		/**
		 * プロパティインスペクターが2行レイアウトと4行レイアウトで変更があったとき
		 */
		public static const PI_COLLAPSE_OR_EXPAND:String="onFwPICollapseOrExpand";
		/**
		 * ドキュメント名が変更されたとき
		 */
		public static const DOCUMENT_NAME_CHANGE:String="onFwDocumentNameChange";
		/**
		 * 別のフレーム(ステート)を選択したとき
		 */
		public static const CURRENT_FRAME_CHANGE:String="onFwCurrentFrameChange";
		/**
		 * 別のレイヤーを選択したとき
		 */
		public static const CURRENT_LAYER_CHANGE:String="onFwCurrentLayerChange";
		/**
		 * スクリプトにできないヒストリーステップが作られたとき
		 */
		public static const HISTORY_CHANGE:String="onFwHistoryChange";
		/**
		 * アイドルステート1段階目
		 */
		public static const IDLE_0:String="onFwIdle0";
		/**
		 * アイドルステート2段階目
		 */
		public static const IDLE_1:String="onFwIdle1";
		/**
		 * アイドルステート3段階目
		 */
		public static const IDLE_2:String="onFwIdle2";
		/**
		 * Fwがフォーカスを失ったとき
		 */
		public static const APPLICATION_DEACTIVATE:String="onFwApplicationDeactivate";
		/**
		 * Fwがフォーカスされたとき
		 */
		public static const APPLICATION_ACTIVATE:String="onFwApplicationActivate";
		/**
		 * シンボルライブラリが変更されたとき
		 */
		public static const SYMBOL_LIBRARY_CHANGE:String="onFwSymbolLibraryChange";
		/**
		 * ドキュメントにURLが追加されたとき
		 */
		public static const URL_LIST_CHANGE:String="onFwURLListChange";
		/**
		 * お気に入りURLが変更されたとき
		 */
		public static const URL_FAVORITES_CHANGE:String="onFwFavoritesChange";
		/**
		 * 環境設定が変更されたとき
		 */
		public static const PREFERENCES_CHANGE:String="onFwPreferencesChange";
		/**
		 * ドキュメントが開かれた時
		 */
		public static const DOCUMENT_OPEN:String="onFwDocumentOpen";
		/**
		 * ドキュメントが閉じられたとき
		 */
		public static const DOCUMENT_CLOSED:String="onFwDocumentClosed";
		/**
		 * ドキュメントが保存されるとき
		 */
		public static const DOCUMENT_SAVE:String="onFwDocumentSave";
		/**
		 * ドキュメントがリサイズされたとき
		 */
		public static const DOCUMENT_SIZE_CHANGE:String="onFwDocumentSizeChange";
		/**
		 * ドキュメントのビューが変更されたとき。2ペインから4ペインになったときに発生
		 */
		public static const ACTIVE_VIEW_CHANGE:String="onFwActiveViewChange";
		/**
		 * ラスター選択が変更されたとき
		 */
		public static const PIXEL_SELECTION_CHANGE:String="onFwPixelSelectionChange";
		/**
		 * 選択オブジェクトが変わったとき
		 */
		public static const ACTIVE_SELECTION_CHANGE:String="onFwActiveSelectionChange";
		/**
		 * アクティブドキュメントが変更されたとき
		 */
		public static const ACTIVE_DOCUMENT_CHANGE:String="onFwActiveDocumentChange";
		/**
		 * アクティブなツールオプションが変更されたとき
		 */
		public static const ACTIVE_TOOL_PARAMS_CHANGE:String="onFwActiveToolParamsChange";
		/**
		 * アクティブなツールが変更されたとき
		 */
		public static const ACTIVE_TOOL_CHANGE:String="onFwActiveToolChange";
		/**
		 * 拡大縮小率が変更されたとき
		 */
		public static const ZOOM_CHANGE:String="onFwZoomChange";
		/**
		 * オブジェクトの設定が変更されたとき
		 */
		public static const OBJECT_SETTING_CHANGE:String="onFwObjectSettingChange";
		
		// Fwに対して、コールバックが存在することを示す初期化処理が完了しているか
		private static var _isInit:Boolean = false;
		// コールバックリスト
		private static var _eventDic:Dictionary;
		private static var _protectedDic:Dictionary;
		/**
		 * デバッグ中かどうか
		 */
		private static var _isDebugMode:Boolean = false;
		static public function get isDebugMode():Boolean { return _isDebugMode; }
		
		static public function set isDebugMode(value:Boolean):void 
		{
			_isDebugMode = value;
		}
		
		public function FireworksEvent() 
		{
			throw new IllegalOperationError("このオブジェクトのインスタンスを作ることはできません");
		}
		
		/**
		 * Fwからイベントを受け取るためのcallbackを追加
		 * @param	event イベント名
		 * @param	func イベントを受け取った後に処理する関数
		 * @param	canCleanUp Boolean cleanメソッドの対象にするかどうか。
		 */
		static public function addCallback(event:String, func:Function, canCleanUp:Boolean = true):void {
			if (_eventDic == null) {
				_eventDic = new Dictionary();
				_protectedDic = new Dictionary();				
			}
			if (isDebugMode) {
				trace("登録したイベント:" + event+"/"+_eventDic.hasOwnProperty(event));
			}
			// 初期化がすんでいなければ初期化処理へ
			if (!_isInit) {
				_isInit = true;
				// コールバックが受け取れるかどうかをFwに返すコールバックを生成
				ExternalInterface.addCallback("IsFwCallbackInstalled", IsFwCallbackInstalled);
			}
			switch (event) {
				case ACTIVE_TOOL_CHANGE:
					ExternalInterface.addCallback(event, function() { } );
					event = event.replace(/onFw/, "setfw").replace(/Change/, "ForSWFs");
				break;
			}
			_eventDic[event] = func;
			ExternalInterface.addCallback(event, func);
			if (!canCleanUp) {
				_protectedDic[event] = func;
			}
		}
		
		/**
		 * cleanUP対象に入っているイベントを全部削除する。
		 */
		static public function clean():void {
			_eventDic = new Dictionary();
			for (var key:* in _protectedDic) {
				_eventDic[key] = _protectedDic[key];
			}
		}
		
		/**
		 * callbackを一時的に辞めたい場合に使用する。removeしたイベント名は登録イベントリストから削除される。
		 * @param	event
		 */
		static public function removeCallback(event):void {
			if (_eventDic.hasOwnProperty(event)) {
				delete _eventDic[event];
			}
		}
		
		/**
		 * Fwから対象となるイベントのコールバックが可能かどうかをFwに返す
		 * @param	functionName
		 * @return
		 */
		static private function IsFwCallbackInstalled( functionName:String ):Boolean {
			if (_eventDic.hasOwnProperty(functionName)) {
				return true;
			} else {
				return false;
			}
		}
		/**
		 * (readonly) ExternalInterfaceでイベントコールバックが可能かどうかを返す。
		 */
		static public function get available():Boolean { return ExternalInterface.available; }
		
	}
	
}

使用上の注意

FireworksEventクラスはExternalInterfaceクラス同様にインスタンスを作らずに使用するクラスです。new FireworksEvent()とすると、IllegalOperationErrorが投げられます。

Fireworksからのイベントは2つのイベントをのぞいてみな引数を持ちません。callback用関数では引数は必要ありません。戻り値もとらないのでvoidになります。例外であるIsFwCallbackInstalledとonFwActiveToolChangeで、それぞれ引数を一つ持ちそれはStringで渡されます。

  • IsFwCallbackInstalled…Fireworksが投げる予定のイベント名が戻り値
  • onFwActiveToolChange…Fireworks上で選択したツール名が戻り値

IsFwCallbackInstalledはFireworksEventクラスを使えば自動生成されますので、onFwActiveToolChange用の関数だけはコールバック関数を作る際、引数に気をつけて作成してください。

ステキな?Fireworks拡張ライフを楽しんでくれる方が増えると嬉しいです。

EventViewerのコード(FireworksEventクラス使用部分)

		private function initialize(e:Event):void 
		{
			stage.align = StageAlign.TOP;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			FireworksEvent.addCallback(FireworksEvent.ACTIVE_DOCUMENT_CHANGE, funcActiveDocumentChange);
			FireworksEvent.addCallback(FireworksEvent.ACTIVE_SELECTION_CHANGE, funcActiveSelectionChange);
			FireworksEvent.addCallback(FireworksEvent.ACTIVE_TOOL_CHANGE, funcActiveToolChange);
			FireworksEvent.addCallback(FireworksEvent.ACTIVE_VIEW_CHANGE, funcActiveViewChange);
			FireworksEvent.addCallback(FireworksEvent.APPLICATION_ACTIVATE, funcApplicationActive);
			FireworksEvent.addCallback(FireworksEvent.APPLICATION_DEACTIVATE, funcAppicationDeactive);
			FireworksEvent.addCallback(FireworksEvent.DOCUMENT_CLOSED, funcDocumentClose);
			FireworksEvent.addCallback(FireworksEvent.DOCUMENT_NAME_CHANGE, funcDocumentNameChange);
			FireworksEvent.addCallback(FireworksEvent.DOCUMENT_OPEN, funcDocumentOpen);
			FireworksEvent.addCallback(FireworksEvent.DOCUMENT_SAVE, funcDocumentSave);
			FireworksEvent.addCallback(FireworksEvent.DOCUMENT_SIZE_CHANGE, funcDocumentSizeChange);
			FireworksEvent.addCallback(FireworksEvent.HISTORY_CHANGE, funcHistoryChange);
			//Fireworksはなにも作業が発生していないとアイドル状態を0~2まで繰り返すので不要
			//FireworksEvent.addCallback(FireworksEvent.IDLE_0, funcIdle0);
			//FireworksEvent.addCallback(FireworksEvent.IDLE_1, funcIdle1);
			//FireworksEvent.addCallback(FireworksEvent.IDLE_2, funcIdle2);
			FireworksEvent.addCallback(FireworksEvent.OBJECT_SETTING_CHANGE, funcObjectSettingChange);
			FireworksEvent.addCallback(FireworksEvent.PI_COLLAPSE_OR_EXPAND, funcPiStatusChange);
			FireworksEvent.addCallback(FireworksEvent.PIXEL_SELECTION_CHANGE, funcPixelSelectionChange);
			FireworksEvent.addCallback(FireworksEvent.PREFERENCES_CHANGE, funcPreferenceChange);
			FireworksEvent.addCallback(FireworksEvent.START_MOVIE, funcStartMovie);
			FireworksEvent.addCallback(FireworksEvent.STOP_MOVIE, funcStopMovie);
			FireworksEvent.addCallback(FireworksEvent.SYMBOL_LIBRARY_CHANGE, funcSymbolLibChange);
			FireworksEvent.addCallback(FireworksEvent.UNITS_CHANGE, funcUnitsChange);
			FireworksEvent.addCallback(FireworksEvent.URL_FAVORITES_CHANGE, funcUrlFavo);
			FireworksEvent.addCallback(FireworksEvent.URL_LIST_CHANGE, funcUrlList);
			FireworksEvent.addCallback(FireworksEvent.ZOOM_CHANGE, funcZoomChange);
			
			FireworksEvent.addCallback(FireworksEvent.CURRENT_FRAME_CHANGE, funcFrameChange);
			FireworksEvent.addCallback(FireworksEvent.CURRENT_LAYER_CHANGE, funcLayerChange);
		}
		private function funcAppicationDeactive(... arg):void
		{
			setData("アプリケーション非アクティブ化", arg);
		}
		
		private function funcStopMovie(... arg):void
		{
			setData("パネル閉じる", arg);
		}
		
		private function funcLayerChange(... arg):void
		{
			setData("レイヤー変更", arg);
		}
		
		private function funcFrameChange(... arg):void
		{
			setData("フレーム変更", arg);
		}
		
		private function funcZoomChange(... arg):void
		{
			setData("拡大縮小率変更", arg);
		}
		
		private function funcUrlList(... arg):void
		{
			setData("URLリスト", arg);
		}
		
		private function funcUrlFavo(... arg):void
		{
			setData("お気に入りURL変更", arg);
		}
		
		private function funcUnitsChange(... arg):void
		{
			setData("ユニット変更", arg);
		}
		
		private function funcSymbolLibChange(... arg):void
		{
			setData("シンボルライブラリ変更", arg);
		}
		
		private function funcStartMovie(... arg):void
		{
			setData("パネル呼び出し", arg);
		}
		
		private function funcPreferenceChange(... arg):void
		{
			setData("環境設定変更", arg);
		}
		
		private function funcPixelSelectionChange(... arg):void
		{
			setData("ラスター選択の変更", arg);
		}
		
		private function funcPiStatusChange(... arg):void
		{
			setData("プロパティの状態変更", arg);
		}
		
		private function funcObjectSettingChange(... arg):void
		{
			setData("オブジェクトの設定変更", arg);
		}
		
		private function funcIdle2(... arg):void
		{
			setData("アイドル2", arg);
		}
		
		private function funcIdle1(... arg):void
		{
			setData("アイドル1", arg);
		}
		
		private function funcIdle0(... arg):void
		{
			setData("アイドル0", arg);
		}
		
		private function funcHistoryChange(... arg):void
		{
			setData("ヒストリー変更", arg);
		}
		
		private function funcDocumentSizeChange(... arg):void
		{
			setData("ドキュメントサイズ変更", arg);
		}
		
		private function funcDocumentSave(... arg):void
		{
			setData("ドキュメント保存", arg);
		}
		
		private function funcDocumentOpen(... arg):void
		{
			setData("ドキュメントオープン", arg);
		}
		
		private function funcDocumentNameChange(... arg):void
		{
			setData("ドキュメント名変更", arg);
		}
		
		private function funcDocumentClose(... arg):void
		{
			setData("ドキュメント閉じる", arg);
		}
		
		private function funcApplicationActive(... arg):void
		{
			setData("Fw選択", arg);
		}
		
		private function funcActiveViewChange(... arg):void
		{
			setData("ビュー変更", arg);
		}
		
		private function funcActiveToolChange(... arg):void
		{
			setData("アクティブなツール変更", arg);
		}
		
		private function funcActiveSelectionChange(... arg):void
		{
			setData("選択オブジェクト変更", arg);
		}
		
		private function funcActiveDocumentChange(... arg):void
		{
			setData("アクティブなドキュメント変更", arg);
		}
		
		/**
		 * イベントリストに発生イベントを追加
		 * @param	msg
		 * @param	arg
		 */
		private function setData(msg,arg:Array=null):void
		{
			eventList.addItemAt( { label:msg + ":" + arg, data:arg }, 0);
			trace("test");
		}

戻る