10.8 メッセージ履歴のカスタマイズ 〜基本編〜(その5)

今回は everypagefalse の時、 つまりページ単位で履歴メッセージを表示しない時の初期履歴メッセージを表示するスクリプトを見てくね。
STEP 3-2 の処理だね。
ん、そう。スクリプト的にはdispInit メソッドのここの else ブロックの中身になるね。
最初の if のとこで、verticalView の値をチェックしてて…
えっと、縦書きの時も横書きの時も dispLines って値を計算してるみたいだけど、これって?
dispLines は画面に一度に何行までメッセージが表示できるかを表してる値だよ。
表示できる行数って縦書きの時と横書きの時で違うの?
ウィンドウの縦と横のサイズが同じだったら同じ行数になるけど、 大体ウィンドウは横の方が長いから、縦書きの時の方が行数が多くなる(つまり dispLines の値が大きくなる)でしょ。
あ、そっか。
まぁこの辺は計算式だけ見てもわかりにくいと思うから、ちょっと図にしてみるね。

<横書きの時のメッセージ履歴画面の例(デフォルトの設定の場合)>

まず、横書きの時(verticalViewfalse の時)はこんな感じ。
この図って前にも似たよーなのが出てきたよね。
まぁね。けど、今回の図は dispLines の値が計算できるように marginT とか lineHeight に具体的な値が書いてあるでしょ。
そーいえば、前は何ピクセルとか書いてなかったね。
え〜っと…この図の場合だと、メッセージが 16 行表示されてるから、 dispLines16 ってことかな?
そうそう。
ちなみに横書きの時は dispLines の値は “(height - marginT - marginB - controlHeight) \ lineHeight” になるんだけど、それぞれどんな値か憶えてる?
height がメッセージ履歴レイヤの高さで、 marginTmarginB がそれぞれ上側と下側の余白で、 controlHeight は『前ページ』とかのボタンの高さで、 lineHeight がメッセージ1行分の高さだよね。
ん、そうだね。で、この図の場合の値を dispLines を計算する式に当てはめてみると…
(480 - 12 - 12 - 20) \ 26 = 436 \ 26 = 16
になるわけね。
確かに 16 になるね。
ちなみに、43626 で割ると 16 余り 20 になるから、 一番最後の行(15行目だね)の下に 20 ピクセル分の高さの余白が出来てるとこにちょっと注意してね。

<メッセージ履歴レイヤ下部にできる隙間>

ホントだ。ちょっと隙間ができてるね。
隙間を作りたくなかったら、 (height - marginT - marginB - controlHeight)lineHeight で割り切れるように設定しとくといいよ。
そっか。わかった。
んで、こっちが縦書きの時の図ね。

<縦書きの時のメッセージ履歴画面の例(デフォルトの設定の場合)>

