custom wxDataFormat, wxDropTarget, wxDataObjectSimple

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
Peri
Experienced Solver
Experienced Solver
Posts: 91
Joined: Wed Nov 09, 2011 10:06 pm
Location: Seattle, USA

custom wxDataFormat, wxDropTarget, wxDataObjectSimple

Post by Peri »

If you are writing an app where you need to drag app objects (not text or some other standard format), you will need a custom wxDataFormat and wxDataObject. As well, you may want custom cursors that change depending on the cursor position over the destination objects.

None of this appears to be documented, so I thought it would be helpful to put this simplified sample code here.

The custom data format is straight forward. Just delcare it and use it.

The custom data object is a bit trickier: you need to get the right levels of indirection on the buffer copying. Since wxDataObjectSimple casts everything to void*, you don't have any help from the compiler. In my example, I show how to properly cast these to your app's object.

wxDropTarget is the messiest part. This is mostly because the implementation doesn't support all of the functionality implied by the class documentation. First, I don't believe there is a way to use wxDragLink. If you look at the source code for wxDropSource, you will see that there is no usage of wxDragLink, and if you try to use SetCursor to make use of it, that will actually set the cursor for wxDragNone instead.

So, for wxDropTarget, all you really have available is wxDragNone, wxDragCopy, and wxDragMove. I've created custom cursors for these and put some simple logic into onDragOver to switch between the latter two cursors.

One other thing worth noting: in wxDropTarget, there's no way to get the "owner" object. So, I subclassed it and passed the in the "owner".

This code was built and tested on Windows XP.

If you have any suggestions to improve this example, or if you find it useful, please let me know :)

Here's the source:

Code: Select all

#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "wx/dnd.h"


// ----------------------------------------------------------------------------
// cursors
// ----------------------------------------------------------------------------


static char * top_half_xpm[] = {
  "16 16 2 1 8 8",
  "  c None",
  ". c #000000",
  "                ",
  " .............. ",
  " .            . ",
  " .            . ",
  " .            . ",
  " .............. ",
  "                ",
  "................",
  "................",
  "                ",
  "                ",
  "                ",
  "                ",
  "                ",
  "                ",
  "                "};

static char * bottom_half_xpm[] = {
  "16 16 2 1 8 8",
  "  c None",
  ". c #000000",
  "                ",
  "                ",
  "                ",
  "                ",
  "                ",
  "                ",
  "                ",
  "................",
  "................",
  "                ",
  " .............. ",
  " .            . ",
  " .            . ",
  " .            . ",
  " .............. ",
  "                "};

static char * none_xpm[] = {
  "16 16 2 1 8 8",
  "  c None",
  ". c #000000",
  ".              .",
  " .            . ",
  "  .          .  ",
  "   .        .   ",
  "    .      .    ",
  "     .    .     ",
  "      .  .      ",
  "................",
  "................",
  "      .  .      ",
  "     .    .     ",
  "    .      .    ",
  "   .        .   ",
  "  .          .  ",
  " .            . ",
  ".              ."};


// ----------------------------------------------------------------------------
// MyDataFormat
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
class MyDataFormat : public wxDataFormat
{
  public:
    MyDataFormat () : wxDataFormat (wxT("MyDataFormat")) {}
};

MyDataFormat myDataFormat;


// ----------------------------------------------------------------------------
// MyDataObject
// ----------------------------------------------------------------------------


class Thing;

// ----------------------------------------------------------------------------
class MyDataObject : public wxDataObjectSimple
{
  private:
    Thing* theThing;

  public:
    MyDataObject () : wxDataObjectSimple () { SetFormat (myDataFormat); }

    size_t GetDataSize() const { return sizeof (void*); }

    bool GetDataHere (void* buf) const { *(Thing**)buf = theThing; return true; }

    bool SetData (size_t len, const void* buf) { theThing = *(Thing**)buf; return true; }

    const Thing* getTheThing()  { return theThing; }
};


// ----------------------------------------------------------------------------
// MyDropTarget interface
// ----------------------------------------------------------------------------


class MyDropTarget : public wxDropTarget
{
  private:
    Thing* destThing;

  public:
    MyDropTarget (Thing* destThing);
    wxDragResult OnData (wxCoord x, wxCoord y, wxDragResult def);
    wxDragResult OnDragOver (wxCoord x, wxCoord y, wxDragResult def);
};


