신틸라에서 접기 사용하는 법

신틸라는 스크립트 편집 컴포넌트로서 더 자세한 정보는 http://www.scintilla.org를 방문해 보자.


다음은 신틸라에서 코드 접기를 사용하는 법을 보여준다


먼저 나중에 사용할 상수들을 준비한다
static const int MARGIN_SCRIPT_FOLD_INDEX = 1;

창에 대하여 여백 클릭 이벤트를 등록한다 (이것은 창에 종속적이다).
static const int WINDOW_ID = 900;

BEGIN_MESSAGE_MAP(CDocumentWindow, CDocumentWindowsBaseClass)
  ON_NOTIFY(SCN_MARGINCLICK, WINDOW_ID, OnMarginClicked)
END_MESSAGE_MAP()

(WINDOW_ID는 창을 만들 때 CreateWindow 호출에 사용된다)

사용하고 싶은 어휘분석기를 설정한다...
(설정은 create 메쏘드 또는 구성자 안에서 처리된다...)
  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 확대되지 않을 경우, 밑에 줄을 그린다. 

scintilla에게 여백에 마우스 클릭이 있으면 고지하라고 알린다
  SendEditor(SCI_SETMARGINSENSITIVEN, MARGIN_SCRIPT_FOLD_INDEX, 1);

SCN_MARGINCLICK 이벤트에 응답한다... (메쏘드 원형이 창에 종속적이다. 주의하자)
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을 사용하는 것 같다...
다행스럽게도 MarginClick 코드를 신틸라에서 어렵지 않게 찾을 수 있다:

먼저 OnMarginClick 변화를 찾아:
      SendEditor(SCI_TOGGLEFOLD, line_number, 0);
다음으로 바꾸자:
      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);


이상이다. 즐기시기를 바란다.
이에 관하여 제안이나 논평이 있으면 vascy@hotmail.com으로 보내 주시면 된다.