也有tjs写的
// --------------------------------------------------------
// CGモード用処理
// --------------------------------------------------------
// システムメニューとして登録
setSystemMenuStorage("cgmode.ks");
/**
* CGモード表示用専用レイヤ
* スクロール処理に対応しています
*/
class CgViewLayer extends Layer {
var _owner, _action; // イベント送信先ターゲット
var _namebase; // 名前ベース
/**
* コンストラクタ
*/
function CgViewLayer(parentLayer, owner = void, action = "action") {
_owner = (owner !== void) ? owner : this;
_action = (typeof action === "String") ? action : "";
super.Layer(parentLayer.window, parentLayer);
with (getParentSize()) setSize(.width, .height);
hitType = htMask;
hitThreshold = 0;
focusable = true;
cursor = window.cursorDefault;
absolute = 4000000;
name = _namebase = "CG View Layer";
focus();
}
function getParentSize() {
with (parent) return %[ width:.width, height:.height ];
}
function finalize() {
super.finalize(...);
}
var fcol = 0;
function loadImages(name) {
super.loadImages(name);
setSizeToImageSize();
var w = width, h = height, pw, ph;
with (getParentSize()) pw=.width, ph=.height;
cursor = window.cursorDefault;
if (w != pw || h != ph) {
if (w > pw) {
cursor = crSizeNS;
width = pw;
} else if (w < pw) {
// 横方向センタリング
width = imageWidth = pw;
var sw = pw-w;
fillRect(w, 0, sw, h, fcol);
copyRect(sw\2, 0, this, 0, 0, w, h);
fillRect(0, 0, sw\2, h, fcol);
}
if (h > ph) {
cursor = crSizeNS;
height = ph;
} else if (h < ph) {
// 縦方向センタリング
height = imageHeight = ph;
var sh = ph-h, iw = imageWidth;
fillRect(0, h, iw, sh, fcol);
copyRect(0, sh\2, this, 0, 0, iw, h);
fillRect(0, 0, iw, sh\2, fcol);
}
}
this.name = _namebase + " : " + name;
}
// stub
function action(message) {}
function sendMessage(mes) {
if (_action.length === 0) _owner(mes);
else _owner[_action](mes);
}
function quit(continuous = true) {
sendMessage(continuous ? "next" : "break");
}
function onMouseEnter() {
super.onMouseEnter(...);
focus();
}
function onMouseUp(x, y, button, shift) {
if (!(this isvalid)) return;
switch (button) {
case mbLeft: quit(true); break;
case mbRight: quit(false); break;
}
return super.onMouseUp(...);
}
var prevx;
var prevy;
function onMouseMove(x, y, button, shift) {
if (!(this isvalid)) return;
if (prevx !== void && prevy !== void) {
offsetScroll(x - prevx, y - prevy);
}
prevx = x;
prevy = y;
focus();
return super.onMouseMove(...);
}
function offsetScroll(ox, oy) {
var left = imageLeft;
var top = imageTop;
var m;
left += ox;
top += oy;
if ( left > 0 ) left = 0;
else if (left < (m = -(imageWidth - width ))) left = m;
if ( top > 0 ) top = 0;
else if (top < (m = -(imageHeight - height))) top = m;
imageLeft = left;
imageTop = top;
}
// キーが押された
function onKeyDown(key, shift, process) {
if (!(isvalid this) || window.preProcessKeys(key, shift)) return;
switch (key) {
case VK_SPACE:
case VK_RETURN:
quit(true);
break;
case VK_ESCAPE:
quit(false);
break;
case VK_UP: imageTop = 0; break;
case VK_DOWN: imageTop = -(imageHeight - height); break;
case VK_LEFT: imageLeft = 0; break;
case VK_RIGHT: imageLeft = -(imageWidth - width); break;
default:
}
focus();
return super.onKeyDown(...);
}
}
// ----------------------------------------------------------------------------
// ギャラリー基底クラス
// UiBasedPageSheet に csv読み込み と ページ復帰処理 を追加
class GalleryMode extends UiBasedPageSheet
{
var _selfClass = void;
var fromTitle = false;
function GalleryMode(view, elm, selfclass = global.GalleryMode) {
super.UiBasedPageSheet(view, elm);
_selfClass = selfclass;
var csv = elm.csv;
/**/csv = getDefaultCsvFile() if (csv == "");
if (csv == "") throw new Exception("csvファイルが指定されていません");
readCsv(csv);
// タイトルからの遷移フラグ
fromTitle = +elm.fromtitle if (elm.fromtitle !== void);
// 前回のページを復帰
var page = 0;
try { page = _selfClass.lastPage; } catch { _selfClass.lastPage = page; }
// elm指定を優先
page = +elm.page if (elm.page !== void);
init(page);
lastItem = elm.lastitem if (elm.lastitem !== void); // フォーカス指定
}
function finalize() {
// 現在のページを保存
_selfClass.lastPage = page if (_selfClass !== void);
super.finalize(...);
}
// 改ページ処理
function renewItemPage(force = false) {
// ページ区切りに合わせる
var cnt = (_rowcol - (count % _rowcol)) % _rowcol;
if (!cnt && force) cnt = _rowcol;
while (--cnt >= 0) items.add(void);
}
function isEnabled(num) {
return (num >= 0 && num < count) ? isSeen(num) : null;
}
// virtual functions
function doLine(columns, lineNo) {} // csv読み込みパーサ
function isSeen(num) {} // 選択できるかどうか
function getDefaultCsvFile() {} // csvファイルデフォルト
function operateThumbnailEffect(sel, layer) {}
}
// ----------------------------------------------------------------------------
// ギャラリーボタン描画クラス
/*
mask:マスク画像ファイル名,
button:通常状態ボタンファイル名,
disabled:無効状態ボタンファイル名,
*/
class GalleryButton extends DecorationButton
{
var autoThumbEnabled;
function GalleryButton(owner, elm) {
super.DecorationButton(...);
autoThumbEnabled = debugWindowEnabled;
}
function finalize() {
super.finalize(...);
}
// 通常ボタン表示
function drawNormalItem(target, pos) {
// サムネイル読み込み
var filename = _owner.getThumbnail(pos);
var orig = _owner.getOriginal(pos);
var loading = getExistImageName(filename);
if (loading === void && autoThumbEnabled) try {
var thumb = "auto_" + filename + ".bmp";
var tfull = @"${kag.saveDataLocation}/${thumb}";
if (!Storages.isExistentStorage(tfull) && typeof orig === "String") {
dm("自動サムネイル生成: " + thumb, orig);
MakeTemporaryThumbnail(tfull, getExistImageName(orig), _mw, _mh);
}
loading = tfull;
} catch {}
var _temp = kag.temporaryLayer;
if (loading !== void) try {
with (_temp) {
.loadImages(loading);
_mask.copyRect(0, 0, _temp, 0, 0, .imageWidth, .imageHeight);
}
} catch {
dm("サムネイル画像の読み込みに失敗しました: "+ filename);
_mask.loadMask();
}
// ボタン描画
// target.loadButtons(_buttonNormal);
_temp.setImageSize(_mw, _mh);
_temp.fillRect(0, 0, _mw, _mh, 0);
if (typeof _owner.makeThumbnailEffect !== "undefined") {
_owner.makeThumbnailEffect(target, _mask, _temp, _mx, _my, _mw, _mh);
} else {
var tw = target.width, th = target.height;
var sel = [ "normal", "on", "over" ];
for (var i = 0; i < 3; i++) {
_temp.copyRect(0, 0, _mask, 0, 0, _mw, _mh);
var opa = _owner.operateThumbnailEffect(sel
, _temp, _mw, _mh);
target.operateRect((tw * i) +_mx, _my, _temp, 0, 0, _mw, _mh, omAlpha, (opa !== void) ? +opa : 255);
}
}
return true;
}
// owner先のmethod
function getThumbnail(pos) {} // サムネイル画像ファイルを取得
function getOriginal(pos) {} // 元画像ファイルを取得
// function makeThumbnailEffect(target, _mask, _temp, _mx, _my, _mw, _mh);
function operateThumbnailEffect(sel, layer) {}
// テンポラリ サムネイル生成(開発途中用)
function MakeTemporaryThumbnail(thumbfile, imagefile, width, height) {
// shrinkCopyプラグイン読み込み
if (typeof global.Layer.shrinkCopy == "undefined" &&
typeof global.shrinkCopyPluginLoadFailed == "undefined") {
try { Plugins.link("shrinkCopy.dll"); } catch {
/**/global.shrinkCopyPluginLoadFailed = true;
}
}
try {
var w, h, temp = kag.temporaryLayer;
with (temp) {
.loadImages(imagefile);
w = .imageWidth;
h = .imageHeight;
}
var layer = new global.Layer(kag, kag.primaryLayer);
with (layer) {
.setImageSize(width, height);
if (typeof .shrinkCopy != "undefined") {
.shrinkCopy( 0, 0, width, height, temp, 0, 0, w, h);
} else {
.stretchCopy(0, 0, width, height, temp, 0, 0, w, h, stFastLinear);
}
.font.height = height\6;
.font.face = "MS ゴシック";
var text = "仮縮小:" + Storages.chopStorageExt(Storages.extractStorageName(imagefile));
w = .font.getTextWidth(text);
h = .font.getTextHeight(text);
.drawText((width-w)\2, (height-h)\2, text, 0x800000, 255, true, 255, 0xFFFFFF, 0, 1, 1);
.saveLayerImage(thumbfile);
}
invalidate layer;
temp.setImageSize(1, 1);
// Storages.getPlacedPath(Storages.getStorageName(thumbfile));
} catch(e) {
dm(e.message);
return false;
}
return true;
}
}
// ----------------------------------------------------------------------------
// CG モード用クラス
class CgGalleryMode extends GalleryMode
{
var cglayer;
var cglayerbak;
var button;
var _effect;
var scWidth, scHeight, rex;
function CgGalleryMode(elm) {
var cgviewcls = global.CgGalleryMode.CgViewLayerClass;
button = new GalleryButton(this, elm);
rex = new RegExp("^([^<]*)<([^>:]*)[^>:]*)(:[^>]*)?>$");
super.GalleryMode(button, elm, .CgGalleryMode);
cglayer = new cgviewcls(kag.back.base, this, "onNext");
cglayerbak = new cgviewcls(kag.back.base, this, "onNext");
with (elm) {
_effect = %[
normal: _makeColorInfo(.normalcolor, .normalopacity),
over: _makeColorInfo(.overcolor, .overopacity),
on: _makeColorInfo(.oncolor, .onopacity)
];
}
scWidth = kag.scWidth;
scHeight = kag.scHeight;
}
function finalize() {
if (cglayer !== void) {
cglayer.visible = false;
invalidate cglayer;
}
if (cglayerbak !== void) {
cglayerbak.visible = false;
invalidate cglayerbak;
}
cglayer = void;
cglayerbak = void;
invalidate rex if (rex !== void);
invalidate button if (button !== void);
super.finalize(...);
}
function _makeColorInfo(col, opa) {
return (col !== void || opa !== void ) ? %[
color: (col !== void) ? (+col & 0xFFFFFF) : 0,
alpha: (col !== void) ? (+col >>> 24) : 0,
opacity: (opa !== void) ? +opa : 255
] : void;
}
// csvファイルデフォルト
function getDefaultCsvFile() { return "cglist.csv"; }
// csv読み込み
function doLine(columns, lineNo) {
switch (columns[0].charAt(0)) {
case ":": return renewItemPage(); // 改ページ
case "*": return items.add(void); // 空枠
}
var info = %[];
info.list = [];
info.tag = columns[0];
for (var i = 1; i < columns.count; i++) {
var s = parseItem(columns);
info.list.add(s) if (s !== void);
}
items.add(info);
}
// GalleryModeから委譲
function getThumbnail(pos) { return items[pos].tag; }
function getOriginal(pos) {
var orig = items[pos].list[0];
if (orig === void) return void;
with (orig) return (.flag == "" || .flag.charAt(0) == "@") ? .file : .flag;
}
function operateThumbnailEffect(sel, layer, w, h) {
var eff = _effect[sel];
if (eff !== void) with (eff) {
var oface = layer.face;
layer.face = dfMain;
layer.colorRect(0, 0, w, h, .color, .alpha);
layer.face = oface;
return .opacity;
}
}
function parseItem(name) {
if (name == "" || (name = name.trim()) == "") return;
var files = name, flags, q;
if ((q = name.indexOf("?")) >= 0) {
files = name.substr(0, q);
flags = name.substr(q+1).trim();
}
var ret = %[];
var div = files.split("|",, true);
ret.file = div[0].trim() if (div[0] != "");
ret.flag = (flags != "") ? flags : ret.file;
var comp = [];
for (var i = 1; i < div.count; i++) {
var item = div.trim();
if (item == "") continue;
var elm, file, m = rex.match(item);
if (m.count != 0) elm = %[ file: (file = m[1].trim()),
"x" => +m[2], "y" => +m[3],
"pos" => ((m[4] != "") ? +(m[4].substr(1)) : 0) ];
else elm = %[ file: (file = item.trim()) ];
if (file.charAt(0) == "*") {
ret.flag = elm.file = file.substr(1);
}
comp.add(elm);
}
ret.composite = comp if (comp.count > 0);
return ret;
}
// itemを既にみているか?
function isSeenItem(info) {
var flag = info.flag;
if (tf.allseen || flag == "") return true;
var fn = (flag.charAt(0) == "@") ? flag.substr(1) : ("cg_" + flag.toUpperCase());
return (fn != "" && sf[fn]);
}
/**
* CG を既にみているか?
* @param num CG番号
* @param i 差分番号
*/
function isSeenOne(num, i) {
if (num < 0 || num >= count || i < 0) return false;
var list = items[num].list;
if (i >= list.count) return false;
return isSeenItem(list);
}
/**
* CG を既にみているか?
* @param num CG番号
*/
function isSeen(num) {
if (num < 0 || num >= count || items[num] === void) return null;
var list = items[num].list;
if (list === void || !list.count) return null;
for (var i = 0; i < list.count; i++)
if (isSeenItem(list)) return true;
return false;
}
/**
* 開いている割合を調べる
* @return %[ seen:見た枚数, total:全体枚数, percent:パーセント ];
*/
function getSeenCounts() {
var total = 0, seen = 0;
for (var i = count-1; i >= 0; i--) {
if (items === void) continue;
var num, list = items.list;
total += (num = list.count);
for (var j = num-1; j >= 0; j--)
if (isSeenItem(list[j])) seen++;
}
return %[ seen:seen, total:total, percenttotal > 0) ? seen*100/total : 0 ];
}
// cglayerの表裏入れ替え
function swapCgLayer(visible) {
cglayerbak <-> cglayer;
cglayer.parent = kag.back.base;
cglayer.visible = visible;
}
function hideBack() {
swapCgLayer(false);
}
function update() {
hideBack();
super.update();
}
function hideView() {
cglayerbak.visible = cglayer.visible = false;
}
var subItemPos, subItems;
/**
* CGを表示
*/
function view() {
swapCgLayer(true);
var data = subItems[subItemPos++], loaded, err;
try {
cglayer.loadImages(data.file);
var comp = data.composite;
if (comp !== void) {
var tmp = kag.temporaryLayer;
for (var i = 0; i < comp.count; i++) {
var info = loadCompositeLayer(comp, tmp);
doComposite(info, cglayer, tmp); // 上書き合成処理
}
}
loaded = true;
} catch (e) {
err = e.message;
loaded = false;
}
if (!loaded) with (cglayer) { // ロード失敗時
.setSize(scWidth, scHeight);
.setSizeToImageSize();
.fillRect(0, 0, .width, .height, 0xFF00FFFF);
.drawText(0, 0, err, 0x000000, 255, true);
dm("画像ロード失敗", err);
}
}
// 合成用CGを読み込む
function loadCompositeLayer(mux, lay) {
var info = %[];
switch (typeof mux) {
case "String": info = parseComposite(mux); break;
case "Object": (Dictionary.assign incontextof info)(mux, true); break;
}
var w = scWidth, h = scHeight;
if (info.file != "") with (lay) {
.loadImages(info.file);
w = .imageWidth;
h = .imageHeight;
}
info.width = w;
info.height = h;
return info;
}
// CGを合成する
function doComposite(info, dst, src) {
var w = dst.imageWidth, h = dst.imageHeight;
var ox, oy, cw, ch, pos;
with (info) cw=.width, ch=.height, ox=.x, oy=.y, pos= +info.pos;
pos = 5 if (!pos);
if ( pos == 2 || pos == 5 || pos == 8) ox += (w - cw) >> 1; // h-center
else if (pos == 3 || pos == 6 || pos == 9) ox += (w - cw); // right
if ( pos == 4 || pos == 5 || pos == 6) oy += (h - ch) >> 1; // v-center
else if (pos == 1 || pos == 2 || pos == 3) oy += (h - ch); // bottom
//dm("doComposite", pos, ox, oy, w, h, cw, ch);
dst.operateRect(ox, oy, src, 0, 0, cw, ch);
}
function focusView() {
cglayer.focus();
cglayerbak.visible = false;
}
function onSelect(num) {
isCancelView = false;
subItemPos = 0;
subItems = [];
var list = items[num].list;
for (var i = 0; i < list.count; i++)
subItems.add(list) if (isSeenOne(num, i));
}
var triggerName = "cgdone";
var isCancelView = false;
function onNext(message) {
switch (message) {
case "break": isCancelView = true; break;
case "next": isCancelView = false; break;
}
kag.trigger(triggerName);
}
property isQuitViewLoop { getter() {
return isCancelView || ((subItems.count - subItemPos) <= 0);
} }
}
with (CgGalleryMode) {
// ページ位置保存用
.lastPage = 0;
// CG表示クラス
.CgViewLayerClass = global.CgViewLayer;
}