444 lines
22 KiB
Text
444 lines
22 KiB
Text
// KAGLayer.tjs - KAG のレイヤの基本クラス
|
||
// Copyright (C)2001-2009, W.Dee and contributors 改変・配布は自由です
|
||
|
||
/*
|
||
レイヤ関連のクラス階層
|
||
|
||
Layer ( 吉里吉里ネイティヴクラス )
|
||
|
|
||
+-- KAGLayer ( このファイル )
|
||
|
|
||
+-- AnimationLayer ( AnimationLayer.tjs )
|
||
| |
|
||
| +-- ClickGlyphLayer ( AnimationLayer.tjs )
|
||
| |
|
||
| +-- GraphicLayer ( GraphicLayer.tjs )
|
||
| |
|
||
| +-- BaseLayer ( GraphicLayer.tjs )
|
||
| |
|
||
| +-- CharacterLayer ( GraphicLayer.tjs )
|
||
|
|
||
+-- MessageLayer ( MessageLayer.tjs )
|
||
|
|
||
+-- ButtonLayer ( ButtonLayer.tjs )
|
||
| |
|
||
| +-- LinkButtonLayer ( MessageLayer.tjs )
|
||
| |
|
||
| +-- LButtonLayer ( HistoryLayer.tjs )
|
||
|
|
||
+-- EditLayer ( EditLayer.tjs )
|
||
| |
|
||
| +-- LinkEditLayer ( MessageLayer.tjs )
|
||
|
|
||
+-- CheckBoxLayer ( CheckBoxLayer.tjs )
|
||
|
|
||
+-- LinkCheckBoxLayer ( MessageLayer.tjs )
|
||
*/
|
||
|
||
/*
|
||
ちょっとわかりづらい、トランジション終了時の動作について覚え書き
|
||
|
||
吉里吉里はトランジション終了時に、トランジション元(src=相手)がある場合は、
|
||
子レイヤを含む(children=true)場合は相手とツリーごと自分自身のレイヤを交換し、
|
||
子レイヤを含まない(children=false)場合は、子の絶対的なツリー上の位置はその
|
||
ままにして相手と入れ替わる。
|
||
|
||
子レイヤを含まないトランジションを行えるのは背景レイヤのみ。
|
||
|
||
トランジションを行うと、上記における「入れ替え」を行うが、吉里吉里本体の
|
||
入れ替え、は name などの重要な情報も入れ替えてしまうので、
|
||
GraphicLayer.exchangeInfo で内容を交換する。
|
||
|
||
また、trans 属性で exchange=true が指定された場合は、両者のレイヤは入れ替わ
|
||
るが、exchange=false (デフォルト) が指定された場合は、トランジション元(src)
|
||
からトランジション先への情報のコピーを行わないとならない。
|
||
|
||
srcなし の時はレイヤ単独でのトランジションが行われるのでこれらの考慮は
|
||
必要ないが、終了時には子レイヤがすべて非表示になる。
|
||
|
||
・メッセージレイヤ、前景レイヤが、srcなしでトランジション (children=true)
|
||
何もしなくてよいが、終了後それらの子レイヤは自動的に非表示になる。
|
||
|
||
・メッセージレイヤ、前景レイヤが、srcありでトランジション (children=true)
|
||
重要な情報をトランジション元と交換、exchange=false の場合はさらに
|
||
トランジション元の情報をトランジション先にコピー。ただし、このコピーの際に
|
||
ウィンドウの可視・不可視の情報はコピーしない。
|
||
|
||
・背景レイヤがsrcなしでトランジション(children=true)
|
||
何もしなくてよいが、終了時に子レイヤは非表示になる。
|
||
|
||
・背景レイヤがsrcなしでトランジション(children=false)
|
||
本当に何もしない。
|
||
|
||
・背景レイヤがsrcありでトランジション(children=true)
|
||
重要な情報をトランジション元と交換、しかも子レイヤに対してもこの
|
||
「重要な情報を相手と交換」の指示を出す。exchange=false の場合はさらに
|
||
トランジション元の情報をトランジション先にコピー。これも、子レイヤすべて
|
||
に対しても指示する。
|
||
|
||
・背景レイヤがsrcありでトランジション(children=false)
|
||
重要な情報をトランジション元と交換。子レイヤに対しては
|
||
「重要な情報を相手と交換」の指示をださない。exchange=false の場合は
|
||
さらにトランジション元の情報をトランジション先にコピー。
|
||
これも子レイヤに対しては指示しない。
|
||
|
||
*/
|
||
|
||
class KAGLayer extends Layer
|
||
{
|
||
// KAG で用いる背景/前景レイヤ、メッセージレイヤ、ボタンレイヤなどの基本クラス
|
||
var inTransition = false; // トランジション中か
|
||
var transExchange = false; // トランジション終了時に入れ替えを行うか
|
||
var transWithChildren = false; // トランジションは子レイヤも含めて行うか
|
||
|
||
var moveObject; // 現在進行中の自動移動用オブジェクト(進行していないときはvoid)
|
||
|
||
function KAGLayer(win, par)
|
||
{
|
||
super.Layer(win, par);
|
||
}
|
||
|
||
function finalize()
|
||
{
|
||
invalidate moveObject if moveObject !== void;
|
||
super.finalize(...);
|
||
}
|
||
|
||
function setOptions(elm)
|
||
{
|
||
// elm に従ってレイヤのオプションを設定
|
||
visible = +elm.visible if elm.visible !== void;
|
||
left = +elm.left if elm.left !== void;
|
||
top = +elm.top if elm.top !== void;
|
||
opacity = +elm.opacity if elm.opacity !== void;
|
||
|
||
if(elm.modal !== void)
|
||
{
|
||
// this would not work well
|
||
var modal = elm.modal;
|
||
if(modal) setMode(), focus(); else removeMode();
|
||
}
|
||
|
||
absolute = +elm.index if elm.index !== void;
|
||
}
|
||
|
||
function loadImages(storage, key)
|
||
{
|
||
// loadImages オーバーライド
|
||
key = adjustColorKey(key);
|
||
return super.loadImages(storage, key);
|
||
}
|
||
|
||
function adjustColorKey(key)
|
||
{
|
||
// 文字列で与えられたカラーキーの変換
|
||
if(key === void)
|
||
key = clNone;
|
||
else if(typeof key == "String")
|
||
{
|
||
if(key == "adapt")
|
||
key = clAdapt; // adaptive color key
|
||
else
|
||
{
|
||
if(key.length >= 7)
|
||
key = +key;
|
||
else
|
||
key = +key + 0x3000000; // 0x3000000 = パレットインデックスによる指定
|
||
}
|
||
}
|
||
return key;
|
||
}
|
||
|
||
function assignImages(src, copyvisiblestate = false)
|
||
{
|
||
// assignImages オーバーライド
|
||
// src の「目に見える」情報をこのレイヤにコピーする
|
||
// コピーされる内容は、
|
||
// ・透明度
|
||
// ・位置
|
||
// ・表示サイズ
|
||
// ・レイヤ内画像表示位置(imageLeft, imageTop)
|
||
// ( 上記3つは copyvisiblestate = true のばあい )
|
||
// ・画像サイズ
|
||
// ・レイヤ画像、領域画像
|
||
super.assignImages(src);
|
||
if(copyvisiblestate)
|
||
{
|
||
var su = super;
|
||
su.visible = src.visible;
|
||
su.opacity = src.opacity;
|
||
su.absolute = src.absolute if !src.isPrimary && src.parent.absoluteOrderMode;
|
||
su.type = src.type;
|
||
su.setPos(src.left, src.top, src.width, src.height);
|
||
su.setImagePos(src.imageLeft, src.imageTop);
|
||
}
|
||
}
|
||
|
||
function assignVisibleState(src)
|
||
{
|
||
// src から上記 assignImages のうち、copyvisiblestate = true に
|
||
// したときだけにコピーされる情報をコピー
|
||
visible = src.visible;
|
||
opacity = src.opacity;
|
||
absolute = src.absolute if !src.isPrimary && src.parent.absoluteOrderMode;
|
||
type = src.type;
|
||
setPos(src.left, src.top, src.width, src.height);
|
||
setImagePos(src.imageLeft, src.imageTop);
|
||
}
|
||
|
||
function beginTransition(elm, src)
|
||
{
|
||
// beginTransition オーバーライド
|
||
// elm に従い、トランジションを開始する
|
||
// src にはトランジションの相手を指定
|
||
// stopTransition(); // 現在のトランジションは停止
|
||
|
||
if(elm.exchange !== void) transExchange = +elm.exchange; else transExchange = false;
|
||
var method = elm.method;
|
||
if(elm.time !== void)
|
||
{
|
||
elm.time = 1 if +elm.time == 0; // 時間に 0 は指定できないので
|
||
}
|
||
if(method === void)
|
||
{
|
||
method = 'universal'; // デフォルトでユニバーサル
|
||
}
|
||
else if(method == 'scroll')
|
||
{
|
||
// パラメータの変換
|
||
switch(elm.from)
|
||
{
|
||
case 'left': elm.from = sttLeft; break;
|
||
case 'top': elm.from = sttTop; break;
|
||
case 'right': elm.from = sttRight; break;
|
||
case 'bottom': elm.from = sttBottom; break;
|
||
}
|
||
switch(elm.stay)
|
||
{
|
||
case 'nostay': elm.stay = ststNoStay; break;
|
||
case 'stayback': elm.stay = ststStaySrc; break;
|
||
case 'stayfore': elm.stay = ststStayDest; break;
|
||
default: elm.stay = ststNoStay; break;
|
||
}
|
||
}
|
||
var withchildren = elm.children;
|
||
if(withchildren === void)
|
||
withchildren = true;
|
||
else
|
||
withchildren = +withchildren;
|
||
transWithChildren = withchildren;
|
||
inTransition = true;
|
||
window.transCount++; // 進行中のトランジションの数を増やす
|
||
super.beginTransition(method, withchildren, src, elm);
|
||
}
|
||
|
||
function onTransitionCompleted(dest, src)
|
||
{
|
||
super.onTransitionCompleted(...);
|
||
if(window != null)
|
||
{
|
||
inTransition = false;
|
||
window.transCount--; // 進行中のトランジションの数を減らす
|
||
atEndOfTransition(src, transWithChildren, transExchange);
|
||
window.onLayerTransitionCompleted(this, dest, src);
|
||
}
|
||
}
|
||
|
||
function atEndOfTransition(src, withchildren, exchange)
|
||
{
|
||
// 必要に応じて オーバーライドすること
|
||
// トランジションが終了したときに呼ばれる。
|
||
// レイヤ単独でトランジションが行われた場合は src は null になる。
|
||
// そうでない場合、exchange が true の時は、src と 自分の内容
|
||
// を取り替え、そうでなければ src に自分の内容
|
||
// をコピー。
|
||
// 子レイヤも含めてトランジションが行われた場合は withchildren が
|
||
// true になる。
|
||
// root は、トランジションの大本に対して呼ばれるときに true になる。
|
||
}
|
||
|
||
function beginMove(elm)
|
||
{
|
||
// elm に従い自動移動を開始する
|
||
stopMove();
|
||
|
||
// path の分解
|
||
var array = [].split("(), ", elm.path, , true);
|
||
for(var i = array.count-1; i>=0; i--) array[i+3] = +array[i];
|
||
array[0] = left;
|
||
array[1] = top;
|
||
array[2] = opacity;
|
||
|
||
// 移動用オブジェクトの作成
|
||
if(elm.spline !== void && +elm.spline)
|
||
{
|
||
// スプライン補間
|
||
moveObject = new SplineMover(this, array, +elm.time,
|
||
elm.accel === void ? 0 : +elm.accel, moveFinalFunction);
|
||
}
|
||
else
|
||
{
|
||
// 直線補間
|
||
moveObject = new LinearMover(this, array, +elm.time,
|
||
elm.accel === void ? 0 : +elm.accel, moveFinalFunction);
|
||
}
|
||
window.moveCount++;
|
||
moveObject.startMove(+elm.delay);
|
||
}
|
||
|
||
function moveFinalFunction()
|
||
{
|
||
// 自動移動が終了するときに呼ばれる関数
|
||
window.moveCount--;
|
||
window.onLayerMoveStop();
|
||
}
|
||
|
||
function stopMove()
|
||
{
|
||
if(moveObject !== void) invalidate moveObject, moveObject = void;
|
||
}
|
||
|
||
// フレーム番号を指定したmove
|
||
function beginFrameMove(elm)
|
||
{
|
||
// elm に従い自動移動を開始する
|
||
stopMove();
|
||
|
||
var ox = elm.ox === void ? 0 : +elm.ox;
|
||
var oy = elm.oy === void ? 0 : +elm.oy;
|
||
var fps = elm.fps === void ? 30 : +elm.fps;
|
||
|
||
// path の分解
|
||
var array = [].split("(), ", elm.path, , true);
|
||
for(var i = array.count-1; i>=0; i--) array[i+4] = +array[i];
|
||
array[0] = 0;
|
||
array[1] = left - ox;
|
||
array[2] = top - oy;
|
||
array[3] = opacity;
|
||
|
||
// 移動用オブジェクトの作成
|
||
moveObject = new LinearFrameMover(this, array, fps, moveFinalFunction, ox, oy );
|
||
|
||
window.moveCount++;
|
||
moveObject.startMove();
|
||
}
|
||
|
||
function store()
|
||
{
|
||
// 辞書配列に現在の状態を保存する
|
||
var dic = %[];
|
||
dic.left = left;
|
||
dic.top = top;
|
||
dic.width = width;
|
||
dic.height = height;
|
||
dic.imageWidth = imageWidth;
|
||
dic.imageHeight = imageHeight;
|
||
dic.opacity = opacity;
|
||
dic.visible = visible;
|
||
dic.imageLeft = imageLeft;
|
||
dic.imageTop = imageTop;
|
||
dic.absolute = absolute;
|
||
dic.type = type;
|
||
return dic;
|
||
}
|
||
|
||
function restore(dic)
|
||
{
|
||
// 辞書配列 dic から情報を読み出し、このレイヤに設定する
|
||
setImageSize(dic.imageWidth, dic.imageHeight);
|
||
setPos(dic.left, dic.top, dic.width, dic.height);
|
||
setImagePos(dic.imageLeft, dic.imageTop);
|
||
opacity = dic.opacity;
|
||
visible = dic.visible;
|
||
absolute = dic.absolute if !isPrimary && dic.absolute !== void;
|
||
type = dic.type if !isPrimary && dic.type !== void;
|
||
}
|
||
|
||
/**
|
||
* レイヤへの色反映処理
|
||
* @param left
|
||
* @param top
|
||
* @param width
|
||
* @param height
|
||
* @param color 塗りつぶす色(マスク値を含む)
|
||
* @param mode 合成モード
|
||
*/
|
||
function fillOperateRect(left, top, width, height, color, mode)
|
||
{
|
||
var tw = 128;
|
||
var th = 64;
|
||
var fillLayer = new global.Layer(window, this);
|
||
// 元々吉里吉里のものなら、不透明の一色レイヤーを、不透明度を指定して描画。
|
||
// PhotoShop準拠のものなら、半透明の一色レイヤーを、透明度を指定せず(opacity=255)に描画。
|
||
var orgmodes = %[ltOpaque=>1,ltAlpha=>1,ltAddAlpha=>1,ltAdditive=>1,ltSubtractive=>1,ltMultiplicative=>1,ltDodge=>1,ltLighten=>1,ltDarken=>1,ltScreen=>1];
|
||
fillLayer.setSize(tw, th);
|
||
var opacity = 255;
|
||
var lastface = face, lastha = holdAlpha;
|
||
if(orgmodes[mode])
|
||
{
|
||
fillLayer.fillRect(0, 0, tw, th, color | 0xFF000000);
|
||
opacity = (color >> 24) & 0xFF;
|
||
face = dfOpaque;
|
||
}
|
||
else
|
||
fillLayer.fillRect(0, 0, tw, th, color);
|
||
holdAlpha = true if !isPrimary;
|
||
var x = 0;
|
||
var y = 0;
|
||
while (y < height) {
|
||
var x2 = x;
|
||
while (x2 < width) {
|
||
//Debug.message("pos:" + x2 + "," + y);
|
||
global.Layer.operateRect(x2, y, fillLayer, 0, 0, tw, th, mode, opacity);
|
||
x2 += tw;
|
||
}
|
||
y += th;
|
||
}
|
||
face = lastface, holdAlpha = lastha;
|
||
// 後片付け
|
||
invalidate fillLayer;
|
||
}
|
||
|
||
/**
|
||
* 影を追加する
|
||
* @param dx 影のX移動量 (右にプラス)
|
||
* @param dy 影のY移動量 (下にプラス)
|
||
* @param blur ぼかし量
|
||
* @param shadowColor 影の色
|
||
* @param shadoAlpha 影の不透明度
|
||
*/
|
||
function doDropShadow(dx=10, dy=10, blur=3, shadowColor=0x000000, shadowOpacity=200)
|
||
{
|
||
var THIS = global.Layer;
|
||
|
||
// 作業用レイヤ
|
||
var work = new THIS(window, parent);
|
||
work.setImagePos(THIS.imageLeft, THIS.imageTop);
|
||
work.setImageSize(THIS.imageWidth, THIS.imageHeight);
|
||
|
||
// 影生成処理
|
||
var shadow = new THIS(window, parent);
|
||
shadow.assignImages(this);
|
||
// 塗りつぶし
|
||
shadow.face = dfMain;
|
||
shadow.holdAlpha = true;
|
||
shadow.fillRect(THIS.imageLeft, THIS.imageTop, THIS.imageWidth, THIS.imageHeight, shadowColor);
|
||
shadow.face = dfBoth;
|
||
shadow.holdAlpha = false;
|
||
// ぼかす
|
||
shadow.doBoxBlur(blur, blur);
|
||
|
||
// 影をコピー
|
||
work.operateRect(THIS.imageLeft + dx, THIS.imageTop + dy, shadow, THIS.imageLeft, THIS.imageTop, THIS.imageWidth, THIS.imageHeight, ltPsNormal, shadowOpacity);
|
||
// 自分をコピー
|
||
work.operateRect(THIS.imageLeft, THIS.imageTop, this, THIS.imageLeft, THIS.imageTop, THIS.imageWidth, THIS.imageHeight, ltPsNormal, 255);
|
||
|
||
// 画像さしかえ
|
||
THIS.assignImages(work);
|
||
|
||
// 後片付け
|
||
invalidate work;
|
||
invalidate shadow;
|
||
};
|
||
}
|
||
|