.커서 관리

이동은 도형 전체를 움직이므로 어떤 부분을 드래그하나 처리가 똑같지만 크기 변경의 경우는 어떤 트래커를 드래그했는가에 따라 조정해야 대상이 달라진다. 가령 도형의 오른쪽 변을 드래그하면 rt.right 조정되어야 하고 도형의 아래쪽을 드래그하면 rt.bottom 바뀔 것이다. 그래서 드래그하는 부분에 따라 커서를 다르게 하여 현재 상태에서 드래그할 경우 어떤 변의 크기가 조정되는지를 표시해야 한다. 처리를 하기 위해서는 커서가 트래커 위에 있는지를 조사하는 함수가 필요하다.

 

int TrackerHitTest(int x,int y)

{

   int i;

   RECT trt;

   POINT pt;

 

   if (NowSel == -1) {

      return 0;

   }

 

   pt.x=x;

   pt.y=y;

   for (i=1;i<=8;i++) {

      GetTrackerRect(NowSel,i,&trt);

      if (PtInRect(&trt,pt) == TRUE) {

          return i;

      }

   }

   return 0;

}

 

함수는 선택된 도형의 1~8 트래커를 순회하면서 트래커 영역안에 인수로 주어진 (x,y)좌표가 포함되어 있는지를 조사하여 번호를 리턴한다. 만약 커서가 트래커 위에 있지 않다면 0 리턴한다. 트래커의 영역을 구하는 GetTrackerRect 함수는 트래커를 그릴 때도 사용되지만 히트 테스트에도 아주 유용하게 사용되고 있다. 부분에서 똑같은 코드를 반복해서 사용하고 있기 때문에 함수로 분리해 것이다. OnSetCursor 함수에서 커서 위치의 트래커 번호를 조사하고 트래커 위에 있으면 적절한 모양의 커서로 변경한다.

 

LRESULT OnSetCursor(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   POINT pt;

   int nHit;

 

   static TCHAR *arCursor[]={0,IDC_SIZENWSE,IDC_SIZENS,IDC_SIZENESW,IDC_SIZEWE,

      IDC_SIZEWE,IDC_SIZENESW,IDC_SIZENS,IDC_SIZENWSE};

 

   if (NowTool == DT_SELECT) {

      GetCursorPos(&pt);

      ScreenToClient(hWnd,&pt);

      nHit=TrackerHitTest(pt.x,pt.y);

      if (nHit != 0) {

          SetCursor(LoadCursor(NULL,arCursor[nHit]));

          return TRUE;

      }

   }

   return(DefWindowProc(hWnd,WM_SETCURSOR,wParam,lParam));

}

 

도형의 크기 조정 동작은 운영체제의 윈도우 크기 조정 동작과 같은 경우이므로 크기 조정에 필요한 커서는 모두 스톡 커서로 미리 정의되어 있어 리소스를 따로 만들 필요가 없다. 트래커 번호를 첨자로 하는 스톡 커서 배열을 작성해 두고 TrackerHitTest 함수가 조사한 번호를 배열 첨자로 사용했다. arCursor 배열은 OnSetCursor 함수 내에서만 사용되지만 값이 변경될 필요는 없으므로 static으로 선언해야 속도상의 불이익이 없다. 지역 배열을 초기화하는데는 상당한 시간이 소요된다. 배열은 문자열 포인터인데다 OnSetCursor 워낙 자주 호출되는 함수라 너무 늦게 처리되어서는 안된다.

함수 중간의 조건문을 보면 선택 모드일 때만 트래커 위에서 커서를 바꾸도록 되어 있다. 도형을 그리고 있는 중에는 트래커 위에 있더라도 선택 상태가 아니므로 크기 변경 동작을 없으며 따라서 커서를 바꾸지 않아야 한다. ApiDraw 한번 선택된 툴을 계속 유지하도록 작성되어 있으며 도형을 그린 직후에 선택 상태로 바뀌지 않기 때문이다. 그래서 트래커 위에서도 다른 도형을 그릴 있다.