こっちは 23 行かぁ…確かに縦書きにした方が行数が多くなってるね。
まぁその代わり1行に表示できるメッセージの長さは横書きの時より短くなるけどね。
あ、確かにそーだね。
じゃあ結局、画面に一度に表示できるメッセージの量は横書きでも縦書きでもそんなに変わらないんだね。
横書きでも縦書きでもウィンドウの面積は同じだから、まぁ当然だよね。
で、縦書きの時は “dispLines = (width - marginR - marginL) \ lineHeight” だから…
えと、この場合は (640 - 12 - 12) \ 26 = 23 余り 18 だから、23 行表示できて、 左端に 18 ピクセル分の隙間ができるってことかな?
ん、そういうこと。じゃ次いくね。
次の if ブロックと else ブロックの中で、メッセージ履歴レイヤにメッセージを書き込んでるんだ。
dataLinesdispLines 以下かどうかをチェックしてるみたいだけど、dataLines って?
dataLines はメッセージ履歴全体のメッセージの行数だよ。
じゃあ、メッセージ履歴全体のメッセージの行数がメッセージ履歴画面に一度に表示できるメッセージの行数以下だったら if ブロックの中身が実行されて、 メッセージ履歴全体のメッセージの行数の方がメッセージ履歴画面に一度に表示できるメッセージの行数より多かったら else ブロックの中身が実行されるってことだよね。
そ。じゃまずは if ブロックの中身から見てくね。
こっちでも canScroll の値を設定してるね。
everypagetrue の時は canScroll はページを切り替えられるかどうかを表してたんだけど(前回参照ね)、 everypagefalse の時は canScroll はメッセージ履歴がスクロールできるかどうかを表すんだ。
じゃあ false が代入されてるってことは、 スクロールできないってこと?
if ブロックの中身が実行されてる時は、 メッセージ履歴全体のメッセージの行数がメッセージ履歴画面に一度に表示できるメッセージの行数以下なわけだから、 メッセージ履歴画面に全部の履歴メッセージが表示できるでしょ。
あ、だからスクロールする必要ないんだね。
そういうこと。
次の dispStart は今何ページ目が表示されてるかを表してるんだよね。
everypagetrue の時はそうなんだけど、everypagefalse の時はちょっと違う意味になるんだ。
え、そーなの?
everypagefalse の時は、 dispStart は今メッセージ履歴画面の一番上の行(縦書きの場合は一番右の行ね)に表示されてるメッセージが何行目のメッセージかを表してるんだ。
だから、履歴メッセージ全体が 100 行あって、 画面に一度に表示できるメッセージが 16 行だとすると、 例えば dispStart50 になってたら、 今画面に表示されてるのは 50 行目〜 65 行目の履歴メッセージってことになるね。
へぇ…
じゃあ、ここだと dispStart0 になるから、 0 行目〜15 行目が表示されるってことかな?
履歴メッセージが 16 行あれば 0 行目〜15 行目が表示されて、 履歴メッセージが 15 行以下だと、 履歴メッセージの行数分だけ表示されるよ(例えば履歴メッセージが 10 行しかなかったら、0〜9 行目が表示されるってことね)。
まぁどっちにしても、履歴メッセージが全部表示されるってことだね。
if ブロックの中身が実行されてるってことは、 履歴メッセージ全体が画面に表示できるってことだもんね。
ん。で、次の for ループで、 それぞれの行の履歴メッセージをメッセージ履歴レイヤに書き込んでるの。
drawLine ってメソッドが履歴メッセージをレイヤに書き込むメソッドなの?
そだよ。ちなみに第1引数で何行目のメッセージを書き込むかを指定するんだ。
引数には i が指定されてるから…
for でループする間に 0 行目〜(dataLines - 1) 行目のメッセージが書き込まれるってこと?
そう。つまり for ループを実行すると、 全部の行の履歴メッセージが書き込まれるってわけだね。
なるほどね。
drawLine メソッドはもうちょっと後で詳しく見てくとして、 次は else ブロックの中身を見てこっか。
else ブロックの中身は、 メッセージ履歴画面に全部のメッセージが表示できない時(つまり dataLinesdispLines より大きい時ってことだね)に実行されるんだよね。
そ。で、その時はメッセージをスクロール表示できるから…
canScrolltrue になるんだね。
ん。
じゃ dispStart はどうなってるかわかる?
dataLines - dispLines” になってるね。
これって履歴メッセージ全体の行数から画面に一度に表示できるメッセージの行数を引いた値だよね。
そうなるね。
じゃあ例えば、履歴メッセージ全体が 100 行あって、 画面に一度に表示できるメッセージが 16 行だとすると、 dispStart はいくつになる?
100 - 16 だから 84 だね。
じゃ何行目から何行目までが表示される?
84 行目〜 99 行目だよね。
それって履歴メッセージのどの辺になってる?
え? どの辺って…だから 84 行目〜 99 行目でしょ?
まぁそーなんだけど、履歴メッセージが 100 行あるってことは、 最後の行は 99 行目になるってことだから、 84 行目〜 99 行目ってのは履歴メッセージの最後から 16 行分になるわけ。
あ、なるほど、そーゆーコトね。
確かにメッセージ履歴画面を表示した時って、最初に履歴メッセージの最後の方が表示されるね。
で、後はさっきと同じで for ループを使ってメッセージを表示するわけね。
…ん?
ねぇ、この for ループって i0 から始まって dispLines - 1 までの間ループするみたいだけど、 dispStart 行目からメッセージを表示するんだから、 dispStart から始まって dataLines - 1 までの間ループするんじゃないの?
drawLine(i);” を実行した時にメッセージ履歴レイヤに書き込まれるのは i 行目じゃなくて dispStart + i 行目の履歴メッセージなんだ。
え、そーなの?
drawLine(i);” の意味は、 「メッセージ履歴レイヤの上から i 番目の行(縦書き表示の時は右から i 番目の行)に、 dispStart + i 行目の履歴メッセージを書き込む」ってことなの。
例えば、さっきの例の場合(dispStart84 の時ね)は、 i0 だとメッセージ履歴レイヤの一番上の行(縦書き表示の時は一番右の行)、 つまり 0 行目を表示する位置に、84 行目の履歴メッセージを書き込むってことね。
だから、横書き表示の場合だと、for ループの中でまずメッセージ履歴画面の一番上の行(0 行目)に 84 行目を書き込んで、 次にその下の行(1 行目)に 85 行目を書き込んで…っていうふうに履歴メッセージを書き込んでって、
最後に一番下の行(15 行目)に 99 行目を書き込むわけね。
あ、そーゆー意味ね。わかった。
んじゃ次は drawLine メソッドの中身を見てくね。

drawLine メソッド(HistoryLayer.tjs より抜粋)>

function drawLine(n)
{
    // 表示行 n を描画する

    // 表示する行の履歴メッセージを取得します
    var line = everypage?getPage(dispStart)[n]:getLine(n + dispStart);
    // (everypage が true の場合) line が空文字列であれば書き込む必要がないのでここで return します
    if(everypage && line==""return;
    // 履歴メッセージの表示開始位置(インデントの長さ)を取得します
    var linestart = everypage?getLineStart2(dispStart, n):getLineStart(n + dispStart);
    // 履歴メッセージを書き込みます
    if(verticalView)
    {
        var x = width - marginR - n*lineHeight;
        drawText(x, marginT + controlHeight + linestart, line, historyColor, 255, antialiased);
    }
    else
    {
        var y = n*lineHeight + controlHeight + marginT;
        drawText(marginL + linestart, y, line, historyColor, 255, antialiased);
    }
}
※コメントを追加しています。

そんな長いスクリプトじゃないみたいだけど…最初の line って変数に値を代入してるとこがまずよくわかんないかな…
line に値を代入してるとこに条件演算子が使われてるのはわかるよね?
※条件演算子については §1.20 参照。
ん〜…スペースが入ってないからちょっとわかりにくいけど、 確かに “?” と “:” が入ってるね。
条件演算子の “?” と “:” の両側には別にスペースを入れなくても OK だからね。
そーなんだ。
えっと、じゃあ…everypagetrue だったら line に “getPage(dispStart)[n]” ってゆー値が代入されて、everypagefalse だったら line に “getLine(n + dispStart)” の戻り値が代入されるってことだよね?
ん、そうそう。
要するに everypagetruefalse かで違う値を line に代入してるってことみたいだけど…
確かこの drawLine メソッドって everypagefalse の時に呼び出されるんじゃなかったっけ?
dispInit メソッドの中だと everypagefalse の時しか呼び出されないけど、 他のメソッドの中で everypagetrue の時でも drawLine メソッドが呼び出されることがあるんだ。
あ、そーなんだ。
じゃあそれはいいとして、everypagefalse の時に line に “getPage(dispStart)[n]” って値を代入してるけど、 これって getPage メソッドの戻り値を代入してるってこと?
getPage メソッドの戻り値をそのまま代入してるわけじゃないよ。
どーゆーコト?
前回 getPage メソッドの戻り値は配列になるって言ったでしょ。
確か getPage メソッドって、 引数に指定したページの履歴メッセージを配列の形で取得するメソッド、だったよね。
そ。で、配列の添え字は “[” と “]” で囲んで指定するでしょ。
そーだね。
だから、“getPage(dispStart)[n]” ってのは、 “getPage メソッドの戻り値の配列の n 番目の要素” って意味になるの。
えっと、それってつまり…

line に値を代入している行と等価なスクリプト>

var line;
if(everypage)
{
    var page = getPage(dispStart); // dispStart ページ目の履歴メッセージを取得します
    line = page[n]; // dispStart ページ目の n 行目の履歴メッセージを line に代入します
}
else
    line = getLine(n + dispStart);

こんなふうに書いてもおんなじ意味ってこと?
ん、そーだよ。
このスクリプトを1行で書くとこれになるわけね。
TJS スクリプトってホント色んな書き方ができるよねぇ…
まぁね。
スクリプトをコンパクトに書きたかったらこっち、 解りやすく書きたかったらこっちって感じで書き分ければいいんじゃないかな。
なるほどねぇ。
ところで、getLine メソッドってまだ出てきてなかったよね?
getLine メソッドは、引数に指定した行の履歴メッセージを取得するメソッドだよ。
getPage メソッドと違って取得できる履歴メッセージは1行だけだから、 戻り値は配列じゃなくて文字列になるよ。
そっか。だから戻り値をそのまま line に代入してるんだね。
そういうこと。
getLine メソッドの中身の説明は省略させてもらうけど、 引数の “n + dispStart” は “n + dispStart 行目の履歴メッセージを取得する” って意味だから。
じゃあ、メッセージ履歴レイヤの上から(縦書きの場合は右から) n 行目に表示する履歴メッセージを取得するってことかな?
ん、そうなるね。
つまり、drawLine メソッドは everypagetrue の時でも false の時でも、メッセージ履歴レイヤの上から(縦書きの場合は右から) n 行目に表示する履歴メッセージを取得してメッセージ履歴レイヤに書き込むメソッドってことだね。
あ、そっか。確かにそーなるね。
じゃ次の行にいくね。
これって everypagetrueline が空文字列だったら return するってことだよね。
まぁ空文字列ってことは1文字も文字がないってことだから、 メッセージ履歴レイヤに何も書き込まなくていいってことになるよね。
だからここで return して、それ以降の処理をやらないようにしてるの。
なるほどね。
…あ、でも everypagefalse だったら line が空文字列でも return しないよね?
ん〜、確かにそーなんだけどね…
実は何でそうなってるかはよくわかんないんだよね…
え?
everypagefalse の時でも、 空文字列だったらメッセージ履歴レイヤに何も書き込む必要ないはずだから、 ここで return してもいいと思うんだけど…何で everypagetrue の時だけ return するようになってるのかはよくわかんなかったんだ。
そーなんだ…
まぁ everypagefalse の時でも line が空文字列だったら(多分)ここで return しても問題ないと思うし、 ここで return してもしなくても同じ結果になるとは思うよ。
同じ結果になるって…メッセージ履歴レイヤに何も書き込まれないってコト?
そう。
ってワケで、ここから先のスクリプトは line が空文字列じゃないって仮定して見ていくことにするね。
りょーかい。
それじゃ次の行に行くね。
今度は linestart っていう変数に値を代入してるけど、 さっき line に値を代入した時とよく似てるね。
じゃ linestart にどんな値が代入されるかは分かるよね?
everypagetrue だったら “getLineStart2(dispStart, n)” の戻り値が代入されて、everypagefalse だったら “getLineStart(n + dispStart)” の戻り値が代入されるよね。
ん、そう。
getLineStart2 メソッドは前回も出てきたから意味はわかるよね?
インデントの長さを取得するメソッド、だったっけ?
そ。で、everypagefalse の時に呼び出される getLineStart メソッドも基本的には同じことをするメソッドなんだ。
それって getLineStart メソッドもインデントの長さを取得するメソッドってこと?
ん。getLineStart メソッドは everypagefalse の時用のメソッドで、 getLineStart2 メソッドは everypagetrue の時用のメソッドなの。
へぇ、そーなんだ。
じゃあ “getLineStart(n + dispStart)” の戻り値は “メッセージ履歴レイヤの上から(縦書きの場合は右から) n 行目に表示する履歴メッセージのインデントの長さ” になるってこと?
そういうこと。
つまり、everypagetrue の時でも false の時でも、 linestart にはメッセージ履歴レイヤの上から(縦書きの場合は右から) n 行目に表示する履歴メッセージのインデントの長さが代入されるってことだね。
だね。
で、あとはこの if ブロックelse ブロックの中でメッセージ履歴レイヤに履歴メッセージを書き込んでるんだ。
メッセージを書き込む処理は前回 drawPage メソッドでやってたのとほぼ同じなんだけど、わかるかな?
う〜ん、確かにどっちも drawText メソッドを呼び出してるし、 引数も似てる感じだけど…完全におんなじってわけでもないよね。
見た目はちょっと違ってても実際はおんなじなんだけどね。
じゃ drawPage メソッドの中で呼び出してる drawText メソッドの引数と drawLine メソッドの中で呼び出してる drawText メソッドの引数を見比べてみるね。
まずは verticalViewtrue の時(縦書き表示の時)はこんな感じだね。

drawPage メソッド内drawLine メソッド内で呼び出される drawText メソッドの引数比較(縦書き表示の場合)>

drawPage メソッド内での引数
i 行目のメッセージを表示する場合)
drawLine メソッド内での引数
第1引数width - marginR - i * lineHeightwidth - marginR - n * lineHeight
第2引数marginT + controlHeight + getLineStart2(dispStart, i)marginT + controlHeight + linestart
第3引数page[i]line
第4引数historyColorhistoryColor
第5引数255255
第6引数antialiasedantialiased
drawText メソッドの引数の意味については §3.4 参照。

まず第1引数から見てみるね。
第1引数って文字を表示する位置の x 座標だよね。
drawText メソッドを呼び出す時に第1引数に指定してるのは “x” になってるけど、この表の第1引数のとこには “x” じゃなくて “width - marginR - i * lineHeight” とか “width - marginR - n * lineHeight” って書いてあるよね?
まず、drawLine メソッドの中で drawText メソッドを呼び出す前に、ここxwidth - marginR - n * lineHeight を代入してるから、 つまり第1引数は width - marginR - n * lineHeight ってことになるよね。
なるほど、確かにそーなるね。
drawPage メソッドの中で drawText メソッドを呼び出す前にも、ここxwidth - marginR を代入してるでしょ。
そーだけど、この表には “width - marginR - i * lineHeight” って書いてあるよ?
for ループを1回実行するごとに x から lineHeight を引いてってるから、 i 番目の行のメッセージを書き込む時(つまり i 回目のループを実行する時)には x の値は width - marginR - i * lineHeight になるの。
あ、そっか。
で、“i” と “n” の違いは、 単に変数の名前が違うだけだから、結局 “width - marginR - i * lineHeight” と “width - marginR - n * lineHeight” は同じ意味になるんだ。
じゃあどっちも同じ位置にメッセージを書き込んでるってこと?
そういうことだね。
じゃ次は第2引数ね。
drawPage メソッドの中で drawText メソッドを呼び出す時は “marginT + controlHeight + getLineStart2(dispStart, i)” だけど、 drawLine メソッドの中で drawText メソッドを呼び出す時は “marginT + controlHeight + linestart” だね。
linestartgetLineStart2(もしくは getLineStart)メソッドの戻り値になってるから、 “marginT + controlHeight + linestart” と “marginT + controlHeight + getLineStart2(dispStart, i)”は同じ意味になるよね。
どっちも履歴メッセージを表示する時の上側の余白(marginT)と「前ページ」とかのボタンの高さ(controlHeight)とインデントの長さ(getLineStart2 メソッドの戻り値)を足した値になってるってことなんだね。
そう。
じゃ次、第3引数ね。
drawPage メソッドの中で drawText メソッドを呼び出す時は “page[i]” で、 drawLine メソッドの中で drawText メソッドを呼び出す時は “line” だね。
page[i] ってどんな値になるんだった?
えっと、右から i 行目に表示される履歴メッセージ、だったかな?
そ。じゃ line は?
右から n 行目に表示される履歴メッセージだよね?
さっきも言ったように、“i” と “n” の違いは単に変数名が違うってだけだから…
page[i]line も同じ意味ってこと?
そういうこと。
あと第4引数〜第6引数は見ての通り全く同じだから、 結局 drawLine メソッドの中でも drawPage メソッドの中でやってたのと同じやり方でメッセージ履歴レイヤに履歴メッセージを書き込んでるってことだね。
なるほどね〜。
んじゃ verticalViewfalse の時(横書き表示の時)の drawText メソッドの引数も同じように比べてみるね。

