1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxDragImage sample 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx/wx.h". 
  13 #include "wx/wxprec.h" 
  25 // Under Windows, change this to 1 
  26 // to use wxGenericDragImage 
  28 #define wxUSE_GENERIC_DRAGIMAGE 1 
  30 #if wxUSE_GENERIC_DRAGIMAGE 
  31 #include "wx/generic/dragimgg.h" 
  32 #define wxDragImage wxGenericDragImage 
  34 #include "wx/dragimag.h" 
  39 #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__) 
  40 #include "mondrian.xpm" 
  41 #include "dragicon.xpm" 
  50 IMPLEMENT_CLASS(MyCanvas
, wxScrolledWindow
) 
  52 BEGIN_EVENT_TABLE(MyCanvas
, wxScrolledWindow
) 
  53   EVT_PAINT(MyCanvas::OnPaint
) 
  54   EVT_ERASE_BACKGROUND(MyCanvas::OnEraseBackground
) 
  55   EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent
) 
  58 MyCanvas::MyCanvas( wxWindow 
*parent
, wxWindowID id
, 
  59                     const wxPoint 
&pos
, const wxSize 
&size 
) 
  60         : wxScrolledWindow( parent
, id
, pos
, size
, wxSUNKEN_BORDER 
) 
  62     SetBackgroundColour(* wxWHITE
); 
  64     SetCursor(wxCursor(wxCURSOR_ARROW
)); 
  66     m_dragMode 
= TEST_DRAG_NONE
; 
  67     m_draggedShape 
= (DragShape
*) NULL
; 
  68     m_dragImage 
= (wxDragImage
*) NULL
; 
  69     m_currentlyHighlighted 
= (DragShape
*) NULL
; 
  80 void MyCanvas::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
  88 void MyCanvas::OnEraseBackground(wxEraseEvent
& event
) 
  90     if (wxGetApp().GetBackgroundBitmap().Ok()) 
  92         wxSize sz 
= GetClientSize(); 
  93         wxRect 
rect(0, 0, sz
.x
, sz
.y
); 
  97             wxGetApp().TileBitmap(rect
, *(event
.GetDC()), wxGetApp().GetBackgroundBitmap()); 
 102             wxGetApp().TileBitmap(rect
, dc
, wxGetApp().GetBackgroundBitmap()); 
 106         event
.Skip(); // The official way of doing it 
 109 void MyCanvas::OnMouseEvent(wxMouseEvent
& event
) 
 111     if (event
.LeftDown()) 
 113         DragShape
* shape 
= FindShape(event
.GetPosition()); 
 116             // We tentatively start dragging, but wait for 
 117             // mouse movement before dragging properly. 
 119             m_dragMode 
= TEST_DRAG_START
; 
 120             m_dragStartPos 
= event
.GetPosition(); 
 121             m_draggedShape 
= shape
; 
 124     else if (event
.LeftUp() && m_dragMode 
!= TEST_DRAG_NONE
) 
 128         m_dragMode 
= TEST_DRAG_NONE
; 
 130         if (!m_draggedShape 
|| !m_dragImage
) 
 133         m_draggedShape
->SetPosition(m_draggedShape
->GetPosition() 
 134                                     + event
.GetPosition() - m_dragStartPos
); 
 137         m_dragImage
->EndDrag(); 
 142         if (m_currentlyHighlighted
) 
 144             m_currentlyHighlighted
->Draw(dc
); 
 146         m_draggedShape
->SetShow(true); 
 147         m_draggedShape
->Draw(dc
); 
 149         m_currentlyHighlighted 
= (DragShape
*) NULL
; 
 151         m_draggedShape 
= (DragShape
*) NULL
; 
 153     else if (event
.Dragging() && m_dragMode 
!= TEST_DRAG_NONE
) 
 155         if (m_dragMode 
== TEST_DRAG_START
) 
 157             // We will start dragging if we've moved beyond a couple of pixels 
 160             int dx 
= abs(event
.GetPosition().x 
- m_dragStartPos
.x
); 
 161             int dy 
= abs(event
.GetPosition().y 
- m_dragStartPos
.y
); 
 162             if (dx 
<= tolerance 
&& dy 
<= tolerance
) 
 166             m_dragMode 
= TEST_DRAG_DRAGGING
; 
 171             // Erase the dragged shape from the canvas 
 172             m_draggedShape
->SetShow(false); 
 174             EraseShape(m_draggedShape
, dc
); 
 177             switch (m_draggedShape
->GetDragMethod()) 
 179                 case SHAPE_DRAG_BITMAP
: 
 181                     m_dragImage 
= new wxDragImage(m_draggedShape
->GetBitmap(), wxCursor(wxCURSOR_HAND
)); 
 184                 case SHAPE_DRAG_TEXT
: 
 186                     m_dragImage 
= new wxDragImage(wxString(_T("Dragging some test text")), wxCursor(wxCURSOR_HAND
)); 
 189                 case SHAPE_DRAG_ICON