// ----------------------------------------------------------------------------
// Thing
// ----------------------------------------------------------------------------


class Thing : public wxWindow
{
  private:
    int id;
    wxCursor* cursorTop;
    wxCursor* cursorBottom;
    wxCursor* cursorNone;
    DECLARE_EVENT_TABLE();

  public:
    // ----------------------------------------------------------------------------
    // constructor
    Thing (wxWindow* parent, int id, wxCursor* cursorTop, wxCursor* cursorBottom, wxCursor* cursorNone) :
        wxWindow (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE),
        id (id),
        cursorTop (cursorTop),
        cursorBottom (cursorBottom),
        cursorNone (cursorNone)
    {
      SetInitialSize (wxSize(50,20));
      SetDropTarget (new MyDropTarget(this));
    }

    // ----------------------------------------------------------------------------
    void Thing::onLeftDown (wxMouseEvent& event)
    {
      Thing* myData = this; // we need one more level of indirection for SetData.
      MyDataObject data;
      data.SetData (sizeof (Thing*), &myData);

      wxDropSource source (data, this, *cursorTop, *cursorBottom, *cursorNone);
      wxDragResult result = source.DoDragDrop (wxDrag_AllowMove);
    }

    // ----------------------------------------------------------------------------
    void Thing::OnPaint (wxPaintEvent& event)
    {
      int xOffset = 20;
      int yOffset = 5;
      wxString s;
      s.Printf (wxT("%d"), id);
      wxPaintDC dc (this);
      dc.DrawText (s, xOffset, yOffset);
    }

    // ----------------------------------------------------------------------------
    int getId () const { return id; }
};

BEGIN_EVENT_TABLE(Thing, wxWindow)
  EVT_PAINT(Thing::OnPaint)
  EVT_LEFT_DOWN (Thing::onLeftDown)
END_EVENT_TABLE()


// ----------------------------------------------------------------------------
// MyDropTarget
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
MyDropTarget::MyDropTarget (Thing* destThing) :
    destThing (destThing)
{
  SetDataObject (new MyDataObject());
}

// ----------------------------------------------------------------------------
wxDragResult MyDropTarget::OnData (wxCoord x, wxCoord y, wxDragResult def)
{
  if (!GetData())
  {
    wxLogDebug ("GetData failed");
    return wxDragError;
  }
  MyDataObject* data = dynamic_cast<MyDataObject*>(m_dataObject);
  wxLogDebug ("onData: from %d to %d", data->getTheThing()->getId(), destThing->getId());
  return def;
}

// ----------------------------------------------------------------------------
wxDragResult MyDropTarget::OnDragOver (wxCoord x, wxCoord y, wxDragResult def)
{
  int height = destThing->GetSize().y;
  if (y < height/2)
    return wxDragCopy;
  else
    return wxDragMove;
}


// ----------------------------------------------------------------------------
// Pane
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
class Pane : public wxScrolledWindow
{
  private:
    wxCursor* cursorTop;
    wxCursor* cursorBottom;
    wxCursor* cursorNone;
    DECLARE_EVENT_TABLE();

  public:
    // ----------------------------------------------------------------------------
    Pane (wxWindow* frame) : 
        wxScrolledWindow (frame, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL)
    {
      SetScrollRate (0, 20);
      SetBackgroundColour (wxT("YELLOW"));
      createCursors ();

      wxSizer* sizer = new wxBoxSizer (wxVERTICAL);
      SetSizer (sizer);
      SetAutoLayout (true);

      for (size_t i = 1;  i < 6;  i++)
      {
        Thing* node = new Thing (this, i, cursorTop, cursorBottom, cursorNone);
        sizer->Add (node);
      }

      wxSize size = GetBestVirtualSize();
      SetVirtualSize( size );
    }

    // ----------------------------------------------------------------------------
    // destructor
    ~Pane ()
    {
      delete cursorTop;
      delete cursorBottom;
      delete cursorNone;
    }

    // ----------------------------------------------------------------------------
    void createCursors ()
    {
      wxBitmap bmTop (top_half_xpm, wxBITMAP_TYPE_XPM);
      wxImage  imgTop = bmTop.ConvertToImage();
      imgTop.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_X, 8);
      imgTop.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8);
      cursorTop = new wxCursor (imgTop);

      wxBitmap bmBottom (bottom_half_xpm, wxBITMAP_TYPE_XPM);
      wxImage  imgBottom = bmBottom.ConvertToImage();
      imgBottom.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_X, 8);
      imgBottom.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8);
      cursorBottom = new wxCursor (imgBottom);

      wxBitmap bmNone (none_xpm, wxBITMAP_TYPE_XPM);
      wxImage  imgNone = bmNone.ConvertToImage();
      imgNone.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_X, 8);
      imgNone.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8);
      cursorNone = new wxCursor (imgNone);
    }

}; // Pane

BEGIN_EVENT_TABLE(Pane, wxScrolledWindow)
END_EVENT_TABLE()


// ----------------------------------------------------------------------------
// MainFrame
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
class MainFrame : public wxFrame
{
  private:
    DECLARE_EVENT_TABLE();
    Pane* pane;

  public:
    // ----------------------------------------------------------------------------
    MainFrame(const wxString& title) :
        wxFrame(NULL, wxID_ANY, title, wxPoint (300,100), wxSize (500,500))
    {
      // build contents
      SetBackgroundColour (wxT("GREEN"));
      pane = new Pane (this);
    }

    // ----------------------------------------------------------------------------
    void onClose(wxCloseEvent& event)
    {
      Destroy();
    }
};

BEGIN_EVENT_TABLE(MainFrame, wxFrame)
  EVT_CLOSE(MainFrame::onClose)
END_EVENT_TABLE();



// ----------------------------------------------------------------------------
// Application
// ----------------------------------------------------------------------------

