. 크기 변경시 첫 문단 유지

ApiEdit는 작업영역 크기가 바뀔 때 정렬을 다시 하고 캐럿의 위치를 옮길 뿐 별다른 처리를 하지 않는다. 그래서 크기 변경 후 화면상의 첫 줄이 유지되지 않는 문제가 있다. 다음 그림을 보자.

 

화면상의 첫 줄은 16줄이고 캐럿은 20줄에 있는데 이 상태에서 윈도우 폭을 줄이면 캐럿은 20줄에 그대로 있지만 화면상의 첫 줄은 14줄이 된다. OnSize에서 아무런 조치도 하지 않기 때문에 크기 변경 후 유지되는 값은 현재의 스크롤 값인 yPos가 된다. 크기 변경 후 캐럿이 숨게 되면 SetCaret에 의해 강제로 스크롤되는데 이때만 제외하고 yPos는 항상 값을 유지한다.

yPos가 가리키는 줄번호는 윗줄의 정렬 상태에 따라 달라질 수 있기 때문에 화면상의 첫 줄이 유지되지 않으며 윈도우 크기를 바꿀 때 첫 줄이 심하게 움직이게 된다. 또한 이 문제로 인해 다음과 같은 상태가 될 수도 있다. 캐럿을 문서의 끝에 둔 상태에서 윈도우 폭을 늘리면 문서의 제일 끝줄이 화면상의 첫 줄이 되고 앞부분은 모두 위로 스크롤되어 버린다.

 

ApiEdit는 문서를 끝까지 스크롤했을 때 절반 여백이 보이는 정책을 취하고 있는데 잘 생각이 나지 않으면 ApiEdit3에서 작성한 UpdateScrollInfo 함수를 보기 바란다. 윈도우 크기가 바뀔 때 스크롤 범위는 재조정되지만 막상 현재 스크롤 값인 yPos는 바뀌지 않기 때문에 이런 현상이 일어난다. 그나마 SetCaret이 캐럿이 보이지 않으면 보이는 위치까지 강제로 스크롤을 하고 있기 때문에 문서 전체가 사라지는 것은 막고 있다.

이 두 문제는 모두 CApiEdit OnSize가 크기 변경시 yPos를 제대로 관리하지 않기 때문이다. 이 함수를 다음과 같이 수정한다.

 

void CApiEdit::OnSize(HWND hWnd, UINT state, int cx, int cy)

{

    int nPara;

    int nLine;

    int toff;

    int r,c;

 

     if (state != SIZE_MINIMIZED) {

          GetClientRect(hWnd,&frt);

          frt.left += MarginWidth;

          if (nWrap) {

           nPara=pLine[yPos/LineHeight].nPara;

           nLine=pLine[yPos/LineHeight].nLine;

           toff=GetOffFromPara(nPara,0);

              UpdateLineInfo();

          }

          UpdateScrollInfo();

        if (nWrap) {

           GetRCFromOff(toff,r,c);

           yPos=(r+nLine)*LineHeight;

           yPos=max(0,min(yPos,yMax-(frt.bottom/LineHeight)*LineHeight));

        }

          if (GetFocus()==hWnd) {

           SetCaret(TRUE,FALSE);

          }

          if (hBit) {

               DeleteObject(hBit);

              hBit=NULL;

          }

     }

}

 

이 처리들은 모두 자동개행 상태일 때만 할 필요가 있다. 자동개행을 하지 않을 때는 yPos가 화면상의 첫 줄을 정확하게 가리키고 있으며 윈도우 크기가 바뀌어도 문서의 줄 수가 바뀌지 않기 때문에 이 처리를 할 필요가 없다. 재정렬하기 전에 현재 화면 제일 첫 줄의 문단과 문단 내 줄번호, 그리고 문단 처음의 오프셋을 구해놓는다. 재정렬 후 문단 처음의 오프셋이 속한 줄번호를 찾고 이 줄번호에 문단 내 줄번호를 더한 값에 줄간을 곱하면 크기 변경 후 가장 적합한 yPos를 구할 수 있다.

이때 yPos가 화면 절반 이하까지 내려가지 않도록 해 줌으로써 문서가 너무 많이 스크롤되지 않도록 했다. 이 코드는 VK_NEXT에 있는 코드와 동일하다. SetCaret 함수의 인수도 변경되었다. 원래 코드는 SetCaret() 함수를 인수없이 호출하는데 둘 다 디폴트값인 TRUE로 지정된다. 이렇게 되면 PrevX도 갱신되고 캐럿이 있는 곳으로 스크롤도 발생하는데 PrevX가 갱신되는 것은 논리적으로 맞지만 굳이 캐럿이 있는 곳으로 강제 스크롤이 발생하면 화면을 첫 줄을 제대로 유지할 수가 없다.

작업영역의 크기를 변경할 때 캐럿이 있는 곳을 우선적으로 보여줄 것인가 아니면 화면의 첫 줄을 유지할 것인가는 선택의 문제이다. ApiEdit는 지금까지 캐럿을 더 중요하게 생각하여 직접 스크롤할 때만 제외하고는 항상 캐럿이 보이도록 했으나 사용자가 보고 있는 현재 위치에 더 비중을 두는 정책을 채택하기로 한다. 이제 크기 변경시 항상 첫 줄이 유지되며 캐럿이 안보이는 곳으로 숨을 수도 있다.