Scintilla/How to implement folding

Last-modified: 2008-02-24 (日) 19:36:18

折りたたみの実装方法

Scintillaで折りたたみを使う方法

Scintillaはスクリプト編集コンポーネントである。http://www.scintilla.orgに情報がある

Scintillaのコード折りたたみにセットアップと使い方

まず、後で使ういくつかの定数を作成する

static const int MARGIN_SCRIPT_FOLD_INDEX = 1;

ウインドウのマージンクリックイベントを登録する(これはWindows特有である)。

static const int WINDOW_ID = 900;
BEGIN_MESSAGE_MAP(CDocumentWindow, CDocumentWindowsBaseClass)
  ON_NOTIFY(SCN_MARGINCLICK, WINDOW_ID, OnMarginClicked)
END_MESSAGE_MAP()

(ウインドウを生成するときに、WINDOW_IDはCreateWindowの呼び出しで使われる)

使いたい場合は解析器をセットする...
(コンストラクタまたは生成メソッドで行う...)

SendEditor(SCI_SETLEXER, SCLEX_CPP);
SendEditor(SCI_SETSTYLEBITS, 5);

解析器が何をすればよいかわかるようにいくつかのプロパティを設定する。

SendEditor(SCI_SETPROPERTY, (WPARAM)"fold", (LPARAM)"1");
SendEditor(SCI_SETPROPERTY, (WPARAM)"fold.compact", (LPARAM)"0");

(fold.compactオプションは空行を折りたたむ。私は好きではないが、デフォルトで1である)

私は以下の設定を好む:

SendEditor(SCI_SETPROPERTY, (WPARAM)"fold.comment", (LPARAM)"1");
SendEditor(SCI_SETPROPERTY, (WPARAM)"fold.preprocessor", (LPARAM)"1");

すべてのマージンをリサイズして0にする。
(RecalcLineMarginメソッドがこれをするだろう...)

SendEditor(SCI_SETMARGINWIDTHN, MARGIN_SCRIPT_FOLD_INDEX, 0);

次にマージンタイプとマージンマスクを設定し、そしてリサイズをする...

SendEditor(SCI_SETMARGINTYPEN,  MARGIN_SCRIPT_FOLD_INDEX, SC_MARGIN_SYMBOL);
SendEditor(SCI_SETMARGINMASKN, MARGIN_SCRIPT_FOLD_INDEX, SC_MASK_FOLDERS);
SendEditor(SCI_SETMARGINWIDTHN, MARGIN_SCRIPT_FOLD_INDEX, 20);

いくつかのビジュアル設定をセットする。

SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_PLUS);
SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS);
SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY);
SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY);
SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY);
SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY);
SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY);
SendEditor(SCI_SETFOLDFLAGS, 16, 0); // 16  	Draw line below if not expanded

マージンでのマウスクリックに関する通知をほしいとScintillaに知らせる。

SendEditor(SCI_SETMARGINSENSITIVEN, MARGIN_SCRIPT_FOLD_INDEX, 1);

SCN_MARGINCLICKイベントに応答する... (メソッドのプロトタイプはWindows特有である)

afx_msg void
CDocumentWindow::OnMarginClick(NMHDR* nmhdr, LRESULT* result)
{
  SCNotification* notify = (SCNotification*)nmhdr;
  const int modifiers = notify->modifiers;
  const int position = notify->position;
  const int margin = notify->margin;
  const int line_number = SendEditor(SCI_LINEFROMPOSITION, position, 0);
  switch (margin) {
    case MARGIN_SCRIPT_FOLD_INDEX:
    {
      SendEditor(SCI_TOGGLEFOLD, line_number, 0);
    }
    break;
  }
}

それは、動作するために十分であるべきである。
あなたは、折り返しがあなたの思い通りになるまでいじくり回したくなるだろう。
Scintillaははるかに複雑なMarginClickを使用するように思える...
ScintillaからMarginClickコードを取り入れることは簡単である:

まず最初にOnMarginClickを変更する:

SendEditor(SCI_TOGGLEFOLD, line_number, 0);

To:

MarginClick(position, modifiers);

次にあなたのヘッダファイル...

bool MarginClick(int position, int modifiers);
void Expand(int &line, bool doExpand,
            bool force = false, int visLevels = 0, int level = -1);
void FoldAll();

次にSciTEBase.cxxからこれらのメソッドを見つけられるようあなたのコードをコピーする。

そしてあなたのGoto Line関数を更新したほうがよい...

SendEditor(SCI_ENSUREVISIBLEENFORCEPOLICY, line_number);
SendEditor(SCI_GOTOLINE, line_number);