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

今回は everypagefalse の時、つまり行単位で履歴メッセージを表示する場合に、スクロールバーを操作した時に呼び出される setLine メソッドを見てくね。
えっと、それも前回やった scrollUp メソッドとか scrollDown メソッドみたいに、 履歴メッセージをスクロール表示するためのメソッドなんだよね?
そだよ。
scrollUp メソッドとか scrollDown メソッドは1行ずつ履歴メッセージをスクロール表示するメソッドだったわけだけど、 スクロールバーの場合は一度に何行もスクロールしなくちゃいけなくなることもあるから、 専用のメソッドを作ることにしたんだ。
じゃあ setLine メソッドって一度に何行もスクロールできるメソッドなんだ?
まぁそういうことだね。
setLine メソッドは、 スクロールできる範囲ならどの行からでも履歴メッセージを表示できるメソッドだからね。
へぇ、そーなんだ。
それじゃ、setLine メソッドのスクリプトを見てくね。

setLine メソッド>

function setLine(line)
{
    if(dispStart == line)
        return// 既に表示されているので何もしません
    // 何行分履歴メッセージを更新する必要があるかを計算します
    var diff = line - dispStart;
    if(diff <= -dispLines || diff >= dispLines)
    {
        // (履歴メッセージをスクロールする量が多くて)画面全体を更新する必要がある場合は
        // 全ての履歴メッセージを消去して全ての行のテキストを書き込みます
        clearBack();
        dispStart = line;
        for(var i=0;i<dispLines;i++)
            drawLine(i);
    }
    else if(diff > 0)
    {
        // 履歴メッセージを上(縦書きの場合右)方向にスクロールする場合は...
        clearActionHighlights(); // hact タグによるリンク表示を全て消去します

        // 画面内に表示されている履歴メッセージのうち
        // スクロールしても画面外に出ない部分はスクロール後の位置に移動します
        if(verticalView)
        {
            copyRect(width - marginR - lineHeight * (dispLines - diff), controlHeight, this,
                width - marginR - lineHeight * dispLines, controlHeight,
                lineHeight * (dispLines - diff), height - controlHeight);
        }
        else
        {
            copyRect(0, controlHeight + marginT, this,
                0, controlHeight + lineHeight * diff + marginT,
                width, lineHeight * (dispLines - diff));
        }

        // スクロールすると画面外に出てしまう履歴メッセージを消去します
        var i;
        for(i=1;i<=diff;i++)
            clearBack(dispLines - i);
        dispStart = line; // 表示開始位置を更新します
        // スクロールすることで新しく出現した行の履歴メッセージを最後の行から書き込んでいきます
        for(i=1;i<=diff;i++)
            drawLine(dispLines - i);
    }
    else if(diff < 0)
    {
        // 履歴メッセージを下(縦書きの場合左)方向にスクロールする場合も
        // 基本的に手順は同じです
        diff = -diff;
        clearActionHighlights();
        if(verticalView)
        {
            copyRect(width - marginR - lineHeight * dispLines, controlHeight, this,
                width - marginR - lineHeight * (dispLines - diff), controlHeight,
                lineHeight * (dispLines - diff), height - controlHeight);
        }
        else
        {
            copyRect(0, controlHeight + lineHeight * diff + marginT, this,
                0, controlHeight + marginT,
                width, lineHeight * (dispLines - diff));
        }
        var i;
        for(i=0;i<diff;i++)
            clearBack(i);
        dispStart = line;
        for(i=0;i<diff;i++)
            drawLine(i);
    }
    updateButtonState(); // ボタンの表示状態を更新します
}
※コメントを一部改変しています。