: 
 191                     m_dragImage 
= new wxDragImage(wxICON(dragicon
), wxCursor(wxCURSOR_HAND
)); 
 196             bool fullScreen 
= wxGetApp().GetUseScreen(); 
 198             // The offset between the top-left of the shape image and the current shape position 
 199             wxPoint beginDragHotSpot 
= m_dragStartPos 
- m_draggedShape
->GetPosition(); 
 201             // Now we do this inside the implementation: always assume 
 202             // coordinates relative to the capture window (client coordinates) 
 205             //    beginDragHotSpot -= ClientToScreen(wxPoint(0, 0)); 
 207             if (!m_dragImage
->BeginDrag(beginDragHotSpot
, this, fullScreen
)) 
 210                 m_dragImage 
= (wxDragImage
*) NULL
; 
 211                 m_dragMode 
= TEST_DRAG_NONE
; 
 215                 m_dragImage
->Move(event
.GetPosition()); 
 219         else if (m_dragMode 
== TEST_DRAG_DRAGGING
) 
 221             // We're currently dragging. See if we're over another shape. 
 222             DragShape
* onShape 
= FindShape(event
.GetPosition()); 
 224             bool mustUnhighlightOld 
= false; 
 225             bool mustHighlightNew 
= false; 
 227             if (m_currentlyHighlighted
) 
 229                 if ((onShape 
== (DragShape
*) NULL
) || (m_currentlyHighlighted 
!= onShape
)) 
 230                     mustUnhighlightOld 
= true; 
 233             if (onShape 
&& (onShape 
!= m_currentlyHighlighted
) && onShape
->IsShown()) 
 234                 mustHighlightNew 
= true; 
 236             if (mustUnhighlightOld 
|| mustHighlightNew
) 
 239             // Now with the drag image switched off, we can change the window contents. 
 241             if (mustUnhighlightOld
) 
 243                 wxClientDC 
clientDC(this); 
 244                 m_currentlyHighlighted
->Draw(clientDC
); 
 245                 m_currentlyHighlighted 
= (DragShape
*) NULL
; 
 247             if (mustHighlightNew
) 
 249                 wxClientDC 
clientDC(this); 
 250                 m_currentlyHighlighted 
= onShape
; 
 251                 m_currentlyHighlighted
->Draw(clientDC
, wxINVERT
); 
 254             // Move and show the image again 
 255             m_dragImage
->Move(event
.GetPosition()); 
 257             if (mustUnhighlightOld 
|| mustHighlightNew
) 
 263 void MyCanvas::DrawShapes(wxDC
& dc
) 
 265     wxList::compatibility_iterator node 
= m_displayList
.GetFirst(); 
 268         DragShape
* shape 
= (DragShape
*) node
->GetData(); 
 269         if (shape
->IsShown()) 
 271         node 
= node
->GetNext(); 
 275 void MyCanvas::EraseShape(DragShape
* shape
, wxDC
& dc
) 
 277     wxSize sz 
= GetClientSize(); 
 278     wxRect 
rect(0, 0, sz
.x
, sz
.y
); 
 280     wxRect 
rect2(shape
->GetRect()); 
 281     dc
.SetClippingRegion(rect2
.x
, rect2
.y
, rect2
.width
, rect2
.height
); 
 283     wxGetApp().TileBitmap(rect
, dc
, wxGetApp().GetBackgroundBitmap()); 
 285     dc
.DestroyClippingRegion(); 
 288 void MyCanvas::ClearShapes() 
 290     wxList::compatibility_iterator node 
= m_displayList
.GetFirst(); 
 293         DragShape
* shape 
= (DragShape
*) node
->GetData(); 
 295         node 
= node
->GetNext(); 
 297     m_displayList
.Clear(); 
 300 DragShape
* MyCanvas::FindShape(const wxPoint
& pt
) const 
 302     wxList::compatibility_iterator node 
= m_displayList
.GetFirst(); 
 305         DragShape
* shape 
= (DragShape
*) node
->GetData(); 
 306         if (shape
->HitTest(pt
)) 
 308         node 
= node
->GetNext(); 
 310     return (DragShape
*) NULL
; 
 314 IMPLEMENT_DYNAMIC_CLASS( MyFrame
, wxFrame 
) 
 316 BEGIN_EVENT_TABLE(MyFrame
,wxFrame
) 
 317   EVT_MENU    (wxID_ABOUT
, MyFrame::OnAbout
) 
 318   EVT_MENU    (wxID_EXIT
,  MyFrame::OnQuit
) 
 322 : wxFrame( (wxFrame 
*)NULL
, wxID_ANY
, _T("wxDragImage sample"), 
 323           wxPoint(20,20), wxSize(470,360) ) 
 325     wxMenu 
*file_menu 
= new wxMenu(); 
 326     file_menu
->Append( wxID_ABOUT
, _T("&About...")); 
 327     file_menu
->AppendCheckItem( TEST_USE_SCREEN
, _T("&Use whole screen for dragging"), _T("Use whole screen")); 
 328     file_menu
->Append( wxID_EXIT
, _T("E&xit")); 
 330     wxMenuBar 
*menu_bar 
= new wxMenuBar(); 
 331     menu_bar
->Append(file_menu
, _T("&File")); 
 333     SetIcon(wxICON(mondrian
)); 
 334     SetMenuBar( menu_bar 
); 
 338     int widths
[] = { -1, 100 }; 
 339     SetStatusWidths( 2, widths 
); 
 340 #endif // wxUSE_STATUSBAR 
 342     m_canvas 
= new MyCanvas( this, wxID_ANY
, wxPoint(0,0), wxSize(10,10) ); 
 345 void MyFrame::OnQuit( wxCommandEvent 
&WXUNUSED(event
) ) 
 350 void MyFrame::OnAbout( wxCommandEvent 
&WXUNUSED(event
) ) 
 352     (void)wxMessageBox( _T("wxDragImage demo\n") 
 353         _T("Julian Smart (c) 2000"), 
 354         _T("About wxDragImage Demo"), 
 355         wxICON_INFORMATION 
| wxOK 
); 
 358 //----------------------------------------------------------------------------- 
 360 //----------------------------------------------------------------------------- 
 362 BEGIN_EVENT_TABLE(MyApp
, wxApp
) 
 363     EVT_MENU(TEST_USE_SCREEN
, MyApp::OnUseScreen
) 
 368     // Drag across whole screen 
 375     wxImage::AddHandler( new wxPNGHandler 
); 
 379     if (image
.LoadFile(_T("backgrnd.png"), wxBITMAP_TYPE_PNG
)) 
 381         m_background 
= wxBitmap(image
); 
 384     MyFrame 
*frame 
= new MyFrame(); 
 386     wxString 
rootName(_T("shape0")); 
 389     for (i 
= 1; i 
< 4; i
++) 
 392         filename
.Printf(wxT("%s%d.png"), (const wxChar
*)rootName
, i
); 
 393     /* For some reason under wxX11, the 2nd LoadFile in this loop fails, with 
 394        a BadMatch inside CreateFromImage (inside ConvertToBitmap). This happens even if you copy 
 395        the first file over the second file. */ 
 396         if (image
.LoadFile(filename
, wxBITMAP_TYPE_PNG
)) 
 398             DragShape
* newShape 
= new DragShape(wxBitmap(image
)); 
 399             newShape
->SetPosition(wxPoint(i
*50, i
*50)); 
 402                 newShape
->SetDragMethod(SHAPE_DRAG_TEXT
); 
 404                 newShape
->SetDragMethod(SHAPE_DRAG_ICON
); 
 406                 newShape
->SetDragMethod(SHAPE_DRAG_BITMAP
); 
 407             frame
->GetCanvas()->GetDisplayList().Append(newShape
); 
 412     // Under Motif or GTK, this demonstrates that 
 413     // wxScreenDC only gets the root window content. 
 414     // We need to be able to copy the overall content 
 415     // for full-screen dragging to work. 
 417     wxDisplaySize(& w
, & h
); 
 418     wxBitmap 
bitmap(w
, h
); 
 422     memDC
.SelectObject(bitmap
); 
 423     memDC
.Blit(0, 0, w
, h
, & dc
, 0, 0); 
 424     memDC
.SelectObject(wxNullBitmap
); 
 425     m_background 
= bitmap
; 
 438 bool MyApp::TileBitmap(const wxRect
& rect
, wxDC
& dc
, wxBitmap
& bitmap
) 
 440     int w 
= bitmap
.GetWidth(); 
 441     int h 
= bitmap
.GetHeight(); 
 444     for (i 
= rect
.x
; i 
< rect
.x 
+ rect
.width
; i 
+= w
) 
 446         for (j 
= rect
.y
; j 
< rect
.y 
+ rect
.height
; j
+= h
) 
 447             dc
.DrawBitmap(bitmap
, i
, j
); 
 452 void MyApp::OnUseScreen(wxCommandEvent
& WXUNUSED(event
)) 
 454     m_useScreen 
= !m_useScreen
; 
 459 DragShape::DragShape(const wxBitmap
& bitmap
) 
 464     m_dragMethod 
= SHAPE_DRAG_BITMAP
; 
 468 bool DragShape::HitTest(const wxPoint
& pt
) const 
 470     wxRect 
rect(GetRect()); 
 471     return rect
.Contains(pt
.x
, pt
.y
); 
 474 bool DragShape::Draw(wxDC
& dc
, int op
) 
 479         memDC
.SelectObject(m_bitmap
); 
 481         dc
.Blit(m_pos
.x
, m_pos
.y
, m_bitmap
.GetWidth(), m_bitmap
.GetHeight(), 
 482             & memDC
, 0, 0, op
, true);