class Test : public wxApp
{
  public:
    virtual bool OnInit()
    {
      // debug settings - for detecting memory leaks
      _CrtSetDbgFlag (_CrtSetDbgFlag (_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

      // call the base class initialization method, currently it only parses a
      // few common command-line options but it could be do more in the future
      if ( !wxApp::OnInit() )
        return false;

      // create the main application window
      MainFrame *frame = new MainFrame(_T("Test"));
      frame->Show(true);

      return true;
    }

    virtual ~Test()
    {
    }
};

IMPLEMENT_APP(Test)
ollydbg23
Super wx Problem Solver
Super wx Problem Solver
Posts: 438
Joined: Fri Dec 12, 2008 10:31 am

Re: custom wxDataFormat, wxDropTarget, wxDataObjectSimple

Post by ollydbg23 »

It looks like your code is build under MS Visual C++, so I need some changes to build and work under MinGW.
1, some wxT macros to wrap raw c strings.
2, comment the line.

Code: Select all

_CrtSetDbgFlag (_CrtSetDbgFlag (_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
because this only works under MSVC.

The code is much simple than the examples/dnd. Thanks.

Though I have read the Chapter 11 Clipboard and Drag and Drop of the book "Cross-Platform GUI Programming with wxWidgets", but I still not quite understand how those custom defined things works.
ollydbg23
Super wx Problem Solver
Super wx Problem Solver
Posts: 438
Joined: Fri Dec 12, 2008 10:31 am

Re: custom wxDataFormat, wxDropTarget, wxDataObjectSimple

Post by ollydbg23 »

I change your code a bit, and here is the screen shot:
Image
It can COPY(hold the ctrl key when dragging) or Move the "Thing" objects in the Panel.
So, both the "Thing" and "Panel" window can served as a drop target.
I also add some comments.
Code below: (tested under windows XP and wx 2.8.12)

Code: Select all

#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "wx/dnd.h"


// ----------------------------------------------------------------------------
// cursors
// ----------------------------------------------------------------------------


static char * move_xpm[] =
{
"16 16 2 1",
" 	c #000000",
".	c #FFFFFF",
"                ",
"                ",
"                ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"   ..........   ",
"                ",
"                ",
"                "
};

static char * copy_xpm[] =
{
"16 16 2 1",
" 	c #FFFFFF",
".	c #D41F1F",
"      ....      ",
"      ....      ",
"      ....      ",
"      ....      ",
"      ....      ",
"      ....      ",
"................",
"................",
"................",
"................",
"      ....      ",
"      ....      ",
"      ....      ",
"      ....      ",
"      ....      ",
"      ....      "}
;

static char * stop_xpm[] =
{
    "16 16 2 1 8 8",
    "  c None",
    ". c #000000",
    ".              .",
    " .            . ",
    "  .          .  ",
    "   .        .   ",
    "    .      .    ",
    "     .    .     ",
    "      .  .      ",
    "................",
    "................",
    "      .  .      ",
    "     .    .     ",
    "    .      .    ",
    "   .        .   ",
    "  .          .  ",
    " .            . ",
    ".              ."
};


// ----------------------------------------------------------------------------
// MyDataFormat
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
class MyDataFormat : public wxDataFormat
{
public:
    MyDataFormat () : wxDataFormat (wxT("MyDataFormat")) {}
};

MyDataFormat myDataFormat;


// ----------------------------------------------------------------------------
// MyDataObject, this class must be derived from wxDataObject class, so
// it works like a wrapper of the user data "Thing" class.
// ----------------------------------------------------------------------------


class Thing;

// ----------------------------------------------------------------------------
class MyDataObject : public wxDataObjectSimple
{
private:
    Thing* theThing;

public:
    MyDataObject () : wxDataObjectSimple ()
    {
        SetFormat (myDataFormat);
    }

    size_t GetDataSize() const
    {
        return sizeof (void*);
    }

    bool GetDataHere (void* buf) const
    {
        *(Thing**)buf = theThing;   //only copy the address
        return true;
    }

    bool SetData (size_t len, const void* buf)
    {
        theThing = *(Thing**)buf;   //store only the buffer address
        return true;
    }

    Thing* getTheThing()
    {
        return theThing;
    }
};


// ----------------------------------------------------------------------------
// MyDropTarget interface, this class will associate with the Thing window
// ----------------------------------------------------------------------------
class MyDropTarget : public wxDropTarget
{
private:
    Thing* destThing;

public:
    MyDropTarget (Thing* destThing);
    wxDragResult OnData (wxCoord x, wxCoord y, wxDragResult def);
    wxDragResult OnDragOver (wxCoord x, wxCoord y, wxDragResult def);
};


// ----------------------------------------------------------------------------
// MyDropTargetPane interface, this class will associate with the Pane window
// ----------------------------------------------------------------------------

class Pane;

class MyDropTargetPane : public wxDropTarget
{
private:
    Pane* m_DestPane;

public:
    MyDropTargetPane (Pane* destPane);
    wxDragResult OnData (wxCoord x, wxCoord y, wxDragResult def);
    wxDragResult OnDragOver (wxCoord x, wxCoord y, wxDragResult def);
};



// ----------------------------------------------------------------------------
// Thing, it is just a small rectangle window show a number on the center
// ----------------------------------------------------------------------------

class Thing : public wxWindow
{
private:
    int id;
    wxCursor* cursorCopy;
    wxCursor* cursorMove;
    wxCursor* cursorStop;
    wxPoint   m_dragStartPos;
    bool      m_dragStartReady;
    DECLARE_EVENT_TABLE();

public:
    // ----------------------------------------------------------------------------
    // constructor
    Thing (wxWindow* parent, int id, wxCursor* cursorCopy, wxCursor* cursorMove, wxCursor* cursorStop) :
        wxWindow (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE),
        id (id),
        cursorCopy (cursorCopy),
        cursorMove (cursorMove),
        cursorStop (cursorStop),
        m_dragStartReady( false )
    {
        SetInitialSize (wxSize(100,100));

        SetDropTarget (new MyDropTarget(this));// associate this window with a drop target
    }

    // ----------------------------------------------------------------------------
    void onLeftDown (wxMouseEvent& event)
    {
        m_dragStartPos = event.GetPosition();
        m_dragStartReady = true;
    }

    void OnMouseMove (wxMouseEvent& event)
    {
        if (event.Dragging() && m_dragStartReady )
        {
            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)
            {
                //m_dragStartReady = false;
                return;
            }

            // a real drag
            Thing* myData = this; // we need one more level of indirection for SetData.
            MyDataObject data;
            data.SetData (sizeof (Thing*), &myData);

            wxDropSource source (data, this, *cursorCopy, *cursorMove, *cursorStop);
            wxDragResult result = source.DoDragDrop (wxDrag_AllowMove);
            //Here, we should check the result value to decide whether we need to update the source
            //e.g. we can move the window to some where, or copy to some place
        }
        else
        {
            m_dragStartReady = false;
        }
    }

    // ----------------------------------------------------------------------------
    void OnPaint (wxPaintEvent& event)
    {
        int xOffset = 50;
        int yOffset = 50;
        wxString s;
        s.Printf (wxT("%d"), id);
        wxPaintDC dc (this);
        dc.DrawRoundedRectangle (0,0,100,100,5.0);
        dc.DrawText (s, xOffset, yOffset);          //draw the ID in the middle of the Thing window
    }
    // ----------------------------------------------------------------------------
    int getId () const
    {
        return id;
    }
    // ----------------------------------------------------------------------------
    void setId (int value)
    {
        id = value;
    }
};

BEGIN_EVENT_TABLE(Thing, wxWindow)
    EVT_PAINT(Thing::OnPaint)
    EVT_LEFT_DOWN (Thing::onLeftDown)
    EVT_MOTION(Thing::OnMouseMove)
END_EVENT_TABLE()


// ----------------------------------------------------------------------------
// MyDropTarget
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
MyDropTarget::MyDropTarget (Thing* destThing) :
    destThing (destThing)
{
    SetDataObject (new MyDataObject());
}

//
// this function will be called when the user release the button (drop) on the target
// ----------------------------------------------------------------------------
wxDragResult MyDropTarget::OnData (wxCoord x, wxCoord y, wxDragResult def)
{
    if (!GetData())
    {
        wxLogMessage  (wxT("GetData failed"));
        return wxDragError;
    }

    //the m_dataObject member in wxDropTarget class holds the actually buffer pointer
    MyDataObject* data = dynamic_cast<MyDataObject*>(m_dataObject);

    //destThing is the target window.
    //data->getTheThing() is the source window.
    wxLogMessage  (wxT("onData: from %d to %d, then swap Id"), data->getTheThing()->getId(), destThing->getId());
    int targetId = destThing->getId();
    int sourceId = data->getTheThing()->getId();
    //swap their Ids
    destThing->setId(sourceId);
    destThing->Refresh();
    data->getTheThing()->setId(targetId);
    data->getTheThing()->Refresh();

    return def;
}

// ----------------------------------------------------------------------------
wxDragResult MyDropTarget::OnDragOver (wxCoord x, wxCoord y, wxDragResult def)
{
//    int height = destThing->GetSize().y;
//    if (y < height/2)
//        return wxDragCopy;
//    else


//always return the Move icon, because when we drop a Thing on a Thing, we do the Id swap
    return wxDragMove;
}


// ----------------------------------------------------------------------------
// Pane
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
class Pane : public wxScrolledWindow
{
private:
    wxCursor* cursorCopy;
    wxCursor* cursorMove;
    wxCursor* cursorStop;
    DECLARE_EVENT_TABLE();

public:
    // ----------------------------------------------------------------------------
    Pane (wxWindow* frame) :
        wxScrolledWindow (frame, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL)
    {
        SetScrollRate (0, 20);
        SetBackgroundColour (wxT("YELLOW"));
        createCursors ();

        //I remove the sizer, because I would like the drag the Thing window anywhere in the Pane
        //wxSizer* sizer = new wxBoxSizer (wxVERTICAL);
        //SetSizer (sizer);
        //SetAutoLayout (true);

        for (size_t i = 1;  i < 6;  i++)
        {
            Thing* node = new Thing (this, i, cursorCopy, cursorMove, cursorStop);
            node->Move(i*100-100,i*100-100);
            //sizer->Add (node);
        }

        wxSize size = GetBestVirtualSize();
        SetVirtualSize( size );

        //The panel can accept the dropping Thing object
        SetDropTarget (new MyDropTargetPane(this));// associate this window with a drop target
    }

    // ----------------------------------------------------------------------------
    // destructor
    ~Pane ()
    {
        delete cursorCopy;
        delete cursorMove;
        delete cursorStop;
    }
    // ----------------------------------------------------------------------------
    // Adding a new Thing object, this is used when the user want to COPY a Thing by dragging
    Thing * AddNewThing(int id)
    {
        return new Thing (this, id, cursorCopy, cursorMove, cursorStop);
    }

    // ----------------------------------------------------------------------------
    void createCursors ()
    {
        wxBitmap bmTop (move_xpm, wxBITMAP_TYPE_XPM);
        wxImage  imgTop = bmTop.ConvertToImage();
        imgTop.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_X, 8);
        imgTop.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8);
        cursorMove = new wxCursor (imgTop);

        wxBitmap bmBottom (copy_xpm, wxBITMAP_TYPE_XPM);
        wxImage  imgBottom = bmBottom.ConvertToImage();
        imgBottom.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_X, 8);
        imgBottom.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8);
        cursorCopy = new wxCursor (imgBottom);