長っ!
まぁ setLine メソッドは HistoryLayer クラスの prevPage メソッドと nextPage メソッドと scrollUp メソッドと scrollDown メソッドを合わせたようなメソッドだからね。
prevPage, nextPage メソッドについては §10.10scrollUp, scrollDown メソッドについては §10.11 参照。
え、そーなの?
それだけのメソッドを合わせてたらそりゃ長くもなるよね…
ま、見た目は長いけど、やってることは prevPage メソッドとか scrollUp メソッドに似てるから、ちょっとはわかりやすいんじゃないかな。
そーなの?
うん。
じゃとりあえず最初から見てくね。
最初の if のとこdispStartline の値が同じかどうかチェックしてて、 同じだったら何もせずに return してるね。
dispStart は、今表示してる履歴メッセージの一番最初の行が履歴メッセージ全体で何行目かを表してる値だけど、 setLine メソッドの引数になってる line ってどんな値なの?
line は、スクロール後の履歴メッセージの一番最初の行が履歴メッセージ全体で何行目かってのを表してる値だよ。
つまり、setLine メソッドが呼び出された後は、 履歴メッセージの一番最初の行が履歴メッセージ全体で line 行目になるってことね。
じゃあ、dispStartline の値がおんなじってことは…
今表示してる履歴メッセージの最初の行(dispStart)と、 スクロール後の履歴メッセージの最初の行(line)がおんなじってことになるから、 何もする必要ないってこと?
ん、そういうこと。
それじゃ次いこっか。
line - dispStartdiff って変数に代入してるね。
line - dispStart” がどんな値になるかはわかる?
えっと…スクロール後の履歴メッセージの最初の行から、 今表示してる履歴メッセージの最初の行を引いた値ってことだよね…?
そ。
うーん…それって何の値になるんだろ…?
例えば、今表示してる履歴メッセージの最初の行(dispStart)が3行目で、 スクロール後の履歴メッセージの最初の行(line)が10行目だとすると、 diff の値は?
10 - 3 だから 7 になるよね。
じゃ、今表示してる履歴メッセージの最初の行が3行目で、 10行目からの履歴メッセージを表示したい時には、 何行先にスクロールすればいいと思う?
7行だね。
これで diff がどんな値かわかったでしょ?
あ、もしかして diff って何行先にスクロールするかを表してる変数ってこと?
そういうこと。
ちなみに、さっきとは逆に、今表示してる履歴メッセージの最初の行が10行目で、 スクロール後の履歴メッセージの最初の行が3行目だとすると、 diff の値は?
それだと 3 - 10-7 になるね。
この場合は、7行前のメッセージを表示することになるよね。
そだね。
つまり、diff の値がプラスだと先の履歴メッセージを表示して、 マイナスだと前の履歴メッセージを表示するって意味なのね。
じゃあ diff7 だと7行先にスクロールして、 -7 だと7行前にスクロールするってことなんだね。
そう。
じゃ次の if ブロックのとこで何をチェックしてるかわかる?
diff <= -dispLines || diff >= dispLines”って条件だから、 diff の値が -dispLines 以下になってるか、dispLines 以上になってれば if ブロックの中が実行されるってことだよね。
そうだね。
-dispLines って dispLines の値のマイナスってこと?
そうだよ。
例えば dispLines5 だったら -dispLines-5 になるよ。
え〜っと…じゃあ dispLines 以下の行数分前にスクロールするか、 dispLines 以上の行数分先にスクロールする時に if ブロックの中が実行されるってことかな?
ん〜、ちょっと違うねー。
えっ、違うの?
例えば dispLines10 だとしたら、 lines-10 以下の時か 10 以上の時に if ブロックの中が実行されるよね。
そーだね。
-10 以下ってことは -10 とか -11 とか -12 とかってことだし、 10 以上ってことは 10 とか 11 とか 12 とかってことだよね。
うん。
10 とか 11 とか 12 の時は dispLines 以上の行数分先にスクロールするってのは合ってるんだけど…
うん?
-10 の時は10行前にスクロールするってことだし、 -11 の時は11行前にスクロールするってことだから、 “dispLines 以下の行数分前にスクロールする”ってのはおかしいでしょ?
あ、そっか。確かにそーだね。
それじゃあ、dispLines 以下じゃなくて、 dispLines 以上の行数分前にスクロールするってことかな?
ん、そう。
つまり、“diff <= -dispLines || diff >= dispLines”は、“dispLines 行以上前か先にスクロールする”場合に真になるってことだね。
なるほどね。
ところで、dispLines ってどんな値だった?
メッセージ履歴画面に表示できる履歴メッセージの行数だよね?
つまり、1ページ分の履歴メッセージの行数ってことになるのかな。
ってことは、dispLines 行以上前か先にスクロールすると、 スクロールする前に表示されてた履歴メッセージは全部画面の外に出ちゃうよね。
メッセージ履歴画面に表示できる履歴メッセージの行数分以上前か先にスクロールするってことだから、 確かにそうなるね。
だから、ここの if ブロックの中では、 メッセージ履歴画面に表示されてる履歴メッセージを全部書き換えてるんだ。
そーなんだ。
最初に clearBack メソッドを呼び出してるでしょ。
clearBack メソッドについては §10.6 参照。
うん。
引数なしで clearBack メソッドを呼び出すとどうなるんだった?
画面に表示されてる履歴メッセージを全部消すんじゃなかったっけ?
そう。で、clearBack メソッドで履歴メッセージを全部消した後、 ここの for ループdrawLine メソッドを呼び出して、 スクロールした後の履歴メッセージを全部書き込んでるんだけど、 ここの for ループがどんなふうに実行されるかわかる?
drawLine メソッドについては §10.8 参照。
えっと…i0 から始まって、 dispLines より小さい間ループするから、 drawLine(0), drawLine(1), drawLine(2), ... , drawLine(dispLines - 1) っていう順番で、全部で dispLinesdrawLine メソッドが呼び出されるのかな?
ん。つまり、(横書き表示の場合だと)上から順番に1行ずつ履歴メッセージを書き込んでいくわけだね。
この部分は everypagefalse の時の HistoryLayer クラスの prevPage メソッドnextPage メソッドの処理に似てるでしょ。
確かに、どっちも clearBack メソッドを呼び出して、 dispStart の値を設定して、 drawLine メソッドで履歴メッセージを書き込んでるってとこがおんなじだね。
prevPage メソッドと nextPage メソッドもメッセージ履歴画面全体を書き換える必要があるからね。
そっか、だから似てるんだね。
それじゃ次はここの else if のブロックを見てくね。
条件が “diff > 0” ってことは、 このブロックは履歴メッセージを先の方にスクロールする時に実行されるってことだよね?
そう。
このブロックは HistoryLayer クラスの scrollUp メソッドに似てるでしょ?
ん〜、そー言われると似てるような感じもするかな。
こっちには最後の方に for ループがあったりしてちょっと違ってるみたいだけど。
scrollUp メソッドの時は1行だけ先にスクロールしてたでしょ。
そだね。
ここの else if ブロックの方は、 複数行先にスクロールすることもできるようになってるの。
それって diff2 以上だったら 2 行以上先にスクロールしなくちゃいけないからなんだよね?
そう。
scrollUp メソッドと違うのはそれだけで、やってることは scrollUp メソッドと同じなんだ。
あ、そーなんだ。
じゃここの else if ブロックでやってることを簡単にチェックしとくね。
はーい。
diff の値(つまりスクロールする行数だね)によってちょっと処理が違ってくるんだけど、 まぁどんな値になってても基本的な処理は変わらないから、とりあえず diff4 の時の処理の流れを見てくことにするね。
diff4 ってことは、 4行先にスクロールするってことだね。
そ。あと、今回は横書きの時の処理だけ見てくね。縦書きの時の処理は scrollUp メソッドを参照ってことで。
それから、dispLines10 ってことにしとくね。
りょーかい。
最初の clearActionHighlights メソッドはわかるよね。
hact タグで表示されるリンクを消すメソッドだね。
ん。じゃ次は copyRect メソッドを呼び出してるとこね。
横書き表示(verticalViewfalse)の時の処理を見てくから else ブロックの方だね。
copyRect メソッドについては §4.4 参照。
scrollUp メソッドで copyRect メソッドを呼び出してたとこと似てるけど、引数がちょっと違ってるみたいだね。
まぁ複数行スクロールできるようになってるからね。
これは前と同じように図にしてみた方が良さそうだね。
そーだね。スクリプトだけじゃわかりにくいもんね。
まず、これがコピー元の四角形領域だよ。

