/**
* AutoSitemap
*
* @author Yasu ( clockmaker.jp )
* @version 2.1.1
* @see http://clockmaker.jp/
*
* AutoSitemap is (c) 2009-2010 yasu (clockmaker.jp) and is released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
*/
package jp.clockmaker.prog4
{
import caurina.transitions.Tweener;
import flash.display.*;
import flash.events.*;
import flash.text.*;
import jp.nium.utils.ClassUtil;
import jp.progression.casts.CastButton;
import jp.progression.Progression;
import jp.progression.scenes.SceneId;
import jp.progression.scenes.SceneLoader;
import jp.progression.scenes.SceneObject;
/**
* AutoSitemap クラスは Progression のシーン構造を GUI で表示するための拡張機能です。
*/
public class AutoSitemap
{
static private const SITEMAP_BACKGROUND_ALPHA:Number = 0.75;
static private const SITEMAP_BACKGROUND_HEIGHT:int = 200;
static private const SITEMAP_SHOW_TAB_HEIGHT:int = 30;
static private const PADDING_LEFT:int = 10;
static private const PADDING_TOP:int = 5;
static private var _menu:Sprite;
static private var _manager:Progression;
static private var _sitemaps:Array;
static private var _btns:Array = [];
static private var _fmt:TextFormat;
static private var _tab:Sprite;
static private var _arrow:Sprite;
static private var _pageArea:Sprite;
static private var _tabText:TextField;
static private var _isTweening:Boolean = false;
static private var _isAttention:Boolean = false;
static private var _isShowSitemap:Boolean = false;
/**
* 初期化をおこないます
* @param progression Progression インスタンスです。
*
* @example
* // Progression インスタンスを作成する
* var manager:Progression = new Progression( "index", stage );
*
* // AutoSitemap を初期化する
* AutoSitemap.initialize( manager );
*
*/
static public function initialize(manager:Progression):void
{
_manager = manager;
_manager.stage.addEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove);
// text format
_fmt = new TextFormat();
_fmt.size = 11;
_fmt.color = 0xFFFFFF;
_fmt.font = "_sans";
// menu
_menu = new Sprite();
_manager.stage.addEventListener(Event.RESIZE, _onResize, false, int.MAX_VALUE, true);
_onResize();
_menu.y = -SITEMAP_BACKGROUND_HEIGHT;
// tab
_tab = new Sprite();
_tab.y = SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT;
_tab.graphics.beginFill(0, 0.25);
_tab.graphics.drawRect(0, 0, _manager.stage.stageWidth, SITEMAP_SHOW_TAB_HEIGHT);
_tab.graphics.endFill();
_tab.buttonMode = true;
//tab.toolTip.delay = 0;
// tab text
_tabText = new TextField();
_tabText.autoSize = TextFieldAutoSize.LEFT;
_tabText.text = "Show Sitemap";
_tabText.x = 25;
_tabText.y = 5;
_tabText.selectable = false;
_tabText.mouseEnabled = false;
_tabText.defaultTextFormat = _fmt
_tab.addChild(_tabText)
// arrow
_arrow = _createArrow();
_arrow.x = 16;
_arrow.y = 14;
_tab.addChild(_arrow)
_menu.addChild(_tab);
// page
var maskArea:Sprite = new Sprite();
maskArea.graphics.beginFill(0);
maskArea.graphics.drawRect(0, 0, _manager.stage.stageWidth, SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT);
_pageArea = new Sprite();
_pageArea.mask = maskArea;
_pageArea.graphics.beginFill(0, 0);
_pageArea.graphics.drawRect(0, 0, 1, SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT);
_menu.addChild(_pageArea);
}
/**
* マウスが動いたときのハンドラー
*/
static private function _onMouseMove(e:MouseEvent):void
{
if (_isTweening) return;
if (_isShowSitemap) return;
if (e.stageY < SITEMAP_SHOW_TAB_HEIGHT)
_attentionSitemap();
else
_hideSitemap();
}
/**
* サイトマップをアテンションします。
*/
static private function _attentionSitemap():void
{
_manager.stage.addChild(_menu);
_tabText.text = "Show Sitemap"
_arrow.rotation = 0;
_isTweening = true;
Tweener.addTween(_menu,
{
y : SITEMAP_SHOW_TAB_HEIGHT - SITEMAP_BACKGROUND_HEIGHT,
transition : "easeOutBack",
time : 0.4,
onComplete : function():void
{
_isTweening = false;
}
});
_tab.addEventListener(MouseEvent.CLICK, _showSitemap);
}
/**
* サイトマップを表示します
*/
static private function _showSitemap(e:MouseEvent = null):void
{
_tab.removeEventListener(MouseEvent.CLICK, _showSitemap);
_generateSitemap();
_isTweening = true;
_isShowSitemap = true;
_pageArea.y = 0;
// マウス操作を無効にする
_menu.mouseChildren = false;
_menu.mouseEnabled = false;
Tweener.addTween(_menu,
{
y : 0,
time : 0.5,
transition : "easeOutExpo",
onComplete : function():void
{
_isTweening = false;
_tabText.text = "Hide Sitemap"
_arrow.rotation = 180;
// マウス操作を有効にする
_menu.mouseChildren = true;
_menu.mouseEnabled = true;
_tab.addEventListener(MouseEvent.CLICK, _hideSitemap);
_manager.stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
}
});
}
/**
* サイトマップを隠します
*/
static private function _hideSitemap(e:MouseEvent = null):void
{
if (_menu.y == -SITEMAP_BACKGROUND_HEIGHT) return;
_manager.stage.removeEventListener(Event.ENTER_FRAME, _onEnterFrame);
_tab.removeEventListener(MouseEvent.CLICK, _hideSitemap);
_isTweening = true;
// マウス操作を無効にする
_menu.mouseChildren = false;
_menu.mouseEnabled = false;
Tweener.addTween(_menu,
{
y : -SITEMAP_BACKGROUND_HEIGHT,
time : 0.5,
transition : "easeInOutExpo",
onComplete : function():void
{
if (_manager.stage.contains(_menu))
_manager.stage.removeChild(_menu);
while (_btns.length)
_pageArea.removeChild(_btns.pop());
_isTweening = false;
_isShowSitemap = false;
// マウス操作を有効にする
_menu.mouseChildren = true;
_menu.mouseEnabled = true;
}
})
}
/**
* サイトマップが開いているときの、ページのスクロール処理です。
*/
static private function _onEnterFrame(e:Event):void
{
var my:Number = Math.min(SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT, Math.max(0, _menu.mouseY));
var aim:Number;
if(_pageArea.height <= SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT)
aim = - (_pageArea.height - SITEMAP_BACKGROUND_HEIGHT + SITEMAP_SHOW_TAB_HEIGHT) * (my / (SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT));
else
aim = - (_pageArea.height - SITEMAP_BACKGROUND_HEIGHT + SITEMAP_SHOW_TAB_HEIGHT + PADDING_TOP * 2) * (my / (SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT));
_pageArea.y += (aim - _pageArea.y) * 0.2;
}
/**
* サイトマップを生成します。
*/
static private function _generateSitemap():void
{
_sitemaps = [];
_searchPRML(_manager.root);
for (var i:int = 0; i < _sitemaps.length; i++)
{
var btn:DisplayObject = _pageArea.addChild(_createBtn(_sitemaps[i]));
btn.y = i * 20 + PADDING_TOP;
_btns.push(btn);
}
}
/**
* SceneObjectから再帰関数として構造を取得します。
*/
static private function _searchPRML(scene:SceneObject):void
{
_sitemaps.push(scene);
// 子シーンオブジェクトの配列を取得する
var children:Array;
if (scene is SceneLoader) {
children = (scene as SceneLoader).content
? (scene as SceneLoader).content.scenes
: [];
}
else if (scene is SceneObject) { children = scene.scenes; }
// 子シーンノードを走査する
var l:int = children.length;
for ( var i:int = 0; i < l; i++ )
{
var child:SceneObject = SceneObject( children[i] );
_searchPRML(child);
}
}
/**
* サイトマップボタンを作成します。
*/
static private function _createBtn(scene:SceneObject):CastButton
{
// ルートからのシーンIDを調べる
var sceneId:SceneId = scene.localToGlobal(scene.sceneId);
// シーンの深さを検出します
var depth:int = sceneId.length - 1;
var btn:CastButton = new CastButton();
var textField:TextField = new TextField();
textField.autoSize = TextFieldAutoSize.LEFT;
textField.htmlText = "» " + (scene.title ? scene.title : scene.name);
textField.x = depth * 75 + PADDING_LEFT;
textField.selectable = false;
btn.mouseChildren = false;
btn.addChild(textField);
textField.setTextFormat(_fmt);
var zabuton:Sprite = new Sprite();
zabuton.graphics.beginFill(0xFFFFFF, 0.1); //背景色
zabuton.graphics.lineStyle(1, 0xFFFFFF); //背景色
zabuton.graphics.drawRect(-1, 0.5, _manager.stage.stageWidth + 1, textField.textHeight + 6);//初期+左上のXY座標,幅,高さ,角丸幅
zabuton.graphics.endFill(); //塗り潰し終了
if(_manager.current == scene)
btn.graphics.beginFill(0xFFFFFF, 0.2); //背景色
else
btn.graphics.beginFill(0x0, 0); //背景色
btn.graphics.drawRect(0, 0, _manager.stage.stageWidth, textField.textHeight + 6)
btn.graphics.endFill(); //塗り潰し終了
zabuton.alpha = 0;
btn.addChild(zabuton);
// ボタンがロールオーバーしたとき
btn.onCastRollOver = function():void
{
zabuton.alpha = 1;
}
// ボタンがロールアウトしたとき
btn.onCastRollOut = function():void
{
zabuton.alpha = 0;
}
btn.addEventListener(MouseEvent.CLICK, _hideSitemap, false, int.MAX_VALUE, true);
// ボタンを押したときの遷移先を指定
btn.sceneId = scene.sceneId;
// SceneObject のクラスパスがわかると開発時に便利だけど、エンドユーザー向けではないので実装保留
btn.toolTip.text = ClassUtil.getClassPath(scene);
if (_manager.current == scene)
{
btn.toolTip.text = "Current Page";
}
return btn;
}
/**
* 矢印アイコンを作成します。
*/
static private function _createArrow():Sprite
{
var sp:Sprite = new Sprite();
sp.graphics.beginFill(0xFFFFFF);
sp.graphics.drawRect(-4, -2, 2, 2);
sp.graphics.drawRect(-2, 0, 2, 2);
sp.graphics.drawRect(0, 2, 2, 2);
sp.graphics.drawRect(2, 0, 2, 2);
sp.graphics.drawRect(4, -2, 2, 2);
sp.graphics.endFill();
return sp;
}
/**
* リサイズ時の処理です。
*/
static private function _onResize(e:Event = null):void
{
_menu.graphics.clear();
_menu.graphics.beginFill(0, SITEMAP_BACKGROUND_ALPHA);
_menu.graphics.drawRect(0, 0, _manager.stage.stageWidth, SITEMAP_BACKGROUND_HEIGHT);
}
/**
* @private
*/
public function AutoSitemap()
{
throw new Error("AutoSitemap クラスはインスタンス化することはできません");
}
}
}