. 픽셀 좌표 계산

앞에서 구한 r, c는 행과 열의 개념이며 문서상의 글자 단위 좌표값이라 할 수 있다. 그런데 글자 단위의 행열 개념 외에 더 필요한 것이 있는데 바로 픽셀 단위의 좌표값이다. 캐럿이나 선택영역, 탭의 위치 등은 행열 좌표에 배치되는 것이 아니라 픽셀 좌표에 배치되기 때문에 오프셋으로부터 x, y값을 구할 수 있어야 한다.

문서상의 현재 위치 nPos가 있을 때 이 위치에 캐럿을 출력하려면 nPos가 과연 화면상의 어느 위치인지 좌표값 x, y를 구해야 한다. 그래서 GetXYFromOff라는 함수가 필요하다. 다음 함수를 작성한다.

 

void GetXYFromOff(int nPos, int &x, int &y)

{

     HDC hdc;

     int r,c,s,e;

 

     GetRCFromOff(nPos, r, c);

     y=r*LineHeight;

 

     GetLine(r, s, e);

     hdc=GetDC(hWndMain);

     x=GetCharWidth(hdc,buf+s,nPos-s);

     ReleaseDC(hWndMain, hdc);

}

 

버퍼상의 오프셋 nPos를 인수로 받아들이고 픽셀값 x, y를 조사해 리턴한다. 구하기 쉬운 y 좌표를 먼저 구하는데 GetRCFromOff 함수로 줄번호를 구한 후 줄번호에 줄간을 곱하면 y 좌표는 간단히 얻을 수 있다. 줄간이 24일 때 0번째 줄은 0, 1번째 줄은 24, 2번째 줄은 48의 위치에 있을 것이다.

x 좌표는 줄의 시작위치에서 nPos까지의 모든 문자폭의 합으로 계산된다. 문자열의 길이는 nPos-s로 구할 수 있으며 이 문자열의 폭을 GetCharWidth 함수로 구하면 x 좌표가 된다. 다음 문서에서 2번째 줄 자의 좌표값을 조사하는 예를 보자.

2번째 줄이므로 y 좌표는 2*줄간이 된다. x 좌표는 자 이전에 있는 어느날 그대 내 곁으문자열의 폭을 구하면 된다. 이렇게 구해진 좌표에 캐럿을 표시하면 정확하게 자 앞에 캐럿이 위치하게 될 것이다. 이 함수도 GetRCFromOff와 마찬가지로 nPos는 항상 유효하다고 가정하고 있으므로 호출 측에서 반드시 유효한 오프셋을 전달해야 한다.

한 가지 주의할 것은 이 함수가 조사하는 좌표 x, y는 화면상의 좌표가 아니라 문서상의 좌표라는 점이다. ApiEdit1은 스크롤 기능이 없기 때문에 화면상의 픽셀 좌표가 곧 문서상의 픽셀 좌표와 같다. 그러나 만약 스크롤 기능이 들어가게 되면 화면 좌표와 문서 좌표는 달라진다. 화면 좌표는 화면의 원점을 기준으로 한 좌표이고 문서 좌표는 문서의 원점을 기준으로 한다.

왼쪽 그림에서 5번째 줄 세 번째 문자 의 좌표는 (5*줄간, 2* 문자폭)이 되는데 스크롤이 되었다고 해도 이 문자의 좌표가 변하는 것은 아니다. 오른쪽 그림처럼 세 줄이 스크롤되어 위로 올라가면 화면상으로 이 줄은 2번째 줄이 되지만 좌표값은 그대로다. 왜냐하면 문서의 원점을 기준으로 하기 때문이다. 이 함수는 항상 문서의 원점을 기준으로 한 문서상의 좌표를 조사하도록 하고 이 좌표값을 사용하는 곳에서 스크롤된 만큼 좌표를 조정하도록 하는 것이 좋다. GetRCFromOff가 리턴하는 행열값도 물론 문서의 원점을 기준으로 한다. 현재 보이는 화면상의 행열값이 아니다.

오프셋으로부터 픽셀 좌표값을 구하는 함수가 필요하다면 그 반대 함수인 GetOffFromXY 함수도 당연히 필요하다. 그러나 이 함수는 당장은 필요치 않으며 다음에 마우스를 프로그래밍할 때 필요하므로 여기서는 아직 작성하지 않았다.

오프셋으로부터 행열값 구하기, 오프셋으로부터 좌표값 구하기 함수가 다 만들어졌으므로 이제 캐럿을 제자리에 놓을 수 있다. SetCaret 함수를 다음과 같이 수정한다. 지역변수 sz는 더 이상 필요없으므로 삭제하도록 하자.

 

void SetCaret()

{

     HDC hdc;

     int toff;

     int caretwidth;

    int x,y;

 

     hdc=GetDC(hWndMain);

     if (bComp) {

          toff=off-2;

          caretwidth=GetCharWidth(hdc,buf+toff,2);

     } else {

          toff=off;

          caretwidth=2;

     }

     CreateCaret(hWndMain,NULL,caretwidth,FontHeight);

     ShowCaret(hWndMain);

 

    GetXYFromOff(toff,x,y);

    SetCaretPos(x,y);

     ReleaseDC(hWndMain,hdc);

}

 

캐럿이 나타나야 할 오프셋 toff로부터 화면상의 좌표를 구해 캐럿을 위치시켰다. 캐럿의 X 좌표뿐만 아니라 Y 좌표도 같이 계산해야 하며 이 계산을 하는 함수가 바로 GetXYFromOff 함수이다. 이제 캐럿이 개행된 위치를 똑똑하게 잘 따라 다닐 것이다.