        wxBitmap bmNone (stop_xpm, wxBITMAP_TYPE_XPM);
        wxImage  imgNone = bmNone.ConvertToImage();
        imgNone.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_X, 8);
        imgNone.SetOption (wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8);
        cursorStop = new wxCursor (imgNone);
    }

}; // Pane

BEGIN_EVENT_TABLE(Pane, wxScrolledWindow)
END_EVENT_TABLE()




// ----------------------------------------------------------------------------
// MyDropTargetPane
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
MyDropTargetPane::MyDropTargetPane (Pane* destPane) :
    m_DestPane (destPane)
{
    SetDataObject (new MyDataObject());  //We use the same DataObject as Thing window
}


//
// this function will be called when the user release the button (drop) on the target
// ----------------------------------------------------------------------------
wxDragResult MyDropTargetPane::OnData (wxCoord x, wxCoord y, wxDragResult def)
{
    if (!GetData())
    {
        wxLogMessage  (wxT("GetData failed"));
        return wxDragError;
    }

    //the m_dataObject member in wxDropTarget class holds the actually buffer pointer
    MyDataObject* data = dynamic_cast<MyDataObject*>(m_dataObject);

    //m_DestPane is the target window.
    //data->getTheThing() is the source window.

    switch ( def )
    {
            case wxDragError:      break;
            case wxDragNone:       break;

            case wxDragCopy:
                {
                    wxLogMessage  (wxT("onData: COPY %d"), data->getTheThing()->getId());
                    Thing* node = m_DestPane->AddNewThing(data->getTheThing()->getId()+10);
                    node->Move(x,y);
                    break;
                }
            case wxDragMove:
                {
                    wxLogMessage  (wxT("onData: MOVE %d"), data->getTheThing()->getId());
                    data->getTheThing()->Move(x,y);
                    break;
                }
            case wxDragCancel:  break;
            default:            break;
    }

    //wxLogMessage  (wxT("onData: MOVE %d"), data->getTheThing()->getId());
    //data->getTheThing()->Move(x,y);
    return def;
}

// ----------------------------------------------------------------------------
wxDragResult MyDropTargetPane::OnDragOver (wxCoord x, wxCoord y, wxDragResult def)
{
    //if we hold the ctrl key, we need to do a copy, so show the copy icon
    if (wxGetKeyState(WXK_CONTROL))
        return wxDragCopy;
    else
        return wxDragMove;
}




// ----------------------------------------------------------------------------
// MainFrame
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
class MainFrame : public wxFrame
{
private:
    DECLARE_EVENT_TABLE();
    Pane* pane;

public:
    // ----------------------------------------------------------------------------
    MainFrame(const wxString& title) :
        wxFrame(NULL, wxID_ANY, title, wxPoint (300,100), wxSize (500,500))
    {
        // build contents
        SetBackgroundColour (wxT("GREEN"));
        pane = new Pane (this);
    }

    // ----------------------------------------------------------------------------
    void onClose(wxCloseEvent& event)
    {
        Destroy();
    }
};

BEGIN_EVENT_TABLE(MainFrame, wxFrame)
    EVT_CLOSE(MainFrame::onClose)
END_EVENT_TABLE();



// ----------------------------------------------------------------------------
// Application
// ----------------------------------------------------------------------------

class TestApp : public wxApp
{
public:
    virtual bool OnInit()
    {

        // debug settings - for detecting memory leaks (MSVC only feature)
        //  _CrtSetDbgFlag (_CrtSetDbgFlag (_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

        // call the base class initialization method, currently it only parses a
        // few common command-line options but it could be do more in the future
        if ( !wxApp::OnInit() )
            return false;

        // create the main application window
        MainFrame *frame = new MainFrame(_T("TestApp"));
        frame->Show(true);

        wxLog::SetActiveTarget(new wxLogStderr());

        return true;
    }

    virtual ~TestApp()
    {
    }
};

IMPLEMENT_APP(TestApp)

Post Reply