. 클리핑 처리

그럼 탭까지 처리했으면 마진과 관련한 모든 처리가 다 끝났을까? 그렇지 않다. 아직도 복잡한 문제 하나가 남아 있는데 이런 문제는 쉽게 발견하기가 참 어렵다. 이 예제는 계속 자동개행 상태에서 작성되고 있기 때문에 수평스크롤이 없지만 수평 스크롤바가 나타나면 마진까지 같이 스크롤된다는 문제점이 있다. F9키에 자동개행 상태를 바꿀 수 있는 임시 기능이 있으므로 이 키를 눌러 자동개행이 없는 상태로 만들어 보고 이 상태에서 수평 스크롤바를 드래그해보아라.

스크롤이란 문서만을 대상으로 하지만 OnHScroll은 작업영역 전체를 스크롤 하기 때문에 마진영역도 스크롤 대상이 되어 버렸고 그래서 수평으로 스크롤하면 화면이 형편없이 깨져 버린다. 스크롤 대상은 전체로 해도 상관없지만 클리핑영역을 포맷팅영역으로 주면 이 문제를 해결할 수 있다.

또한 수평스크롤시에 캐럿이 마진영역을 안으로 들어가 깜박거리고 있는 것을 볼 수 있는데 마진에서는 캐럿을 숨겨야 한다. 이 두 처리는 모두 OnHScroll에서 한다.

 

void OnHScroll(HWND hWnd, HWND hwndCtl, UINT code, int pos)

{

     int xInc;

     SCROLLINFO si;

    POINT pt;

    static BOOL bHideCaret=FALSE;

 

     xInc=0;

     switch (code) {

     case SB_LINEUP:

          xInc=-FontHeight;

          break;

     case SB_LINEDOWN:

          xInc=FontHeight;

          break;

     case SB_PAGEUP:

          xInc=-(frt.right-frt.left);

          break;

     case SB_PAGEDOWN:

          xInc=frt.right-frt.left;

          break;

     case SB_THUMBTRACK:

          si.cbSize=sizeof(SCROLLINFO);

          si.fMask=SIF_TRACKPOS;

          GetScrollInfo(hWnd,SB_HORZ,&si);

          xInc=si.nTrackPos-xPos;

          break;

     default:

          break;

     }

 

     xInc=max(-xPos, min(xInc, xMax-xPos));

     xPos=xPos+xInc;

    ScrollWindow(hWnd, -xInc, 0, NULL, &frt);

     SetScrollPos(hWnd, SB_HORZ, xPos, TRUE);

 

    GetCaretPos(&pt);

    if (pt.x < MarginWidth) {

        if (bHideCaret==FALSE) {

           HideCaret(hWnd);

           bHideCaret=TRUE;

        }

    } else {

        ShowCaret(hWnd);

        bHideCaret=FALSE;

    }

}

 

스크롤 영역도 frt로 줄 수 있지만 이렇게 되면 ScrollWindow가 캐럿을 옮겨주지 않기 때문에 클리핑영역만 frt로 주어 마진을 건드리지 않도록 하였다. 스크롤을 한 후 캐럿의 위치를 조사해보고 캐럿이 마진 안에 있으면 HideCaret 함수를 호출하여 캐럿을 숨기도록 했으며 다시 마진 밖으로 나오면 ShowCaret 함수를 호출하여 캐럿이 다시 보이도록 했다. , HideCaret 함수는 캐럿을 숨긴 횟수를 기억하는데 HideCaret을 호출한 만큼 ShowCaret을 호출해야 캐럿이 다시 보인다. 그래서 딱 한 번만 HideCaret을 호출하기 위해 bHideCaret 정적 변수를 사용하였다. 이 변수가 TRUE일 때는 이미 캐럿이 숨겨져 있는 상태이므로 HideCaret을 호출할 필요가 없고 호출해서도 안된다.

SetCaret 함수는 캐럿이 작업영역을 벗어나면 자동으로 스크롤을 하는 기능이 있는데 이제 작업영역이 아니라 포맷팅영역을 벗어나는지 감시해야 한다. x와 왼쪽 좌표를 비교하는 식에 MarginWidth를 넣어 주도록 하자.

 

void SetCaret(BOOL bUpdatePrevX/*=TRUE*/, BOOL bScrollToCaret/*=TRUE*/)

{

     ....

     if (bScrollToCaret) {

          if (nWrap==0) {

               if ((x+caretwidth > xPos+frt.right) || (x < xPos+MarginWidth)) {

                    xPos=max(0,x-frt.right/2);

                    bScroll=TRUE;

               }

          }

     ....

 

이제 수평스크롤시 클리핑도 잘 처리하고 SetCaret 함수도 마진으로 캐럿이 들어가는 것을 방지한다.