<4行先の方にスクロールする場合(diff4 の場合)の copyRect メソッドでのコピー元領域>

scrollUp メソッドの時のコピー元領域と比べてみると、違いがよくわかると思うよ。
scrollUp メソッドの時は一番上の1行以外がコピー元になってたけど、 こっちの方は上から4行分以外のとこがコピー元になってるね。
これってスクロールする行数が4行だからこうなってるの?
ん、そうだよ。
だからスクロールする行数が3行だったら、上から3行分以外のとこがコピー元になるし、 2行スクロールするんだったら、上から2行分以外のとこがコピー元になるわけね。
なるほどね。
んじゃ次はコピー先を見てみるね。

<4行先の方にスクロールする場合(diff4 の場合)の copyRect メソッドでのコピー先領域>

これも scrollUp メソッドの時のコピー先領域と比べてみるとわかりやすいんじゃないかな。
scrollUp メソッドの時は一番下の1行以外がコピー先になってたけど、 こっちの方は下から4行分以外のとこがコピー元になってるね。
これもスクロールする行数が4行だからこうなってるんだよね?
そう。特にわかりにくくはないでしょ?
まーね。
で、copyRect メソッドを呼び出した後はこうなるよね。

copyRect メソッド呼び出し後の状態>

じゃ次いくね。
clearBack メソッドを呼び出してるみたいだけど、 for ループがあるから、 何回か繰り返し呼び出してるってことだよね。
diff4 だったら何回呼び出される?
んーと、diff4 だと “for(i=1;i<=4;i++)” になって、i1, 2, 3, 4 の時に clearBack メソッドが呼び出されるから、4回だね。
clearBack メソッドは、 引数を指定するとその行の履歴メッセージを消すから、 この for ループで4行分の履歴メッセージを消してるってわけだね。
これも4行スクロールするからなの?
そ。この図見るとわかると思うけど、 4行先にスクロールすると、 下から4行分の“6行目のメッセージ” 〜 “9行目のメッセージ”の部分は、 “10行目のメッセージ” 〜 “13行目のメッセージ”にならなくちゃいけないでしょ。
そっか。だから下から4行分のメッセージを消さなきゃいけないんだね。
えっと、i1, 2, 3, 4 の時に、clearBack メソッドの引数は dispLines - 1, dispLines - 2, dispLines - 3, dispLines - 4 になるから、これで下から 1, 2, 3, 4 行目のメッセージが消せるってことかな。
そう。clearBack メソッドを呼び出した後はこうなるよね。

