Menu

Row

develop (84)
novice123

内部構造>Window Messageの流れ

物理行とレイアウト行

2000/09/28

物理行,論理行,レイアウト行,キャレット位置など位置を表す言葉がソースコード上でいろいろ使われています.行の数え方には改行までを1行と数える方法と画面上での折り返し位置までを1行と数える方法がありますが,これらについての用語がソースコード中では統一されていません.

サクラエディタのソースコードではこれらの言葉は以下のように使い分けられています.

改行記号で区切られた1つの固まり...論理行, 物理行
画面上で左端から折り返し位置まで...レイアウト行,キャレット位置

関数によって論理行を受け取るものとレイアウト行を受け取るものがありますが,これを間違えると間違いなく「不正な処理」で落ちますので,ここをはっきりさせることはきわめて重要です.

このページでは前者を「論理行」,後者を「レイアウト行」と呼ぶことにします.

座標を扱う関数

基本的にはCDocLineMgrとその関係関数には論理行, CLayoutMgrにはレイアウト行を渡すようになっていると思います.せっかくですから,ここで主要な関数についてどちらを渡すべきか記しておきます.

座標変換関数

論理位置とレイアウト位置を相互に変換するには以下の関数を用います.

CLayoutMgr::CaretPos_Phys2Log

int nX, // 論理行X
int nY, // 論理行Y
int* pnCaretPosX, //レイアウト行X
int* pnCaretPosY // レイアウト行Y

論理行での位置(nX, nY)からレイアウト行での位置(nCaretPosX, nCaretPosY)に変換する.

CLayoutMgr::CaretPos_Log2Phys

int nCaretPosX, //レイアウト行X
int nCaretPosY, //レイアウト行Y
int* pnX, // 論理行X
int* pnY // 論理行Y

レイアウト行での位置(nCaretPosX, nCaretPosY)から物理行での位置(nX, nY)に変換する.

データ取得関数

CLayoutMgr::GetLineStr

int nLine,  // 論理行番号
int *pnLineLen // 該当行の長さを受け取る

指定された論理行番号に対応する文字列,文字列長を取得する.文字列長はレイアウト行1行に含まれる長さ.

CLayoutMgr::GetLineStr2

int nLine,  // 論理行番号
int *pnLineLen, // 該当行の長さを受け取る
const CLayout** ppcLayoutDes // CLayoutへのポインタ

GetLineStrで取得できる行の長さに加えて,CLayout へのポインタも返す.

レイアウト位置を扱う仕組み

テキストエディタでは文字列データはCDocLineMgrクラスが保持しています.このクラスでは論理行1行のデータを1つのCDocLineクラスが管理するようになっています.

一方,CLayoutではデータの代わりに折り返し位置,すなわち対応する論理行と開始文字位置を保持しています.

CLayoutのメンバーは以下のようになっています.

番号 メンバー 内容
CLayout* m_pPrev; リストのメンバーなので,前後へのポインタを持つ.
CLayout* m_pNext;
int m_nLinePhysical; 対応する改行単位の行の番号(論理行番号)
const CDocLine* m_pCDocLine; 対応する論理行を保持する要素へのポインタ
int m_nOffset; 対応する改行単位の行の先頭からのオフセット
int m_nLength; このレイアウト行の長さ(ハイト数)
int m_nTypePrev; タイプ*
int m_nTypeNext;
CEOL m_cEol; 改行コード種別
タイプ
0=通常
1=行コメント
2=ブロックコメント
3=シングルクォーテーション文字列
4=ダブルクォーテーション文字列

CLayoutMgr::Searchは論理行番号に対応するレイアウト行の情報を取得する関数です.レイアウト行番号から物理行番号を知るのは書かれている番号を返すだけなので簡単ですが,その逆は大変です.リストは先頭または末尾からしかたどることが出来ないので行数nのオーダーO(n)で遅くなります.

この関数では以下のような高速化手法が使われています.

  • 行番号が前半に近ければ前から,後半に近ければ後ろから探す.
  • 前回の検索結果を覚えておき,そこから前後に検索する.

1はファイルの後半を探すときの速度が約1/2になるというもので,目に見えるほどの効果は出ていないのではないかと思います.

2は計算量だけ考えると大したことがないように思われるかもしれませんが,実際には連続した行番号で関数が呼び出されることが多いため,かなりの効果が見込めます.

この関数では該当する行番号を持つ要素を見つけ次第結果を返していますが,論理行1行に対して複数のレイアウト行が対応するので,上に示した手法では順方向に探すときには先頭部分のレイアウト行要素が,逆方向に探すときは末尾部分のレイアウト行要素が見つかってしまいます.

レイアウトの更新

行の挿入,削除や折り返し位置の変更を行うなど論理行に変更があったときは論理行番号を更新する必要があります.

CLayoutMgr::DoLayoutと CLayoutMgr::DoLayout3_Newが番号を更新するための関数です.両者の違いは全体を更新するか一部分を更新するかです.


Related

Wiki: Design

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.