. 문단번호

마진 영역을 어렵게 만들었으니 이 영역을 유용하게 사용해보도록 하자. 먼저 줄번호 출력 기능부터 작성하자. 이 기능은 사용자의 조작이 필요없기 때문에 다른 기능보다 구현하기가 쉽다. 줄번호를 항상 가지고 있다가 마진영역에 뿌려주기만 하면 된다. 줄번호 출력을 위해 필요한 전역변수를 선언하고 초기화한다.

 

BOOL bShowLineNum;

HFONT hLineNumFont;

COLORREF NumColor;

 

BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)

{

     ....

     bShowLineNum=TRUE;

     hLineNumFont=CreateFont(12,0,0,0,0,0,0,0,HANGEUL_CHARSET,3,2,1,

          VARIABLE_PITCH | FF_MODERN,"굴림");

     NumColor=RGB(0,0,0);

 

     return TRUE;

}

 

void OnDestroy(HWND hWnd)

{

     ....

     DeleteObject(hLineNumFont);

}

 

줄번호를 출력하는 기능은 편집기에 반드시 필요한 필수 기능은 아니며 소스 코드 외에는 오히려 더 지저분해 보일 수도 있다. 사용자의 취향에 따라 원할 때만 줄번호를 볼 수 있도록 하기 위해 bShowLineNum 변수를 선언하였다. 이 변수가 TRUE일 때만 마진에 줄번호를 보여줄 것이다. 테스트를 위해 OnCreate에서 이 변수를 TRUE로 초기화하였다.

hLineNumFont는 줄번호 출력에 사용할 폰트이며 굴림체의 12픽셀 크기로 생성했다. 줄번호는 알아볼 수 있을 정도면 되고 마진영역이 좁기 때문에 굳이 큰 폰트를 쓸 필요가 없다. 이 폰트로 마진영역에 줄번호를 출력할 것이며 프로그램을 종료하기 직전인 OnDestroy에서 폰트를 해제하였다. NumColor는 줄번호의 색상이며 검정색으로 초기화하였다.

마진 영역에 출력할 줄번호라는 것은 pLine 배열의 줄번호와는 다른 개념이다. pLine은 정렬 결과 한 행에 출력되어야 할 줄의 범위를 가지고 있는데 문서의 줄번호는 개행코드에 의해 강제로 개행된 문단을 의미한다. 문단번호가 문서상의 고유한 줄번호이므로 마진영역에는 문단번호를 출력해야 한다.

그런데 현재 ApiEdit의 구조로는 정렬 결과 생성된 줄번호만 있을 뿐 문단번호는 따로 가지고 있지 않다. 그렇다고 해서 이 정보를 실시간으로 구해 출력하고자 한다면 무척 속도가 느려지므로 정렬할 때 pLine 배열에 문단번호를 같이 저장하도록 구조체를 확장하자.

 

struct tagLine

{

     int Start;

     int End;

     int nPara;

     int nLine;

};

 

문단번호를 기억할 nPara 멤버와 문단 내의 줄번호를 기억할 nLine 멤버가 추가되었다. 이 멤버는 UpdateLineInfo에서 정렬할 때 같이 계산된다.

 

void UpdateLineInfo()

{

     int l,s,e;

     int nPara, nLine=0;

 

     for (l=0, nPara=0;;l++) {

          GetLine(l,s,e);

 

          pLine[l].Start=s;

          pLine[l].End=e;

          pLine[l].nPara=nPara;

          pLine[l].nLine=nLine;

          if (s==-1) {

              TotalLine=l;

              break;

          }

 

          if (buf[e]==‘\r’) {

              nPara++;

              nLine=0;

          } else {

              nLine++;

          }

     }

}

 

최초 nPara 0이며 nLine 0이다. 정렬을 진행하다가 개행코드를 만나면 문단번호를 하나 증가시키고 nLine 0이 된다. 개행코드가 아닌 줄 끝이면, 즉 자동개행된 줄이면 nLine만 증가시키고 nPara는 값을 유지한다. 이 함수에 의해 어떻게 줄번호와 문단번호가 계산되는지 보자.

배열 첨자는 화면상의 줄번호가 되며 nPara는 문서상의 문단번호가 된다. pLine 배열에 출력할 문단번호를 이미 계산해두었으므로 이제 이 번호를 마진영역에 출력하기만 하면 된다. 마진영역에 문단번호를 출력하는 일은 각 줄을 출력하는 DrawLine에서 한다. DrawLine에 다음 코드를 추가하자.

 

int DrawLine(HDC hdc, int Line)

{

     ....

     TCHAR szLine[10];

     UINT OldAlign;

     UINT OldBkMode;

     HFONT OldFont;

     int OldExtra;

     ....

     if (MarginWidth != 0) {

          ....

          if (bShowLineNum && pLine[Line].nLine==0) {

              wsprintf(szLine,"%d",pLine[Line].nPara+1);

              OldAlign=SetTextAlign(hdc,TA_RIGHT);

              OldBkMode=SetBkMode(hdc,TRANSPARENT);

              SetTextColor(hdc,NumColor);

              OldFont=(HFONT)SelectObject(hdc,hLineNumFont);

              OldExtra=SetTextCharacterExtra(hdc,-1);

 

              TextOut(hdc,MarginWidth-4,(FontHeight-10)/2,szLine,lstrlen(szLine));

             

              SetTextCharacterExtra(hdc,OldExtra);

              SelectObject(hdc,OldFont);

              SetTextAlign(hdc,OldAlign);

              SetBkMode(hdc,OldBkMode);

          }

     }

 

문단번호가 출력되기 위해서는 세 가지 조건이 맞아야 한다. 일단 줄번호를 출력할 마진이 있어야 하고 bShowLineNum TRUE여야만 문단번호가 출력된다. 또한 각 문단의 선두에만 줄번호가 출력되며 자동개행된 줄에는 번호를 출력하지 않는다. nLine 0일 때 이 줄이 문단의 선두이다.

출력문은 아주 간단하다. 오른쪽으로 정렬하며 투명 배경을 사용하여 줄번호 문자열을 마진영역에 출력하였다. 줄번호는 pLine 배열의 nPara+1을 문자열로 변환하여 출력하면 되는데 nPara Zero Base이므로 1을 더해야 한다. 가급적 마진영역을 넓게 차지하지 않도록 하기 위해 -1자간을 주었으며 마진폭과는 4만큼의 여유를 주었다. 마진폭에서 4를 뺐지만 실제로는 마진의 여유분과 테두리폭이 있기 때문에 오른쪽 끝과 1픽셀밖에 떨어지지 않는다. 마진의 구조를 그림으로 그려 보면 다음과 같다.

MarginWidth 변수가 가리키는 좌표는 마진 다음의 본문출력 영역이다. 한 칸 왼쪽(-1)은 본문과 마진과의 구분을 위한 여백인데 OnPaint에서 본문의 배경색으로 채워진다. 다시 한 칸 왼쪽(-2)은 마진의 경계선 영역이며 MarColor2로 선이 그어진다. 경계선의 안쪽인 -3부터가 마진영역이며 MarColor1로 채색된다. 경계선과 줄번호가 너무 붙지 않도록 다시 1픽셀 여백을 넣었으며 그래서 줄번호 출력 좌표는 MarginWidth-4가 되었다.