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