]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/dragimag/test.cpp
Added wxDragImage generic implementation and sample; added mask handling to Motif's
[wxWidgets.git] / samples / dragimag / test.cpp
diff --git a/samples/dragimag/test.cpp b/samples/dragimag/test.cpp
new file mode 100644 (file)
index 0000000..08acf09
--- /dev/null
@@ -0,0 +1,512 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        test.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 0
+
+#if wxUSE_GENERIC_DRAGIMAGE
+#include <wx/generic/dragimgg.h>
+#define wxDragImage wxGenericDragImage
+#else
+#include <wx/dragimag.h>
+#endif
+
+#include "test.h"
+
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+#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;
+
+        wxPoint newPos(m_draggedShape->GetPosition().x + (event.GetPosition().x - m_dragStartPos.x),
+                           m_draggedShape->GetPosition().y + (event.GetPosition().y - m_dragStartPos.y));
+
+        m_draggedShape->SetPosition(newPos);
+
+        m_dragImage->Hide();
+        m_dragImage->EndDrag();
+        delete m_dragImage;
+        m_dragImage = NULL;
+
+        wxClientDC dc(this);
+        if (m_currentlyHighlighted)
+        {
+            m_currentlyHighlighted->Draw(dc);
+        }
+        m_draggedShape->SetShow(TRUE);
+        m_draggedShape->Draw(dc);
+
+        m_currentlyHighlighted = (DragShape*) NULL;
+
+        m_draggedShape = (DragShape*) NULL;
+    }
+    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;
+
+            wxPoint newPos(m_draggedShape->GetPosition().x + (event.GetPosition().x - m_dragStartPos.x),
+                           m_draggedShape->GetPosition().y + (event.GetPosition().y - m_dragStartPos.y));
+
+            // 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);
+            wxClientDC dc(this);
+            EraseShape(m_draggedShape, dc);
+            DrawShapes(dc);
+
+            switch (m_draggedShape->GetDragMethod())
+            {
+                case SHAPE_DRAG_BITMAP:
+                {
+                    wxPoint hotSpot(event.GetPosition().x - newPos.x, event.GetPosition().y - newPos.y);
+                    m_dragImage = new wxDragImage(m_draggedShape->GetBitmap(), wxCursor(wxCURSOR_HAND), hotSpot);
+                    break;
+                }
+                case SHAPE_DRAG_TEXT:
+                {
+                    wxPoint hotSpot(event.GetPosition().x - newPos.x, event.GetPosition().y - newPos.y);
+                    m_dragImage = new wxDragImage("Dragging some test text", wxCursor(wxCURSOR_HAND), hotSpot);
+                    break;
+                }
+                case SHAPE_DRAG_ICON:
+                {
+                    wxPoint hotSpot(event.GetPosition().x - newPos.x, event.GetPosition().y - newPos.y);
+
+                    // Can anyone explain why this test is necessary,
+                    // to prevent a gcc error?
+#ifdef __WXMOTIF__
+                   wxIcon icon(dragicon_xpm);
+#else
+                   wxIcon icon(wxICON(dragicon));
+#endif
+
+                    m_dragImage = new wxDragImage(icon, wxCursor(wxCURSOR_HAND), hotSpot);
+                    break;
+                }
+            }
+
+            bool fullScreen = FALSE;
+            if (wxGetApp().GetUseScreen())
+            {
+                newPos = ClientToScreen(newPos);
+                fullScreen = TRUE;
+            }
+
+            bool retValue;
+
+            if (fullScreen)
+                // This line uses the whole screen...
+                retValue = m_dragImage->BeginDrag(wxPoint(0, 0), this, TRUE);
+                // while this line restricts dragging to the parent frame.
+                // retValue = m_dragImage->BeginDrag(wxPoint(0, 0), this, GetParent());
+            else
+                retValue = m_dragImage->BeginDrag(wxPoint(0, 0), this);
+
+            if (!retValue)
+            {
+                delete m_dragImage;
+                m_dragImage = (wxDragImage*) NULL;
+                m_dragMode = TEST_DRAG_NONE;
+            }
+            m_dragImage->Move(newPos);
+            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)
+            {
+                wxClientDC clientDC(this);
+                m_currentlyHighlighted->Draw(clientDC);
+                m_currentlyHighlighted = (DragShape*) NULL;
+            }
+            if (mustHighlightNew)
+            {
+                wxClientDC clientDC(this);
+                m_currentlyHighlighted = onShape;
+                m_currentlyHighlighted->Draw(clientDC, wxINVERT);
+            }
+
+            wxPoint newPos(m_draggedShape->GetPosition().x + (event.GetPosition().x - m_dragStartPos.x),
+                           m_draggedShape->GetPosition().y + (event.GetPosition().y - m_dragStartPos.y));
+
+            if (wxGetApp().GetUseScreen())
+            {
+                newPos = ClientToScreen(newPos);
+            }
+
+            // Move and show the image again
+            m_dragImage->Move(newPos);
+
+            if (mustUnhighlightOld || mustHighlightNew)
+                 m_dragImage->Show();
+        }
+    }
+}
+
+void MyCanvas::DrawShapes(wxDC& dc)
+{
+    wxNode* node = m_displayList.First();
+    while (node)
+    {
+        DragShape* shape = (DragShape*) node->Data();
+        if (shape->IsShown())
+          shape->Draw(dc);
+        node = node->Next();
+    }
+}
+
+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()
+{
+    wxNode* node = m_displayList.First();
+    while (node)
+    {
+        DragShape* shape = (DragShape*) node->Data();
+        delete shape;
+        node = node->Next();
+    }
+    m_displayList.Clear();
+}
+
+DragShape* MyCanvas::FindShape(const wxPoint& pt) const
+{
+    wxNode* node = m_displayList.First();
+    while (node)
+    {
+        DragShape* shape = (DragShape*) node->Data();
+        if (shape->HitTest(pt))
+            return shape;
+        node = node->Next();
+    }
+    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, -1, "wxDragImage sample",
+                  wxPoint(20,20), wxSize(470,360) )
+{
+  wxMenu *file_menu = new wxMenu();
+  file_menu->Append( wxID_ABOUT, "&About...");
+  file_menu->Append( TEST_USE_SCREEN, "&Use whole screen for dragging", "Use whole screen", TRUE);
+  file_menu->Append( wxID_EXIT, "E&xit");
+
+  wxMenuBar *menu_bar = new wxMenuBar();
+  menu_bar->Append(file_menu, "&File");
+
+  SetMenuBar( menu_bar );
+
+  CreateStatusBar(2);
+  int widths[] = { -1, 100 };
+  SetStatusWidths( 2, widths );
+
+  m_canvas = new MyCanvas( this, -1, wxPoint(0,0), wxSize(10,10) );
+}
+
+void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
+{
+  Close( TRUE );
+}
+
+void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
+{
+  (void)wxMessageBox( "wxDragImage demo\n"
+                      "Julian Smart (c) 2000",
+                      "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 wxUSE_LIBPNG
+    wxImage::AddHandler( new wxPNGHandler );
+#endif
+
+    wxImage image;
+    if (image.LoadFile("backgrnd.png", wxBITMAP_TYPE_PNG))
+    {
+        m_background = image.ConvertToBitmap();
+    }
+
+
+    MyFrame *frame = new MyFrame();
+
+    wxString rootName("shape0");
+
+    int i;
+    for (i = 1; i < 4; i++)
+    {
+        wxString filename;
+        filename.Printf("%s%d.png", (const char*) rootName, i);
+        if (image.LoadFile(filename, wxBITMAP_TYPE_PNG))
+        {
+            DragShape* newShape = new DragShape(image.ConvertToBitmap());
+            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;
+}
+
+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& 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;
+}
+
+DragShape::~DragShape()
+{
+}
+
+bool DragShape::HitTest(const wxPoint& pt) const
+{
+    wxRect rect(GetRect());
+    return rect.Inside(pt.x, pt.y);
+}
+
+bool DragShape::Draw(wxDC& dc, int op)
+{
+    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, op, TRUE);
+
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+