drawPage メソッド内drawLine メソッド内で呼び出される drawText メソッドの引数比較(横書き表示の場合)>

drawPage メソッド内での引数
i 行目のメッセージを表示する場合)
drawLine メソッド内での引数
第1引数marginL + getLineStart2(dispStart, i)marginL + linestart
第2引数i * lineHeight + controlHeight + marginTn * lineHeight + controlHeight + marginT
第3引数page[i]line
第4引数historyColorhistoryColor
第5引数255255
第6引数antialiasedantialiased

第1引数の “marginL + getLineStart2(dispStart, i)” と “marginL + linestart” が同じ意味になるのはわかるよね?
getLineStart2(dispStart, i)” と “linestart” は同じ意味だからだよね。
そ。じゃ第2引数ね。
まず drawLine メソッドの方が “n * lineHeight + controlHeight + marginT” になってるのは、 drawText メソッドを呼び出す前に y に “n*lineHeight + controlHeight + marginT” を代入してy を第2引数に指定してるからなんだよね?
そだよ。
drawPage メソッドの方が “i * lineHeight + controlHeight + marginT” になってるのは…
for ループに入る前に y に “controlHeight + marginT” を代入しててループを1回実行するごとに ylineHeight を足してってるから、かな?
ん、そのとーり。
第3引数〜第6引数は縦書き表示の時と同じだから特に説明の必要ないよね?
うん。
横書き表示の時も drawPage メソッドの中でやってたのと同じやり方でメッセージ履歴レイヤに履歴メッセージを書き込んでるんだね。
だから、基本的に drawPage メソッドと drawLine メソッドの違いは、1ページ分の履歴メッセージを書き込むか、1行分の履歴メッセージを書き込むかってことだけだね。
そーみたいだね。
さて、それじゃこれで STEP 3-2 のスクリプトの内容は一通りチェックできたから、今回はここまでにしとくね。
は〜い。
次回は STEP 4 〜 STEP 6 を見てく予定だよ。
あ、じゃあ次回でやっと dispInit メソッドが終わるんだね。
そういうことになるね。
それじゃ、また次回ね!


前へ | TOP | 次へ