1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #pragma warning(disable : 4917 4555)
25 #include "syswinwrapper.hxx"
28 HCURSOR _afxCursors
[10] = { 0, };
29 HBRUSH _afxHalftoneBrush
= 0;
32 // the struct below is used to determine the qualities of a particular handle
35 size_t nOffsetX
; // offset within RECT for X coordinate
36 size_t nOffsetY
; // offset within RECT for Y coordinate
37 int nCenterX
; // adjust X by Width()/2 * this number
38 int nCenterY
; // adjust Y by Height()/2 * this number
39 int nHandleX
; // adjust X by handle size * this number
40 int nHandleY
; // adjust Y by handle size * this number
41 int nInvertX
; // handle converts to this when X inverted
42 int nInvertY
; // handle converts to this when Y inverted
45 // this array describes all 8 handles (clock-wise)
46 const AFX_HANDLEINFO _afxHandleInfo
[] =
48 // corner handles (top-left, top-right, bottom-right, bottom-left
49 { offsetof(RECT
, left
), offsetof(RECT
, top
), 0, 0, 0, 0, 1, 3 },
50 { offsetof(RECT
, right
), offsetof(RECT
, top
), 0, 0, -1, 0, 0, 2 },
51 { offsetof(RECT
, right
), offsetof(RECT
, bottom
), 0, 0, -1, -1, 3, 1 },
52 { offsetof(RECT
, left
), offsetof(RECT
, bottom
), 0, 0, 0, -1, 2, 0 },
54 // side handles (top, right, bottom, left)
55 { offsetof(RECT
, left
), offsetof(RECT
, top
), 1, 0, 0, 0, 4, 6 },
56 { offsetof(RECT
, right
), offsetof(RECT
, top
), 0, 1, -1, 0, 7, 5 },
57 { offsetof(RECT
, left
), offsetof(RECT
, bottom
), 1, 0, 0, -1, 6, 4 },
58 { offsetof(RECT
, left
), offsetof(RECT
, top
), 0, 1, 0, 0, 5, 7 }
61 // the struct below gives us information on the layout of a RECT struct and
62 // the relationship between its members
65 size_t nOffsetAcross
; // offset of opposite point (ie. left->right)
66 int nSignAcross
; // sign relative to that point (ie. add/subtract)
69 // this array is indexed by the offset of the RECT member / sizeof(int)
70 const AFX_RECTINFO _afxRectInfo
[] =
72 { offsetof(RECT
, right
), +1 },
73 { offsetof(RECT
, bottom
), +1 },
74 { offsetof(RECT
, left
), -1 },
75 { offsetof(RECT
, top
), -1 },
79 HBRUSH
HalftoneBrush()
81 if (_afxHalftoneBrush
== NULL
)
84 for (int i
= 0; i
< 8; i
++)
85 grayPattern
[i
] = (WORD
)(0x5555 << (i
& 1));
86 HBITMAP grayBitmap
= CreateBitmap(8, 8, 1, 1, &grayPattern
);
87 if (grayBitmap
!= NULL
)
89 _afxHalftoneBrush
= CreatePatternBrush(grayBitmap
);
90 DeleteObject(grayBitmap
);
93 return _afxHalftoneBrush
;
99 HDC hDC
,LPRECT lpRect
,SIZE size
,
100 LPRECT lpRectLast
,SIZE sizeLast
,
101 HBRUSH hBrush
= NULL
,HBRUSH hBrushLast
= NULL
)
103 // first, determine the update region and select it
105 HRGN rgnOutside
,rgnInside
;
106 rgnOutside
= CreateRectRgnIndirect(lpRect
);
108 InflateRect(&rect
,-size
.cx
, -size
.cy
);
109 IntersectRect(&rect
,&rect
,lpRect
);
110 rgnInside
= CreateRectRgnIndirect(&rect
);
111 rgnNew
= CreateRectRgn(0, 0, 0, 0);
112 CombineRgn(rgnNew
,rgnOutside
,rgnInside
,RGN_XOR
);
114 HBRUSH hBrushOld
= NULL
;
116 hBrush
= HalftoneBrush();
117 if (hBrushLast
== NULL
)
121 HRGN
rgnUpdate(NULL
);
122 if (lpRectLast
!= NULL
)
124 // find difference between new region and old region
125 rgnLast
= CreateRectRgn(0, 0, 0, 0);
133 InflateRect(&rect
,-sizeLast
.cx
, -sizeLast
.cy
);
134 IntersectRect(&rect
,&rect
, lpRectLast
);
135 SetRectRgn(rgnInside
,rect
.left
,rect
.top
,rect
.right
,rect
.bottom
);
136 CombineRgn(rgnLast
,rgnOutside
,rgnInside
, RGN_XOR
);
138 // // only diff them if brushes are the same
139 if (hBrush
== hBrushLast
)
141 rgnUpdate
= CreateRectRgn(0, 0, 0, 0);
142 CombineRgn(rgnUpdate
,rgnLast
,rgnNew
, RGN_XOR
);
145 if (hBrush
!= hBrushLast
&& lpRectLast
!= NULL
)
147 // brushes are different -- erase old region first
148 SelectClipRgn(hDC
,rgnLast
);
149 GetClipBox(hDC
,&rect
);
150 hBrushOld
= (HBRUSH
)SelectObject(hDC
,(HGDIOBJ
)hBrushLast
);
151 PatBlt(hDC
,rect
.left
,rect
.top
,(rect
.right
-rect
.left
),(rect
.bottom
-rect
.top
),PATINVERT
);
153 SelectObject(hDC
,(HGDIOBJ
)hBrushOld
);
157 // draw into the update/new region
158 SelectClipRgn(hDC
,rgnUpdate
);
160 GetClipBox(hDC
,&rect
);
161 hBrushOld
= (HBRUSH
) SelectObject(hDC
,(HGDIOBJ
) hBrush
);
162 PatBlt(hDC
,rect
.left
, rect
.top
,(rect
.right
-rect
.left
),(rect
.bottom
-rect
.top
), PATINVERT
);
165 if (hBrushOld
!= NULL
)
166 SelectObject(hDC
,(HGDIOBJ
)hBrushOld
);
167 SelectClipRgn(hDC
,NULL
);
171 void winwrap::TransformRect(LPRECT rect
,HWND pWnd
,HWND pWndClipTo
)
174 pt
.x
= rect
->left
;pt
.y
= rect
->top
;
175 ClientToScreen(pWnd
,&pt
);
176 ScreenToClient(pWndClipTo
,&pt
);
177 rect
->left
= pt
.x
; rect
->top
= pt
.y
;
179 pt
.x
= rect
->right
;pt
.y
= rect
->bottom
;
180 ClientToScreen(pWnd
,&pt
);
181 ScreenToClient(pWndClipTo
,&pt
);
182 rect
->right
= pt
.x
; rect
->bottom
= pt
.y
;
186 void NormalizeRect(LPRECT rp
)
188 if(rp
->left
> rp
->right
) {
190 rp
->left
= rp
->right
;
194 if(rp
->top
> rp
->bottom
) {
196 rp
->top
= rp
->bottom
;
202 using namespace winwrap
;
210 Tracker::Tracker(LPCRECT lpSrcRect
, UINT nStyle
)
213 CopyRect(&m_rect
,lpSrcRect
);
217 HBRUSH _afxHatchBrush
= 0;
218 HPEN _afxBlackDottedPen
= 0;
219 int _afxHandleSize
= 0;
222 void Tracker::Construct()
224 static BOOL bInitialized
= false;
227 if (_afxHatchBrush
== NULL
)
229 // create the hatch pattern + bitmap
230 WORD hatchPattern
[8];
231 WORD wPattern
= 0x1111;
232 for (int i
= 0; i
< 4; i
++)
234 hatchPattern
[i
] = wPattern
;
235 hatchPattern
[i
+4] = wPattern
;
238 HBITMAP hatchBitmap
= CreateBitmap(8, 8, 1, 1,&hatchPattern
);
240 // create black hatched brush
241 _afxHatchBrush
= CreatePatternBrush(hatchBitmap
);
242 DeleteObject(hatchBitmap
);
245 if (_afxBlackDottedPen
== NULL
)
247 // create black dotted pen
248 _afxBlackDottedPen
= CreatePen(PS_DOT
, 0, RGB(0, 0, 0));
251 // get default handle size from Windows profile setting
252 static const TCHAR szWindows
[] = TEXT("windows");
253 static const TCHAR szInplaceBorderWidth
[] =
254 TEXT("oleinplaceborderwidth");
255 _afxHandleSize
= GetProfileInt(szWindows
, szInplaceBorderWidth
, 4);
258 _afxCursors
[0] = _afxCursors
[2] = LoadCursor(0,IDC_SIZENWSE
);
259 _afxCursors
[4] = _afxCursors
[6] = LoadCursor(0,IDC_SIZENS
);
260 _afxCursors
[1] = _afxCursors
[3] = LoadCursor(0,IDC_SIZENESW
);
261 _afxCursors
[5] = _afxCursors
[7] = LoadCursor(0,IDC_SIZEWE
);
262 _afxCursors
[8] = LoadCursor(0,IDC_SIZEALL
);
266 m_nHandleSize
= _afxHandleSize
;
267 m_sizeMin
.cy
= m_sizeMin
.cx
= m_nHandleSize
*2;
269 SetRectEmpty(&m_rectLast
);
270 m_sizeLast
.cx
= m_sizeLast
.cy
= 0;
272 m_bFinalErase
= FALSE
;
280 int Tracker::HitTest(POINT point
) const
282 TrackerHit hitResult
= hitNothing
;
285 GetTrueRect(&rectTrue
);
286 NormalizeRect(&rectTrue
);
287 if (PtInRect(&rectTrue
,point
))
289 if ((m_nStyle
& (resizeInside
|resizeOutside
)) != 0)
290 hitResult
= (TrackerHit
)HitTestHandles(point
);
292 hitResult
= hitMiddle
;
298 BOOL
Tracker::SetCursor(HWND pWnd
, UINT nHitTest
) const
300 // trackers should only be in client area
301 if (nHitTest
!= HTCLIENT
)
304 // convert cursor position to client co-ordinates
306 GetCursorPos(&point
);
307 ScreenToClient(pWnd
,&point
);
309 // do hittest and normalize hit
310 int nHandle
= HitTestHandles(point
);
314 // need to normalize the hittest such that we get proper cursors
315 nHandle
= NormalizeHit(nHandle
);
317 // handle special case of hitting area between handles
318 // (logically the same -- handled as a move -- but different cursor)
319 if (nHandle
== hitMiddle
&& !PtInRect(&m_rect
,point
))
321 // only for trackers with hatchedBorder (ie. in-place resizing)
322 if (m_nStyle
& hatchedBorder
)
323 nHandle
= (TrackerHit
)9;
326 ::SetCursor(_afxCursors
[nHandle
]);
332 BOOL
Tracker::Track(HWND hWnd
,POINT point
,BOOL bAllowInvert
,
335 // perform hit testing on the handles
336 int nHandle
= HitTestHandles(point
);
339 // didn't hit a handle, so just return FALSE
343 // otherwise, call helper function to do the tracking
344 m_bAllowInvert
= bAllowInvert
;
345 SetCursor(hWnd
,nHandle
);
346 return TrackHandle(nHandle
, hWnd
, point
, hWndClipTo
);
350 BOOL
Tracker::TrackHandle(int nHandle
,HWND hWnd
,POINT point
,HWND hWndClipTo
)
352 // don't handle if capture already set
353 if (GetCapture() != NULL
)
356 // save original width & height in pixels
357 int nWidth
= m_rect
.right
- m_rect
.left
;
358 int nHeight
= m_rect
.bottom
- m_rect
.top
;
360 // set capture to the window which received this message
363 if (hWndClipTo
!= NULL
)
364 UpdateWindow(hWndClipTo
);
365 RECT rectSave
= m_rect
;
367 // find out what x/y coords we are supposed to modify
370 GetModifyPointers(nHandle
, &px
, &py
, &xDiff
, &yDiff
);
371 xDiff
= point
.x
- xDiff
;
372 yDiff
= point
.y
- yDiff
;
374 // get DC for drawing
376 if (hWndClipTo
!= NULL
)
378 // clip to arbitrary window by using adjusted Window DC
379 hDrawDC
= GetDCEx(hWndClipTo
,NULL
, DCX_CACHE
);
383 // otherwise, just use normal DC
384 hDrawDC
= GetDC(hWnd
);
390 // get messages until capture lost or cancelled/accepted
394 GetMessage(&msg
, NULL
, 0, 0);
396 if (GetCapture() != hWnd
)
401 // handle movement/accept messages
405 // handle resize cases (and part of move)
407 *px
= (int)(short)LOWORD(msg
.lParam
) - xDiff
;
409 *py
= (int)(short)HIWORD(msg
.lParam
) - yDiff
;
412 if (nHandle
== hitMiddle
)
414 m_rect
.right
= m_rect
.left
+ nWidth
;
415 m_rect
.bottom
= m_rect
.top
+ nHeight
;
417 // allow caller to adjust the rectangle if necessary
418 AdjustRect(nHandle
,&m_rect
);
420 // only redraw and callback if the rect actually changed!
421 m_bFinalErase
= (msg
.message
== WM_LBUTTONUP
);
422 if (!EqualRect(&rectOld
,&m_rect
) || m_bFinalErase
)
427 DrawTrackerRect(&rectOld
,hWndClipTo
,hDrawDC
,hWnd
);
429 OnChangedRect(rectOld
);
430 if (msg
.message
!= WM_LBUTTONUP
)
436 if (!EqualRect(&rectOld
,&m_rect
))
439 DrawTrackerRect(&m_rect
,hWndClipTo
,hDrawDC
,hWnd
);
443 // handle cancel messages
445 if (msg
.wParam
!= VK_ESCAPE
)
450 m_bErase
= m_bFinalErase
= TRUE
;
451 DrawTrackerRect(&m_rect
, hWndClipTo
, hDrawDC
, hWnd
);
456 // just dispatch rest of the messages
458 DispatchMessage(&msg
);
464 if (hWndClipTo
!= NULL
)
465 ReleaseDC(hWndClipTo
,hDrawDC
);
467 ReleaseDC(hWnd
,hDrawDC
);
470 // restore rect in case bMoved is still FALSE
473 m_bFinalErase
= FALSE
;
476 // return TRUE only if rect has changed
477 return !EqualRect(&rectSave
,&m_rect
);
481 void Tracker::OnChangedRect(const RECT
& /*rectOld*/)
486 void Tracker::AdjustRect(int nHandle
, LPRECT
)
488 if(nHandle
== hitMiddle
)
491 // convert the handle into locations within m_rect
493 GetModifyPointers(nHandle
, &px
, &py
, NULL
, NULL
);
495 // enforce minimum width
496 int nNewWidth
= m_rect
.right
- m_rect
.left
;
497 int nAbsWidth
= m_bAllowInvert
? abs(nNewWidth
) : nNewWidth
;
498 if (px
!= NULL
&& nAbsWidth
< m_sizeMin
.cx
)
500 nNewWidth
= nAbsWidth
!= 0 ? nNewWidth
/ nAbsWidth
: 1;
501 const AFX_RECTINFO
* pRectInfo
=
502 &_afxRectInfo
[(int*)px
- (int*)&m_rect
];
503 *px
= *(int*)((BYTE
*)&m_rect
+ pRectInfo
->nOffsetAcross
) +
504 nNewWidth
* m_sizeMin
.cx
* -pRectInfo
->nSignAcross
;
507 // enforce minimum height
508 int nNewHeight
= m_rect
.bottom
- m_rect
.top
;
509 int nAbsHeight
= m_bAllowInvert
? abs(nNewHeight
) : nNewHeight
;
510 if (py
!= NULL
&& nAbsHeight
< m_sizeMin
.cy
)
512 nNewHeight
= nAbsHeight
!= 0 ? nNewHeight
/ nAbsHeight
: 1;
513 const AFX_RECTINFO
* pRectInfo
=
514 &_afxRectInfo
[(int*)py
- (int*)&m_rect
];
515 *py
= *(int*)((BYTE
*)&m_rect
+ pRectInfo
->nOffsetAcross
) +
516 nNewHeight
* m_sizeMin
.cy
* -pRectInfo
->nSignAcross
;
521 void Tracker::DrawTrackerRect(
522 LPRECT lpRect
,HWND pWndClipTo
,HDC pDC
,HWND pWnd
)
524 // first, normalize the rectangle for drawing
526 NormalizeRect(&rect
);
528 // convert to client coordinates
529 if (pWndClipTo
!= NULL
)
530 TransformRect(&rect
,pWnd
,pWndClipTo
);
533 size
.cx
= 0; size
.cy
= 0;
536 // otherwise, size depends on the style
537 if (m_nStyle
& hatchedBorder
)
539 size
.cx
= size
.cy
= max(1,GetHandleSize(&rect
)-1);
540 InflateRect(&rect
,size
.cx
,size
.cy
);
544 size
.cx
= 1; // CX_BORDER;
545 size
.cy
= 1; // CY_BORDER;
550 if (m_bFinalErase
|| !m_bErase
)
551 DrawDragRect(pDC
,&rect
,size
,&m_rectLast
,m_sizeLast
);
553 // remember last rectangles
559 void Tracker::Draw(HDC hDC
) const
561 // set initial DC state
562 SetMapMode(hDC
,MM_TEXT
);
563 SetViewportOrgEx(hDC
,0, 0,NULL
);
564 SetWindowOrgEx(hDC
,0, 0,NULL
);
566 // get normalized rectangle
568 NormalizeRect(&rect
);
571 HBRUSH pOldBrush
= NULL
;
576 if ((m_nStyle
& (dottedLine
|solidLine
)) != 0)
578 if (m_nStyle
& dottedLine
)
579 pOldPen
= (HPEN
)SelectObject(hDC
,_afxBlackDottedPen
);
581 pOldPen
= (HPEN
)SelectObject(hDC
,(HGDIOBJ
)BLACK_PEN
);
582 pOldBrush
= (HBRUSH
)SelectObject(hDC
,(HGDIOBJ
)NULL_BRUSH
);
583 nOldROP
= SetROP2(hDC
,R2_COPYPEN
);
584 InflateRect(&rect
,+1, +1); // borders are one pixel outside
585 Rectangle(hDC
,rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
586 SetROP2(hDC
,nOldROP
);
589 // if hatchBrush is going to be used, need to unrealize it
590 if ((m_nStyle
& (hatchInside
|hatchedBorder
)) != 0)
591 UnrealizeObject((HGDIOBJ
)_afxHatchBrush
);
594 if ((m_nStyle
& hatchInside
) != 0)
596 pTemp
= SelectObject(hDC
,(HGDIOBJ
)NULL_PEN
);
598 pOldPen
= (HPEN
)pTemp
;
599 pTemp
= SelectObject(hDC
,(HGDIOBJ
)_afxHatchBrush
);
600 if (pOldBrush
== NULL
)
601 pOldBrush
= (HBRUSH
)pTemp
;
602 SetBkMode(hDC
,TRANSPARENT
);
603 nOldROP
= SetROP2(hDC
,R2_MASKNOTPEN
);
604 Rectangle(hDC
,rect
.left
+1, rect
.top
+1, rect
.right
, rect
.bottom
);
605 SetROP2(hDC
,nOldROP
);
608 // draw hatched border
609 if ((m_nStyle
& hatchedBorder
) != 0)
611 pTemp
= SelectObject(hDC
,(HGDIOBJ
)_afxHatchBrush
);
612 if (pOldBrush
== NULL
)
613 pOldBrush
= (HBRUSH
)pTemp
;
614 SetBkMode(hDC
,OPAQUE
);
616 GetTrueRect(&rectTrue
);
617 PatBlt(hDC
,rectTrue
.left
, rectTrue
.top
, rectTrue
.right
-rectTrue
.left
,
618 rect
.top
-rectTrue
.top
, 0x000F0001 /* Pn */);
619 PatBlt(hDC
,rectTrue
.left
, rect
.bottom
,
620 rectTrue
.right
-rectTrue
.left
,
621 rectTrue
.bottom
-rect
.bottom
, 0x000F0001 /* Pn */);
622 PatBlt(hDC
,rectTrue
.left
, rect
.top
, rect
.left
-rectTrue
.left
,
623 rect
.bottom
-rect
.top
, 0x000F0001 /* Pn */);
624 PatBlt(hDC
,rect
.right
, rect
.top
, rectTrue
.right
-rect
.right
,
625 rect
.bottom
-rect
.top
, 0x000F0001 /* Pn */);
628 // draw resize handles
629 if ((m_nStyle
& (resizeInside
|resizeOutside
)) != 0)
631 UINT mask
= GetHandleMask();
632 HBRUSH hbrush
= CreateSolidBrush(RGB(0,0,0));
633 for (int i
= 0; i
< 8; ++i
)
637 GetHandleRect((TrackerHit
)i
, &rect
);
638 // FillSolidRect(hDC,rect, RGB(0, 0, 0));
639 FillRect(hDC
,&rect
,hbrush
);
642 DeleteObject(hbrush
);
647 SelectObject(hDC
,pOldPen
);
648 if (pOldBrush
!= NULL
)
649 SelectObject(hDC
,pOldBrush
);
654 void Tracker::GetHandleRect(int nHandle
,RECT
* pHandleRect
) const
656 // get normalized rectangle of the tracker
658 NormalizeRect(&rectT
);
659 if ((m_nStyle
& (solidLine
|dottedLine
)) != 0)
660 InflateRect(&rectT
,+1, +1);
662 // since the rectangle itself was normalized, we also have to invert the
664 nHandle
= NormalizeHit(nHandle
);
666 // handle case of resize handles outside the tracker
667 int size
= GetHandleSize();
668 if (m_nStyle
& resizeOutside
)
669 InflateRect(&rectT
,size
-1, size
-1);
671 // calculate position of the resize handle
672 int nWidth
= rectT
.right
- rectT
.left
;
673 int nHeight
= rectT
.bottom
- rectT
.top
;
675 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
676 rect
.left
= *(int*)((BYTE
*)&rectT
+ pHandleInfo
->nOffsetX
);
677 rect
.top
= *(int*)((BYTE
*)&rectT
+ pHandleInfo
->nOffsetY
);
678 rect
.left
+= size
* pHandleInfo
->nHandleX
;
679 rect
.top
+= size
* pHandleInfo
->nHandleY
;
680 rect
.left
+= pHandleInfo
->nCenterX
* (nWidth
- size
) / 2;
681 rect
.top
+= pHandleInfo
->nCenterY
* (nHeight
- size
) / 2;
682 rect
.right
= rect
.left
+ size
;
683 rect
.bottom
= rect
.top
+ size
;
689 int Tracker::GetHandleSize(LPRECT lpRect
) const
692 lpRect
= (LPRECT
)&m_rect
;
694 int size
= m_nHandleSize
;
695 if (!(m_nStyle
& resizeOutside
))
697 // make sure size is small enough for the size of the rect
698 int sizeMax
= min(abs(lpRect
->right
- lpRect
->left
),
699 abs(lpRect
->bottom
- lpRect
->top
));
700 if (size
* 2 > sizeMax
)
707 UINT
Tracker::GetHandleMask() const
709 UINT mask
= 0x0F; // always have 4 corner handles
710 int size
= m_nHandleSize
*3;
711 if (abs(m_rect
.right
- m_rect
.left
) - size
> 4)
713 if (abs(m_rect
.bottom
- m_rect
.top
) - size
> 4)
719 void Tracker::GetTrueRect(LPRECT lpTrueRect
) const
722 NormalizeRect(&rect
);
724 if ((m_nStyle
& (resizeOutside
|hatchedBorder
)) != 0)
725 nInflateBy
+= GetHandleSize() - 1;
726 if ((m_nStyle
& (solidLine
|dottedLine
)) != 0)
728 InflateRect(&rect
,nInflateBy
, nInflateBy
);
733 int Tracker::NormalizeHit(int nHandle
) const
735 if (nHandle
== hitMiddle
|| nHandle
== hitNothing
)
737 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
738 if (m_rect
.right
- m_rect
.left
< 0)
740 nHandle
= (TrackerHit
)pHandleInfo
->nInvertX
;
741 pHandleInfo
= &_afxHandleInfo
[nHandle
];
743 if (m_rect
.bottom
- m_rect
.top
< 0)
744 nHandle
= (TrackerHit
)pHandleInfo
->nInvertY
;
749 int Tracker::HitTestHandles(POINT point
) const
752 UINT mask
= GetHandleMask();
754 // see if hit anywhere inside the tracker
756 if (!PtInRect(&rect
,point
))
757 return hitNothing
; // totally missed
759 // see if we hit a handle
760 for (int i
= 0; i
< 8; ++i
)
764 GetHandleRect((TrackerHit
)i
, &rect
);
765 if (PtInRect(&rect
,point
))
766 return (TrackerHit
)i
;
770 // last of all, check for non-hit outside of object, between resize handles
771 if ((m_nStyle
& hatchedBorder
) == 0)
774 NormalizeRect(&rect
);
775 if ((m_nStyle
& dottedLine
|solidLine
) != 0)
776 InflateRect(&rect
,+1, +1);
777 if (!PtInRect(&rect
,point
))
778 return hitNothing
; // must have been between resize handles
780 return hitMiddle
; // no handle hit, but hit object (or object border)
785 void Tracker::GetModifyPointers(
786 int nHandle
, int** ppx
, int** ppy
, int* px
, int* py
)
788 if (nHandle
== hitMiddle
)
789 nHandle
= hitTopLeft
; // same as hitting top-left
794 // fill in the part of the rect that this handle modifies
795 // (Note: handles that map to themselves along a given axis when that
796 // axis is inverted don't modify the value on that axis)
798 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
799 if (pHandleInfo
->nInvertX
!= nHandle
)
801 *ppx
= (int*)((BYTE
*)&m_rect
+ pHandleInfo
->nOffsetX
);
807 // middle handle on X axis
809 *px
= m_rect
.left
+ (m_rect
.left
-m_rect
.right
) / 2;
811 if (pHandleInfo
->nInvertY
!= nHandle
)
813 *ppy
= (int*)((BYTE
*)&m_rect
+ pHandleInfo
->nOffsetY
);
819 // middle handle on Y axis
821 *py
= m_rect
.top
+ (m_rect
.top
-m_rect
.bottom
) / 2;
825 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */