git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51131 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			510 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			510 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| // Name:        dragimag.cpp
 | |
| // Purpose:     wxDragImage sample
 | |
| // Author:      Julian Smart
 | |
| // Modified by:
 | |
| // Created:     28/2/2000
 | |
| // RCS-ID:      $Id$
 | |
| // Copyright:   (c) Julian Smart
 | |
| // Licence:     wxWindows licence
 | |
| /////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| // For compilers that support precompilation, includes "wx/wx.h".
 | |
| #include "wx/wxprec.h"
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
| #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #ifndef WX_PRECOMP
 | |
| #include "wx/wx.h"
 | |
| #endif
 | |
| 
 | |
| #include "wx/image.h"
 | |
| 
 | |
| // Under Windows, change this to 1
 | |
| // to use wxGenericDragImage
 | |
| 
 | |
| #define wxUSE_GENERIC_DRAGIMAGE 1
 | |
| 
 | |
| #if wxUSE_GENERIC_DRAGIMAGE
 | |
| #include "wx/generic/dragimgg.h"
 | |
| #define wxDragImage wxGenericDragImage
 | |
| #else
 | |
| #include "wx/dragimag.h"
 | |
| #endif
 | |
| 
 | |
| #include "dragimag.h"
 | |
| 
 | |
| #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__)
 | |
| #include "mondrian.xpm"
 | |
| #include "dragicon.xpm"
 | |
| #endif
 | |
| 
 | |
| // main program
 | |
| 
 | |
| IMPLEMENT_APP(MyApp)
 | |
| 
 | |
| // MyCanvas
 | |
| 
 | |
| IMPLEMENT_CLASS(MyCanvas, wxScrolledWindow)
 | |
| 
 | |
| BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
 | |
|   EVT_PAINT(MyCanvas::OnPaint)
 | |
|   EVT_ERASE_BACKGROUND(MyCanvas::OnEraseBackground)
 | |
|   EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
 | |
| END_EVENT_TABLE()
 | |
| 
 | |
| MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
 | |
|                     const wxPoint &pos, const wxSize &size )
 | |
|         : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER )
 | |
| {
 | |
|     SetBackgroundColour(* wxWHITE);
 | |
| 
 | |
|     SetCursor(wxCursor(wxCURSOR_ARROW));
 | |
| 
 | |
|     m_dragMode = TEST_DRAG_NONE;
 | |
|     m_draggedShape = (DragShape*) NULL;
 | |
|     m_dragImage = (wxDragImage*) NULL;
 | |
|     m_currentlyHighlighted = (DragShape*) NULL;
 | |
| }
 | |
| 
 | |
| MyCanvas::~MyCanvas()
 | |
| {
 | |
|     ClearShapes();
 | |
| 
 | |
|     if (m_dragImage)
 | |
|         delete m_dragImage;
 | |
| }
 | |
| 
 | |
| void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
 | |
| {
 | |
|     wxPaintDC dc( this );
 | |
|     PrepareDC( dc );
 | |
| 
 | |
|     DrawShapes(dc);
 | |
| }
 | |
| 
 | |
| void MyCanvas::OnEraseBackground(wxEraseEvent& event)
 | |
| {
 | |
|     if (wxGetApp().GetBackgroundBitmap().Ok())
 | |
|     {
 | |
|         wxSize sz = GetClientSize();
 | |
|         wxRect rect(0, 0, sz.x, sz.y);
 | |
| 
 | |
|         if (event.GetDC())
 | |
|         {
 | |
|             wxGetApp().TileBitmap(rect, *(event.GetDC()), wxGetApp().GetBackgroundBitmap());
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             wxClientDC dc(this);
 | |
|             wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|         event.Skip(); // The official way of doing it
 | |
| }
 | |
| 
 | |
| void MyCanvas::OnMouseEvent(wxMouseEvent& event)
 | |
| {
 | |
|     if (event.LeftDown())
 | |
|     {
 | |
|         DragShape* shape = FindShape(event.GetPosition());
 | |
|         if (shape)
 | |
|         {
 | |
|             // We tentatively start dragging, but wait for
 | |
|             // mouse movement before dragging properly.
 | |
| 
 | |
|             m_dragMode = TEST_DRAG_START;
 | |
|             m_dragStartPos = event.GetPosition();
 | |
|             m_draggedShape = shape;
 | |
|         }
 | |
|     }
 | |
|     else if (event.LeftUp() && m_dragMode != TEST_DRAG_NONE)
 | |
|     {
 | |
|         // Finish dragging
 | |
| 
 | |
|         m_dragMode = TEST_DRAG_NONE;
 | |
| 
 | |
|         if (!m_draggedShape || !m_dragImage)
 | |
|             return;
 | |
| 
 | |
|         m_draggedShape->SetPosition(m_draggedShape->GetPosition()
 | |
|                                     + event.GetPosition() - m_dragStartPos);
 | |
| 
 | |
|         m_dragImage->Hide();
 | |
|         m_dragImage->EndDrag();
 | |
|         delete m_dragImage;
 | |
|         m_dragImage = NULL;
 | |
| 
 | |
|         m_draggedShape->SetShow(true);
 | |
| 
 | |
|         m_currentlyHighlighted = (DragShape*) NULL;
 | |
| 
 | |
|         m_draggedShape = (DragShape*) NULL;
 | |
|         
 | |
|         Refresh(true);
 | |
|     }
 | |
|     else if (event.Dragging() && m_dragMode != TEST_DRAG_NONE)
 | |
|     {
 | |
|         if (m_dragMode == TEST_DRAG_START)
 | |
|         {
 | |
|             // We will start dragging if we've moved beyond a couple of pixels
 | |
| 
 | |
|             int tolerance = 2;
 | |
|             int dx = abs(event.GetPosition().x - m_dragStartPos.x);
 | |
|             int dy = abs(event.GetPosition().y - m_dragStartPos.y);
 | |
|             if (dx <= tolerance && dy <= tolerance)
 | |
|                 return;
 | |
| 
 | |
|             // Start the drag.
 | |
|             m_dragMode = TEST_DRAG_DRAGGING;
 | |
| 
 | |
|             if (m_dragImage)
 | |
|                 delete m_dragImage;
 | |
| 
 | |
|             // Erase the dragged shape from the canvas
 | |
|             m_draggedShape->SetShow(false);
 | |
| 
 | |
|             // redraw immediately
 | |
|             Refresh(true);
 | |
|             Update();
 | |
| 
 | |
|             switch (m_draggedShape->GetDragMethod())
 | |
|             {
 | |
|                 case SHAPE_DRAG_BITMAP:
 | |
|                 {
 | |
|                     m_dragImage = new MyDragImage(this, m_draggedShape->GetBitmap(), wxCursor(wxCURSOR_HAND));
 | |
|                     break;
 | |
|                 }
 | |
|                 case SHAPE_DRAG_TEXT:
 | |
|                 {
 | |
|                     m_dragImage = new MyDragImage(this, wxString(_T("Dragging some test text")), wxCursor(wxCURSOR_HAND));
 | |
|                     break;
 | |
|                 }
 | |
|                 case SHAPE_DRAG_ICON:
 | |
|                 {
 | |
|                     m_dragImage = new MyDragImage(this, wxICON(dragicon), wxCursor(wxCURSOR_HAND));
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             bool fullScreen = wxGetApp().GetUseScreen();
 | |
| 
 | |
|             // The offset between the top-left of the shape image and the current shape position
 | |
|             wxPoint beginDragHotSpot = m_dragStartPos - m_draggedShape->GetPosition();
 | |
| 
 | |
|             // Now we do this inside the implementation: always assume
 | |
|             // coordinates relative to the capture window (client coordinates)
 | |
| 
 | |
|             //if (fullScreen)
 | |
|             //    beginDragHotSpot -= ClientToScreen(wxPoint(0, 0));
 | |
| 
 | |
|             if (!m_dragImage->BeginDrag(beginDragHotSpot, this, fullScreen))
 | |
|             {
 | |
|                 delete m_dragImage;
 | |
|                 m_dragImage = (wxDragImage*) NULL;
 | |
|                 m_dragMode = TEST_DRAG_NONE;
 | |
| 
 | |
|             } else
 | |
|             {
 | |
|                 m_dragImage->Move(event.GetPosition());
 | |
|                 m_dragImage->Show();
 | |
|             }
 | |
|         }
 | |
|         else if (m_dragMode == TEST_DRAG_DRAGGING)
 | |
|         {
 | |
|             // We're currently dragging. See if we're over another shape.
 | |
|             DragShape* onShape = FindShape(event.GetPosition());
 | |
| 
 | |
|             bool mustUnhighlightOld = false;
 | |
|             bool mustHighlightNew = false;
 | |
| 
 | |
|             if (m_currentlyHighlighted)
 | |
|             {
 | |
|                 if ((onShape == (DragShape*) NULL) || (m_currentlyHighlighted != onShape))
 | |
|                     mustUnhighlightOld = true;
 | |
|             }
 | |
| 
 | |
|             if (onShape && (onShape != m_currentlyHighlighted) && onShape->IsShown())
 | |
|                 mustHighlightNew = true;
 | |
| 
 | |
|             if (mustUnhighlightOld || mustHighlightNew)
 | |
|                 m_dragImage->Hide();
 | |
|             
 | |
|             // Now with the drag image switched off, we can change the window contents.
 | |
|             if (mustUnhighlightOld)
 | |
|                 m_currentlyHighlighted = (DragShape*) NULL;
 | |
| 
 | |
|             if (mustHighlightNew)
 | |
|                 m_currentlyHighlighted = onShape;
 | |
| 
 | |
|             if (mustUnhighlightOld || mustHighlightNew)
 | |
|             {
 | |
|                 Refresh(mustUnhighlightOld);
 | |
|                 Update();
 | |
|             }
 | |
| 
 | |
|             // Move and show the image again
 | |
|             m_dragImage->Move(event.GetPosition());
 | |
| 
 | |
|             if (mustUnhighlightOld || mustHighlightNew)
 | |
|                  m_dragImage->Show();
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void MyCanvas::DrawShapes(wxDC& dc)
 | |
| {
 | |
|     wxList::compatibility_iterator node = m_displayList.GetFirst();
 | |
|     while (node)
 | |
|     {
 | |
|         DragShape* shape = (DragShape*) node->GetData();
 | |
|         if (shape->IsShown() && m_draggedShape != shape)
 | |
|         {
 | |
|             shape->Draw(dc, (m_currentlyHighlighted == shape));
 | |
|         }
 | |
|         node = node->GetNext();
 | |
|     }
 | |
| }
 | |
| 
 | |
| void MyCanvas::EraseShape(DragShape* shape, wxDC& dc)
 | |
| {
 | |
|     wxSize sz = GetClientSize();
 | |
|     wxRect rect(0, 0, sz.x, sz.y);
 | |
| 
 | |
|     wxRect rect2(shape->GetRect());
 | |
|     dc.SetClippingRegion(rect2.x, rect2.y, rect2.width, rect2.height);
 | |
| 
 | |
|     wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
 | |
| 
 | |
|     dc.DestroyClippingRegion();
 | |
| }
 | |
| 
 | |
| void MyCanvas::ClearShapes()
 | |
| {
 | |
|     wxList::compatibility_iterator node = m_displayList.GetFirst();
 | |
|     while (node)
 | |
|     {
 | |
|         DragShape* shape = (DragShape*) node->GetData();
 | |
|         delete shape;
 | |
|         node = node->GetNext();
 | |
|     }
 | |
|     m_displayList.Clear();
 | |
| }
 | |
| 
 | |
| DragShape* MyCanvas::FindShape(const wxPoint& pt) const
 | |
| {
 | |
|     wxList::compatibility_iterator node = m_displayList.GetFirst();
 | |
|     while (node)
 | |
|     {
 | |
|         DragShape* shape = (DragShape*) node->GetData();
 | |
|         if (shape->HitTest(pt))
 | |
|             return shape;
 | |
|         node = node->GetNext();
 | |
|     }
 | |
|     return (DragShape*) NULL;
 | |
| }
 | |
| 
 | |
| // MyFrame
 | |
| IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
 | |
| 
 | |
| BEGIN_EVENT_TABLE(MyFrame,wxFrame)
 | |
|   EVT_MENU    (wxID_ABOUT, MyFrame::OnAbout)
 | |
|   EVT_MENU    (wxID_EXIT,  MyFrame::OnQuit)
 | |
| END_EVENT_TABLE()
 | |
| 
 | |
| MyFrame::MyFrame()
 | |
| : wxFrame( (wxFrame *)NULL, wxID_ANY, _T("wxDragImage sample"),
 | |
|           wxPoint(20,20), wxSize(470,360) )
 | |
| {
 | |
|     wxMenu *file_menu = new wxMenu();
 | |
|     file_menu->Append( wxID_ABOUT, _T("&About..."));
 | |
|     file_menu->AppendCheckItem( TEST_USE_SCREEN, _T("&Use whole screen for dragging"), _T("Use whole screen"));
 | |
|     file_menu->Append( wxID_EXIT, _T("E&xit"));
 | |
| 
 | |
|     wxMenuBar *menu_bar = new wxMenuBar();
 | |
|     menu_bar->Append(file_menu, _T("&File"));
 | |
| 
 | |
|     SetIcon(wxICON(mondrian));
 | |
|     SetMenuBar( menu_bar );
 | |
| 
 | |
| #if wxUSE_STATUSBAR
 | |
|     CreateStatusBar(2);
 | |
|     int widths[] = { -1, 100 };
 | |
|     SetStatusWidths( 2, widths );
 | |
| #endif // wxUSE_STATUSBAR
 | |
| 
 | |
|     m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(10,10) );
 | |
| }
 | |
| 
 | |
| void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
 | |
| {
 | |
|     Close( true );
 | |
| }
 | |
| 
 | |
| void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
 | |
| {
 | |
|     (void)wxMessageBox( _T("wxDragImage demo\n")
 | |
|         _T("Julian Smart (c) 2000"),
 | |
|         _T("About wxDragImage Demo"),
 | |
|         wxICON_INFORMATION | wxOK );
 | |
| }
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // MyApp
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| BEGIN_EVENT_TABLE(MyApp, wxApp)
 | |
|     EVT_MENU(TEST_USE_SCREEN, MyApp::OnUseScreen)
 | |
| END_EVENT_TABLE()
 | |
| 
 | |
| MyApp::MyApp()
 | |
| {
 | |
|     // Drag across whole screen
 | |
|     m_useScreen = false;
 | |
| }
 | |
| 
 | |
| bool MyApp::OnInit()
 | |
| {
 | |
|     if ( !wxApp::OnInit() )
 | |
|         return false;
 | |
| 
 | |
| #if wxUSE_LIBPNG
 | |
|     wxImage::AddHandler( new wxPNGHandler );
 | |
| #endif
 | |
| 
 | |
|     wxImage image;
 | |
|     if (image.LoadFile(_T("backgrnd.png"), wxBITMAP_TYPE_PNG))
 | |
|     {
 | |
|         m_background = wxBitmap(image);
 | |
|     }
 | |
| 
 | |
|     MyFrame *frame = new MyFrame();
 | |
| 
 | |
|     wxString rootName(_T("shape0"));
 | |
| 
 | |
|     for (int i = 1; i < 4; i++)
 | |
|     {
 | |
|     /* For some reason under wxX11, the 2nd LoadFile in this loop fails, with
 | |
|        a BadMatch inside CreateFromImage (inside ConvertToBitmap). This happens even if you copy
 | |
|        the first file over the second file. */
 | |
|         if (image.LoadFile(wxString::Format("%s%d.png", rootName, i), wxBITMAP_TYPE_PNG))
 | |
|         {
 | |
|             DragShape* newShape = new DragShape(wxBitmap(image));
 | |
|             newShape->SetPosition(wxPoint(i*50, i*50));
 | |
| 
 | |
|             if (i == 2)
 | |
|                 newShape->SetDragMethod(SHAPE_DRAG_TEXT);
 | |
|             else if (i == 3)
 | |
|                 newShape->SetDragMethod(SHAPE_DRAG_ICON);
 | |
|             else
 | |
|                 newShape->SetDragMethod(SHAPE_DRAG_BITMAP);
 | |
|             frame->GetCanvas()->GetDisplayList().Append(newShape);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #if 0
 | |
|     // Under Motif or GTK, this demonstrates that
 | |
|     // wxScreenDC only gets the root window content.
 | |
|     // We need to be able to copy the overall content
 | |
|     // for full-screen dragging to work.
 | |
|     int w, h;
 | |
|     wxDisplaySize(& w, & h);
 | |
|     wxBitmap bitmap(w, h);
 | |
| 
 | |
|     wxScreenDC dc;
 | |
|     wxMemoryDC memDC;
 | |
|     memDC.SelectObject(bitmap);
 | |
|     memDC.Blit(0, 0, w, h, & dc, 0, 0);
 | |
|     memDC.SelectObject(wxNullBitmap);
 | |
|     m_background = bitmap;
 | |
| #endif
 | |
| 
 | |
|     frame->Show( true );
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| int MyApp::OnExit()
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| bool MyApp::TileBitmap(const wxRect& rect, wxDC& dc, wxBitmap& bitmap)
 | |
| {
 | |
|     int w = bitmap.GetWidth();
 | |
|     int h = bitmap.GetHeight();
 | |
| 
 | |
|     int i, j;
 | |
|     for (i = rect.x; i < rect.x + rect.width; i += w)
 | |
|     {
 | |
|         for (j = rect.y; j < rect.y + rect.height; j+= h)
 | |
|             dc.DrawBitmap(bitmap, i, j);
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| void MyApp::OnUseScreen(wxCommandEvent& WXUNUSED(event))
 | |
| {
 | |
|     m_useScreen = !m_useScreen;
 | |
| }
 | |
| 
 | |
| // DragShape
 | |
| 
 | |
| DragShape::DragShape(const wxBitmap& bitmap)
 | |
| {
 | |
|     m_bitmap = bitmap;
 | |
|     m_pos.x = 0;
 | |
|     m_pos.y = 0;
 | |
|     m_dragMethod = SHAPE_DRAG_BITMAP;
 | |
|     m_show = true;
 | |
| }
 | |
| 
 | |
| bool DragShape::HitTest(const wxPoint& pt) const
 | |
| {
 | |
|     wxRect rect(GetRect());
 | |
|     return rect.Contains(pt.x, pt.y);
 | |
| }
 | |
| 
 | |
| bool DragShape::Draw(wxDC& dc, bool highlight)
 | |
| {
 | |
|     if (m_bitmap.Ok())
 | |
|     {
 | |
|         wxMemoryDC memDC;
 | |
|         memDC.SelectObject(m_bitmap);
 | |
| 
 | |
|         dc.Blit(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight(),
 | |
|             & memDC, 0, 0, wxCOPY, true);
 | |
|             
 | |
|         if (highlight)
 | |
|         {
 | |
|             dc.SetPen(*wxWHITE_PEN);
 | |
|             dc.SetBrush(*wxTRANSPARENT_BRUSH);
 | |
|             dc.DrawRectangle(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
|     else
 | |
|         return false;
 | |
| }
 | |
| 
 | |
| // MyDragImage
 | |
| 
 | |
| // On some platforms, notably Mac OS X with Core Graphics, we can't blit from
 | |
| // a window, so we need to draw the background explicitly.
 | |
| bool MyDragImage::UpdateBackingFromWindow(wxDC& WXUNUSED(windowDC), wxMemoryDC& destDC, const wxRect& WXUNUSED(sourceRect),
 | |
|                     const wxRect& destRect) const
 | |
| {
 | |
|     destDC.SetClippingRegion(destRect);
 | |
| 
 | |
|     if (wxGetApp().GetBackgroundBitmap().Ok())
 | |
|         wxGetApp().TileBitmap(destRect, destDC, wxGetApp().GetBackgroundBitmap());
 | |
| 
 | |
|     m_canvas->DrawShapes(destDC);
 | |
|     return true;
 | |
| }
 | |
| 
 |