1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tracker.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #if defined(_MSC_VER) && (_MSC_VER > 1310)
31 #pragma warning(disable : 4917 4555)
36 #include "syswinwrapper.hxx"
39 HCURSOR _afxCursors
[10] = { 0, };
40 HBRUSH _afxHalftoneBrush
= 0;
43 // the struct below is used to determine the qualities of a particular handle
46 size_t nOffsetX
; // offset within RECT for X coordinate
47 size_t nOffsetY
; // offset within RECT for Y coordinate
48 int nCenterX
; // adjust X by Width()/2 * this number
49 int nCenterY
; // adjust Y by Height()/2 * this number
50 int nHandleX
; // adjust X by handle size * this number
51 int nHandleY
; // adjust Y by handle size * this number
52 int nInvertX
; // handle converts to this when X inverted
53 int nInvertY
; // handle converts to this when Y inverted
56 // this array describes all 8 handles (clock-wise)
57 const AFX_HANDLEINFO _afxHandleInfo
[] =
59 // corner handles (top-left, top-right, bottom-right, bottom-left
60 { offsetof(RECT
, left
), offsetof(RECT
, top
), 0, 0, 0, 0, 1, 3 },
61 { offsetof(RECT
, right
), offsetof(RECT
, top
), 0, 0, -1, 0, 0, 2 },
62 { offsetof(RECT
, right
), offsetof(RECT
, bottom
), 0, 0, -1, -1, 3, 1 },
63 { offsetof(RECT
, left
), offsetof(RECT
, bottom
), 0, 0, 0, -1, 2, 0 },
65 // side handles (top, right, bottom, left)
66 { offsetof(RECT
, left
), offsetof(RECT
, top
), 1, 0, 0, 0, 4, 6 },
67 { offsetof(RECT
, right
), offsetof(RECT
, top
), 0, 1, -1, 0, 7, 5 },
68 { offsetof(RECT
, left
), offsetof(RECT
, bottom
), 1, 0, 0, -1, 6, 4 },
69 { offsetof(RECT
, left
), offsetof(RECT
, top
), 0, 1, 0, 0, 5, 7 }
72 // the struct below gives us information on the layout of a RECT struct and
73 // the relationship between its members
76 size_t nOffsetAcross
; // offset of opposite point (ie. left->right)
77 int nSignAcross
; // sign relative to that point (ie. add/subtract)
80 // this array is indexed by the offset of the RECT member / sizeof(int)
81 const AFX_RECTINFO _afxRectInfo
[] =
83 { offsetof(RECT
, right
), +1 },
84 { offsetof(RECT
, bottom
), +1 },
85 { offsetof(RECT
, left
), -1 },
86 { offsetof(RECT
, top
), -1 },
90 HBRUSH
HalftoneBrush()
92 if (_afxHalftoneBrush
== NULL
)
95 for (int i
= 0; i
< 8; i
++)
96 grayPattern
[i
] = (WORD
)(0x5555 << (i
& 1));
97 HBITMAP grayBitmap
= CreateBitmap(8, 8, 1, 1, &grayPattern
);
98 if (grayBitmap
!= NULL
)
100 _afxHalftoneBrush
= CreatePatternBrush(grayBitmap
);
101 DeleteObject(grayBitmap
);
104 return _afxHalftoneBrush
;
110 HDC hDC
,LPRECT lpRect
,SIZE size
,
111 LPRECT lpRectLast
,SIZE sizeLast
,
112 HBRUSH hBrush
= NULL
,HBRUSH hBrushLast
= NULL
)
114 // first, determine the update region and select it
116 HRGN rgnOutside
,rgnInside
;
117 rgnOutside
= CreateRectRgnIndirect(lpRect
);
119 InflateRect(&rect
,-size
.cx
, -size
.cy
);
120 IntersectRect(&rect
,&rect
,lpRect
);
121 rgnInside
= CreateRectRgnIndirect(&rect
);
122 rgnNew
= CreateRectRgn(0, 0, 0, 0);
123 CombineRgn(rgnNew
,rgnOutside
,rgnInside
,RGN_XOR
);
125 HBRUSH hBrushOld
= NULL
;
127 hBrush
= HalftoneBrush();
128 if (hBrushLast
== NULL
)
132 HRGN
rgnUpdate(NULL
);
133 if (lpRectLast
!= NULL
)
135 // find difference between new region and old region
136 rgnLast
= CreateRectRgn(0, 0, 0, 0);
144 InflateRect(&rect
,-sizeLast
.cx
, -sizeLast
.cy
);
145 IntersectRect(&rect
,&rect
, lpRectLast
);
146 SetRectRgn(rgnInside
,rect
.left
,rect
.top
,rect
.right
,rect
.bottom
);
147 CombineRgn(rgnLast
,rgnOutside
,rgnInside
, RGN_XOR
);
149 // // only diff them if brushes are the same
150 if (hBrush
== hBrushLast
)
152 rgnUpdate
= CreateRectRgn(0, 0, 0, 0);
153 CombineRgn(rgnUpdate
,rgnLast
,rgnNew
, RGN_XOR
);
156 if (hBrush
!= hBrushLast
&& lpRectLast
!= NULL
)
158 // brushes are different -- erase old region first
159 SelectClipRgn(hDC
,rgnLast
);
160 GetClipBox(hDC
,&rect
);
161 hBrushOld
= (HBRUSH
)SelectObject(hDC
,(HGDIOBJ
)hBrushLast
);
162 PatBlt(hDC
,rect
.left
,rect
.top
,(rect
.right
-rect
.left
),(rect
.bottom
-rect
.top
),PATINVERT
);
164 SelectObject(hDC
,(HGDIOBJ
)hBrushOld
);
168 // draw into the update/new region
169 SelectClipRgn(hDC
,rgnUpdate
);
171 GetClipBox(hDC
,&rect
);
172 hBrushOld
= (HBRUSH
) SelectObject(hDC
,(HGDIOBJ
) hBrush
);
173 PatBlt(hDC
,rect
.left
, rect
.top
,(rect
.right
-rect
.left
),(rect
.bottom
-rect
.top
), PATINVERT
);
176 if (hBrushOld
!= NULL
)
177 SelectObject(hDC
,(HGDIOBJ
)hBrushOld
);
178 SelectClipRgn(hDC
,NULL
);
182 void winwrap::TransformRect(LPRECT rect
,HWND pWnd
,HWND pWndClipTo
)
185 pt
.x
= rect
->left
;pt
.y
= rect
->top
;
186 ClientToScreen(pWnd
,&pt
);
187 ScreenToClient(pWndClipTo
,&pt
);
188 rect
->left
= pt
.x
; rect
->top
= pt
.y
;
190 pt
.x
= rect
->right
;pt
.y
= rect
->bottom
;
191 ClientToScreen(pWnd
,&pt
);
192 ScreenToClient(pWndClipTo
,&pt
);
193 rect
->right
= pt
.x
; rect
->bottom
= pt
.y
;
197 void NormalizeRect(LPRECT rp
)
199 if(rp
->left
> rp
->right
) {
201 rp
->left
= rp
->right
;
205 if(rp
->top
> rp
->bottom
) {
207 rp
->top
= rp
->bottom
;
213 using namespace winwrap
;
221 Tracker::Tracker(LPCRECT lpSrcRect
, UINT nStyle
)
224 CopyRect(&m_rect
,lpSrcRect
);
228 HBRUSH _afxHatchBrush
= 0;
229 HPEN _afxBlackDottedPen
= 0;
230 int _afxHandleSize
= 0;
233 void Tracker::Construct()
235 static BOOL bInitialized
= false;
238 if (_afxHatchBrush
== NULL
)
240 // create the hatch pattern + bitmap
241 WORD hatchPattern
[8];
242 WORD wPattern
= 0x1111;
243 for (int i
= 0; i
< 4; i
++)
245 hatchPattern
[i
] = wPattern
;
246 hatchPattern
[i
+4] = wPattern
;
249 HBITMAP hatchBitmap
= CreateBitmap(8, 8, 1, 1,&hatchPattern
);
251 // create black hatched brush
252 _afxHatchBrush
= CreatePatternBrush(hatchBitmap
);
253 DeleteObject(hatchBitmap
);
256 if (_afxBlackDottedPen
== NULL
)
258 // create black dotted pen
259 _afxBlackDottedPen
= CreatePen(PS_DOT
, 0, RGB(0, 0, 0));
262 // get default handle size from Windows profile setting
263 static const TCHAR szWindows
[] = TEXT("windows");
264 static const TCHAR szInplaceBorderWidth
[] =
265 TEXT("oleinplaceborderwidth");
266 _afxHandleSize
= GetProfileInt(szWindows
, szInplaceBorderWidth
, 4);
269 _afxCursors
[0] = _afxCursors
[2] = LoadCursor(0,IDC_SIZENWSE
);
270 _afxCursors
[4] = _afxCursors
[6] = LoadCursor(0,IDC_SIZENS
);
271 _afxCursors
[1] = _afxCursors
[3] = LoadCursor(0,IDC_SIZENESW
);
272 _afxCursors
[5] = _afxCursors
[7] = LoadCursor(0,IDC_SIZEWE
);
273 _afxCursors
[8] = LoadCursor(0,IDC_SIZEALL
);
277 m_nHandleSize
= _afxHandleSize
;
278 m_sizeMin
.cy
= m_sizeMin
.cx
= m_nHandleSize
*2;
280 SetRectEmpty(&m_rectLast
);
281 m_sizeLast
.cx
= m_sizeLast
.cy
= 0;
283 m_bFinalErase
= FALSE
;
291 int Tracker::HitTest(POINT point
) const
293 TrackerHit hitResult
= hitNothing
;
296 GetTrueRect(&rectTrue
);
297 NormalizeRect(&rectTrue
);
298 if (PtInRect(&rectTrue
,point
))
300 if ((m_nStyle
& (resizeInside
|resizeOutside
)) != 0)
301 hitResult
= (TrackerHit
)HitTestHandles(point
);
303 hitResult
= hitMiddle
;
309 BOOL
Tracker::SetCursor(HWND pWnd
, UINT nHitTest
) const
311 // trackers should only be in client area
312 if (nHitTest
!= HTCLIENT
)
315 // convert cursor position to client co-ordinates
317 GetCursorPos(&point
);
318 ScreenToClient(pWnd
,&point
);
320 // do hittest and normalize hit
321 int nHandle
= HitTestHandles(point
);
325 // need to normalize the hittest such that we get proper cursors
326 nHandle
= NormalizeHit(nHandle
);
328 // handle special case of hitting area between handles
329 // (logically the same -- handled as a move -- but different cursor)
330 if (nHandle
== hitMiddle
&& !PtInRect(&m_rect
,point
))
332 // only for trackers with hatchedBorder (ie. in-place resizing)
333 if (m_nStyle
& hatchedBorder
)
334 nHandle
= (TrackerHit
)9;
337 ::SetCursor(_afxCursors
[nHandle
]);
343 BOOL
Tracker::Track(HWND hWnd
,POINT point
,BOOL bAllowInvert
,
346 // perform hit testing on the handles
347 int nHandle
= HitTestHandles(point
);
350 // didn't hit a handle, so just return FALSE
354 // otherwise, call helper function to do the tracking
355 m_bAllowInvert
= bAllowInvert
;
356 SetCursor(hWnd
,nHandle
);
357 return TrackHandle(nHandle
, hWnd
, point
, hWndClipTo
);
361 BOOL
Tracker::TrackHandle(int nHandle
,HWND hWnd
,POINT point
,HWND hWndClipTo
)
363 // don't handle if capture already set
364 if (GetCapture() != NULL
)
367 // save original width & height in pixels
368 int nWidth
= m_rect
.right
- m_rect
.left
;
369 int nHeight
= m_rect
.bottom
- m_rect
.top
;
371 // set capture to the window which received this message
374 if (hWndClipTo
!= NULL
)
375 UpdateWindow(hWndClipTo
);
376 RECT rectSave
= m_rect
;
378 // find out what x/y coords we are supposed to modify
381 GetModifyPointers(nHandle
, &px
, &py
, &xDiff
, &yDiff
);
382 xDiff
= point
.x
- xDiff
;
383 yDiff
= point
.y
- yDiff
;
385 // get DC for drawing
387 if (hWndClipTo
!= NULL
)
389 // clip to arbitrary window by using adjusted Window DC
390 hDrawDC
= GetDCEx(hWndClipTo
,NULL
, DCX_CACHE
);
394 // otherwise, just use normal DC
395 hDrawDC
= GetDC(hWnd
);
401 // get messages until capture lost or cancelled/accepted
405 GetMessage(&msg
, NULL
, 0, 0);
407 if (GetCapture() != hWnd
)
412 // handle movement/accept messages
416 // handle resize cases (and part of move)
418 *px
= (int)(short)LOWORD(msg
.lParam
) - xDiff
;
420 *py
= (int)(short)HIWORD(msg
.lParam
) - yDiff
;
423 if (nHandle
== hitMiddle
)
425 m_rect
.right
= m_rect
.left
+ nWidth
;
426 m_rect
.bottom
= m_rect
.top
+ nHeight
;
428 // allow caller to adjust the rectangle if necessary
429 AdjustRect(nHandle
,&m_rect
);
431 // only redraw and callback if the rect actually changed!
432 m_bFinalErase
= (msg
.message
== WM_LBUTTONUP
);
433 if (!EqualRect(&rectOld
,&m_rect
) || m_bFinalErase
)
438 DrawTrackerRect(&rectOld
,hWndClipTo
,hDrawDC
,hWnd
);
440 OnChangedRect(rectOld
);
441 if (msg
.message
!= WM_LBUTTONUP
)
447 if (!EqualRect(&rectOld
,&m_rect
))
450 DrawTrackerRect(&m_rect
,hWndClipTo
,hDrawDC
,hWnd
);
454 // handle cancel messages
456 if (msg
.wParam
!= VK_ESCAPE
)
461 m_bErase
= m_bFinalErase
= TRUE
;
462 DrawTrackerRect(&m_rect
, hWndClipTo
, hDrawDC
, hWnd
);
467 // just dispatch rest of the messages
469 DispatchMessage(&msg
);
475 if (hWndClipTo
!= NULL
)
476 ReleaseDC(hWndClipTo
,hDrawDC
);
478 ReleaseDC(hWnd
,hDrawDC
);
481 // restore rect in case bMoved is still FALSE
484 m_bFinalErase
= FALSE
;
487 // return TRUE only if rect has changed
488 return !EqualRect(&rectSave
,&m_rect
);
492 void Tracker::OnChangedRect(const RECT
& /*rectOld*/)
497 void Tracker::AdjustRect(int nHandle
, LPRECT
)
499 if(nHandle
== hitMiddle
)
502 // convert the handle into locations within m_rect
504 GetModifyPointers(nHandle
, &px
, &py
, NULL
, NULL
);
506 // enforce minimum width
507 int nNewWidth
= m_rect
.right
- m_rect
.left
;
508 int nAbsWidth
= m_bAllowInvert
? abs(nNewWidth
) : nNewWidth
;
509 if (px
!= NULL
&& nAbsWidth
< m_sizeMin
.cx
)
511 nNewWidth
= nAbsWidth
!= 0 ? nNewWidth
/ nAbsWidth
: 1;
512 const AFX_RECTINFO
* pRectInfo
=
513 &_afxRectInfo
[(int*)px
- (int*)&m_rect
];
514 *px
= *(int*)((BYTE
*)&m_rect
+ pRectInfo
->nOffsetAcross
) +
515 nNewWidth
* m_sizeMin
.cx
* -pRectInfo
->nSignAcross
;
518 // enforce minimum height
519 int nNewHeight
= m_rect
.bottom
- m_rect
.top
;
520 int nAbsHeight
= m_bAllowInvert
? abs(nNewHeight
) : nNewHeight
;
521 if (py
!= NULL
&& nAbsHeight
< m_sizeMin
.cy
)
523 nNewHeight
= nAbsHeight
!= 0 ? nNewHeight
/ nAbsHeight
: 1;
524 const AFX_RECTINFO
* pRectInfo
=
525 &_afxRectInfo
[(int*)py
- (int*)&m_rect
];
526 *py
= *(int*)((BYTE
*)&m_rect
+ pRectInfo
->nOffsetAcross
) +
527 nNewHeight
* m_sizeMin
.cy
* -pRectInfo
->nSignAcross
;
532 void Tracker::DrawTrackerRect(
533 LPRECT lpRect
,HWND pWndClipTo
,HDC pDC
,HWND pWnd
)
535 // first, normalize the rectangle for drawing
537 NormalizeRect(&rect
);
539 // convert to client coordinates
540 if (pWndClipTo
!= NULL
)
541 TransformRect(&rect
,pWnd
,pWndClipTo
);
544 size
.cx
= 0; size
.cy
= 0;
547 // otherwise, size depends on the style
548 if (m_nStyle
& hatchedBorder
)
550 size
.cx
= size
.cy
= max(1,GetHandleSize(&rect
)-1);
551 InflateRect(&rect
,size
.cx
,size
.cy
);
555 size
.cx
= 1; // CX_BORDER;
556 size
.cy
= 1; // CY_BORDER;
561 if (m_bFinalErase
|| !m_bErase
)
562 DrawDragRect(pDC
,&rect
,size
,&m_rectLast
,m_sizeLast
);
564 // remember last rectangles
570 void Tracker::Draw(HDC hDC
) const
572 // set initial DC state
573 SetMapMode(hDC
,MM_TEXT
);
574 SetViewportOrgEx(hDC
,0, 0,NULL
);
575 SetWindowOrgEx(hDC
,0, 0,NULL
);
577 // get normalized rectangle
579 NormalizeRect(&rect
);
582 HBRUSH pOldBrush
= NULL
;
587 if ((m_nStyle
& (dottedLine
|solidLine
)) != 0)
589 if (m_nStyle
& dottedLine
)
590 pOldPen
= (HPEN
)SelectObject(hDC
,_afxBlackDottedPen
);
592 pOldPen
= (HPEN
)SelectObject(hDC
,(HGDIOBJ
)BLACK_PEN
);
593 pOldBrush
= (HBRUSH
)SelectObject(hDC
,(HGDIOBJ
)NULL_BRUSH
);
594 nOldROP
= SetROP2(hDC
,R2_COPYPEN
);
595 InflateRect(&rect
,+1, +1); // borders are one pixel outside
596 Rectangle(hDC
,rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
597 SetROP2(hDC
,nOldROP
);
600 // if hatchBrush is going to be used, need to unrealize it
601 if ((m_nStyle
& (hatchInside
|hatchedBorder
)) != 0)
602 UnrealizeObject((HGDIOBJ
)_afxHatchBrush
);
605 if ((m_nStyle
& hatchInside
) != 0)
607 pTemp
= SelectObject(hDC
,(HGDIOBJ
)NULL_PEN
);
609 pOldPen
= (HPEN
)pTemp
;
610 pTemp
= SelectObject(hDC
,(HGDIOBJ
)_afxHatchBrush
);
611 if (pOldBrush
== NULL
)
612 pOldBrush
= (HBRUSH
)pTemp
;
613 SetBkMode(hDC
,TRANSPARENT
);
614 nOldROP
= SetROP2(hDC
,R2_MASKNOTPEN
);
615 Rectangle(hDC
,rect
.left
+1, rect
.top
+1, rect
.right
, rect
.bottom
);
616 SetROP2(hDC
,nOldROP
);
619 // draw hatched border
620 if ((m_nStyle
& hatchedBorder
) != 0)
622 pTemp
= SelectObject(hDC
,(HGDIOBJ
)_afxHatchBrush
);
623 if (pOldBrush
== NULL
)
624 pOldBrush
= (HBRUSH
)pTemp
;
625 SetBkMode(hDC
,OPAQUE
);
627 GetTrueRect(&rectTrue
);
628 PatBlt(hDC
,rectTrue
.left
, rectTrue
.top
, rectTrue
.right
-rectTrue
.left
,
629 rect
.top
-rectTrue
.top
, 0x000F0001 /* Pn */);
630 PatBlt(hDC
,rectTrue
.left
, rect
.bottom
,
631 rectTrue
.right
-rectTrue
.left
,
632 rectTrue
.bottom
-rect
.bottom
, 0x000F0001 /* Pn */);
633 PatBlt(hDC
,rectTrue
.left
, rect
.top
, rect
.left
-rectTrue
.left
,
634 rect
.bottom
-rect
.top
, 0x000F0001 /* Pn */);
635 PatBlt(hDC
,rect
.right
, rect
.top
, rectTrue
.right
-rect
.right
,
636 rect
.bottom
-rect
.top
, 0x000F0001 /* Pn */);
639 // draw resize handles
640 if ((m_nStyle
& (resizeInside
|resizeOutside
)) != 0)
642 UINT mask
= GetHandleMask();
643 HBRUSH hbrush
= CreateSolidBrush(RGB(0,0,0));
644 for (int i
= 0; i
< 8; ++i
)
648 GetHandleRect((TrackerHit
)i
, &rect
);
649 // FillSolidRect(hDC,rect, RGB(0, 0, 0));
650 FillRect(hDC
,&rect
,hbrush
);
653 DeleteObject(hbrush
);
658 SelectObject(hDC
,pOldPen
);
659 if (pOldBrush
!= NULL
)
660 SelectObject(hDC
,pOldBrush
);
665 void Tracker::GetHandleRect(int nHandle
,RECT
* pHandleRect
) const
667 // get normalized rectangle of the tracker
669 NormalizeRect(&rectT
);
670 if ((m_nStyle
& (solidLine
|dottedLine
)) != 0)
671 InflateRect(&rectT
,+1, +1);
673 // since the rectangle itself was normalized, we also have to invert the
675 nHandle
= NormalizeHit(nHandle
);
677 // handle case of resize handles outside the tracker
678 int size
= GetHandleSize();
679 if (m_nStyle
& resizeOutside
)
680 InflateRect(&rectT
,size
-1, size
-1);
682 // calculate position of the resize handle
683 int nWidth
= rectT
.right
- rectT
.left
;
684 int nHeight
= rectT
.bottom
- rectT
.top
;
686 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
687 rect
.left
= *(int*)((BYTE
*)&rectT
+ pHandleInfo
->nOffsetX
);
688 rect
.top
= *(int*)((BYTE
*)&rectT
+ pHandleInfo
->nOffsetY
);
689 rect
.left
+= size
* pHandleInfo
->nHandleX
;
690 rect
.top
+= size
* pHandleInfo
->nHandleY
;
691 rect
.left
+= pHandleInfo
->nCenterX
* (nWidth
- size
) / 2;
692 rect
.top
+= pHandleInfo
->nCenterY
* (nHeight
- size
) / 2;
693 rect
.right
= rect
.left
+ size
;
694 rect
.bottom
= rect
.top
+ size
;
700 int Tracker::GetHandleSize(LPRECT lpRect
) const
703 lpRect
= (LPRECT
)&m_rect
;
705 int size
= m_nHandleSize
;
706 if (!(m_nStyle
& resizeOutside
))
708 // make sure size is small enough for the size of the rect
709 int sizeMax
= min(abs(lpRect
->right
- lpRect
->left
),
710 abs(lpRect
->bottom
- lpRect
->top
));
711 if (size
* 2 > sizeMax
)
718 UINT
Tracker::GetHandleMask() const
720 UINT mask
= 0x0F; // always have 4 corner handles
721 int size
= m_nHandleSize
*3;
722 if (abs(m_rect
.right
- m_rect
.left
) - size
> 4)
724 if (abs(m_rect
.bottom
- m_rect
.top
) - size
> 4)
730 void Tracker::GetTrueRect(LPRECT lpTrueRect
) const
733 NormalizeRect(&rect
);
735 if ((m_nStyle
& (resizeOutside
|hatchedBorder
)) != 0)
736 nInflateBy
+= GetHandleSize() - 1;
737 if ((m_nStyle
& (solidLine
|dottedLine
)) != 0)
739 InflateRect(&rect
,nInflateBy
, nInflateBy
);
744 int Tracker::NormalizeHit(int nHandle
) const
746 if (nHandle
== hitMiddle
|| nHandle
== hitNothing
)
748 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
749 if (m_rect
.right
- m_rect
.left
< 0)
751 nHandle
= (TrackerHit
)pHandleInfo
->nInvertX
;
752 pHandleInfo
= &_afxHandleInfo
[nHandle
];
754 if (m_rect
.bottom
- m_rect
.top
< 0)
755 nHandle
= (TrackerHit
)pHandleInfo
->nInvertY
;
760 int Tracker::HitTestHandles(POINT point
) const
763 UINT mask
= GetHandleMask();
765 // see if hit anywhere inside the tracker
767 if (!PtInRect(&rect
,point
))
768 return hitNothing
; // totally missed
770 // see if we hit a handle
771 for (int i
= 0; i
< 8; ++i
)
775 GetHandleRect((TrackerHit
)i
, &rect
);
776 if (PtInRect(&rect
,point
))
777 return (TrackerHit
)i
;
781 // last of all, check for non-hit outside of object, between resize handles
782 if ((m_nStyle
& hatchedBorder
) == 0)
785 NormalizeRect(&rect
);
786 if ((m_nStyle
& dottedLine
|solidLine
) != 0)
787 InflateRect(&rect
,+1, +1);
788 if (!PtInRect(&rect
,point
))
789 return hitNothing
; // must have been between resize handles
791 return hitMiddle
; // no handle hit, but hit object (or object border)
796 void Tracker::GetModifyPointers(
797 int nHandle
, int** ppx
, int** ppy
, int* px
, int* py
)
799 if (nHandle
== hitMiddle
)
800 nHandle
= hitTopLeft
; // same as hitting top-left
805 // fill in the part of the rect that this handle modifies
806 // (Note: handles that map to themselves along a given axis when that
807 // axis is inverted don't modify the value on that axis)
809 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
810 if (pHandleInfo
->nInvertX
!= nHandle
)
812 *ppx
= (int*)((BYTE
*)&m_rect
+ pHandleInfo
->nOffsetX
);
818 // middle handle on X axis
820 *px
= m_rect
.left
+ (m_rect
.left
-m_rect
.right
) / 2;
822 if (pHandleInfo
->nInvertY
!= nHandle
)
824 *ppy
= (int*)((BYTE
*)&m_rect
+ pHandleInfo
->nOffsetY
);
830 // middle handle on Y axis
832 *py
= m_rect
.top
+ (m_rect
.top
-m_rect
.bottom
) / 2;
836 // Fix strange warnings about some
837 // ATL::CAxHostWindow::QueryInterface|AddRef|Releae functions.
838 // warning C4505: 'xxx' : unreferenced local function has been removed
839 #if defined(_MSC_VER)
840 #pragma warning(disable: 4505)