clearBack メソッド呼び出し後の状態>

んで次にさっき消したとこに10〜13行目のメッセージを書き込んでいくの。
ま、その前に dispStartline の値を代入する必要があるけどね。
確か drawLine メソッドで履歴メッセージを書き込む前に、 dispStart に一番上に表示される履歴メッセージの行の番号を代入しとかなくちゃいけないんだったよね?
そ。それから drawLine メソッドを呼び出すわけね。
今度も for ループになってるけど、 これってさっきの for ループで “clearBack” になってたとこが “drawLine” に変わっただけみたいだね。
まぁ clearBack メソッドで履歴メッセージを消したとこに書き込むわけだからね。
あ、そっか。
これで10〜13行目の履歴メッセージがこんなふうに書き込まれて、スクロール完了だね。

drawLine メソッド呼び出し後(スクロール完了)の状態>

この辺の処理HistoryLayer クラスの scrollUp メソッドのスクリプトと見比べてみると、 似てるのがわかると思うよ。
確かにやってることは似てるね。
それじゃ今度は diff0 より小さい時の処理を見てこっか。
履歴メッセージを前の方にスクロールする時だね。
ん。スクリプトを見てもらえばわかると思うけど、 履歴メッセージを先の方にスクロールする時とやり方はほぼおんなじだね。
今度は HistoryLayer クラスの scrollDown メソッドに似てるってことだよね?
そ。これも1行スクロールするか複数行スクロールするかの違いだね。
あ、でもこっちは最初に “diff = -diff;” って書いてあるけど?
あー、これね。
この後 copyRect メソッドの引数を指定したり for ループのループ条件を指定する時に、 diff がマイナスになってるとちょっとわかりにくくなりそうだから、 diff の値をプラスに変えてるの。
それってどーゆーコト?
例えば、4行前にスクロールする場合は diff-4 になってるから、 “diff = -diff;” を実行して diff の値を 4 にするってこと。
diff-4 の時に “diff = -diff;” を実行したら 4 になるの?
diff = -diff;” を実行すると、 diff の値のプラスマイナスが逆になるの。
ふぅん、そーなんだ。
要するに、今まで diff は “何行先にスクロールするか” を表してたんだけど、ここから(“diff = -diff;” を実行した後)は “何行前にスクロールするか” を表すことになるって考えてもらえば OK だよ。
そっか。りょーかい。
さて、こっからは履歴メッセージを先にスクロールする時と基本的にやり方はおんなじだから、 あとは説明よろしくね。
えっ、ここからわたしが説明するの?
scrollDown メソッドの時もほとんど説明してくれたし、大丈夫でしょ?
う〜ん…まぁ多分大丈夫だと思うけどねぇ。
ん、じゃよろしく。
えーっと、最初の clearActionHighLights メソッドは前に何回も出てきてるからいーよね?
うん。じゃ次いこっか。
あ、こっちも横書き表示の時だけでいいよ。
わかった。
横書き表示は verticalViewfalse だから、else ブロックの方だね。
ん。あ、あとメッセージ履歴画面に表示できるメッセージは10行(dispLines10)になってて、 4行前にスクロールする(diff4 になってる)ってことにしといて。
おっけー。
えっと、scrollDown メソッドの時は copyRect メソッドのコピー元の四角形は一番下の行以外の部分だったから、 4行前にスクロールするんだったら…

