1 // $Id: dragmgr.cpp 1671 2006-08-04 15:56:13Z luke $
2 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
3 ================================XARAHEADERSTART===========================
5 Xara LX, a vector drawing and manipulation program.
6 Copyright (C) 1993-2006 Xara Group Ltd.
7 Copyright on certain contributions may be held in joint with their
8 respective authors. See AUTHORS file for details.
10 LICENSE TO USE AND MODIFY SOFTWARE
11 ----------------------------------
13 This file is part of Xara LX.
15 Xara LX is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License version 2 as published
17 by the Free Software Foundation.
19 Xara LX and its component source files are distributed in the hope
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 See the GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License along
25 with Xara LX (see the file GPL in the root directory of the
26 distribution); if not, write to the Free Software Foundation, Inc., 51
27 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
37 The additional rights are to use, modify, and distribute the software
38 together with the wxWidgets library, the wxXtra library, and the "CDraw"
39 library and any other such library that any version of Xara LX relased
40 by Xara Group Ltd requires in order to compile and execute, including
41 the static linking of that library to XaraLX. In the case of the
42 "CDraw" library, you may satisfy obligation under the GNU General Public
43 License to provide source code by providing a binary copy of the library
44 concerned and a copy of the license accompanying it.
46 Nothing in this section restricts any of the rights you have under
47 the GNU General Public License.
53 This license applies to this program (XaraLX) and its constituent source
54 files only, and does not necessarily apply to other Xara products which may
55 in part share the same code base, and are subject to their own licensing
58 This license does not apply to files in the wxXtra directory, which
59 are built into a separate library, and are subject to the wxWindows
60 license contained within that directory in the file "WXXTRA-LICENSE".
62 This license does not apply to the binary libraries (if any) within
63 the "libs" directory, which are subject to a separate license contained
64 within that directory in the file "LIBS-LICENSE".
67 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
68 ----------------------------------------------
70 Subject to the terms of the GNU Public License (see above), you are
71 free to do whatever you like with your modifications. However, you may
72 (at your option) wish contribute them to Xara's source tree. You can
73 find details of how to do this at:
74 http://www.xaraxtreme.org/developers/
76 Prior to contributing your modifications, you will need to complete our
77 contributor agreement. This can be found at:
78 http://www.xaraxtreme.org/developers/contribute/
80 Please note that Xara will not accept modifications which modify any of
81 the text between the start and end of this header (marked
82 XARAHEADERSTART and XARAHEADEREND).
88 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
89 designs are registered or unregistered trademarks, design-marks, and/or
90 service marks of Xara Group Ltd. All rights in these marks are reserved.
93 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
96 =================================XARAHEADEREND============================
99 // dragmgr.cpp - Implementation of global dragging system manager (DragManagerOp)
105 #include "camtypes.h"
107 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
109 //#include "dialogop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
111 #include "keypress.h"
112 //#include "oilcoord.h" - in camtypes.h [AUTOMATICALLY REMOVED]
113 #include "camframe.h"
114 //#include "cursor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
115 #include "csrstack.h"
119 #include "oilbitmap.h"
120 #include "osrndrgn.h"
122 CC_IMPLEMENT_DYNCREATE(DragManagerOp
, Operation
)
123 IMPLEMENT_DYNAMIC_CLASS(CaptureHandler
, wxEvtHandler
)
125 #define new CAM_DEBUG_NEW
127 //------------------------------------------------------------------------------------------
129 //------------------------------------------------------------------------------------------
131 // -----------------------------------------------------------------------------------------
132 // CaptureHandler event table
134 BEGIN_EVENT_TABLE( CaptureHandler
, wxEvtHandler
)
135 EVT_LEFT_UP( CaptureHandler::OnLButtonUp
)
136 EVT_RIGHT_UP( CaptureHandler::OnRButtonUp
)
137 EVT_MOTION( CaptureHandler::OnMouseMove
)
141 /********************************************************************************************
143 > CaptureHandler::CaptureHandler()
145 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
148 Purpose: CaptureHandler constructor
150 ********************************************************************************************/
152 CaptureHandler::CaptureHandler(wxWindow
* pWindow
)
154 // TRACEUSER("Gerry", _T("CaptureHandler::CaptureHandler"));
156 m_bHasCapture
= FALSE
;
158 m_pBackBitmap
= NULL
;
159 m_pMaskBitmap
= NULL
;
162 /********************************************************************************************
164 > CaptureHandler::~CaptureHandler()
166 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
169 Purpose: CaptureWnd destructor
171 ********************************************************************************************/
173 CaptureHandler::~CaptureHandler()
175 // TRACEUSER("Gerry", _T("CaptureHandler::~CaptureHandler"));
176 // Need to clean up all the pointers here...
180 if (m_pWindow
->PopEventHandler() != this)
182 TRACEUSER("Gerry", _T("Popped event handler is not this one, expect a crash"));
185 if (m_pWindow
->HasCapture())
187 m_pWindow
->ReleaseMouse();
188 if (m_pWindow
->HasCapture())
190 TRACEUSER("Gerry", _T("Still got capture"));
194 TRACEUSER("Gerry", _T("Capture released"));
197 CursorStack::GSetActive();
201 TRACEUSER("Gerry", _T("Haven't got capture"));
203 m_bHasCapture
= FALSE
;
208 /********************************************************************************************
210 > BOOL CaptureHandler::StartCapture()
212 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
215 Purpose: Attaches us to the window and starts mouse capture
217 ********************************************************************************************/
219 BOOL
CaptureHandler::StartCapture()
221 TRACEUSER("Gerry", _T("CaptureHandler::StartCapture"));
222 if (m_pWindow
&& !m_bHasCapture
)
224 if (m_pWindow
->HasCapture())
226 TRACEUSER("Gerry", _T("Already got capture"));
229 m_pWindow
->CaptureMouse();
231 if (m_pWindow
->HasCapture())
233 TRACEUSER("Gerry", _T("Got capture"));
234 m_bHasCapture
= true;
235 m_pWindow
->PushEventHandler(this);
243 //-------------------------------------------------------------------------------------------
244 // CaptureHandler Message Handlers
245 //-------------------------------------------------------------------------------------------
247 /********************************************************************************************
249 > void CaptureHandler::OnLButtonUp(wxMouseEvent& event)
251 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
258 ********************************************************************************************/
259 void CaptureHandler::OnLButtonUp(wxMouseEvent
& event
)
263 wxPoint point
= event
.GetPosition();
264 point
= m_pWindow
->ClientToScreen(point
);
266 if (DragManagerOp::CurrentManager
&& DragManagerOp::CurrentManager
->CurrentDragInfo
)
268 DragManagerOp::CurrentManager
->CurrentDragInfo
->OnMouseMove(point
);
269 DragManagerOp::CurrentManager
->CurrentDragInfo
->OnButtonUp(point
);
273 TRACEUSER("Gerry", _T("CaptureHandler::OnLButtonUp"));
274 DragManagerOp::EndDrag(1);// 1 == left click for now
275 // Don't call Skip as the window wont be expecting the button up
280 /********************************************************************************************
282 > void CaptureHandler::OnRButtonUp(wxMouseEvent& event)
284 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
291 ********************************************************************************************/
292 void CaptureHandler::OnRButtonUp(wxMouseEvent
& event
)
296 wxPoint point
= event
.GetPosition();
297 point
= m_pWindow
->ClientToScreen(point
);
299 if (DragManagerOp::CurrentManager
&& DragManagerOp::CurrentManager
->CurrentDragInfo
)
301 DragManagerOp::CurrentManager
->CurrentDragInfo
->OnMouseMove(point
);
302 DragManagerOp::CurrentManager
->CurrentDragInfo
->OnButtonUp(point
);
306 TRACEUSER("Gerry", _T("CaptureHandler::OnRButtonUp"));
307 DragManagerOp::EndDrag(-1);// -1 == Right click for now
309 // Don't call Skip as the window wont be expecting the button up
314 /********************************************************************************************
316 > void CaptureHandler::SetUpSolidDrag(CPoint StartPos)
318 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
321 Purpose: Sets up Device Contexts / Bitmaps etc.. for Solid Drag
325 // ********************************************************************************************/
327 BOOL
CaptureHandler::SetUpSolidDrag(wxPoint StartPos
)
329 TRACEUSER("Gerry", _T("SetUpSolidDrag(%d, %d)"), StartPos
.x
, StartPos
.y
);
331 ERROR2IF(DragManagerOp::CurrentManager
== NULL
||
332 DragManagerOp::CurrentManager
->CurrentDragInfo
== NULL
,
334 _T("CaptureHandler::SetUpSolidDrag - The current drag manager is invalid"));
336 if (!DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
339 if (DragManagerOp::CurrentManager
->RedrawInProgress
|| m_pDisplayDC
!= NULL
)
342 // get a couple of draggy bits
343 wxPoint SolidDragOffset
= DragManagerOp::CurrentManager
->CurrentDragInfo
->SolidDragOffset
;
344 wxSize DSize
= DragManagerOp::CurrentManager
->CurrentDragInfo
->SolidDragSize
;
346 m_pDisplayDC
= new wxScreenDC();
347 wxMemoryDC BackGroundDC
;
348 m_pBackBitmap
= new wxBitmap(DSize
.x
, DSize
.y
);
350 if (m_pDisplayDC
==NULL
|| m_pBackBitmap
== NULL
)
355 // Offset the drag from the pointer
356 wxPoint ClientPos
= StartPos
+ SolidDragOffset
;
358 // select bitmap into the dc
359 BackGroundDC
.SelectObject(*m_pBackBitmap
);
361 ClientPos
= m_pWindow
->ScreenToClient(ClientPos
);
364 m_DragRect
= wxRect(ClientPos
.x
, ClientPos
.y
, DSize
.x
, DSize
.y
);
366 // blit the screen into the bitmap
367 BackGroundDC
.Blit(0,0,DSize
.x
,DSize
.y
,m_pDisplayDC
,m_DragRect
.x
,m_DragRect
.y
);
369 BackGroundDC
.SelectObject(wxNullBitmap
);
371 INT32 DragTransparency
=
372 DragManagerOp::CurrentManager
->CurrentDragInfo
->GetDragTransparency();
374 KernelBitmap
* DragMask
=
375 DragManagerOp::CurrentManager
->CurrentDragInfo
->GetSolidDragMask();
377 BOOL TransparentMask
= DragManagerOp::CurrentManager
->CurrentDragInfo
->HasTransparentMask();
379 if (DragTransparency
> 0 || TransparentMask
|| DragMask
!= NULL
)
381 // If we're doing a transparency drag, then we'll need
382 // a monochome mask bitmap.
383 // This will be a simple grey level, hatch pattern,
384 // which will be used to 'knock' pixels out of the
387 // Sadly, the world has conspired against us in terms of producing this
388 // in any rational manner. 1bpp wxBitmaps do not work as brushes (random
389 // memory). 24bpp wxBitmaps do not work as brushes into wxMemoryDCs backed
390 // by 1bpp brushes. Conversion of 24bpp bitmaps to 1bpp does not dither.
391 // making 1bpp brushes with a stipple does not dither. So we just manually
392 // implement they bayer dithering algorithm.
394 // Create a wxImage, don't initalize it
395 wxImage
MaskImage(DSize
.x
, DSize
.y
, false);
396 unsigned char * pix
=MaskImage
.GetData();
397 unsigned char * tpix
= NULL
;
399 wxImage
* pTransparentMask
= NULL
;
402 wxBitmap
*pTMbitmap
=DragManagerOp::CurrentManager
->CurrentDragInfo
->GetTransparentMask();
404 pTransparentMask
= new wxImage();
405 if (!pTransparentMask
)
406 TransparentMask
=FALSE
;
409 *pTransparentMask
=pTMbitmap
->ConvertToImage();
410 tpix
=pTransparentMask
->GetData();
414 // DragTransparency is between 0 and 100,
415 // and we need a grey level between 0 and 255.
416 INT32 GreyLevel
= (DragTransparency
* 255) / 100;
418 // for (i=0; i<4*4*3; i++) ImageData[i]=GreyLevel;
419 // The above would be far too easy. wxWidgets doesn't seem to want to dither. Sigh
420 // write our own ordered dither! And neither do 1bpp wxBitmaps work as brushes
421 // sigh... And painting a 24bpp brush into a 1bpp bitmap dies horribly. Aaarrggghh
423 INT32 OrderedDither
[4*4]={ 1, 9, 3,11,
429 for (y
=0; y
<DSize
.y
; y
++) for (x
=0; x
<DSize
.x
; x
++)
431 INT32 tlevel
=GreyLevel
;
434 // Combine the transparency level with the transparency of the mask
435 // Note if EITHER are 255 we want full transparency. The appropriate
436 // operation is thus 1-((1-x)(1-y)), except of course they are 0..255
437 tlevel
=((255*255+(255/2)) - // that's the maximum value (as we invert), but also add 255/2 for rounding when we divide by 255
438 ((255-GreyLevel
)*(*tpix
))
442 BYTE thresh
= (tlevel
>(OrderedDither
[(x
&3)|((y
&3)<<2)]*16-8))?0xff:0x00;
443 // write three bytes (R, G, B)
449 if (pTransparentMask
)
450 delete pTransparentMask
;
452 m_pMaskBitmap
= new wxBitmap(MaskImage
, 1);
455 // Now combine the DragMask with the transparency mask.
459 MaskDC
.SelectObject(*m_pMaskBitmap
);
461 // This needs to create a wxBitmap from DragMask
462 // and OR it into the MaskDC
464 CWxBitmap
* pMaskBmp
= (CWxBitmap
*)DragMask
->ActualBitmap
;
465 RGBQUAD
* Palette
= (RGBQUAD
*) (pMaskBmp
->BMInfo
->bmiColors
);
467 // set the first colours to black and white
468 Palette
[0].rgbRed
= Palette
[0].rgbBlue
= Palette
[0].rgbGreen
= 0;
469 Palette
[1].rgbRed
= Palette
[1].rgbBlue
= Palette
[1].rgbGreen
= 255;
471 // set the reserved bytes to zero
472 Palette
[0].rgbReserved
= Palette
[1].rgbReserved
= 0;
474 UINT32 bpp
=pMaskBmp
->GetBPP();
477 wxBitmap
MemBitmap(DSize
.x
, DSize
.y
, bpp
);
478 MemDC
.SelectObject(MemBitmap
);
484 LPBITMAPINFO MemBInfo
= AllocDIB(DSize
.x
, DSize
.y
, bpp
, &MemBBits
);
486 GRenderRegion::StaticPlotBitmap(&MemDC
, DIB_RGB_COLORS
, MemBInfo
, MemBBits
, 0, 0, DSize
.x
, DSize
.y
, m_pMaskBitmap
->GetPalette(), 0, 0);
488 // Now OR the Mask Bitmap into the MaskDC, so that
489 // it 'masks' the transparency mask.
490 MaskDC
.Blit(0, 0, DSize
.x
, DSize
.y
, &MemDC
, 0, 0, wxOR
);
493 MaskDC
.SetBrush(*wxTRANSPARENT_BRUSH
);
494 MaskDC
.SetPen(*wxTRANSPARENT_PEN
);
495 MaskDC
.SelectObject(wxNullBitmap
);
500 m_pMaskBitmap
= NULL
;
502 DrawSolidDrag(StartPos
);
509 /********************************************************************************************
511 > BOOL CaptureHandler::CleanUpSolidDrag()
513 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
517 Returns: FALSE if it fails
519 Purpose: Removes any solid-drag stuff we may have on-screen at the moment and cleans up
520 the solid drag system. Called at the end of a drag to clean up, and also
521 whenever someone is redrawing underneath us, and we thus need to remove the
522 drag stuff while they redraw.
524 SeeAlso: CaptureHandler::CleanUpSolidDragInScreenArea
526 ********************************************************************************************/
528 BOOL
CaptureHandler::CleanUpSolidDrag()
530 TRACEUSER("Gerry", _T("CleanUpSolidDrag"));
532 if (DragManagerOp::CurrentManager
== NULL
)
535 if (DragManagerOp::CurrentManager
->CurrentDragInfo
&&
536 !DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
539 if (m_pDisplayDC
== NULL
)
544 wxMemoryDC BackGroundDC
;
546 // select bitmap into the dc
547 BackGroundDC
.SelectObject(*m_pBackBitmap
);
549 // remove the last drag draw (only if we drew something)
550 if (!DragManagerOp::CurrentManager
->DragPending
)
552 m_pDisplayDC
->Blit(m_DragRect
.x
,m_DragRect
.y
,m_DragRect
.width
, m_DragRect
.height
,&BackGroundDC
,0,0);
555 // clean up and delete the DC's
556 BackGroundDC
.SelectObject(wxNullBitmap
);
567 delete m_pBackBitmap
;
568 m_pBackBitmap
= NULL
;
573 delete m_pMaskBitmap
;
574 m_pMaskBitmap
= NULL
;
577 m_DragRect
= wxRect(0, 0, 0, 0);
584 /********************************************************************************************
586 > BOOL CaptureHandler::CleanUpSolidDragInScreenArea(const wxRect& Area)
588 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
591 Inputs: Area - The SCREEN coordinates of the area ofd screen which has become
592 compromised (usually because it is being redrawn).
594 Returns: TRUE if it called CleanUpSolidDrag, FALSE if it didn't bother
596 Purpose: Calls CleanUpSolidDrag. However, it ONLY calls that method if the
597 compromised screen area overlaps the solid drag area - if not, then the
598 solid drag stuff can't be overwritten, so there is no need to remove it.
599 This can drastically reduce flicker when things are background redrawing
600 on other parts of the screen.
602 SeeAlso: CaptureHandler::CleanUpSolidDrag
604 ********************************************************************************************/
606 BOOL
CaptureHandler::CleanUpSolidDragInScreenArea(const wxRect
& Area
)
608 // TRACEUSER("Gerry", _T("CleanUpSolidDragInScreenArea"));
610 // No solid drag, so no need to do anything
611 if (!DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
614 // No solid stuff has yet been drawn, so no need to do anything
615 if (DragManagerOp::CurrentManager
->DragPending
|| m_DragRect
.IsEmpty())
619 if (!Isect
.Intersect(m_DragRect
).IsEmpty())
630 /********************************************************************************************
632 > void CaptureHandler::OnMouseMove(wxMouseEvent& event)
634 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
637 Purpose: call solid drag draw code.
641 ********************************************************************************************/
643 void CaptureHandler::OnMouseMove(wxMouseEvent
& event
)
645 // TRACEUSER("Gerry", _T("CaptureHandler::OnMouseMove"));
646 // Abort if the system has been disabled (for an error box)
647 if (CCamApp::IsDisabled())
649 // DragManagerOp::AbortDrag(); // This could be deeply scary - it mustn't cause a redraw!
653 if (DragManagerOp::CurrentManager
&& !DragManagerOp::CurrentManager
->RedrawInProgress
)
655 wxPoint point
= event
.GetPosition();
656 point
= m_pWindow
->ClientToScreen(point
);
658 if (DragManagerOp::CurrentManager
->CurrentDragInfo
)
659 DragManagerOp::CurrentManager
->CurrentDragInfo
->OnMouseMove(point
);
661 DrawSolidDrag(point
);
667 /********************************************************************************************
669 > void CaptureHandler::DrawSolidDrag(wxPoint point)
671 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
674 Purpose: to allow solid flicker-free drag objects to be drawn.
675 a helper function in the current drag is called - but this function
676 looks after the rest.
680 ********************************************************************************************/
682 BOOL
CaptureHandler::DrawSolidDrag(wxPoint point
)
684 // ignore if not intialized
685 if (!m_pBackBitmap
|| !m_pDisplayDC
)
688 // TRACEUSER("Gerry", _T("DrawSolidDrag(%d, %d)"), point.x, point.y);
690 ERROR2IF(DragManagerOp::CurrentManager
== NULL
||
691 DragManagerOp::CurrentManager
->CurrentDragInfo
== NULL
,
693 "No current drag in CaptureHandler::DrawSolidDrag!");
695 // not interested ? ...
696 if(DragManagerOp::CurrentManager
->DragPending
)
698 if(!DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
701 INT32 DragTransparency
= DragManagerOp::CurrentManager
->CurrentDragInfo
->
702 GetDragTransparency();
703 // If the Drag Info says it wants to be transparent,
704 // then call the transparent drag routine.
705 if (DragTransparency
> 0 || m_pMaskBitmap
!= NULL
)
707 if (DrawTransparentDrag(point
, DragTransparency
))
710 // If the Transparency Drag fails (eg. not enough resources under Win32s !!)
711 // then just fall though, and try a normal solid drag .....
714 // offset mouse pos by drag offset
715 point
+= DragManagerOp::CurrentManager
->CurrentDragInfo
->SolidDragOffset
;
717 // size of solid drag draw bounds
718 wxSize DSize
= DragManagerOp::CurrentManager
->CurrentDragInfo
->SolidDragSize
;
720 // create a few DCs !!!
722 // this one will hold the old background
725 // select bitmap into the dc
726 BackDC
.SelectObject(*m_pBackBitmap
);
728 // this one is just temp
729 wxMemoryDC ScratchDC
;
730 wxBitmap
ScratchBit(DSize
.x
, DSize
.y
);
732 // select bitmap into the dc
733 ScratchDC
.SelectObject(ScratchBit
);
735 // make copy of last rect
736 wxRect
OldRect(m_DragRect
);
738 // set new drag draw bounds
739 m_DragRect
= wxRect(point
.x
, point
.y
, DSize
.x
, DSize
.y
);
741 // Copy screen to new background
742 ScratchDC
.Blit(0,0,DSize
.x
,DSize
.y
,m_pDisplayDC
,m_DragRect
.x
,m_DragRect
.y
);
744 wxPoint Change
= OldRect
.GetPosition() - m_DragRect
.GetPosition();
746 // Replace part of new bkg with old background
747 if (!OldRect
.IsEmpty())
748 ScratchDC
.Blit(Change
.x
,Change
.y
,DSize
.x
,DSize
.y
,&BackDC
,0,0);
750 // Copy image to screen
751 DragManagerOp::CurrentManager
->CurrentDragInfo
->
752 OnDrawSolidDrag(m_DragRect
.GetPosition(), m_pDisplayDC
);
754 // Copy part of image to old background
755 DragManagerOp::CurrentManager
->CurrentDragInfo
->
756 OnDrawSolidDrag(wxPoint(-Change
.x
,-Change
.y
), &BackDC
);
758 // Copy old background to screen
759 if (!OldRect
.IsEmpty())
760 m_pDisplayDC
->Blit(OldRect
.x
,OldRect
.y
,DSize
.x
,DSize
.y
,&BackDC
,0,0);
762 // copy new background into old for next time round
763 BackDC
.Blit(0,0,DSize
.x
,DSize
.y
,&ScratchDC
,0,0);
765 // clean up and delete scratch dc and bitmap
766 ScratchDC
.SelectObject(wxNullBitmap
);
768 BackDC
.SelectObject(wxNullBitmap
);
774 /********************************************************************************************
776 > void CaptureHandler::DrawTransparentDrag(wxPoint point)
778 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
781 Purpose: to allow solid flicker-free semi-transparent drag objects to be drawn.
782 a helper function in the current drag is called - but this function
783 looks after the rest.
787 ********************************************************************************************/
789 BOOL
CaptureHandler::DrawTransparentDrag(wxPoint point
, INT32 Transparency
)
791 // TRACEUSER("Gerry", _T("DrawTransparentDrag(%d, %d, %d)"), point.x, point.y, Transparency);
793 // offset mouse pos by drag offset
794 point
+= DragManagerOp::CurrentManager
->CurrentDragInfo
->SolidDragOffset
;
796 // size of solid drag draw bounds
797 wxSize DSize
= DragManagerOp::CurrentManager
->CurrentDragInfo
->SolidDragSize
;
799 // create a few DCs !!!
800 // this one will hold the old background
803 // select bitmap into the dc
804 BackDC
.SelectObject(*m_pBackBitmap
);
806 // this one is just temp
807 wxMemoryDC ScratchDC
;
808 wxBitmap
ScratchBit(DSize
.x
,DSize
.y
);
810 wxBitmap
TempBitmap(DSize
.x
, DSize
.y
);
815 // select bitmap into the dc
816 ScratchDC
.SelectObject(ScratchBit
);
818 // make copy of last rect
819 wxRect OldRect
= m_DragRect
;
821 // set new drag draw bounds
822 m_DragRect
= wxRect(point
.x
,point
.y
,DSize
.x
,DSize
.y
);
824 // Copy screen to new background
825 ScratchDC
.Blit(0,0,DSize
.x
,DSize
.y
,m_pDisplayDC
,m_DragRect
.x
,m_DragRect
.y
);
827 wxPoint Change
= OldRect
.GetPosition() - m_DragRect
.GetPosition();
829 // Replace part of new bkg with old background
830 if (!OldRect
.IsEmpty())
831 ScratchDC
.Blit(Change
.x
,Change
.y
,DSize
.x
,DSize
.y
,&BackDC
,0,0);
833 TempDC
.SelectObject(TempBitmap
);
835 // Render into the temporary bitmap
836 DragManagerOp::CurrentManager
->CurrentDragInfo
->
837 OnDrawSolidDrag(wxPoint(0,0), &TempDC
);
839 // set the colours for the masking
840 // TempDC.SetBkColor(RGB(0,0,0));
841 // TempDC.SetTextColor(RGB(255,255,255));
843 MaskDC
.SelectObject(*m_pMaskBitmap
);
845 TempDC
.Blit(0, 0, DSize
.x
, DSize
.y
, &MaskDC
, 0, 0, wxAND_INVERT
);
847 wxBitmap
OffScreenBmp(DSize
.x
, DSize
.y
);
848 wxMemoryDC OffScreenDC
;
849 OffScreenDC
.SelectObject(OffScreenBmp
);
851 OffScreenDC
.Blit(0, 0, DSize
.x
, DSize
.y
, &ScratchDC
, 0, 0);
853 OffScreenDC
.Blit(0, 0, DSize
.x
, DSize
.y
, &MaskDC
, 0, 0, wxAND
);
855 OffScreenDC
.Blit(0, 0, DSize
.x
, DSize
.y
, &TempDC
, 0, 0, wxOR
);
857 // Copy part of image to old background
858 BackDC
.Blit(-Change
.x
,-Change
.y
, DSize
.x
, DSize
.y
, &OffScreenDC
, 0,0);
860 // Copy image to screen
861 m_pDisplayDC
->Blit(m_DragRect
.x
, m_DragRect
.y
, DSize
.x
, DSize
.y
, &OffScreenDC
, 0, 0);
863 // Copy old background to screen
864 if(!OldRect
.IsEmpty())
865 m_pDisplayDC
->Blit(OldRect
.x
, OldRect
.y
, DSize
.x
, DSize
.y
, &BackDC
, 0, 0);
867 // copy new background into old for next time round
868 BackDC
.Blit(0, 0, DSize
.x
, DSize
.y
, &ScratchDC
, 0, 0);
870 // clean up and delete DCs and bitmaps
871 OffScreenDC
.SelectObject(wxNullBitmap
);
872 TempDC
.SelectObject(wxNullBitmap
);
873 MaskDC
.SelectObject(wxNullBitmap
);
874 ScratchDC
.SelectObject(wxNullBitmap
);
875 BackDC
.SelectObject(wxNullBitmap
);
881 //------------------------------------------------------------------------------------------
883 //------------------------------------------------------------------------------------------
885 // ----------------- STATICS
887 DragManagerOp
*DragManagerOp::CurrentManager
= NULL
;
888 CaptureHandler
*DragManagerOp::TheCaptureHandler
= NULL
;
890 // Drag delay and distance. These are not the suggested OLE-2 default values, because
891 // those values are mindbogglingly dumb (2 pixels, which makes it dead easy to accidentally
892 // start a drag if the mouse wobbles, and 0.2 secs which means any non-fast click
893 // will always be a drag).
894 const UINT32 DEFAULT_DRAGDIST
= 6; // 6 pixel "radius" outside which click becomes drag
895 const UINT32 DEFAULT_DRAGDELAY
= 400; // 400 millisecond (0.4 sec) delay before click=>drag
896 UINT32
DragManagerOp::DragMinDist
= DEFAULT_DRAGDIST
;
897 UINT32
DragManagerOp::DragDelay
= DEFAULT_DRAGDELAY
;
899 MonotonicTime
DragManagerOp::DragStartTimer
;
900 BOOL
DragManagerOp::DragPending
= FALSE
;
901 BOOL
DragManagerOp::DragEnded
= FALSE
;
902 BOOL
DragManagerOp::DragActive
= FALSE
;
904 wxRect
DragManagerOp::DragStartRect
;
905 wxRect
DragManagerOp::StillClickRect
;
907 BOOL
DragManagerOp::RedrawInProgress
= FALSE
;
909 UINT32
DragManagerOp::StatusLineStringID
= 0;
911 DragInformation
* DragManagerOp::CurrentDragInfo
= NULL
; // Descriptor of current drag
912 DragTarget
* DragManagerOp::CurrentDragTarget
= NULL
; // Current drag target
916 /********************************************************************************************
918 > DragManagerOp::DragManagerOp()
920 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
923 Purpose: DragManagerOp constructor - DO NOT CALL THE DEFAULT CONSTRUCTOR!
925 ********************************************************************************************/
927 DragManagerOp::DragManagerOp()
929 ERROR3("DragManagerOp::DragManagerOp - Illegal (default) constructor called!\n");
931 ERROR3IF(CurrentManager
!= NULL
, "Attempt to start a drag while already dragging!");
932 CurrentManager
= this;
935 CurrentCursor
= NULL
;
940 /********************************************************************************************
942 > DragManagerOp::DragManagerOp(DragInformation *Descriptor)
944 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
947 Inputs: Descriptor - Describes the current drag. May not be NULL.
949 Purpose: DragManagerOp constructor
951 ********************************************************************************************/
953 DragManagerOp::DragManagerOp(DragInformation
*Descriptor
)
955 ERROR3IF(Descriptor
== NULL
, "DragManagerOp must be given a valid DragInformation ptr");
956 ERROR3IF(CurrentManager
!= NULL
, "Attempt to start a drag while already dragging!");
959 CurrentManager
= this;
960 CurrentDragInfo
= Descriptor
;
962 CurrentKeypress
= NULL
;
967 CurrentCursor
= NULL
;
969 // get system drag start values. We override the default values suggested by the
970 // OLE2 docs, because their values are stupid. (2 pixels? Bleedin' heck! I wish MY
971 // mouse was that steady!). However, we red the values from Win.INI like good boys, so
972 // the user can override them if they so desire.
973 // DragMinDist = GetProfileInt("windows", "DragMinDist", DEFAULT_DRAGDIST);
974 // DragDelay = GetProfileInt("windows", "DragDelay", DEFAULT_DRAGDELAY);
976 DragMinDist
= DEFAULT_DRAGDIST
;
977 DragDelay
= DEFAULT_DRAGDELAY
;
979 DragStartRect
= wxRect();
984 /********************************************************************************************
986 > DragManagerOp::~DragManagerOp()
988 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
991 Purpose: DragManagerOp destructor
993 ********************************************************************************************/
995 DragManagerOp::~DragManagerOp()
997 // Ensure all memory allocations are deleted
1000 // We are no longer the current drag manager
1001 CurrentManager
= NULL
;
1005 StatusLineStringID
= 0;
1008 delete CurrentCursor
;
1013 /********************************************************************************************
1015 > static CPoint DragManagerOp::GetDragMousePos()
1017 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1020 Purpose: return a CPoint for the Last Mouse Position
1022 ********************************************************************************************/
1024 wxPoint
DragManagerOp::GetDragMousePos()
1028 if( CurrentManager
!= NULL
)
1029 MPos
= CurrentManager
->CurrentMousePos
;
1034 /********************************************************************************************
1036 > static CaptureHandler * DragManagerOp::GetDragCaptureHandler()
1038 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1041 Purpose: return the capture handler
1043 ********************************************************************************************/
1045 CaptureHandler
*DragManagerOp::GetDragCaptureHandler()
1047 if( CurrentManager
== NULL
)
1050 return TheCaptureHandler
;
1053 /********************************************************************************************
1055 > static CaptureWnd * DragManagerOp::GetCurrentDragInfo()
1057 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1060 Purpose: return Current drag information
1062 ********************************************************************************************/
1064 DragInformation
* DragManagerOp::GetCurrentDragInfo()
1066 if( CurrentManager
== NULL
)
1069 return CurrentDragInfo
;
1075 /********************************************************************************************
1077 > static void DragManagerOp::StartDrag(DragInformation *Descriptor, CWindowID DragWindow)
1079 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1082 Inputs: Descriptor - A DragInformation object describing the current drag.
1083 NOTE WELL that this is given to the DragManager, who is then responsible
1084 for deleting it when the drag completes. DO NOT DELETE IT!
1085 DragWindow - The window that is starting the drag.
1086 NOTE: For correct operation under wxGTK this must be the window that
1087 received the button down event that started this drag
1089 Purpose: Starts a global-drag off
1090 This will create a new DragManagerOp object, set up the drag, and
1091 broadcast a DragMsg DRAGSTARTED, as a result of which, DragTargets
1092 should be created by interested parties (these will register with the
1093 Drag Manager, and then be called to handle events during the drag)
1095 ********************************************************************************************/
1097 void DragManagerOp::StartDrag(DragInformation
*Descriptor
, CWindowID DragWindow
)
1099 if (Descriptor
== NULL
)
1101 // Handle a NULL pointer by just not starting up the drag
1102 TRACE( _T("NULL Descriptor given to DragManagerOp::StartDrag()\n"));
1106 ERROR3IF(Descriptor
== NULL
, "DragManagerOp must be given a valid DragInformation ptr");
1108 DragManagerOp
* pNewManager
= new DragManagerOp(Descriptor
);
1110 if (Descriptor
->IsAdjustDrag
) // Adjust drags just immediately become clicks
1112 DragPending
= TRUE
; // Make sure it turns into a click properly (see EndDrag)
1113 if (pNewManager
!= NULL
)
1115 pNewManager
->CurrentMousePos
= wxGetMousePosition();
1116 pNewManager
->InitialMousePos
= pNewManager
->LastMousePos
= pNewManager
->CurrentMousePos
;
1123 if (pNewManager
!= NULL
)
1125 // Attach the CaptureHandler to the correct window
1126 wxWindow
* pWindow
= (wxWindow
*)DragWindow
;
1127 if (pWindow
== NULL
)
1128 pWindow
= GetMainFrame();
1130 TheCaptureHandler
= new CaptureHandler(pWindow
);
1131 if (TheCaptureHandler
!= NULL
)
1135 // Remember where the mouse is at the start of the drag
1136 pNewManager
->CurrentMousePos
= wxGetMousePosition();
1137 pNewManager
->InitialMousePos
= pNewManager
->LastMousePos
= pNewManager
->CurrentMousePos
;
1139 // Request that all interested parties attach DragTargets now
1140 BROADCAST_TO_ALL(DragMessage(DragMessage::DRAGSTARTED
, pNewManager
, Descriptor
));
1142 // views don't receive messages so we'll have to do this the hard way..
1143 // App->Document->View...
1144 GetApplication()->CreateDragTargets(Descriptor
);
1146 // Send an Initialise event to all registered targets
1148 // Forget this - drags with no targets are perfectly legal - see colour picker
1151 if (pNewManager
->Targets
.IsEmpty())
1152 TRACE( _T("DragManagerOp::StartDrag - No drag targets specified for this drag!"));
1155 pNewManager
->ProcessEvent(DRAGEVENT_INITIALISE
);
1157 // Start the mouse capture
1158 TheCaptureHandler
->StartCapture();
1160 // Register for idle events
1161 GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_HIGH
, pNewManager
);
1163 // get drag start time
1164 DragStartTimer
.Sample();
1166 // we will use this rect to test whether we have started a drag
1167 StillClickRect
= wxRect( pNewManager
->InitialMousePos
.x
- DragMinDist
,
1168 pNewManager
->InitialMousePos
.y
- DragMinDist
,
1171 SetDragActive(TRUE
);
1174 GetMainFrame()->SetFocus();
1179 /********************************************************************************************
1181 > static void DragManagerOp::EndDrag(INT32 Flags)
1183 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1186 Input : Flags : mouse button state( 1=leftclick/-1= rightclick )
1188 ********************************************************************************************/
1190 void DragManagerOp::EndDrag(INT32 Flags
)
1196 if (TheCaptureHandler
!= NULL
)
1198 TheCaptureHandler
->CleanUpSolidDrag();
1201 if(DragPending
) // not a drag - user intended a click
1203 // call the click handler in the drag
1205 StartMouse
.x
= CurrentManager
->InitialMousePos
.x
;
1206 StartMouse
.y
= CurrentManager
->InitialMousePos
.y
;
1207 CurrentManager
->CurrentDragInfo
->OnClick(Flags
,StartMouse
);
1209 else // this is a genuine end of drag
1211 // Update the mouse position, so we give the event to the correct target
1212 CurrentManager
->LastMousePos
= CurrentManager
->CurrentMousePos
;
1213 CurrentManager
->CurrentMousePos
= wxGetMousePosition();
1215 // Process the drag completion event
1216 DragEventType Event
= DRAGEVENT_COMPLETED
;
1217 CurrentManager
->ProcessEvent(Event
);
1219 // make sure we don't get any idles after the drag has finished
1223 // Let all drag targets know that the drag is well and truly dead
1225 CurrentManager
->ProcessEvent(DRAGEVENT_DEINITIALISE
);
1227 SetDragActive(FALSE
);
1231 CurrentManager
->End();
1235 /********************************************************************************************
1237 > static void DragManagerOp::AbortDrag(void)
1239 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1242 Purpose: To forcibly abort the current drag. If there is no current drag, then
1243 nothing happens (so it can be called just to ensure that no drag is
1244 left current on exit for example)
1246 ********************************************************************************************/
1248 void DragManagerOp::AbortDrag(void)
1250 if (CurrentManager
!= NULL
)
1252 CurrentManager
->LastMousePos
= CurrentManager
->CurrentMousePos
;
1253 CurrentManager
->CurrentMousePos
= wxGetMousePosition();
1255 if (TheCaptureHandler
!= NULL
)
1256 TheCaptureHandler
->CleanUpSolidDrag();
1258 CurrentManager
->ProcessEvent(DRAGEVENT_ABORT
);
1260 // Let all drag targets know that the drag is well and truly dead
1261 CurrentManager
->ProcessEvent(DRAGEVENT_DEINITIALISE
);
1263 CurrentManager
->End();
1266 SetDragActive(FALSE
);
1271 /********************************************************************************************
1273 > static DragManagerOp *DragManagerOp::GetCurrentManager(void)
1275 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1278 Returns: NULL (if no current drag), or a pointer to the current DragManagerOp
1280 Purpose: To find the current drag manager
1282 ********************************************************************************************/
1284 DragManagerOp
*DragManagerOp::GetCurrentManager(void)
1286 return(CurrentManager
);
1291 /********************************************************************************************
1293 > virtual BOOL DragManagerOp::ProcessEvent(DragEventType Event)
1295 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1298 Inputs: Event - Indicates what type of Drag Event is occurring
1300 Returns: TRUE if a DragTarget claimed the event
1302 Purpose: To process global drag events
1303 This method calls each DragTarget event processor in turn (until one
1304 claims the event), with the event. The 3 'Current' member variables are
1305 passed in to the event processor, so ensure they are set up appropriately
1306 before calling this method.
1308 Notes: DragTargets can safely de-register themselves during processing of the
1309 events (i.e. the list traversal code won't get upset)
1311 When calling a kernel target which includes both a dialogue ID and a gadget,
1312 the coordinates passed into the event handler are millipoint offsets from
1313 the bottom left corner of the gadget, just as with normal kernel-rendered
1314 gadgets. Note that the event will not be passed to the gadget unless the
1315 mouse pointer is over the gadget window. If no gadget is specified, then
1316 the mouse coordinates will always be (0,0) at present.
1318 The INITIALISE and DEINITIALISE events are broadcast to all active targets,
1319 while all other events are broadcast only to general (no target window)
1320 targets, and the target (if any) over which the mouse pointer lies.
1322 SeeAlso: keyword DragEventType
1323 SeeAlso: DragTarget::ProcessEvent
1325 ********************************************************************************************/
1327 BOOL
DragManagerOp::ProcessEvent(DragEventType Event
)
1329 BOOL BroadcastToAll
= FALSE
; // Determine if the event goes to everybody or
1330 // only to target under the pointer
1331 if (Event
== DRAGEVENT_INITIALISE
|| Event
== DRAGEVENT_DEINITIALISE
)
1332 BroadcastToAll
= TRUE
;
1334 if(CurrentManager
== NULL
|| (DragEnded
&& Event
!= DRAGEVENT_DEINITIALISE
))
1337 LastEvent
= Event
; // Remember the type of the last event we processed
1339 DragTarget
*Ptr
= (DragTarget
*) Targets
.GetHead();
1342 OilCoord
KernelMousePos(0,0);
1343 wxPoint
WinoilMousePos(CurrentMousePos
);
1344 CurrentDragTarget
= NULL
;
1345 BOOL OverTarget
= FALSE
;
1347 // TRACEUSER("Gerry", _T("ProcessEvent = (%d, %d)"), WinoilMousePos.x, WinoilMousePos.y);
1351 // Copy the mouse position, as each iteration of the loop corrupts it
1352 WinoilMousePos
= CurrentMousePos
;
1354 // Allow things like targets de-registering during processing
1355 Next
= (DragTarget
*) Targets
.GetNext(Ptr
);
1356 BOOL GoAhead
= TRUE
;
1358 if (Ptr
->IsAKernelObject())
1360 KernelMousePos
= OilCoord(0,0);
1362 DialogOp
*pDialogOp
;
1364 Ptr
->GetTargetAreaInfo(&pDialogOp
, &GadgetID
);
1366 if (pDialogOp
!= NULL
)
1368 wxWindow
* TargetWindow
= (wxWindow
*)pDialogOp
->WindowID
; // use whole window if no gadget specified
1371 TargetWindow
= TargetWindow
->FindWindow((INT32
)GadgetID
);
1373 // We want to do the following. But it doesn't work because GetRect() is relative to the
1374 // parent window when TargetWindow is not a TLW. What we need is (consistently) screen
1377 // TRACEUSER("Gerry", _T("KernelTargetWindow = %s"), TargetWindow->GetClassInfo()->GetClassName());
1378 wxRect TargetRect
= TargetWindow
->GetRect();
1379 // TRACEUSER("Gerry", _T("TargetRect = (%d, %d) [%d, %d]"), TargetRect.x, TargetRect.y, TargetRect.width, TargetRect.height);
1380 if (TargetWindow
->GetParent() && !TargetWindow
->IsTopLevel())
1382 TargetWindow
->GetParent()->ClientToScreen(&TargetRect
.x
, &TargetRect
.y
);
1383 // TRACEUSER("Gerry", _T("TargetRect = (%d, %d) [%d, %d]"), TargetRect.x, TargetRect.y, TargetRect.width, TargetRect.height);
1386 // TRACEUSER("Gerry", _T("Point is %sinside"), TargetRect.Inside(WinoilMousePos) ? _T("") : _T("not "));
1388 if (BroadcastToAll
|| Ptr
->WantsAllEvents() ||
1389 TargetRect
.Inside(WinoilMousePos
))
1391 // Determine if the pointer is over the target window, or any of its children
1392 wxWindow
* WindowUnderPoint
= wxChildWindowFromPoint(WinoilMousePos
, false, -1);
1393 BOOL AreOverTargetWnd
= (WindowUnderPoint
== TargetWindow
);
1395 if (!AreOverTargetWnd
)
1397 // We're not immediately over the background of the window, but may be over
1398 // a child-window of our window! The subtlety here is that wxChildWindowFromPoint may have
1399 // failed because another window is on top (in the way). So we also check the child window
1400 // of the target window which is under the mousepointer is also the window which is
1401 // under the mouse pointner
1402 wxWindow
* ChildWindowUnderPoint
= ::wxChildWindowFromPoint(TargetWindow
, WinoilMousePos
, false, -1);
1403 AreOverTargetWnd
= (ChildWindowUnderPoint
!= NULL
&&
1404 ChildWindowUnderPoint
== WindowUnderPoint
);
1407 if (BroadcastToAll
|| Ptr
->WantsAllEvents() || AreOverTargetWnd
)
1410 wxSize ppi
= OSRenderRegion::GetFixedDCPPI(dc
);
1412 KernelMousePos
.x
= ((WinoilMousePos
.x
- TargetRect
.GetLeft()) * 72000) / ppi
.GetWidth();
1413 // CHECKRECT: This may need to be the exclusive bottom coord
1414 KernelMousePos
.y
= ((TargetRect
.GetBottom() - WinoilMousePos
.y
) * 72000) / ppi
.GetHeight();
1423 // TRACEUSER("Gerry", _T("%s"), GoAhead ? _T("Process") : _T("Skipping"));
1426 Ptr
->ProcessEvent(Event
, CurrentDragInfo
, &KernelMousePos
, CurrentKeypress
))
1428 CurrentDragTarget
= Ptr
;
1429 OverTarget
= TRUE
; // This Target claimed the event, so return TRUE
1431 if (!BroadcastToAll
)
1437 wxWindow
* TargetWindow
;
1439 Ptr
->GetTargetAreaInfo(&TargetWindow
, &TargetRect
);
1443 TRACEUSER("Gerry", _T("OilTargetWindow = %s"), TargetWindow
->GetClassInfo()->GetClassName());
1444 TRACEUSER("Gerry", _T("TargetRect = (%d, %d) [%d, %d]"), TargetRect
.x
, TargetRect
.y
, TargetRect
.width
, TargetRect
.height
);
1448 TRACEUSER("Gerry", _T("OilTargetWindow = <NONE>"));
1451 wxPoint ClientPoint
; // This will be screen coords, or will end up as
1452 ClientPoint
.x
= WinoilMousePos
.x
; // client coords if we have a window...
1453 ClientPoint
.y
= WinoilMousePos
.y
;
1455 if (TargetWindow
!= NULL
)
1457 // Get the mouse position in client coords
1458 ClientPoint
= TargetWindow
->ScreenToClient(ClientPoint
);
1460 // Don't bother giving the event to targets which don't contain the pointer
1461 if (BroadcastToAll
|| Ptr
->WantsAllEvents() ||
1462 TargetRect
.Inside(ClientPoint
))
1464 // Don't give the event to oil targets unless the pointer is over the
1465 // window (ie dont pass on events to overlapped windows) unless we want
1466 // to broadcast to all, or this target really wants to know!
1468 wxWindow
* WindowUnderPoint
= ::wxChildWindowFromPoint(WinoilMousePos
, false, -1);
1469 // TRACEUSER("Gerry", _T("WindowUnderPoint = 0x%08x (%s)"), WindowUnderPoint, WindowUnderPoint ? WindowUnderPoint->GetClassInfo()->GetClassName() : _T("null"));
1470 if (WindowUnderPoint
)
1472 // TRACEUSER("Gerry", _T("Title = %s"), WindowUnderPoint->GetTitle().c_str());
1475 BOOL AreOverTargetWnd
= (WindowUnderPoint
== TargetWindow
);
1476 // TRACEUSER("Gerry", _T("Point is %sover target window"), AreOverTargetWnd ? _T("") : _T("not "));
1478 if (!AreOverTargetWnd
)
1480 // We're not immediately over the background of the window, but may be over
1481 // a child-window of our window! The subtlety here is that wxChildWindowFromPoint may have
1482 // failed because another window is on top (in the way). So we also check the child window
1483 // of the target window which is under the mousepointer is also the window which is
1484 // under the mouse pointner
1485 wxWindow
* ChildWindowUnderPoint
= ::wxChildWindowFromPoint(TargetWindow
, WinoilMousePos
, false, -1);
1486 // TRACEUSER("Gerry", _T("ChildFromPoint = 0x%08x (%s)"), ChildWindowUnderPoint, ChildWindowUnderPoint ? ChildWindowUnderPoint->GetClassInfo()->GetClassName() : _T("null"));
1487 AreOverTargetWnd
= (ChildWindowUnderPoint
!= NULL
&&
1488 ChildWindowUnderPoint
== WindowUnderPoint
);
1490 // TRACEUSER("Gerry", _T("Point is %sover child of target window"), AreOverTargetWnd ? _T("") : _T("not "));
1493 if (!BroadcastToAll
&& !Ptr
->WantsAllEvents() && !AreOverTargetWnd
)
1502 // TRACEUSER("Gerry", _T("%s"), GoAhead ? _T("Process") : _T("Skipping"));
1504 // we are in a target area, or this is a broadcast-to-all, so send the event
1507 wxPoint
PointInWindow(ClientPoint
); // "Cast" to wxPoint
1509 if (Ptr
->ProcessEvent(Event
, CurrentDragInfo
, &PointInWindow
, CurrentKeypress
))
1511 CurrentDragTarget
= Ptr
;
1512 OverTarget
= TRUE
; // This Target claimed the event, so return TRUE
1514 if (!BroadcastToAll
)
1523 if (!DragPending
&& Event
!= DRAGEVENT_COMPLETED
)
1525 SetStatusLineText();
1529 return OverTarget
; // Return status to indicate wheteher or not the event was claimed
1534 /********************************************************************************************
1536 > virtual BOOL DragManagerOp::OnIdleEvent(void)
1538 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> & Chris
1541 Returns: TRUE if it does not want low-priority idle handlers to be called this time
1542 FALSE if it's OK to call low-priority idles (i.e. if I'm not busy this turn)
1544 Purpose: To process idle events. If the mouse hasn't moved, then we'll allow low
1545 priority handlers a look-in. This means that (e.g.) when dragging background-
1546 redrawing galleries, we get instant response while dragging, and the
1547 background redraw will only occur while the mouse is held still.
1549 ********************************************************************************************/
1551 BOOL
DragManagerOp::OnIdleEvent(void)
1553 LastMousePos
= CurrentMousePos
;
1554 CurrentMousePos
= wxGetMousePosition();
1557 return(FALSE
); // Done nothing, so let low-priority handlers have a go
1559 BOOL JustStartedDrag
= FALSE
;
1561 // We have received a start drag message but we are not sure whether this is the real
1565 // We start a drag if DragDelay milliseconds have elapsed
1566 // or the pointer has left DragStartRect
1567 if (!DragStartTimer
.Elapsed(DragDelay
) &&
1568 StillClickRect
.Inside(CurrentMousePos
))
1570 // The drag is still pending
1571 return(FALSE
); // Done nothing, so let low-priority handlers have a go
1574 DragPending
= FALSE
;
1575 JustStartedDrag
= TRUE
; // Flag that we have "just turned on" the drag
1577 TheCaptureHandler
->SetUpSolidDrag(CurrentMousePos
);
1580 // Determine what event type to send around...
1581 DragEventType Event
= DRAGEVENT_MOUSEIDLE
;
1582 if (LastMousePos
== CurrentMousePos
)
1584 if (LastEvent
== DRAGEVENT_MOUSESTOPPED
|| LastEvent
== DRAGEVENT_MOUSEIDLE
)
1586 // The mouse has not moved for a while, so send another idle
1587 Event
= DRAGEVENT_MOUSEIDLE
;
1591 // The mouse has only just stopped moving, so send a mouse-stopped
1592 Event
= DRAGEVENT_MOUSESTOPPED
;
1597 // The mouse has moved since we last checked, so send a mouse-moved
1598 Event
= DRAGEVENT_MOUSEMOVED
;
1601 // If the mouse moved, then we will not allow low-priority idle processors to have a go
1602 // this time around, for maximum mouse-move interactiveness.
1603 BOOL ClaimTheIdle
= (Event
== DRAGEVENT_MOUSEMOVED
);
1605 // **** !!!! ToDo: This could be considered bodgy and nasty, mostly because it is.
1607 // ToDo: Somehow detect if the drag has ended? A bodge I know, but we wanna compile
1608 // this and see if it works!
1610 if (KeyPress::IsEscapePressed()) // If escape (or equivalent) pressed, abort the drag
1613 return(FALSE
); // Let low-priority handlers have a go
1618 ProcessEvent(Event
); // Pass the event around all registered DragTargets
1621 /* On the first update, the mouse may not have moved, so we need to pop up the
1622 solid drag stuff. Unfortunately, this doesn't work quite right and I don't
1623 have time to deal with it right now.
1625 if (!DragEnded && JustStartedDrag)
1627 // The mouse may not have moved, but we have just 'turned on' the drag - we'd
1628 // better ensure that the solid drag stuff is drawn onto screen for the fist time
1630 if (TheCaptureWindow != NULL)
1632 CPoint PointInCaptureWnd(CurrentMousePos);
1634 // Convert the current mouse coordinate into capture window client coords,
1635 // and call it to update the solid drag
1636 TheCaptureWindow->ScreenToClient(&PointInCaptureWnd);
1637 TheCaptureWindow->DrawSolidDrag(PointInCaptureWnd);
1643 return(ClaimTheIdle
); // Return, allowing or not-allowing low-priority handlers to have a go
1644 // depending on whether the mouse moved or not.
1649 /********************************************************************************************
1651 > void DragManagerOp::RegisterTarget(DragTarget *NewTarget, BOOL HighPriority = FALSE)
1653 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1656 Inputs: NewTarget - points at the DragTarget object to add. NOTE that from this
1657 time on, the manager owns the target, and it will delete it when the drag
1658 completes. However, the caller may delete the target at any time, in which
1659 case it will automatically deregister itself before it dies.
1661 HighPriority - TRUE to place the target on the front of the target list,
1662 FALSE to place it on the end. (Targets are called in list order to handle
1663 events, so one on the front of the list has higher priority...)
1665 Purpose: To register a Drag Target with the current Drag Manager
1666 This method is automatically called by DragTargets when they are
1667 constructed, and is only available to frined classes.
1669 Notes: A drag target object can be registered several times, in which case it will
1670 be placed on the list several times. Not that this should happen...
1672 Scope: protected (for friend class DragTarget only)
1674 ********************************************************************************************/
1676 void DragManagerOp::RegisterTarget(DragTarget
*NewTarget
, BOOL HighPriority
)
1678 ERROR3IF(NewTarget
== NULL
,
1679 "DragManagerOp::RegisterTarget - NULL Target parameter is illegal");
1682 Targets
.AddHead(NewTarget
);
1684 Targets
.AddTail(NewTarget
);
1689 /********************************************************************************************
1691 > void DragManagerOp::DeregisterTarget(DragTarget *OldTarget)
1693 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1696 Inputs: OldTarget - points at the DragTarget object to remove
1698 Purpose: To register a Drag Target with the current Drag Manager
1699 This method is automatically called by DragTargets when they are
1700 constructed, and is only available to frined classes.
1702 Notes: Copes with a drag target being registered several times.
1704 Scope: protected (for friend class DragTarget only)
1706 ********************************************************************************************/
1708 void DragManagerOp::DeregisterTarget(DragTarget
*OldTarget
)
1710 DragTarget
*Ptr
= (DragTarget
*) Targets
.GetHead();
1715 Next
= (DragTarget
*) Targets
.GetNext(Ptr
);
1717 if (Ptr
== OldTarget
)
1719 Targets
.RemoveItem(Ptr
);
1729 /********************************************************************************************
1731 > void DragManagerOp::CleanUpAfterDrag(void)
1733 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1736 Purpose: Generic clean-up method. Deletes all registered DragTargets, and any
1737 other information (DragInformation, last keypress info, etc) which is
1738 still lying about in the DragManagerOp.
1739 Also deregisters our idle event handlers etc.
1740 Used by destructor, and also by all forms of Drag completion to free
1741 our memory claims, etc.
1745 ********************************************************************************************/
1747 void DragManagerOp::CleanUpAfterDrag(void)
1749 TRACEUSER("Gerry", _T("DragManagerOp::CleanUpAfterDrag"));
1751 GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_HIGH
, this);
1753 if (TheCaptureHandler
!= NULL
)
1755 TRACEUSER("Gerry", _T("Deleting TheCaptureHandler"));
1756 // Simply delete the CaptureHandler and it will detach itself
1757 delete TheCaptureHandler
;
1758 TheCaptureHandler
= NULL
;
1761 if (CurrentDragInfo
!= NULL
)
1763 delete CurrentDragInfo
;
1764 CurrentDragInfo
= NULL
;
1767 if (CurrentKeypress
!= NULL
)
1769 delete CurrentKeypress
;
1770 CurrentKeypress
= NULL
;
1773 // Delete all entries from the list. We do it this way to ensure that we don't try
1774 // to destruct the same target multiple times if it registered multiple times
1775 while (!Targets
.IsEmpty())
1776 DeregisterTarget((DragTarget
*) Targets
.GetHead());
1781 /********************************************************************************************
1783 > void DragManagerOp::SetCursor()
1785 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1788 Purpose: Set the cursor !
1790 ********************************************************************************************/
1792 void DragManagerOp::SetCursor()
1796 // are we over a target ??
1797 if(CurrentDragTarget
== NULL
)
1798 CursorID
= CurrentDragInfo
->GetCursorID(); // nope
1800 CursorID
= CurrentDragTarget
->GetCursorID(); // yep
1802 // the target does not want to change the cursor
1806 if(CurrentManager
->CurrentID
!= CursorID
) // nothing to change
1808 if(CurrentManager
->CurrentCursor
) // delete the old
1810 delete CurrentManager
->CurrentCursor
;
1811 CurrentManager
->CurrentCursor
= NULL
;
1813 if(CurrentManager
->CurrentCursor
==NULL
)
1815 CurrentManager
->CurrentCursor
= new Cursor(CursorID
); // create the new
1816 if (CurrentManager
->CurrentCursor
)
1817 CurrentManager
->CurrentCursor
->SetActive(); // make the active cursor
1820 CurrentManager
->CurrentID
= CursorID
;
1825 /********************************************************************************************
1827 > void DragManagerOp::SetStatusLineText()
1829 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1832 Purpose: Write Status line help
1834 ********************************************************************************************/
1836 void DragManagerOp::SetStatusLineText()
1838 String_256 StatusText
;
1839 if(CurrentDragTarget
==NULL
) //we are not over a target
1840 { // get the drag status text
1842 if(CurrentDragInfo
->GetStatusLineText(&StatusText
))
1843 GetApplication()->UpdateStatusBarText(&StatusText
,FALSE
);
1846 { // get the target status text
1847 if(CurrentDragTarget
->GetStatusLineText(&StatusText
))
1848 GetApplication()->UpdateStatusBarText(&StatusText
,FALSE
);
1855 /********************************************************************************************
1857 > virtual BOOL DragManagerOp::GetStatusText(String_256 * StatusText)
1859 Author: Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
1863 Returns: TRUE if the buffer is valid FALSE otherwise
1864 Purpose: put status text in a buffer
1868 ********************************************************************************************/
1870 BOOL
DragManagerOp::GetStatusText(String_256
* StatusText
)
1872 ERROR2IF(StatusText
==NULL
,FALSE
,"DragManagerOp::GetStatusLineText() - StatusText==NULL!");
1875 if(CurrentDragTarget
)
1877 if(CurrentDragInfo
->GetStatusLineText(&Text
))
1878 * StatusText
= Text
;
1884 if(CurrentDragTarget
->GetStatusLineText(&Text
))
1885 * StatusText
= Text
;
1896 /********************************************************************************************
1898 > void DragManagerOp::RedrawStarting()
1900 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
1903 Purpose: Tell the drag manager that an external redraw has started.
1904 This allows it to remove its solid drag stuff so that the screen display is
1905 not screwed up. You should also call RedrawFinished when you finish redrawing
1907 Notes: If you are redrawing in a particular window & gadget, see the other variant
1908 of this method, which will reduce solid-drag flicker.
1910 SeeAlso: DragManagerOp::RedrawFinished()
1912 ********************************************************************************************/
1914 void DragManagerOp::RedrawStarting()
1916 if (RedrawInProgress
)
1919 RedrawInProgress
= TRUE
;
1921 if (DragManagerOp::CurrentManager
&&
1922 DragManagerOp::CurrentManager
->CurrentDragInfo
&&
1923 DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
1925 DragManagerOp::CurrentManager
->TheCaptureHandler
->CleanUpSolidDrag();
1931 /********************************************************************************************
1933 > static void DragManagerOp::RedrawStarting(CWindowID TheWindow, CGadgetID TheGadget,
1934 DocRect *TheArea = NULL)
1936 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
1939 Inputs: TheWindow - The CWindowID of your DialogOp
1940 TheGadget - The Gadget ID of the gadget being redrawn
1941 TheArea - A kernel-rendered dialogue rectangle (MILLIPOINTS) which is being
1942 redrawn. If NULL, the entire gadget is assumed. NOTE that this is clipped
1943 within the gadget bounds, so may be outside the 'visible area' of the gadget
1947 Purpose: Tell the drag manager that an external redraw has started, within a specific
1950 This allows it to remove its solid drag stuff so that the screen display is
1951 not screwed up. You should also call RedrawFinished when you finish redrawing
1953 This call specifies a particular gadget that is redrawing - if this doesn't
1954 overlap the solid drag area, then nothing will be done - this will reduce
1955 flicker if you're background redrawing while a drag is going on.
1957 SeeAlso: DragManagerOp::RedrawFinished()
1959 ********************************************************************************************/
1961 void DragManagerOp::RedrawStarting(CWindowID TheWindow
, CGadgetID TheGadget
, DocRect
*TheArea
)
1963 if (RedrawInProgress
)
1966 if (DragManagerOp::CurrentManager
&&
1967 DragManagerOp::CurrentManager
->CurrentDragInfo
&&
1968 DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
1970 wxWindow
* pWindow
= (wxWindow
*)TheWindow
;
1971 wxWindow
* pGadget
= pWindow
->FindWindow((INT32
)TheGadget
);
1972 if (pGadget
!= NULL
)
1974 wxRect AreaClientRect
;
1976 if (TheArea
!= NULL
)
1978 ReDrawInfoType DlgInfo
;
1979 DialogManager::GetKernelRenderedGadgetInfo(TheWindow
, TheGadget
, &DlgInfo
);
1981 INT32 PixelSize
= 72000 / DlgInfo
.Dpi
; // Size of a pixel in MILLIPOINTS
1982 AreaClientRect
.x
= TheArea
->lo
.x
/ PixelSize
;
1983 AreaClientRect
.y
= TheArea
->hi
.x
/ PixelSize
;
1984 AreaClientRect
.width
= TheArea
->Width() / PixelSize
;
1985 AreaClientRect
.height
= TheArea
->Height() / PixelSize
;
1988 AreaClientRect
= pGadget
->GetClientRect();
1990 ClientRect
= pGadget
->GetClientRect();
1992 wxRect
ScreenRect(ClientRect
);
1994 // Get the intersection of the rects (clip the redrawing area within the window)
1995 if (!ScreenRect
.Intersect(AreaClientRect
).IsEmpty())
1997 // Convert the client coordinates to screen coords, and tell the drag capture window
1998 // to get it's solid drag stuff out of the way
1999 pGadget
->ClientToScreen(&ScreenRect
.x
, &ScreenRect
.y
);
2001 RedrawInProgress
= DragManagerOp::CurrentManager
->TheCaptureHandler
->
2002 CleanUpSolidDragInScreenArea(ScreenRect
);
2005 RedrawInProgress
= FALSE
;
2009 // We failed to get the window area, so we'll have to clean up just in case
2010 DragManagerOp::CurrentManager
->TheCaptureHandler
->CleanUpSolidDrag();
2011 RedrawInProgress
= TRUE
;
2017 /********************************************************************************************
2019 > void DragManagerOp::RedrawFinished()
2021 Author: Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
2024 Purpose: Tell the drag manager that an external redraw has finished.
2026 ********************************************************************************************/
2028 void DragManagerOp::RedrawFinished()
2030 if (!RedrawInProgress
)
2033 RedrawInProgress
= FALSE
;
2035 if (DragManagerOp::CurrentManager
&&
2036 DragManagerOp::CurrentManager
->CurrentDragInfo
&&
2037 DragManagerOp::CurrentManager
->CurrentDragInfo
->DoesSolidDrag
)
2039 wxPoint LastMousePos
= DragManagerOp::CurrentManager
->GetDragMousePos();
2040 DragManagerOp::CurrentManager
->TheCaptureHandler
->SetUpSolidDrag(LastMousePos
);