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 #include <sal/config.h>
22 #include <sal/types.h>
25 #pragma warning(disable : 4917 4555)
30 #include "syswinwrapper.hxx"
33 HCURSOR _afxCursors
[10] = { 0, };
34 HBRUSH _afxHalftoneBrush
= 0;
37 // the struct below is used to determine the qualities of a particular handle
40 size_t nOffsetX
; // offset within RECT for X coordinate
41 size_t nOffsetY
; // offset within RECT for Y coordinate
42 int nCenterX
; // adjust X by Width()/2 * this number
43 int nCenterY
; // adjust Y by Height()/2 * this number
44 int nHandleX
; // adjust X by handle size * this number
45 int nHandleY
; // adjust Y by handle size * this number
46 int nInvertX
; // handle converts to this when X inverted
47 int nInvertY
; // handle converts to this when Y inverted
50 // this array describes all 8 handles (clock-wise)
51 const AFX_HANDLEINFO _afxHandleInfo
[] =
53 // corner handles (top-left, top-right, bottom-right, bottom-left
54 { offsetof(RECT
, left
), offsetof(RECT
, top
), 0, 0, 0, 0, 1, 3 },
55 { offsetof(RECT
, right
), offsetof(RECT
, top
), 0, 0, -1, 0, 0, 2 },
56 { offsetof(RECT
, right
), offsetof(RECT
, bottom
), 0, 0, -1, -1, 3, 1 },
57 { offsetof(RECT
, left
), offsetof(RECT
, bottom
), 0, 0, 0, -1, 2, 0 },
59 // side handles (top, right, bottom, left)
60 { offsetof(RECT
, left
), offsetof(RECT
, top
), 1, 0, 0, 0, 4, 6 },
61 { offsetof(RECT
, right
), offsetof(RECT
, top
), 0, 1, -1, 0, 7, 5 },
62 { offsetof(RECT
, left
), offsetof(RECT
, bottom
), 1, 0, 0, -1, 6, 4 },
63 { offsetof(RECT
, left
), offsetof(RECT
, top
), 0, 1, 0, 0, 5, 7 }
66 // the struct below gives us information on the layout of a RECT struct and
67 // the relationship between its members
70 size_t nOffsetAcross
; // offset of opposite point (ie. left->right)
71 int nSignAcross
; // sign relative to that point (ie. add/subtract)
74 // this array is indexed by the offset of the RECT member / sizeof(int)
75 const AFX_RECTINFO _afxRectInfo
[] =
77 { offsetof(RECT
, right
), +1 },
78 { offsetof(RECT
, bottom
), +1 },
79 { offsetof(RECT
, left
), -1 },
80 { offsetof(RECT
, top
), -1 },
84 HBRUSH
HalftoneBrush()
86 if (_afxHalftoneBrush
== NULL
)
89 for (int i
= 0; i
< 8; i
++)
90 grayPattern
[i
] = (WORD
)(0x5555 << (i
& 1));
91 HBITMAP grayBitmap
= CreateBitmap(8, 8, 1, 1, &grayPattern
);
92 if (grayBitmap
!= NULL
)
94 _afxHalftoneBrush
= CreatePatternBrush(grayBitmap
);
95 DeleteObject(grayBitmap
);
98 return _afxHalftoneBrush
;
103 HDC hDC
,LPRECT lpRect
,SIZE size
,
104 LPRECT lpRectLast
,SIZE sizeLast
,
105 HBRUSH hBrush
= NULL
,HBRUSH hBrushLast
= NULL
)
107 // first, determine the update region and select it
109 HRGN rgnOutside
,rgnInside
;
110 rgnOutside
= CreateRectRgnIndirect(lpRect
);
112 InflateRect(&rect
,-size
.cx
, -size
.cy
);
113 IntersectRect(&rect
,&rect
,lpRect
);
114 rgnInside
= CreateRectRgnIndirect(&rect
);
115 rgnNew
= CreateRectRgn(0, 0, 0, 0);
116 CombineRgn(rgnNew
,rgnOutside
,rgnInside
,RGN_XOR
);
118 HBRUSH hBrushOld
= NULL
;
120 hBrush
= HalftoneBrush();
121 if (hBrushLast
== NULL
)
125 HRGN
rgnUpdate(NULL
);
126 if (lpRectLast
!= NULL
)
128 // find difference between new region and old region
129 rgnLast
= CreateRectRgn(0, 0, 0, 0);
137 InflateRect(&rect
,-sizeLast
.cx
, -sizeLast
.cy
);
138 IntersectRect(&rect
,&rect
, lpRectLast
);
139 SetRectRgn(rgnInside
,rect
.left
,rect
.top
,rect
.right
,rect
.bottom
);
140 CombineRgn(rgnLast
,rgnOutside
,rgnInside
, RGN_XOR
);
142 // // only diff them if brushes are the same
143 if (hBrush
== hBrushLast
)
145 rgnUpdate
= CreateRectRgn(0, 0, 0, 0);
146 CombineRgn(rgnUpdate
,rgnLast
,rgnNew
, RGN_XOR
);
149 if (hBrush
!= hBrushLast
&& lpRectLast
!= NULL
)
151 // brushes are different -- erase old region first
152 SelectClipRgn(hDC
,rgnLast
);
153 GetClipBox(hDC
,&rect
);
154 hBrushOld
= (HBRUSH
)SelectObject(hDC
,(HGDIOBJ
)hBrushLast
);
155 PatBlt(hDC
,rect
.left
,rect
.top
,(rect
.right
-rect
.left
),(rect
.bottom
-rect
.top
),PATINVERT
);
157 SelectObject(hDC
,(HGDIOBJ
)hBrushOld
);
161 // draw into the update/new region
162 SelectClipRgn(hDC
,rgnUpdate
);
164 GetClipBox(hDC
,&rect
);
165 hBrushOld
= (HBRUSH
) SelectObject(hDC
,(HGDIOBJ
) hBrush
);
166 PatBlt(hDC
,rect
.left
, rect
.top
,(rect
.right
-rect
.left
),(rect
.bottom
-rect
.top
), PATINVERT
);
169 if (hBrushOld
!= NULL
)
170 SelectObject(hDC
,(HGDIOBJ
)hBrushOld
);
171 SelectClipRgn(hDC
,NULL
);
175 void winwrap::TransformRect(LPRECT rect
,HWND pWnd
,HWND pWndClipTo
)
178 pt
.x
= rect
->left
;pt
.y
= rect
->top
;
179 ClientToScreen(pWnd
,&pt
);
180 ScreenToClient(pWndClipTo
,&pt
);
181 rect
->left
= pt
.x
; rect
->top
= pt
.y
;
183 pt
.x
= rect
->right
;pt
.y
= rect
->bottom
;
184 ClientToScreen(pWnd
,&pt
);
185 ScreenToClient(pWndClipTo
,&pt
);
186 rect
->right
= pt
.x
; rect
->bottom
= pt
.y
;
190 void NormalizeRect(LPRECT rp
)
192 if(rp
->left
> rp
->right
) {
194 rp
->left
= rp
->right
;
198 if(rp
->top
> rp
->bottom
) {
200 rp
->top
= rp
->bottom
;
206 using namespace winwrap
;
214 Tracker::Tracker(LPCRECT lpSrcRect
, UINT nStyle
)
217 CopyRect(&m_rect
,lpSrcRect
);
221 HBRUSH _afxHatchBrush
= 0;
222 HPEN _afxBlackDottedPen
= 0;
223 int _afxHandleSize
= 0;
226 void Tracker::Construct()
228 static BOOL bInitialized
= false;
231 if (_afxHatchBrush
== NULL
)
233 // create the hatch pattern + bitmap
234 WORD hatchPattern
[8];
235 WORD wPattern
= 0x1111;
236 for (int i
= 0; i
< 4; i
++)
238 hatchPattern
[i
] = wPattern
;
239 hatchPattern
[i
+4] = wPattern
;
242 HBITMAP hatchBitmap
= CreateBitmap(8, 8, 1, 1,&hatchPattern
);
244 // create black hatched brush
245 _afxHatchBrush
= CreatePatternBrush(hatchBitmap
);
246 DeleteObject(hatchBitmap
);
249 if (_afxBlackDottedPen
== NULL
)
251 // create black dotted pen
252 _afxBlackDottedPen
= CreatePen(PS_DOT
, 0, RGB(0, 0, 0));
255 // get default handle size from Windows profile setting
256 static const TCHAR szWindows
[] = TEXT("windows");
257 static const TCHAR szInplaceBorderWidth
[] =
258 TEXT("oleinplaceborderwidth");
259 _afxHandleSize
= GetProfileInt(szWindows
, szInplaceBorderWidth
, 4);
262 _afxCursors
[0] = _afxCursors
[2] = LoadCursor(0,IDC_SIZENWSE
);
263 _afxCursors
[4] = _afxCursors
[6] = LoadCursor(0,IDC_SIZENS
);
264 _afxCursors
[1] = _afxCursors
[3] = LoadCursor(0,IDC_SIZENESW
);
265 _afxCursors
[5] = _afxCursors
[7] = LoadCursor(0,IDC_SIZEWE
);
266 _afxCursors
[8] = LoadCursor(0,IDC_SIZEALL
);
270 m_nHandleSize
= _afxHandleSize
;
271 m_sizeMin
.cy
= m_sizeMin
.cx
= m_nHandleSize
*2;
273 SetRectEmpty(&m_rectLast
);
274 m_sizeLast
.cx
= m_sizeLast
.cy
= 0;
276 m_bFinalErase
= FALSE
;
284 int Tracker::HitTest(POINT point
) const
286 TrackerHit hitResult
= hitNothing
;
289 GetTrueRect(&rectTrue
);
290 NormalizeRect(&rectTrue
);
291 if (PtInRect(&rectTrue
,point
))
293 if ((m_nStyle
& (resizeInside
|resizeOutside
)) != 0)
294 hitResult
= (TrackerHit
)HitTestHandles(point
);
296 hitResult
= hitMiddle
;
302 BOOL
Tracker::SetCursor(HWND pWnd
, UINT nHitTest
) const
304 // trackers should only be in client area
305 if (nHitTest
!= HTCLIENT
)
308 // convert cursor position to client co-ordinates
310 GetCursorPos(&point
);
311 ScreenToClient(pWnd
,&point
);
313 // do hittest and normalize hit
314 int nHandle
= HitTestHandles(point
);
318 // need to normalize the hittest such that we get proper cursors
319 nHandle
= NormalizeHit(nHandle
);
321 // handle special case of hitting area between handles
322 // (logically the same -- handled as a move -- but different cursor)
323 if (nHandle
== hitMiddle
&& !PtInRect(&m_rect
,point
))
325 // only for trackers with hatchedBorder (ie. in-place resizing)
326 if (m_nStyle
& hatchedBorder
)
327 nHandle
= (TrackerHit
)9;
330 ::SetCursor(_afxCursors
[nHandle
]);
335 BOOL
Tracker::Track(HWND hWnd
,POINT point
,BOOL bAllowInvert
,
338 // perform hit testing on the handles
339 int nHandle
= HitTestHandles(point
);
342 // didn't hit a handle, so just return FALSE
346 // otherwise, call helper function to do the tracking
347 m_bAllowInvert
= bAllowInvert
;
348 SetCursor(hWnd
,nHandle
);
349 return TrackHandle(nHandle
, hWnd
, point
, hWndClipTo
);
353 BOOL
Tracker::TrackHandle(int nHandle
,HWND hWnd
,POINT point
,HWND hWndClipTo
)
355 // don't handle if capture already set
356 if (GetCapture() != NULL
)
359 // save original width & height in pixels
360 int nWidth
= m_rect
.right
- m_rect
.left
;
361 int nHeight
= m_rect
.bottom
- m_rect
.top
;
363 // set capture to the window which received this message
366 if (hWndClipTo
!= NULL
)
367 UpdateWindow(hWndClipTo
);
368 RECT rectSave
= m_rect
;
370 // find out what x/y coords we are supposed to modify
373 GetModifyPointers(nHandle
, &px
, &py
, &xDiff
, &yDiff
);
374 xDiff
= point
.x
- xDiff
;
375 yDiff
= point
.y
- yDiff
;
377 // get DC for drawing
379 if (hWndClipTo
!= NULL
)
381 // clip to arbitrary window by using adjusted Window DC
382 hDrawDC
= GetDCEx(hWndClipTo
,NULL
, DCX_CACHE
);
386 // otherwise, just use normal DC
387 hDrawDC
= GetDC(hWnd
);
393 // get messages until capture lost or cancelled/accepted
397 GetMessage(&msg
, NULL
, 0, 0);
399 if (GetCapture() != hWnd
)
404 // handle movement/accept messages
408 // handle resize cases (and part of move)
410 *px
= (int)(short)LOWORD(msg
.lParam
) - xDiff
;
412 *py
= (int)(short)HIWORD(msg
.lParam
) - yDiff
;
415 if (nHandle
== hitMiddle
)
417 m_rect
.right
= m_rect
.left
+ nWidth
;
418 m_rect
.bottom
= m_rect
.top
+ nHeight
;
420 // allow caller to adjust the rectangle if necessary
421 AdjustRect(nHandle
,&m_rect
);
423 // only redraw and callback if the rect actually changed!
424 m_bFinalErase
= (msg
.message
== WM_LBUTTONUP
);
425 if (!EqualRect(&rectOld
,&m_rect
) || m_bFinalErase
)
430 DrawTrackerRect(&rectOld
,hWndClipTo
,hDrawDC
,hWnd
);
432 OnChangedRect(rectOld
);
433 if (msg
.message
!= WM_LBUTTONUP
)
439 if (!EqualRect(&rectOld
,&m_rect
))
442 DrawTrackerRect(&m_rect
,hWndClipTo
,hDrawDC
,hWnd
);
446 // handle cancel messages
448 if (msg
.wParam
!= VK_ESCAPE
)
454 m_bErase
= m_bFinalErase
= TRUE
;
455 DrawTrackerRect(&m_rect
, hWndClipTo
, hDrawDC
, hWnd
);
460 // just dispatch rest of the messages
462 DispatchMessage(&msg
);
468 if (hWndClipTo
!= NULL
)
469 ReleaseDC(hWndClipTo
,hDrawDC
);
471 ReleaseDC(hWnd
,hDrawDC
);
474 // restore rect in case bMoved is still FALSE
477 m_bFinalErase
= FALSE
;
480 // return TRUE only if rect has changed
481 return !EqualRect(&rectSave
,&m_rect
);
485 void Tracker::OnChangedRect(const RECT
& /*rectOld*/)
490 void Tracker::AdjustRect(int nHandle
, LPRECT
)
492 if(nHandle
== hitMiddle
)
495 // convert the handle into locations within m_rect
497 GetModifyPointers(nHandle
, &px
, &py
, NULL
, NULL
);
499 // enforce minimum width
500 int nNewWidth
= m_rect
.right
- m_rect
.left
;
501 int nAbsWidth
= m_bAllowInvert
? abs(nNewWidth
) : nNewWidth
;
502 if (px
!= NULL
&& nAbsWidth
< m_sizeMin
.cx
)
504 nNewWidth
= nAbsWidth
!= 0 ? nNewWidth
/ nAbsWidth
: 1;
505 const AFX_RECTINFO
* pRectInfo
=
506 &_afxRectInfo
[(int*)px
- (int*)&m_rect
];
507 *px
= *(int*)((BYTE
*)&m_rect
+ pRectInfo
->nOffsetAcross
) +
508 nNewWidth
* m_sizeMin
.cx
* -pRectInfo
->nSignAcross
;
511 // enforce minimum height
512 int nNewHeight
= m_rect
.bottom
- m_rect
.top
;
513 int nAbsHeight
= m_bAllowInvert
? abs(nNewHeight
) : nNewHeight
;
514 if (py
!= NULL
&& nAbsHeight
< m_sizeMin
.cy
)
516 nNewHeight
= nAbsHeight
!= 0 ? nNewHeight
/ nAbsHeight
: 1;
517 const AFX_RECTINFO
* pRectInfo
=
518 &_afxRectInfo
[(int*)py
- (int*)&m_rect
];
519 *py
= *(int*)((BYTE
*)&m_rect
+ pRectInfo
->nOffsetAcross
) +
520 nNewHeight
* m_sizeMin
.cy
* -pRectInfo
->nSignAcross
;
525 void Tracker::DrawTrackerRect(
526 LPRECT lpRect
,HWND pWndClipTo
,HDC pDC
,HWND pWnd
)
528 // first, normalize the rectangle for drawing
530 NormalizeRect(&rect
);
532 // convert to client coordinates
533 if (pWndClipTo
!= NULL
)
534 TransformRect(&rect
,pWnd
,pWndClipTo
);
537 size
.cx
= 0; size
.cy
= 0;
540 // otherwise, size depends on the style
541 if (m_nStyle
& hatchedBorder
)
543 size
.cx
= size
.cy
= max(1,GetHandleSize(&rect
)-1);
544 InflateRect(&rect
,size
.cx
,size
.cy
);
548 size
.cx
= 1; // CX_BORDER;
549 size
.cy
= 1; // CY_BORDER;
554 if (m_bFinalErase
|| !m_bErase
)
555 DrawDragRect(pDC
,&rect
,size
,&m_rectLast
,m_sizeLast
);
557 // remember last rectangles
563 void Tracker::Draw(HDC hDC
) const
565 // set initial DC state
566 SetMapMode(hDC
,MM_TEXT
);
567 SetViewportOrgEx(hDC
,0, 0,NULL
);
568 SetWindowOrgEx(hDC
,0, 0,NULL
);
570 // get normalized rectangle
572 NormalizeRect(&rect
);
575 HBRUSH pOldBrush
= NULL
;
580 if ((m_nStyle
& (dottedLine
|solidLine
)) != 0)
582 if (m_nStyle
& dottedLine
)
583 pOldPen
= (HPEN
)SelectObject(hDC
,_afxBlackDottedPen
);
585 pOldPen
= (HPEN
)SelectObject(hDC
,(HGDIOBJ
)BLACK_PEN
);
586 pOldBrush
= (HBRUSH
)SelectObject(hDC
,(HGDIOBJ
)NULL_BRUSH
);
587 nOldROP
= SetROP2(hDC
,R2_COPYPEN
);
588 InflateRect(&rect
,+1, +1); // borders are one pixel outside
589 Rectangle(hDC
,rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
590 SetROP2(hDC
,nOldROP
);
593 // if hatchBrush is going to be used, need to unrealize it
594 if ((m_nStyle
& (hatchInside
|hatchedBorder
)) != 0)
595 UnrealizeObject((HGDIOBJ
)_afxHatchBrush
);
598 if ((m_nStyle
& hatchInside
) != 0)
600 pTemp
= SelectObject(hDC
,(HGDIOBJ
)NULL_PEN
);
602 pOldPen
= (HPEN
)pTemp
;
603 pTemp
= SelectObject(hDC
,(HGDIOBJ
)_afxHatchBrush
);
604 if (pOldBrush
== NULL
)
605 pOldBrush
= (HBRUSH
)pTemp
;
606 SetBkMode(hDC
,TRANSPARENT
);
607 nOldROP
= SetROP2(hDC
,R2_MASKNOTPEN
);
608 Rectangle(hDC
,rect
.left
+1, rect
.top
+1, rect
.right
, rect
.bottom
);
609 SetROP2(hDC
,nOldROP
);
612 // draw hatched border
613 if ((m_nStyle
& hatchedBorder
) != 0)
615 pTemp
= SelectObject(hDC
,(HGDIOBJ
)_afxHatchBrush
);
616 if (pOldBrush
== NULL
)
617 pOldBrush
= (HBRUSH
)pTemp
;
618 SetBkMode(hDC
,OPAQUE
);
620 GetTrueRect(&rectTrue
);
621 PatBlt(hDC
,rectTrue
.left
, rectTrue
.top
, rectTrue
.right
-rectTrue
.left
,
622 rect
.top
-rectTrue
.top
, 0x000F0001 /* Pn */);
623 PatBlt(hDC
,rectTrue
.left
, rect
.bottom
,
624 rectTrue
.right
-rectTrue
.left
,
625 rectTrue
.bottom
-rect
.bottom
, 0x000F0001 /* Pn */);
626 PatBlt(hDC
,rectTrue
.left
, rect
.top
, rect
.left
-rectTrue
.left
,
627 rect
.bottom
-rect
.top
, 0x000F0001 /* Pn */);
628 PatBlt(hDC
,rect
.right
, rect
.top
, rectTrue
.right
-rect
.right
,
629 rect
.bottom
-rect
.top
, 0x000F0001 /* Pn */);
632 // draw resize handles
633 if ((m_nStyle
& (resizeInside
|resizeOutside
)) != 0)
635 UINT mask
= GetHandleMask();
636 HBRUSH hbrush
= CreateSolidBrush(RGB(0,0,0));
637 for (int i
= 0; i
< 8; ++i
)
641 GetHandleRect((TrackerHit
)i
, &rect
);
642 // FillSolidRect(hDC,rect, RGB(0, 0, 0));
643 FillRect(hDC
,&rect
,hbrush
);
646 DeleteObject(hbrush
);
651 SelectObject(hDC
,pOldPen
);
652 if (pOldBrush
!= NULL
)
653 SelectObject(hDC
,pOldBrush
);
658 void Tracker::GetHandleRect(int nHandle
,RECT
* pHandleRect
) const
660 // get normalized rectangle of the tracker
662 NormalizeRect(&rectT
);
663 if ((m_nStyle
& (solidLine
|dottedLine
)) != 0)
664 InflateRect(&rectT
,+1, +1);
666 // since the rectangle itself was normalized, we also have to invert the
668 nHandle
= NormalizeHit(nHandle
);
670 // handle case of resize handles outside the tracker
671 int size
= GetHandleSize();
672 if (m_nStyle
& resizeOutside
)
673 InflateRect(&rectT
,size
-1, size
-1);
675 // calculate position of the resize handle
676 int nWidth
= rectT
.right
- rectT
.left
;
677 int nHeight
= rectT
.bottom
- rectT
.top
;
679 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
680 rect
.left
= *(int*)((BYTE
*)&rectT
+ pHandleInfo
->nOffsetX
);
681 rect
.top
= *(int*)((BYTE
*)&rectT
+ pHandleInfo
->nOffsetY
);
682 rect
.left
+= size
* pHandleInfo
->nHandleX
;
683 rect
.top
+= size
* pHandleInfo
->nHandleY
;
684 rect
.left
+= pHandleInfo
->nCenterX
* (nWidth
- size
) / 2;
685 rect
.top
+= pHandleInfo
->nCenterY
* (nHeight
- size
) / 2;
686 rect
.right
= rect
.left
+ size
;
687 rect
.bottom
= rect
.top
+ size
;
693 int Tracker::GetHandleSize(LPRECT lpRect
) const
696 lpRect
= (LPRECT
)&m_rect
;
698 int size
= m_nHandleSize
;
699 if (!(m_nStyle
& resizeOutside
))
701 // make sure size is small enough for the size of the rect
702 int sizeMax
= min(abs(lpRect
->right
- lpRect
->left
),
703 abs(lpRect
->bottom
- lpRect
->top
));
704 if (size
* 2 > sizeMax
)
711 UINT
Tracker::GetHandleMask() const
713 UINT mask
= 0x0F; // always have 4 corner handles
714 int size
= m_nHandleSize
*3;
715 if (abs(m_rect
.right
- m_rect
.left
) - size
> 4)
717 if (abs(m_rect
.bottom
- m_rect
.top
) - size
> 4)
723 void Tracker::GetTrueRect(LPRECT lpTrueRect
) const
726 NormalizeRect(&rect
);
728 if ((m_nStyle
& (resizeOutside
|hatchedBorder
)) != 0)
729 nInflateBy
+= GetHandleSize() - 1;
730 if ((m_nStyle
& (solidLine
|dottedLine
)) != 0)
732 InflateRect(&rect
,nInflateBy
, nInflateBy
);
737 int Tracker::NormalizeHit(int nHandle
) const
739 if (nHandle
== hitMiddle
|| nHandle
== hitNothing
)
741 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
742 if (m_rect
.right
- m_rect
.left
< 0)
744 nHandle
= (TrackerHit
)pHandleInfo
->nInvertX
;
745 pHandleInfo
= &_afxHandleInfo
[nHandle
];
747 if (m_rect
.bottom
- m_rect
.top
< 0)
748 nHandle
= (TrackerHit
)pHandleInfo
->nInvertY
;
753 int Tracker::HitTestHandles(POINT point
) const
756 UINT mask
= GetHandleMask();
758 // see if hit anywhere inside the tracker
760 if (!PtInRect(&rect
,point
))
761 return hitNothing
; // totally missed
763 // see if we hit a handle
764 for (int i
= 0; i
< 8; ++i
)
768 GetHandleRect((TrackerHit
)i
, &rect
);
769 if (PtInRect(&rect
,point
))
770 return (TrackerHit
)i
;
774 // last of all, check for non-hit outside of object, between resize handles
775 if ((m_nStyle
& hatchedBorder
) == 0)
778 NormalizeRect(&rect
);
779 if ((m_nStyle
& (dottedLine
|solidLine
)) != 0)
780 InflateRect(&rect
,+1, +1);
781 if (!PtInRect(&rect
,point
))
782 return hitNothing
; // must have been between resize handles
784 return hitMiddle
; // no handle hit, but hit object (or object border)
788 void Tracker::GetModifyPointers(
789 int nHandle
, int** ppx
, int** ppy
, int* px
, int* py
)
791 if (nHandle
== hitMiddle
)
792 nHandle
= hitTopLeft
; // same as hitting top-left
797 // fill in the part of the rect that this handle modifies
798 // (Note: handles that map to themselves along a given axis when that
799 // axis is inverted don't modify the value on that axis)
801 const AFX_HANDLEINFO
* pHandleInfo
= &_afxHandleInfo
[nHandle
];
802 if (pHandleInfo
->nInvertX
!= nHandle
)
804 *ppx
= (int*)((BYTE
*)&m_rect
+ pHandleInfo
->nOffsetX
);
810 // middle handle on X axis
812 *px
= m_rect
.left
+ (m_rect
.left
-m_rect
.right
) / 2;
814 if (pHandleInfo
->nInvertY
!= nHandle
)
816 *ppy
= (int*)((BYTE
*)&m_rect
+ pHandleInfo
->nOffsetY
);
822 // middle handle on Y axis
824 *py
= m_rect
.top
+ (m_rect
.top
-m_rect
.bottom
) / 2;
828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */