カーソル移動の実装。無知を思い知る
TUI のファイラーまがい、というか単にディレクトリ間を移動してファイル一覧を閲覧できるようなものを C言語で作ってみようとしてカーソル移動の考え方に苦しむ。
カーソルの移動を実装しようとして四苦八苦する。
ただ単に上下に移動したらフォーカスが移動すればいいというような話ではないことに気づき愕然とする。
必要な変数が何かもよくわからずコードを書いては実行して試してみたが埒が明かない。
一度立ち止まってどういうことになっているのか考え直す。
仮に表示領域が10行分でファイルの数が20の場合。
pos: ありのままの実際のポジション
head: 表示されるファイル群の1番上
tail: 表示されるファイル群の1番下
focus: フォーカスされる行 (> や 反転など)
カーソルが下がり続ける時
pos 0 -> 1 head 0 -> 0 tail 10 -> 10 fucus 0 -> 1
pos 1 -> 2 head 0 -> 0 tail 10 -> 10 fucus 1 -> 2
pos 2 -> 3 head 0 -> 0 tail 10 -> 10 fucus 2 -> 3
pos 3 -> 4 head 0 -> 0 tail 10 -> 10 fucus 3 -> 4
pos 4 -> 5 head 0 -> 0 tail 10 -> 10 fucus 4 -> 5
pos 5 -> 6 head 0 -> 0 tail 10 -> 10 fucus 5 -> 6
pos 6 -> 7 head 0 -> 0 tail 10 -> 10 fucus 6 -> 7
pos 7 -> 8 head 0 -> 0 tail 10 -> 10 fucus 7 -> 8
pos 8 -> 9 head 0 -> 0 tail 10 -> 10 fucus 8 -> 9
pos 9 -> 10 head 0 -> 0 tail 10 -> 10 fucus 9 -> 10
pos 10 -> 11 head 0 -> 1 tail 10 -> 11 fucus 10 -> 10
pos 11 -> 12 head 1 -> 2 tail 11 -> 12 fucus 10 -> 10
pos 12 -> 13 head 2 -> 3 tail 12 -> 13 fucus 10 -> 10
pos 13 -> 14 head 3 -> 4 tail 13 -> 14 fucus 10 -> 10
pos 14 -> 15 head 4 -> 5 tail 14 -> 15 fucus 10 -> 10
pos 15 -> 16 head 5 -> 6 tail 15 -> 16 fucus 10 -> 10
pos 16 -> 17 head 6 -> 7 tail 16 -> 17 fucus 10 -> 10
pos 17 -> 18 head 7 -> 8 tail 17 -> 18 fucus 10 -> 10
pos 18 -> 19 head 8 -> 9 tail 18 -> 19 fucus 10 -> 10
pos 19 -> 20 head 9 -> 10 tail 19 -> 20 fucus 10 -> 10
カーソルが上がり続ける時
pos 20 -> 19 head 10 -> 9 tail 20 -> 19 fucus 10 -> 9
pos 19 -> 18 head 9 -> 8 tail 19 -> 18 fucus 9 -> 8
pos 18 -> 17 head 8 -> 7 tail 18 -> 17 fucus 8 -> 7
pos 17 -> 16 head 7 -> 6 tail 17 -> 16 fucus 7 -> 6
pos 16 -> 15 head 6 -> 5 tail 16 -> 15 fucus 6 -> 5
pos 15 -> 14 head 5 -> 4 tail 15 -> 14 fucus 5 -> 4
pos 14 -> 13 head 4 -> 3 tail 14 -> 13 fucus 4 -> 3
pos 13 -> 12 head 3 -> 2 tail 13 -> 12 fucus 3 -> 2
pos 12 -> 11 head 2 -> 1 tail 12 -> 11 fucus 2 -> 1
pos 11 -> 10 head 1 -> 0 tail 11 -> 10 fucus 1 -> 0
pos 10 -> 9 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 9 -> 8 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 8 -> 7 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 7 -> 6 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 6 -> 5 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 5 -> 4 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 4 -> 3 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 3 -> 2 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 2 -> 1 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
pos 1 -> 0 head 0 -> 0 tail 10 -> 10 focus 0 -> 0
さらに、一旦表示領域をはみ出す位置まで pos が進んだ後に、一旦上に戻して、また下に移動するときなどはまた話が変わってくる。
// 一部抜粋.
// j で下、 k で上に移動
if (c == 'j' && pos < fcount - 1) {
pos++;
if (pos < max_visible) {
focus++;
} else if (pos >= max_visible - 1) {
if (focus < max_visible - 1) {
// pos が max_visibleを超えていて、focus が末端にないということは、一旦上に動いた後
// head は変わらないまま、focus だけが変わる
focus++;
} else if (focus == max_visible - 1) {
// pos が max_visibleを超えていて、focus が末端にあるということは、前回も末端にいたということ
// focus をいじる必要はない
head++;
}
}
} else if (c == 'k' && pos > 0) {
pos--;
// 1周前の foucs が0でないということは focus は常に上に動いて良い
if (focus != 0) {
focus--;
} else {
focus = 0;
head--;
}
}
ややこしい。