<4行前の方にスクロールする場合の copyRect メソッドでのコピー元領域>

こんなふうに、下から4行分以外の部分がコピー元になるよね。
それから、scrollDown メソッドの時は copyRect メソッドのコピー先の四角形は一番上の行以外の部分だったから、 4行前にスクロールする時のコピー先は…

<4行前の方にスクロールする場合の copyRect メソッドでのコピー先領域>

こんな感じで、上から4行分以外の部分がコピー先になるね。
うんうん。
だから、copyRect メソッドを呼び出すと…

copyRect メソッド呼び出し後の状態>

こうなるよね。
そーだね。
次は clearBack メソッドで、 こんなふうに上から4行分の履歴メッセージを消すんだね。

clearBack メソッド呼び出し後の状態>

ちなみに、ここの for ループの中の clearBack メソッドは、 i0, 1, 2, 3 の時に呼び出されるから、上から4行分が消えるんだよね。
そうそう。
それから、drawLine メソッドを呼び出す前に dispStartline の値を代入してclearBack メソッドで履歴メッセージを消したとこに、 ここの for ループの中の drawLine メソッドで0〜3行目の履歴メッセージを書き込むんだね。
だから、最終的に…

drawLine メソッド呼び出し後(スクロール完了)の状態>

こうなって、スクロール完了だよっ。
うん、バッチリだね。
スクロール処理ってパターンがあるから結構わかりやすいよね。
だね。
後は、スクロール処理でメッセージ履歴画面の内容が変わったから、 最後に updateButtonState メソッドを呼び出して終了だね。
そーいえば、updateButtonState メソッドってなんにもやってなかったと思うんだけど、呼び出す意味あるの?
§10.9 参照。
今は何もやってないけど、後でちゃんと使うから。
あ、そーなんだ。
それじゃ、今回はここまでね。
次回で基本編は終わりだよ。
基本編ってタイトルのわりにはすごい長く続いてるよね…
う〜ん…ホントはもっと簡単にまとめるつもりだったんだけど、 うまくまとめられなくって長くなっちゃったんだよね…
ま、とりあえず次回で基本編は最後ってことで。
それじゃ、また次回ね!


前へ | TOP | 次へ