xref: /aoo41x/main/embedserv/source/embed/tracker.cxx (revision f78e906f)
1*f78e906fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*f78e906fSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*f78e906fSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*f78e906fSAndrew Rist  * distributed with this work for additional information
6*f78e906fSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*f78e906fSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*f78e906fSAndrew Rist  * "License"); you may not use this file except in compliance
9*f78e906fSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*f78e906fSAndrew Rist  *
11*f78e906fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*f78e906fSAndrew Rist  *
13*f78e906fSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*f78e906fSAndrew Rist  * software distributed under the License is distributed on an
15*f78e906fSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*f78e906fSAndrew Rist  * KIND, either express or implied.  See the License for the
17*f78e906fSAndrew Rist  * specific language governing permissions and limitations
18*f78e906fSAndrew Rist  * under the License.
19*f78e906fSAndrew Rist  *
20*f78e906fSAndrew Rist  *************************************************************/
21*f78e906fSAndrew Rist 
22*f78e906fSAndrew Rist 
23cdf0e10cSrcweir #if defined(_MSC_VER) && (_MSC_VER > 1310)
24cdf0e10cSrcweir #pragma warning(disable : 4917 4555)
25cdf0e10cSrcweir #endif
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "stdafx.h"
28cdf0e10cSrcweir #include <stddef.h>
29cdf0e10cSrcweir #include "syswinwrapper.hxx"
30cdf0e10cSrcweir 
31cdf0e10cSrcweir 
32cdf0e10cSrcweir HCURSOR _afxCursors[10] = { 0, };
33cdf0e10cSrcweir HBRUSH _afxHalftoneBrush = 0;
34cdf0e10cSrcweir 
35cdf0e10cSrcweir 
36cdf0e10cSrcweir // the struct below is used to determine the qualities of a particular handle
37cdf0e10cSrcweir struct AFX_HANDLEINFO
38cdf0e10cSrcweir {
39cdf0e10cSrcweir     size_t nOffsetX;    // offset within RECT for X coordinate
40cdf0e10cSrcweir     size_t nOffsetY;    // offset within RECT for Y coordinate
41cdf0e10cSrcweir     int nCenterX;       // adjust X by Width()/2 * this number
42cdf0e10cSrcweir     int nCenterY;       // adjust Y by Height()/2 * this number
43cdf0e10cSrcweir     int nHandleX;       // adjust X by handle size * this number
44cdf0e10cSrcweir     int nHandleY;       // adjust Y by handle size * this number
45cdf0e10cSrcweir     int nInvertX;       // handle converts to this when X inverted
46cdf0e10cSrcweir     int nInvertY;       // handle converts to this when Y inverted
47cdf0e10cSrcweir };
48cdf0e10cSrcweir 
49cdf0e10cSrcweir // this array describes all 8 handles (clock-wise)
50cdf0e10cSrcweir const AFX_HANDLEINFO _afxHandleInfo[] =
51cdf0e10cSrcweir {
52cdf0e10cSrcweir     // corner handles (top-left, top-right, bottom-right, bottom-left
53cdf0e10cSrcweir     { offsetof(RECT, left), offsetof(RECT, top),        0, 0,  0,  0, 1, 3 },
54cdf0e10cSrcweir     { offsetof(RECT, right), offsetof(RECT, top),       0, 0, -1,  0, 0, 2 },
55cdf0e10cSrcweir     { offsetof(RECT, right), offsetof(RECT, bottom),    0, 0, -1, -1, 3, 1 },
56cdf0e10cSrcweir     { offsetof(RECT, left), offsetof(RECT, bottom),     0, 0,  0, -1, 2, 0 },
57cdf0e10cSrcweir 
58cdf0e10cSrcweir     // side handles (top, right, bottom, left)
59cdf0e10cSrcweir     { offsetof(RECT, left), offsetof(RECT, top),        1, 0,  0,  0, 4, 6 },
60cdf0e10cSrcweir     { offsetof(RECT, right), offsetof(RECT, top),       0, 1, -1,  0, 7, 5 },
61cdf0e10cSrcweir     { offsetof(RECT, left), offsetof(RECT, bottom),     1, 0,  0, -1, 6, 4 },
62cdf0e10cSrcweir     { offsetof(RECT, left), offsetof(RECT, top),        0, 1,  0,  0, 5, 7 }
63cdf0e10cSrcweir };
64cdf0e10cSrcweir 
65cdf0e10cSrcweir // the struct below gives us information on the layout of a RECT struct and
66cdf0e10cSrcweir //  the relationship between its members
67cdf0e10cSrcweir struct AFX_RECTINFO
68cdf0e10cSrcweir {
69cdf0e10cSrcweir     size_t nOffsetAcross;   // offset of opposite point (ie. left->right)
70cdf0e10cSrcweir     int nSignAcross;        // sign relative to that point (ie. add/subtract)
71cdf0e10cSrcweir };
72cdf0e10cSrcweir 
73cdf0e10cSrcweir // this array is indexed by the offset of the RECT member / sizeof(int)
74cdf0e10cSrcweir const AFX_RECTINFO _afxRectInfo[] =
75cdf0e10cSrcweir {
76cdf0e10cSrcweir     { offsetof(RECT, right), +1 },
77cdf0e10cSrcweir     { offsetof(RECT, bottom), +1 },
78cdf0e10cSrcweir     { offsetof(RECT, left), -1 },
79cdf0e10cSrcweir     { offsetof(RECT, top), -1 },
80cdf0e10cSrcweir };
81cdf0e10cSrcweir 
82cdf0e10cSrcweir 
HalftoneBrush()83cdf0e10cSrcweir HBRUSH HalftoneBrush()
84cdf0e10cSrcweir {
85cdf0e10cSrcweir     if (_afxHalftoneBrush == NULL)
86cdf0e10cSrcweir     {
87cdf0e10cSrcweir         WORD grayPattern[8];
88cdf0e10cSrcweir         for (int i = 0; i < 8; i++)
89cdf0e10cSrcweir             grayPattern[i] = (WORD)(0x5555 << (i & 1));
90cdf0e10cSrcweir         HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern);
91cdf0e10cSrcweir         if (grayBitmap != NULL)
92cdf0e10cSrcweir         {
93cdf0e10cSrcweir             _afxHalftoneBrush = CreatePatternBrush(grayBitmap);
94cdf0e10cSrcweir             DeleteObject(grayBitmap);
95cdf0e10cSrcweir         }
96cdf0e10cSrcweir     }
97cdf0e10cSrcweir     return _afxHalftoneBrush;
98cdf0e10cSrcweir }
99cdf0e10cSrcweir 
100cdf0e10cSrcweir 
101cdf0e10cSrcweir 
DrawDragRect(HDC hDC,LPRECT lpRect,SIZE size,LPRECT lpRectLast,SIZE sizeLast,HBRUSH hBrush=NULL,HBRUSH hBrushLast=NULL)102cdf0e10cSrcweir void DrawDragRect(
103cdf0e10cSrcweir     HDC hDC,LPRECT lpRect,SIZE size,
104cdf0e10cSrcweir     LPRECT lpRectLast,SIZE sizeLast,
105cdf0e10cSrcweir     HBRUSH hBrush = NULL,HBRUSH hBrushLast = NULL)
106cdf0e10cSrcweir {
107cdf0e10cSrcweir     // first, determine the update region and select it
108cdf0e10cSrcweir     HRGN rgnNew;
109cdf0e10cSrcweir     HRGN rgnOutside,rgnInside;
110cdf0e10cSrcweir     rgnOutside = CreateRectRgnIndirect(lpRect);
111cdf0e10cSrcweir     RECT rect = *lpRect;
112cdf0e10cSrcweir     InflateRect(&rect,-size.cx, -size.cy);
113cdf0e10cSrcweir     IntersectRect(&rect,&rect,lpRect);
114cdf0e10cSrcweir     rgnInside = CreateRectRgnIndirect(&rect);
115cdf0e10cSrcweir     rgnNew = CreateRectRgn(0, 0, 0, 0);
116cdf0e10cSrcweir     CombineRgn(rgnNew,rgnOutside,rgnInside,RGN_XOR);
117cdf0e10cSrcweir 
118cdf0e10cSrcweir     HBRUSH hBrushOld = NULL;
119cdf0e10cSrcweir     if (hBrush == NULL)
120cdf0e10cSrcweir         hBrush = HalftoneBrush();
121cdf0e10cSrcweir     if (hBrushLast == NULL)
122cdf0e10cSrcweir         hBrushLast = hBrush;
123cdf0e10cSrcweir 
124cdf0e10cSrcweir     HRGN rgnLast(NULL);
125cdf0e10cSrcweir     HRGN rgnUpdate(NULL);
126cdf0e10cSrcweir     if (lpRectLast != NULL)
127cdf0e10cSrcweir     {
128cdf0e10cSrcweir         // find difference between new region and old region
129cdf0e10cSrcweir         rgnLast = CreateRectRgn(0, 0, 0, 0);
130cdf0e10cSrcweir         SetRectRgn(
131cdf0e10cSrcweir             rgnOutside,
132cdf0e10cSrcweir             lpRectLast->left,
133cdf0e10cSrcweir             lpRectLast->top,
134cdf0e10cSrcweir             lpRectLast->right,
135cdf0e10cSrcweir             lpRectLast->bottom);
136cdf0e10cSrcweir         rect = *lpRectLast;
137cdf0e10cSrcweir         InflateRect(&rect,-sizeLast.cx, -sizeLast.cy);
138cdf0e10cSrcweir         IntersectRect(&rect,&rect, lpRectLast);
139cdf0e10cSrcweir         SetRectRgn(rgnInside,rect.left,rect.top,rect.right,rect.bottom);
140cdf0e10cSrcweir         CombineRgn(rgnLast,rgnOutside,rgnInside, RGN_XOR);
141cdf0e10cSrcweir 
142cdf0e10cSrcweir // 		// only diff them if brushes are the same
143cdf0e10cSrcweir         if (hBrush == hBrushLast)
144cdf0e10cSrcweir         {
145cdf0e10cSrcweir             rgnUpdate = CreateRectRgn(0, 0, 0, 0);
146cdf0e10cSrcweir             CombineRgn(rgnUpdate,rgnLast,rgnNew, RGN_XOR);
147cdf0e10cSrcweir         }
148cdf0e10cSrcweir     }
149cdf0e10cSrcweir     if (hBrush != hBrushLast && lpRectLast != NULL)
150cdf0e10cSrcweir     {
151cdf0e10cSrcweir         // brushes are different -- erase old region first
152cdf0e10cSrcweir         SelectClipRgn(hDC,rgnLast);
153cdf0e10cSrcweir         GetClipBox(hDC,&rect);
154cdf0e10cSrcweir         hBrushOld = (HBRUSH)SelectObject(hDC,(HGDIOBJ)hBrushLast);
155cdf0e10cSrcweir         PatBlt(hDC,rect.left,rect.top,(rect.right-rect.left),(rect.bottom-rect.top),PATINVERT);
156cdf0e10cSrcweir 
157cdf0e10cSrcweir         SelectObject(hDC,(HGDIOBJ)hBrushOld);
158cdf0e10cSrcweir         hBrushOld = NULL;
159cdf0e10cSrcweir     }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir     // draw into the update/new region
162cdf0e10cSrcweir     SelectClipRgn(hDC,rgnUpdate);
163cdf0e10cSrcweir 
164cdf0e10cSrcweir     GetClipBox(hDC,&rect);
165cdf0e10cSrcweir     hBrushOld = (HBRUSH) SelectObject(hDC,(HGDIOBJ) hBrush);
166cdf0e10cSrcweir     PatBlt(hDC,rect.left, rect.top,(rect.right-rect.left),(rect.bottom-rect.top), PATINVERT);
167cdf0e10cSrcweir 
168cdf0e10cSrcweir     // cleanup DC
169cdf0e10cSrcweir     if (hBrushOld != NULL)
170cdf0e10cSrcweir         SelectObject(hDC,(HGDIOBJ)hBrushOld);
171cdf0e10cSrcweir     SelectClipRgn(hDC,NULL);
172cdf0e10cSrcweir }
173cdf0e10cSrcweir 
174cdf0e10cSrcweir 
TransformRect(LPRECT rect,HWND pWnd,HWND pWndClipTo)175cdf0e10cSrcweir void winwrap::TransformRect(LPRECT rect,HWND pWnd,HWND pWndClipTo)
176cdf0e10cSrcweir {
177cdf0e10cSrcweir     POINT pt;
178cdf0e10cSrcweir     pt.x = rect->left;pt.y = rect->top;
179cdf0e10cSrcweir     ClientToScreen(pWnd,&pt);
180cdf0e10cSrcweir     ScreenToClient(pWndClipTo,&pt);
181cdf0e10cSrcweir     rect->left = pt.x; rect->top = pt.y;
182cdf0e10cSrcweir 
183cdf0e10cSrcweir     pt.x = rect->right;pt.y = rect->bottom;
184cdf0e10cSrcweir     ClientToScreen(pWnd,&pt);
185cdf0e10cSrcweir     ScreenToClient(pWndClipTo,&pt);
186cdf0e10cSrcweir     rect->right = pt.x; rect->bottom = pt.y;
187cdf0e10cSrcweir }
188cdf0e10cSrcweir 
189cdf0e10cSrcweir 
NormalizeRect(LPRECT rp)190cdf0e10cSrcweir void NormalizeRect(LPRECT rp)
191cdf0e10cSrcweir {
192cdf0e10cSrcweir     if(rp->left > rp->right) {
193cdf0e10cSrcweir         UINT tmp = rp->left;
194cdf0e10cSrcweir         rp->left = rp->right;
195cdf0e10cSrcweir         rp->right = tmp;
196cdf0e10cSrcweir     }
197cdf0e10cSrcweir 
198cdf0e10cSrcweir     if(rp->top > rp->bottom) {
199cdf0e10cSrcweir         UINT tmp = rp->top;
200cdf0e10cSrcweir         rp->top = rp->bottom;
201cdf0e10cSrcweir         rp->bottom = tmp;
202cdf0e10cSrcweir     }
203cdf0e10cSrcweir }
204cdf0e10cSrcweir 
205cdf0e10cSrcweir 
206cdf0e10cSrcweir using namespace winwrap;
207cdf0e10cSrcweir 
208cdf0e10cSrcweir 
Tracker()209cdf0e10cSrcweir Tracker::Tracker()
210cdf0e10cSrcweir {
211cdf0e10cSrcweir }
212cdf0e10cSrcweir 
213cdf0e10cSrcweir 
Tracker(LPCRECT lpSrcRect,UINT nStyle)214cdf0e10cSrcweir Tracker::Tracker(LPCRECT lpSrcRect, UINT nStyle)
215cdf0e10cSrcweir {
216cdf0e10cSrcweir     Construct();
217cdf0e10cSrcweir     CopyRect(&m_rect,lpSrcRect);
218cdf0e10cSrcweir     m_nStyle = nStyle;
219cdf0e10cSrcweir }
220cdf0e10cSrcweir 
221cdf0e10cSrcweir HBRUSH _afxHatchBrush = 0;
222cdf0e10cSrcweir HPEN _afxBlackDottedPen = 0;
223cdf0e10cSrcweir int _afxHandleSize = 0;
224cdf0e10cSrcweir 
225cdf0e10cSrcweir 
Construct()226cdf0e10cSrcweir void Tracker::Construct()
227cdf0e10cSrcweir {
228cdf0e10cSrcweir     static BOOL bInitialized = false;
229cdf0e10cSrcweir     if (!bInitialized)
230cdf0e10cSrcweir     {
231cdf0e10cSrcweir         if (_afxHatchBrush == NULL)
232cdf0e10cSrcweir         {
233cdf0e10cSrcweir             // create the hatch pattern + bitmap
234cdf0e10cSrcweir             WORD hatchPattern[8];
235cdf0e10cSrcweir             WORD wPattern = 0x1111;
236cdf0e10cSrcweir             for (int i = 0; i < 4; i++)
237cdf0e10cSrcweir             {
238cdf0e10cSrcweir                 hatchPattern[i] = wPattern;
239cdf0e10cSrcweir                 hatchPattern[i+4] = wPattern;
240cdf0e10cSrcweir                 wPattern <<= 1;
241cdf0e10cSrcweir             }
242cdf0e10cSrcweir             HBITMAP hatchBitmap = CreateBitmap(8, 8, 1, 1,&hatchPattern);
243cdf0e10cSrcweir 
244cdf0e10cSrcweir             // create black hatched brush
245cdf0e10cSrcweir             _afxHatchBrush = CreatePatternBrush(hatchBitmap);
246cdf0e10cSrcweir             DeleteObject(hatchBitmap);
247cdf0e10cSrcweir         }
248cdf0e10cSrcweir 
249cdf0e10cSrcweir         if (_afxBlackDottedPen == NULL)
250cdf0e10cSrcweir         {
251cdf0e10cSrcweir             // create black dotted pen
252cdf0e10cSrcweir             _afxBlackDottedPen = CreatePen(PS_DOT, 0, RGB(0, 0, 0));
253cdf0e10cSrcweir         }
254cdf0e10cSrcweir 
255cdf0e10cSrcweir         // get default handle size from Windows profile setting
256cdf0e10cSrcweir         static const TCHAR szWindows[] = TEXT("windows");
257cdf0e10cSrcweir         static const TCHAR szInplaceBorderWidth[] =
258cdf0e10cSrcweir             TEXT("oleinplaceborderwidth");
259cdf0e10cSrcweir         _afxHandleSize = GetProfileInt(szWindows, szInplaceBorderWidth, 4);
260cdf0e10cSrcweir         bInitialized = TRUE;
261cdf0e10cSrcweir 
262cdf0e10cSrcweir         _afxCursors[0] = _afxCursors[2] = LoadCursor(0,IDC_SIZENWSE);
263cdf0e10cSrcweir         _afxCursors[4] = _afxCursors[6] = LoadCursor(0,IDC_SIZENS);
264cdf0e10cSrcweir         _afxCursors[1] = _afxCursors[3] = LoadCursor(0,IDC_SIZENESW);
265cdf0e10cSrcweir         _afxCursors[5] = _afxCursors[7] = LoadCursor(0,IDC_SIZEWE);
266cdf0e10cSrcweir         _afxCursors[8] = LoadCursor(0,IDC_SIZEALL);
267cdf0e10cSrcweir     }
268cdf0e10cSrcweir 
269cdf0e10cSrcweir     m_nStyle = 0;
270cdf0e10cSrcweir     m_nHandleSize = _afxHandleSize;
271cdf0e10cSrcweir     m_sizeMin.cy = m_sizeMin.cx = m_nHandleSize*2;
272cdf0e10cSrcweir 
273cdf0e10cSrcweir     SetRectEmpty(&m_rectLast);
274cdf0e10cSrcweir     m_sizeLast.cx = m_sizeLast.cy = 0;
275cdf0e10cSrcweir     m_bErase = FALSE;
276cdf0e10cSrcweir     m_bFinalErase =  FALSE;
277cdf0e10cSrcweir }
278cdf0e10cSrcweir 
~Tracker()279cdf0e10cSrcweir Tracker::~Tracker()
280cdf0e10cSrcweir {
281cdf0e10cSrcweir }
282cdf0e10cSrcweir 
283cdf0e10cSrcweir 
HitTest(POINT point) const284cdf0e10cSrcweir int Tracker::HitTest(POINT point) const
285cdf0e10cSrcweir {
286cdf0e10cSrcweir     TrackerHit hitResult = hitNothing;
287cdf0e10cSrcweir 
288cdf0e10cSrcweir     RECT rectTrue;
289cdf0e10cSrcweir     GetTrueRect(&rectTrue);
290cdf0e10cSrcweir     NormalizeRect(&rectTrue);
291cdf0e10cSrcweir     if (PtInRect(&rectTrue,point))
292cdf0e10cSrcweir     {
293cdf0e10cSrcweir         if ((m_nStyle & (resizeInside|resizeOutside)) != 0)
294cdf0e10cSrcweir             hitResult = (TrackerHit)HitTestHandles(point);
295cdf0e10cSrcweir         else
296cdf0e10cSrcweir             hitResult = hitMiddle;
297cdf0e10cSrcweir     }
298cdf0e10cSrcweir     return hitResult;
299cdf0e10cSrcweir }
300cdf0e10cSrcweir 
301cdf0e10cSrcweir 
SetCursor(HWND pWnd,UINT nHitTest) const302cdf0e10cSrcweir BOOL Tracker::SetCursor(HWND pWnd, UINT nHitTest) const
303cdf0e10cSrcweir {
304cdf0e10cSrcweir     // trackers should only be in client area
305cdf0e10cSrcweir     if (nHitTest != HTCLIENT)
306cdf0e10cSrcweir         return FALSE;
307cdf0e10cSrcweir 
308cdf0e10cSrcweir     // convert cursor position to client co-ordinates
309cdf0e10cSrcweir     POINT point;
310cdf0e10cSrcweir     GetCursorPos(&point);
311cdf0e10cSrcweir     ScreenToClient(pWnd,&point);
312cdf0e10cSrcweir 
313cdf0e10cSrcweir     // do hittest and normalize hit
314cdf0e10cSrcweir     int nHandle = HitTestHandles(point);
315cdf0e10cSrcweir     if (nHandle < 0)
316cdf0e10cSrcweir         return FALSE;
317cdf0e10cSrcweir 
318cdf0e10cSrcweir     // need to normalize the hittest such that we get proper cursors
319cdf0e10cSrcweir     nHandle = NormalizeHit(nHandle);
320cdf0e10cSrcweir 
321cdf0e10cSrcweir     // handle special case of hitting area between handles
322cdf0e10cSrcweir     //  (logically the same -- handled as a move -- but different cursor)
323cdf0e10cSrcweir     if (nHandle == hitMiddle && !PtInRect(&m_rect,point))
324cdf0e10cSrcweir     {
325cdf0e10cSrcweir         // only for trackers with hatchedBorder (ie. in-place resizing)
326cdf0e10cSrcweir         if (m_nStyle & hatchedBorder)
327cdf0e10cSrcweir             nHandle = (TrackerHit)9;
328cdf0e10cSrcweir     }
329cdf0e10cSrcweir 
330cdf0e10cSrcweir     ::SetCursor(_afxCursors[nHandle]);
331cdf0e10cSrcweir     return TRUE;
332cdf0e10cSrcweir }
333cdf0e10cSrcweir 
334cdf0e10cSrcweir 
335cdf0e10cSrcweir 
Track(HWND hWnd,POINT point,BOOL bAllowInvert,HWND hWndClipTo)336cdf0e10cSrcweir BOOL Tracker::Track(HWND hWnd,POINT point,BOOL bAllowInvert,
337cdf0e10cSrcweir                     HWND hWndClipTo)
338cdf0e10cSrcweir {
339cdf0e10cSrcweir     // perform hit testing on the handles
340cdf0e10cSrcweir     int nHandle = HitTestHandles(point);
341cdf0e10cSrcweir     if (nHandle < 0)
342cdf0e10cSrcweir     {
343cdf0e10cSrcweir         // didn't hit a handle, so just return FALSE
344cdf0e10cSrcweir         return FALSE;
345cdf0e10cSrcweir     }
346cdf0e10cSrcweir 
347cdf0e10cSrcweir     // otherwise, call helper function to do the tracking
348cdf0e10cSrcweir     m_bAllowInvert = bAllowInvert;
349cdf0e10cSrcweir     SetCursor(hWnd,nHandle);
350cdf0e10cSrcweir     return TrackHandle(nHandle, hWnd, point, hWndClipTo);
351cdf0e10cSrcweir }
352cdf0e10cSrcweir 
353cdf0e10cSrcweir 
TrackHandle(int nHandle,HWND hWnd,POINT point,HWND hWndClipTo)354cdf0e10cSrcweir BOOL Tracker::TrackHandle(int nHandle,HWND hWnd,POINT point,HWND hWndClipTo)
355cdf0e10cSrcweir {
356cdf0e10cSrcweir     // don't handle if capture already set
357cdf0e10cSrcweir     if (GetCapture() != NULL)
358cdf0e10cSrcweir         return FALSE;
359cdf0e10cSrcweir 
360cdf0e10cSrcweir     // save original width & height in pixels
361cdf0e10cSrcweir     int nWidth = m_rect.right - m_rect.left;
362cdf0e10cSrcweir     int nHeight = m_rect.bottom - m_rect.top;
363cdf0e10cSrcweir 
364cdf0e10cSrcweir     // set capture to the window which received this message
365cdf0e10cSrcweir     SetCapture(hWnd);
366cdf0e10cSrcweir     UpdateWindow(hWnd);
367cdf0e10cSrcweir     if (hWndClipTo != NULL)
368cdf0e10cSrcweir         UpdateWindow(hWndClipTo);
369cdf0e10cSrcweir     RECT rectSave = m_rect;
370cdf0e10cSrcweir 
371cdf0e10cSrcweir 	// find out what x/y coords we are supposed to modify
372cdf0e10cSrcweir     int *px, *py;
373cdf0e10cSrcweir     int xDiff, yDiff;
374cdf0e10cSrcweir     GetModifyPointers(nHandle, &px, &py, &xDiff, &yDiff);
375cdf0e10cSrcweir     xDiff = point.x - xDiff;
376cdf0e10cSrcweir     yDiff = point.y - yDiff;
377cdf0e10cSrcweir 
378cdf0e10cSrcweir     // get DC for drawing
379cdf0e10cSrcweir     HDC hDrawDC;
380cdf0e10cSrcweir     if (hWndClipTo != NULL)
381cdf0e10cSrcweir     {
382cdf0e10cSrcweir         // clip to arbitrary window by using adjusted Window DC
383cdf0e10cSrcweir         hDrawDC = GetDCEx(hWndClipTo,NULL, DCX_CACHE);
384cdf0e10cSrcweir     }
385cdf0e10cSrcweir     else
386cdf0e10cSrcweir     {
387cdf0e10cSrcweir         // otherwise, just use normal DC
388cdf0e10cSrcweir         hDrawDC = GetDC(hWnd);
389cdf0e10cSrcweir     }
390cdf0e10cSrcweir 
391cdf0e10cSrcweir     RECT rectOld;
392cdf0e10cSrcweir     BOOL bMoved = FALSE;
393cdf0e10cSrcweir 
394cdf0e10cSrcweir     // get messages until capture lost or cancelled/accepted
395cdf0e10cSrcweir     for (;;)
396cdf0e10cSrcweir     {
397cdf0e10cSrcweir         MSG msg;
398cdf0e10cSrcweir         GetMessage(&msg, NULL, 0, 0);
399cdf0e10cSrcweir 
400cdf0e10cSrcweir         if (GetCapture() != hWnd)
401cdf0e10cSrcweir             break;
402cdf0e10cSrcweir 
403cdf0e10cSrcweir         switch (msg.message)
404cdf0e10cSrcweir         {
405cdf0e10cSrcweir             // handle movement/accept messages
406cdf0e10cSrcweir         case WM_LBUTTONUP:
407cdf0e10cSrcweir         case WM_MOUSEMOVE:
408cdf0e10cSrcweir             rectOld = m_rect;
409cdf0e10cSrcweir             // handle resize cases (and part of move)
410cdf0e10cSrcweir             if (px != NULL)
411cdf0e10cSrcweir                 *px = (int)(short)LOWORD(msg.lParam) - xDiff;
412cdf0e10cSrcweir             if (py != NULL)
413cdf0e10cSrcweir                 *py = (int)(short)HIWORD(msg.lParam) - yDiff;
414cdf0e10cSrcweir 
415cdf0e10cSrcweir             // handle move case
416cdf0e10cSrcweir             if (nHandle == hitMiddle)
417cdf0e10cSrcweir             {
418cdf0e10cSrcweir                 m_rect.right = m_rect.left + nWidth;
419cdf0e10cSrcweir                 m_rect.bottom = m_rect.top + nHeight;
420cdf0e10cSrcweir             }
421cdf0e10cSrcweir             // allow caller to adjust the rectangle if necessary
422cdf0e10cSrcweir             AdjustRect(nHandle,&m_rect);
423cdf0e10cSrcweir 
424cdf0e10cSrcweir             // only redraw and callback if the rect actually changed!
425cdf0e10cSrcweir             m_bFinalErase = (msg.message == WM_LBUTTONUP);
426cdf0e10cSrcweir             if (!EqualRect(&rectOld,&m_rect) || m_bFinalErase)
427cdf0e10cSrcweir             {
428cdf0e10cSrcweir                 if (bMoved)
429cdf0e10cSrcweir                 {
430cdf0e10cSrcweir                     m_bErase = TRUE;
431cdf0e10cSrcweir                     DrawTrackerRect(&rectOld,hWndClipTo,hDrawDC,hWnd);
432cdf0e10cSrcweir                 }
433cdf0e10cSrcweir                 OnChangedRect(rectOld);
434cdf0e10cSrcweir                 if (msg.message != WM_LBUTTONUP)
435cdf0e10cSrcweir                     bMoved = TRUE;
436cdf0e10cSrcweir             }
437cdf0e10cSrcweir             if (m_bFinalErase)
438cdf0e10cSrcweir                 goto ExitLoop;
439cdf0e10cSrcweir 
440cdf0e10cSrcweir             if (!EqualRect(&rectOld,&m_rect))
441cdf0e10cSrcweir             {
442cdf0e10cSrcweir                 m_bErase = FALSE;
443cdf0e10cSrcweir                 DrawTrackerRect(&m_rect,hWndClipTo,hDrawDC,hWnd);
444cdf0e10cSrcweir             }
445cdf0e10cSrcweir             break;
446cdf0e10cSrcweir 
447cdf0e10cSrcweir             // handle cancel messages
448cdf0e10cSrcweir         case WM_KEYDOWN:
449cdf0e10cSrcweir             if (msg.wParam != VK_ESCAPE)
450cdf0e10cSrcweir                 break;
451cdf0e10cSrcweir         case WM_RBUTTONDOWN:
452cdf0e10cSrcweir             if (bMoved)
453cdf0e10cSrcweir             {
454cdf0e10cSrcweir                 m_bErase = m_bFinalErase = TRUE;
455cdf0e10cSrcweir                 DrawTrackerRect(&m_rect, hWndClipTo, hDrawDC, hWnd);
456cdf0e10cSrcweir             }
457cdf0e10cSrcweir             m_rect = rectSave;
458cdf0e10cSrcweir             goto ExitLoop;
459cdf0e10cSrcweir 
460cdf0e10cSrcweir             // just dispatch rest of the messages
461cdf0e10cSrcweir         default:
462cdf0e10cSrcweir             DispatchMessage(&msg);
463cdf0e10cSrcweir             break;
464cdf0e10cSrcweir         }
465cdf0e10cSrcweir     }
466cdf0e10cSrcweir 
467cdf0e10cSrcweir   ExitLoop:
468cdf0e10cSrcweir     if (hWndClipTo != NULL)
469cdf0e10cSrcweir         ReleaseDC(hWndClipTo,hDrawDC);
470cdf0e10cSrcweir     else
471cdf0e10cSrcweir         ReleaseDC(hWnd,hDrawDC);
472cdf0e10cSrcweir     ReleaseCapture();
473cdf0e10cSrcweir 
474cdf0e10cSrcweir     // restore rect in case bMoved is still FALSE
475cdf0e10cSrcweir     if (!bMoved)
476cdf0e10cSrcweir         m_rect = rectSave;
477cdf0e10cSrcweir     m_bFinalErase = FALSE;
478cdf0e10cSrcweir     m_bErase = FALSE;
479cdf0e10cSrcweir 
480cdf0e10cSrcweir     // return TRUE only if rect has changed
481cdf0e10cSrcweir     return !EqualRect(&rectSave,&m_rect);
482cdf0e10cSrcweir }
483cdf0e10cSrcweir 
484cdf0e10cSrcweir 
OnChangedRect(const RECT &)485cdf0e10cSrcweir void Tracker::OnChangedRect(const RECT& /*rectOld*/)
486cdf0e10cSrcweir {
487cdf0e10cSrcweir }
488cdf0e10cSrcweir 
489cdf0e10cSrcweir 
AdjustRect(int nHandle,LPRECT)490cdf0e10cSrcweir void Tracker::AdjustRect(int nHandle, LPRECT)
491cdf0e10cSrcweir {
492cdf0e10cSrcweir     if(nHandle == hitMiddle)
493cdf0e10cSrcweir         return;
494cdf0e10cSrcweir 
495cdf0e10cSrcweir     // convert the handle into locations within m_rect
496cdf0e10cSrcweir     int *px, *py;
497cdf0e10cSrcweir     GetModifyPointers(nHandle, &px, &py, NULL, NULL);
498cdf0e10cSrcweir 
499cdf0e10cSrcweir     // enforce minimum width
500cdf0e10cSrcweir     int nNewWidth = m_rect.right - m_rect.left;
501cdf0e10cSrcweir     int nAbsWidth = m_bAllowInvert ? abs(nNewWidth) : nNewWidth;
502cdf0e10cSrcweir     if (px != NULL && nAbsWidth < m_sizeMin.cx)
503cdf0e10cSrcweir     {
504cdf0e10cSrcweir         nNewWidth = nAbsWidth != 0 ? nNewWidth / nAbsWidth : 1;
505cdf0e10cSrcweir         const AFX_RECTINFO* pRectInfo =
506cdf0e10cSrcweir             &_afxRectInfo[(int*)px - (int*)&m_rect];
507cdf0e10cSrcweir         *px = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
508cdf0e10cSrcweir             nNewWidth * m_sizeMin.cx * -pRectInfo->nSignAcross;
509cdf0e10cSrcweir     }
510cdf0e10cSrcweir 
511cdf0e10cSrcweir     // enforce minimum height
512cdf0e10cSrcweir     int nNewHeight = m_rect.bottom - m_rect.top;
513cdf0e10cSrcweir     int nAbsHeight = m_bAllowInvert ? abs(nNewHeight) : nNewHeight;
514cdf0e10cSrcweir     if (py != NULL && nAbsHeight < m_sizeMin.cy)
515cdf0e10cSrcweir     {
516cdf0e10cSrcweir         nNewHeight = nAbsHeight != 0 ? nNewHeight / nAbsHeight : 1;
517cdf0e10cSrcweir         const AFX_RECTINFO* pRectInfo =
518cdf0e10cSrcweir             &_afxRectInfo[(int*)py - (int*)&m_rect];
519cdf0e10cSrcweir         *py = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
520cdf0e10cSrcweir             nNewHeight * m_sizeMin.cy * -pRectInfo->nSignAcross;
521cdf0e10cSrcweir     }
522cdf0e10cSrcweir }
523cdf0e10cSrcweir 
524cdf0e10cSrcweir 
DrawTrackerRect(LPRECT lpRect,HWND pWndClipTo,HDC pDC,HWND pWnd)525cdf0e10cSrcweir void Tracker::DrawTrackerRect(
526cdf0e10cSrcweir     LPRECT lpRect,HWND pWndClipTo,HDC pDC,HWND pWnd)
527cdf0e10cSrcweir {
528cdf0e10cSrcweir     // first, normalize the rectangle for drawing
529cdf0e10cSrcweir     RECT rect = *lpRect;
530cdf0e10cSrcweir     NormalizeRect(&rect);
531cdf0e10cSrcweir 
532cdf0e10cSrcweir     // convert to client coordinates
533cdf0e10cSrcweir     if (pWndClipTo != NULL)
534cdf0e10cSrcweir         TransformRect(&rect,pWnd,pWndClipTo);
535cdf0e10cSrcweir 
536cdf0e10cSrcweir     SIZE size;
537cdf0e10cSrcweir     size.cx = 0; size.cy = 0;
538cdf0e10cSrcweir     if (!m_bFinalErase)
539cdf0e10cSrcweir     {
540cdf0e10cSrcweir         // otherwise, size depends on the style
541cdf0e10cSrcweir         if (m_nStyle & hatchedBorder)
542cdf0e10cSrcweir         {
543cdf0e10cSrcweir             size.cx = size.cy = max(1,GetHandleSize(&rect)-1);
544cdf0e10cSrcweir             InflateRect(&rect,size.cx,size.cy);
545cdf0e10cSrcweir         }
546cdf0e10cSrcweir         else
547cdf0e10cSrcweir         {
548cdf0e10cSrcweir             size.cx = 1; // CX_BORDER;
549cdf0e10cSrcweir             size.cy = 1; // CY_BORDER;
550cdf0e10cSrcweir         }
551cdf0e10cSrcweir     }
552cdf0e10cSrcweir 
553cdf0e10cSrcweir     // and draw it
554cdf0e10cSrcweir     if (m_bFinalErase || !m_bErase)
555cdf0e10cSrcweir         DrawDragRect(pDC,&rect,size,&m_rectLast,m_sizeLast);
556cdf0e10cSrcweir 
557cdf0e10cSrcweir     // remember last rectangles
558cdf0e10cSrcweir     m_rectLast = rect;
559cdf0e10cSrcweir     m_sizeLast = size;
560cdf0e10cSrcweir }
561cdf0e10cSrcweir 
562cdf0e10cSrcweir 
Draw(HDC hDC) const563cdf0e10cSrcweir void Tracker::Draw(HDC hDC) const
564cdf0e10cSrcweir {
565cdf0e10cSrcweir     // set initial DC state
566cdf0e10cSrcweir     SetMapMode(hDC,MM_TEXT);
567cdf0e10cSrcweir     SetViewportOrgEx(hDC,0, 0,NULL);
568cdf0e10cSrcweir     SetWindowOrgEx(hDC,0, 0,NULL);
569cdf0e10cSrcweir 
570cdf0e10cSrcweir     // get normalized rectangle
571cdf0e10cSrcweir     RECT rect = m_rect;
572cdf0e10cSrcweir     NormalizeRect(&rect);
573cdf0e10cSrcweir 
574cdf0e10cSrcweir     HPEN pOldPen = NULL;
575cdf0e10cSrcweir     HBRUSH pOldBrush = NULL;
576cdf0e10cSrcweir     HGDIOBJ pTemp;
577cdf0e10cSrcweir     int nOldROP;
578cdf0e10cSrcweir 
579cdf0e10cSrcweir     // draw lines
580cdf0e10cSrcweir     if ((m_nStyle & (dottedLine|solidLine)) != 0)
581cdf0e10cSrcweir     {
582cdf0e10cSrcweir         if (m_nStyle & dottedLine)
583cdf0e10cSrcweir             pOldPen = (HPEN)SelectObject(hDC,_afxBlackDottedPen);
584cdf0e10cSrcweir         else
585cdf0e10cSrcweir             pOldPen = (HPEN)SelectObject(hDC,(HGDIOBJ)BLACK_PEN);
586cdf0e10cSrcweir         pOldBrush = (HBRUSH)SelectObject(hDC,(HGDIOBJ)NULL_BRUSH);
587cdf0e10cSrcweir         nOldROP = SetROP2(hDC,R2_COPYPEN);
588cdf0e10cSrcweir         InflateRect(&rect,+1, +1);   // borders are one pixel outside
589cdf0e10cSrcweir         Rectangle(hDC,rect.left, rect.top, rect.right, rect.bottom);
590cdf0e10cSrcweir         SetROP2(hDC,nOldROP);
591cdf0e10cSrcweir     }
592cdf0e10cSrcweir 
593cdf0e10cSrcweir     // if hatchBrush is going to be used, need to unrealize it
594cdf0e10cSrcweir     if ((m_nStyle & (hatchInside|hatchedBorder)) != 0)
595cdf0e10cSrcweir         UnrealizeObject((HGDIOBJ)_afxHatchBrush);
596cdf0e10cSrcweir 
597cdf0e10cSrcweir     // hatch inside
598cdf0e10cSrcweir     if ((m_nStyle & hatchInside) != 0)
599cdf0e10cSrcweir     {
600cdf0e10cSrcweir         pTemp = SelectObject(hDC,(HGDIOBJ)NULL_PEN);
601cdf0e10cSrcweir         if (pOldPen == NULL)
602cdf0e10cSrcweir             pOldPen = (HPEN)pTemp;
603cdf0e10cSrcweir         pTemp = SelectObject(hDC,(HGDIOBJ)_afxHatchBrush);
604cdf0e10cSrcweir         if (pOldBrush == NULL)
605cdf0e10cSrcweir             pOldBrush = (HBRUSH)pTemp;
606cdf0e10cSrcweir         SetBkMode(hDC,TRANSPARENT);
607cdf0e10cSrcweir         nOldROP = SetROP2(hDC,R2_MASKNOTPEN);
608cdf0e10cSrcweir         Rectangle(hDC,rect.left+1, rect.top+1, rect.right, rect.bottom);
609cdf0e10cSrcweir         SetROP2(hDC,nOldROP);
610cdf0e10cSrcweir     }
611cdf0e10cSrcweir 
612cdf0e10cSrcweir     // draw hatched border
613cdf0e10cSrcweir     if ((m_nStyle & hatchedBorder) != 0)
614cdf0e10cSrcweir     {
615cdf0e10cSrcweir         pTemp = SelectObject(hDC,(HGDIOBJ)_afxHatchBrush);
616cdf0e10cSrcweir         if (pOldBrush == NULL)
617cdf0e10cSrcweir             pOldBrush = (HBRUSH)pTemp;
618cdf0e10cSrcweir         SetBkMode(hDC,OPAQUE);
619cdf0e10cSrcweir         RECT rectTrue;
620cdf0e10cSrcweir         GetTrueRect(&rectTrue);
621cdf0e10cSrcweir         PatBlt(hDC,rectTrue.left, rectTrue.top, rectTrue.right-rectTrue.left,
622cdf0e10cSrcweir                rect.top-rectTrue.top, 0x000F0001 /* Pn */);
623cdf0e10cSrcweir         PatBlt(hDC,rectTrue.left, rect.bottom,
624cdf0e10cSrcweir                rectTrue.right-rectTrue.left,
625cdf0e10cSrcweir                rectTrue.bottom-rect.bottom, 0x000F0001 /* Pn */);
626cdf0e10cSrcweir         PatBlt(hDC,rectTrue.left, rect.top, rect.left-rectTrue.left,
627cdf0e10cSrcweir                rect.bottom-rect.top, 0x000F0001 /* Pn */);
628cdf0e10cSrcweir         PatBlt(hDC,rect.right, rect.top, rectTrue.right-rect.right,
629cdf0e10cSrcweir                rect.bottom-rect.top, 0x000F0001 /* Pn */);
630cdf0e10cSrcweir     }
631cdf0e10cSrcweir 
632cdf0e10cSrcweir     // draw resize handles
633cdf0e10cSrcweir     if ((m_nStyle & (resizeInside|resizeOutside)) != 0)
634cdf0e10cSrcweir     {
635cdf0e10cSrcweir         UINT mask = GetHandleMask();
636cdf0e10cSrcweir         HBRUSH hbrush = CreateSolidBrush(RGB(0,0,0));
637cdf0e10cSrcweir         for (int i = 0; i < 8; ++i)
638cdf0e10cSrcweir         {
639cdf0e10cSrcweir             if (mask & (1<<i))
640cdf0e10cSrcweir             {
641cdf0e10cSrcweir                 GetHandleRect((TrackerHit)i, &rect);
642cdf0e10cSrcweir                 // FillSolidRect(hDC,rect, RGB(0, 0, 0));
643cdf0e10cSrcweir                 FillRect(hDC,&rect,hbrush);
644cdf0e10cSrcweir             }
645cdf0e10cSrcweir         }
646cdf0e10cSrcweir         DeleteObject(hbrush);
647cdf0e10cSrcweir     }
648cdf0e10cSrcweir 
649cdf0e10cSrcweir     // cleanup pDC state
650cdf0e10cSrcweir     if (pOldPen != NULL)
651cdf0e10cSrcweir         SelectObject(hDC,pOldPen);
652cdf0e10cSrcweir     if (pOldBrush != NULL)
653cdf0e10cSrcweir         SelectObject(hDC,pOldBrush);
654cdf0e10cSrcweir     RestoreDC(hDC,-1);
655cdf0e10cSrcweir }
656cdf0e10cSrcweir 
657cdf0e10cSrcweir 
GetHandleRect(int nHandle,RECT * pHandleRect) const658cdf0e10cSrcweir void Tracker::GetHandleRect(int nHandle,RECT* pHandleRect) const
659cdf0e10cSrcweir {
660cdf0e10cSrcweir     // get normalized rectangle of the tracker
661cdf0e10cSrcweir     RECT rectT = m_rect;
662cdf0e10cSrcweir     NormalizeRect(&rectT);
663cdf0e10cSrcweir     if ((m_nStyle & (solidLine|dottedLine)) != 0)
664cdf0e10cSrcweir         InflateRect(&rectT,+1, +1);
665cdf0e10cSrcweir 
666cdf0e10cSrcweir     // since the rectangle itself was normalized, we also have to invert the
667cdf0e10cSrcweir     //  resize handles.
668cdf0e10cSrcweir     nHandle = NormalizeHit(nHandle);
669cdf0e10cSrcweir 
670cdf0e10cSrcweir     // handle case of resize handles outside the tracker
671cdf0e10cSrcweir     int size = GetHandleSize();
672cdf0e10cSrcweir     if (m_nStyle & resizeOutside)
673cdf0e10cSrcweir         InflateRect(&rectT,size-1, size-1);
674cdf0e10cSrcweir 
675cdf0e10cSrcweir     // calculate position of the resize handle
676cdf0e10cSrcweir     int nWidth = rectT.right - rectT.left;
677cdf0e10cSrcweir     int nHeight = rectT.bottom - rectT.top;
678cdf0e10cSrcweir     RECT rect;
679cdf0e10cSrcweir     const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];
680cdf0e10cSrcweir     rect.left = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetX);
681cdf0e10cSrcweir     rect.top = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetY);
682cdf0e10cSrcweir     rect.left += size * pHandleInfo->nHandleX;
683cdf0e10cSrcweir     rect.top += size * pHandleInfo->nHandleY;
684cdf0e10cSrcweir     rect.left += pHandleInfo->nCenterX * (nWidth - size) / 2;
685cdf0e10cSrcweir     rect.top += pHandleInfo->nCenterY * (nHeight - size) / 2;
686cdf0e10cSrcweir     rect.right = rect.left + size;
687cdf0e10cSrcweir     rect.bottom = rect.top + size;
688cdf0e10cSrcweir 
689cdf0e10cSrcweir     *pHandleRect = rect;
690cdf0e10cSrcweir }
691cdf0e10cSrcweir 
692cdf0e10cSrcweir 
GetHandleSize(LPRECT lpRect) const693cdf0e10cSrcweir int Tracker::GetHandleSize(LPRECT lpRect) const
694cdf0e10cSrcweir {
695cdf0e10cSrcweir     if (lpRect == NULL)
696cdf0e10cSrcweir         lpRect = (LPRECT)&m_rect;
697cdf0e10cSrcweir 
698cdf0e10cSrcweir     int size = m_nHandleSize;
699cdf0e10cSrcweir     if (!(m_nStyle & resizeOutside))
700cdf0e10cSrcweir     {
701cdf0e10cSrcweir         // make sure size is small enough for the size of the rect
702cdf0e10cSrcweir         int sizeMax = min(abs(lpRect->right - lpRect->left),
703cdf0e10cSrcweir                           abs(lpRect->bottom - lpRect->top));
704cdf0e10cSrcweir         if (size * 2 > sizeMax)
705cdf0e10cSrcweir             size = sizeMax / 2;
706cdf0e10cSrcweir     }
707cdf0e10cSrcweir     return size;
708cdf0e10cSrcweir }
709cdf0e10cSrcweir 
710cdf0e10cSrcweir 
GetHandleMask() const711cdf0e10cSrcweir UINT Tracker::GetHandleMask() const
712cdf0e10cSrcweir {
713cdf0e10cSrcweir     UINT mask = 0x0F;   // always have 4 corner handles
714cdf0e10cSrcweir     int size = m_nHandleSize*3;
715cdf0e10cSrcweir     if (abs(m_rect.right - m_rect.left) - size > 4)
716cdf0e10cSrcweir         mask |= 0x50;
717cdf0e10cSrcweir     if (abs(m_rect.bottom - m_rect.top) - size > 4)
718cdf0e10cSrcweir         mask |= 0xA0;
719cdf0e10cSrcweir     return mask;
720cdf0e10cSrcweir }
721cdf0e10cSrcweir 
722cdf0e10cSrcweir 
GetTrueRect(LPRECT lpTrueRect) const723cdf0e10cSrcweir void Tracker::GetTrueRect(LPRECT lpTrueRect) const
724cdf0e10cSrcweir {
725cdf0e10cSrcweir     RECT rect = m_rect;
726cdf0e10cSrcweir     NormalizeRect(&rect);
727cdf0e10cSrcweir     int nInflateBy = 0;
728cdf0e10cSrcweir     if ((m_nStyle & (resizeOutside|hatchedBorder)) != 0)
729cdf0e10cSrcweir         nInflateBy += GetHandleSize() - 1;
730cdf0e10cSrcweir     if ((m_nStyle & (solidLine|dottedLine)) != 0)
731cdf0e10cSrcweir         ++nInflateBy;
732cdf0e10cSrcweir     InflateRect(&rect,nInflateBy, nInflateBy);
733cdf0e10cSrcweir     *lpTrueRect = rect;
734cdf0e10cSrcweir }
735cdf0e10cSrcweir 
736cdf0e10cSrcweir 
NormalizeHit(int nHandle) const737cdf0e10cSrcweir int Tracker::NormalizeHit(int nHandle) const
738cdf0e10cSrcweir {
739cdf0e10cSrcweir     if (nHandle == hitMiddle || nHandle == hitNothing)
740cdf0e10cSrcweir         return nHandle;
741cdf0e10cSrcweir     const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];
742cdf0e10cSrcweir     if (m_rect.right - m_rect.left < 0)
743cdf0e10cSrcweir     {
744cdf0e10cSrcweir         nHandle = (TrackerHit)pHandleInfo->nInvertX;
745cdf0e10cSrcweir         pHandleInfo = &_afxHandleInfo[nHandle];
746cdf0e10cSrcweir     }
747cdf0e10cSrcweir     if (m_rect.bottom - m_rect.top < 0)
748cdf0e10cSrcweir         nHandle = (TrackerHit)pHandleInfo->nInvertY;
749cdf0e10cSrcweir     return nHandle;
750cdf0e10cSrcweir }
751cdf0e10cSrcweir 
752cdf0e10cSrcweir 
HitTestHandles(POINT point) const753cdf0e10cSrcweir int Tracker::HitTestHandles(POINT point) const
754cdf0e10cSrcweir {
755cdf0e10cSrcweir     RECT rect;
756cdf0e10cSrcweir     UINT mask = GetHandleMask();
757cdf0e10cSrcweir 
758cdf0e10cSrcweir     // see if hit anywhere inside the tracker
759cdf0e10cSrcweir     GetTrueRect(&rect);
760cdf0e10cSrcweir     if (!PtInRect(&rect,point))
761cdf0e10cSrcweir         return hitNothing;  // totally missed
762cdf0e10cSrcweir 
763cdf0e10cSrcweir     // see if we hit a handle
764cdf0e10cSrcweir     for (int i = 0; i < 8; ++i)
765cdf0e10cSrcweir     {
766cdf0e10cSrcweir         if (mask & (1<<i))
767cdf0e10cSrcweir         {
768cdf0e10cSrcweir             GetHandleRect((TrackerHit)i, &rect);
769cdf0e10cSrcweir             if (PtInRect(&rect,point))
770cdf0e10cSrcweir                 return (TrackerHit)i;
771cdf0e10cSrcweir         }
772cdf0e10cSrcweir     }
773cdf0e10cSrcweir 
774cdf0e10cSrcweir     // last of all, check for non-hit outside of object, between resize handles
775cdf0e10cSrcweir     if ((m_nStyle & hatchedBorder) == 0)
776cdf0e10cSrcweir     {
777cdf0e10cSrcweir         RECT rect = m_rect;
778cdf0e10cSrcweir         NormalizeRect(&rect);
779cdf0e10cSrcweir         if ((m_nStyle & dottedLine|solidLine) != 0)
780cdf0e10cSrcweir             InflateRect(&rect,+1, +1);
781cdf0e10cSrcweir         if (!PtInRect(&rect,point))
782cdf0e10cSrcweir             return hitNothing;  // must have been between resize handles
783cdf0e10cSrcweir     }
784cdf0e10cSrcweir     return hitMiddle;   // no handle hit, but hit object (or object border)
785cdf0e10cSrcweir }
786cdf0e10cSrcweir 
787cdf0e10cSrcweir 
788cdf0e10cSrcweir 
GetModifyPointers(int nHandle,int ** ppx,int ** ppy,int * px,int * py)789cdf0e10cSrcweir void Tracker::GetModifyPointers(
790cdf0e10cSrcweir     int nHandle, int** ppx, int** ppy, int* px, int* py)
791cdf0e10cSrcweir {
792cdf0e10cSrcweir     if (nHandle == hitMiddle)
793cdf0e10cSrcweir         nHandle = hitTopLeft;   // same as hitting top-left
794cdf0e10cSrcweir 
795cdf0e10cSrcweir     *ppx = NULL;
796cdf0e10cSrcweir     *ppy = NULL;
797cdf0e10cSrcweir 
798cdf0e10cSrcweir     // fill in the part of the rect that this handle modifies
799cdf0e10cSrcweir     //  (Note: handles that map to themselves along a given axis when that
800cdf0e10cSrcweir     //   axis is inverted don't modify the value on that axis)
801cdf0e10cSrcweir 
802cdf0e10cSrcweir     const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];
803cdf0e10cSrcweir     if (pHandleInfo->nInvertX != nHandle)
804cdf0e10cSrcweir     {
805cdf0e10cSrcweir         *ppx = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetX);
806cdf0e10cSrcweir         if (px != NULL)
807cdf0e10cSrcweir             *px = **ppx;
808cdf0e10cSrcweir     }
809cdf0e10cSrcweir     else
810cdf0e10cSrcweir     {
811cdf0e10cSrcweir         // middle handle on X axis
812cdf0e10cSrcweir         if (px != NULL)
813cdf0e10cSrcweir             *px = m_rect.left + (m_rect.left-m_rect.right) / 2;
814cdf0e10cSrcweir     }
815cdf0e10cSrcweir     if (pHandleInfo->nInvertY != nHandle)
816cdf0e10cSrcweir     {
817cdf0e10cSrcweir         *ppy = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetY);
818cdf0e10cSrcweir         if (py != NULL)
819cdf0e10cSrcweir             *py = **ppy;
820cdf0e10cSrcweir     }
821cdf0e10cSrcweir     else
822cdf0e10cSrcweir     {
823cdf0e10cSrcweir         // middle handle on Y axis
824cdf0e10cSrcweir         if (py != NULL)
825cdf0e10cSrcweir             *py = m_rect.top + (m_rect.top-m_rect.bottom) / 2;
826cdf0e10cSrcweir     }
827cdf0e10cSrcweir }
828cdf0e10cSrcweir 
829cdf0e10cSrcweir // Fix strange warnings about some
830cdf0e10cSrcweir // ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions.
831cdf0e10cSrcweir // warning C4505: 'xxx' : unreferenced local function has been removed
832cdf0e10cSrcweir #if defined(_MSC_VER)
833cdf0e10cSrcweir #pragma warning(disable: 4505)
834cdf0e10cSrcweir #endif
835