Menu

#3 Drag and drop requires wxDropSource::DoDragDrop

closed-fixed
None
5
2012-04-07
2010-09-07
Anonymous
No

it seems that the DoDragDrop function is required to get drag and drop working

In wxcore_clipddrag.cpp add the following
// MODIFICATION
static wxLuaArgType s_wxluatypeArray_wxLua_wxDropSource_DoDragDrop[] = { &wxluatype_wxDropSource, &wxluatype_TINTEGER, NULL };
static int LUACALL wxLua_wxDropSource_DoDragDrop(lua_State *L);
static wxLuaBindCFunc s_wxluafunc_wxLua_wxDropSource_DoDragDrop[1] = {{ wxLua_wxDropSource_DoDragDrop, WXLUAMETHOD_METHOD, 2, 2, s_wxluatypeArray_wxLua_wxDropSource_DoDragDrop }};
// virtual wxDragResult DoDragDrop(int flags = wxDrag_CopyOnly)
static int LUACALL wxLua_wxDropSource_DoDragDrop(lua_State *L)
{
// wxDragResult effect
int flags = (int)wxlua_getintegertype(L, 2);
// get this
wxDropSource * self = (wxDropSource *)wxluaT_getuserdatatype(L, 1, wxluatype_wxDropSource);
// call GiveFeedback
wxDragResult result = (self->DoDragDrop(flags));
// push the result flag
lua_pushinteger(L, result);

return 1;
}
// MODIFICATION

and register the function after GiveFeedback for example:
{ "GiveFeedback", WXLUAMETHOD_METHOD, s_wxluafunc_wxLua_wxDropSource_GiveFeedback, 1, NULL },

{ "DoDragDrop", WXLUAMETHOD_METHOD, s_wxluafunc_wxLua_wxDropSource_DoDragDrop, 1, NULL },

in lua, the following can now be used to start a drag and drop operation:
local control = wx.wxListCtrl(parent, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxSize(200, 200),
wx.wxLC_ICON)

control:InsertItem(0, "Cube",0)
control:InsertItem(1, "Sphere",1)
control:InsertItem(2, "Cylinder",2)
control:InsertItem(3, "Rectangle",3)

control:Connect(wx.wxEVT_COMMAND_LIST_BEGIN_DRAG,
function(event)
local data = wx.wxTextDataObject("This text will be dragged.");
local dropsource = wx.wxDropSource(data,control)
dropsource:DoDragDrop(1)
end)

Discussion

  • Anonymous

    Anonymous - 2010-09-07

    btw, wxDropTarget is missing some functions too. I'll post more details after some more testing.

     
  • Anonymous

    Anonymous - 2010-09-08

    After some more digging, I end up to 2 fundamental issues with the way wxLua and wx are implemented. I guess now it makes sense why wxDropTarget wasn't implemented.

    ------------
    First, wxDropTarget still has some pure virtual member. So in wxLua, you are not supposed to be able to do dropTarget = wx.wxDropTarget.
    The reason for this is that wxDropTarget is a callback call, it has an OnData function which is used by the wxWidget user to implement his own callback code in response to the drag and drop. How do we translate that in wxLua ?
    I can easily define in wxcore_clipdrag.cpp the following:

    [code]
    //create a class derived from wxDropTarget which can be instantiated
    class wxDropTarget_ForLUA : public wxDropTarget
    {
    public:
    wxDropTarget_ForLUA(wxDataObject *dataObject = NULL):wxDropTarget(dataObject){}
    virtual ~wxDropTarget_ForLUA(){}

    // called after OnDrop() returns TRUE: you will usually just call
    // GetData() from here and, probably, also refresh something to update the
    // new data and, finally, return the code indicating how did the operation
    // complete (returning default value in case of success and wxDragError on
    // failure is usually ok)virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
    virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
    {
    bool ret = GetData();

    //HERE I NEED TO SIGNAL SOMEONE!!! how to do that in wxLua???

    wxDragResult res;
    if (ret)
    res = GetDefaultAction();
    else
    res = wxDragError;
    return res;
    }
    };

    static int LUACALL wxLua_wxDropTarget_constructor(lua_State *L)
    {
    // get number of arguments
    int argCount = lua_gettop(L);
    //ignores the parameter
    //wxDataObject *dataObject = (argCount >= 1 ? (wxDataObject *)wxluaT_getuserdatatype(L, 1, wxluatype_wxDataObject) : NULL);
    //create a new wxTextDataObject here, this is because wxDropTarget needs to own the wxDataObject, it will delete it in its destructor!!!!
    wxDataObject *dataObject = new wxTextDataObject;
    // call constructor
    wxDropTarget* returns = new wxDropTarget_ForLUA(dataObject);
    // add to tracked memory list
    wxluaO_addgcobject(L, (void*)returns, new wxLua_wxObject_wxDropTarget((wxDropTarget*)returns));
    // push the constructed class pointer
    wxluaT_pushuserdatatype(L, returns, wxluatype_wxDropTarget);

    return 1;
    }

    [/code]
    so this solve the virtual class issue and we can now create a wxDropTarget in lua. But this object is not firing any event. We somehow need to connect this to the wxLua event systtem.
    I am not familiar enough with wxLua, How is it usually done?

    ------------
    Second, wxWindow::SetDropTarget and the wxDropTargetBase constructors are nasty. They both stores pointers on objects and assume that they now own them and are now responsible of deleting them when the program exist.

    for setDropTarget for example, in wxcore_windows.cpp, it's implemented like this:
    static int LUACALL wxLua_wxWindow_SetDropTarget(lua_State *L)
    {
    // wxDropTarget target
    wxDropTarget * target = (wxDropTarget *)wxluaT_getuserdatatype(L, 2, wxluatype_wxDropTarget);
    // get this
    wxWindow * self = (wxWindow *)wxluaT_getuserdatatype(L, 1, wxluatype_wxWindow);
    // call SetDropTarget
    self->SetDropTarget(target);

    return 0;
    }

    So the droptarget pointer is passed directly to the wxWindow. This causes a crash when the application quit. Because lua still has a reference on that object when it was created in the lua program. So when the application closes both the wxWindow and the regular lua garbage collector will try to delete this object. based on the order of things, one or the other will crash.
    The same happen with wxDropTargetBase which assumes ownership of the wxDataObject passed in parameters.
    Again, how is this solved in wxLua usually. An ok solution would be to pass a duplicate of the instance to wx, so that wx can delete it if it wishes, while lua keeps a pointer on the original. but those 2 objects would not be linked anymore. and any operation done on the one would affect the content of the second one as it should?

    I can help with the patch or the temporary solution, but I need some hints regarding how wxLua is designed and what are the typical solutions for those issues, beside modyfing the wx code ( which from far would be the easiest :)

    thanks,
    Cedric

     
  • Anonymous

    Anonymous - 2010-09-09

    Hi,

    This is fixed for me. I implemented a wxLuaDropTarget class which does pretty much what wxLuaArtProvider does, I used wxluaO_undeletegcobject to solve the problems of ownership, and changed the signature of the binding of wxWindow:SetDropTarget to accept a wxLuaDropTarget instead of a wxLuaTarget, as I couldn't find how to get the derivation working in lua.

    ---------------------------------------
    \wxLua\modules\wxbind\src\wxcore_wxlcore.cpp:
    #if wxLUA_USE_wxDragDrop && wxUSE_DRAG_AND_DROP

    // This lua tag is defined in clipdrag
    extern WXDLLIMPEXP_DATA_BINDWXCORE(int) wxluatype_wxLuaDropTarget;

    wxLuaDropTarget::wxLuaDropTarget(const wxLuaState& wxlState, wxDataObject *dataObject) : wxDropTarget(dataObject), m_wxlState(wxlState)
    {
    }

    wxDragResult wxLuaDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def)
    {
    wxDragResult res;

    if (m_wxlState.Ok() && !m_wxlState.GetCallBaseClassFunction() &&
    m_wxlState.HasDerivedMethod(this, "OnData", true))
    {
    int nOldTop = m_wxlState.lua_GetTop();
    m_wxlState.wxluaT_PushUserDataType(this, wxluatype_wxLuaDropTarget, true);
    m_wxlState.lua_PushNumber((int)x);
    m_wxlState.lua_PushNumber((int)y);
    m_wxlState.lua_PushNumber((int)def);

    if (m_wxlState.LuaPCall(4, 1) == 0)
    {
    res = (wxDragResult)m_wxlState.GetIntegerType(-1);
    }
    else
    res = wxDragError;

    m_wxlState.lua_SetTop(nOldTop);
    }
    else
    {
    res = GetData() ? GetDefaultAction() : wxDragError;
    }

    return res;

    m_wxlState.SetCallBaseClassFunction(false); // clear flag always
    }

    #endif

    -------------------------------------------------------
    wxLua\modules\wxbind\src\wxcore_clipdrag.cpp

    #if wxLUA_USE_wxDragDrop && wxUSE_DRAG_AND_DROP
    // ---------------------------------------------------------------------------
    // Bind class wxDropTarget
    // ---------------------------------------------------------------------------

    // Lua MetaTable Tag for Class 'wxDropTarget'
    int wxluatype_wxDropTarget = WXLUA_TUNKNOWN;

    static int LUACALL wxLua_wxDropTarget_GetData(lua_State *L);
    static wxLuaBindCFunc s_wxluafunc_wxLua_wxDropTarget_GetData[1] = {{ wxLua_wxDropTarget_GetData, WXLUAMETHOD_METHOD, 0, 0, g_wxluaargtypeArray_None }};
    // virtual bool GetData()
    static int LUACALL wxLua_wxDropTarget_GetData(lua_State *L)
    {
    // get this
    wxDropTarget * self = (wxDropTarget *)wxluaT_getuserdatatype(L, 1, wxluatype_wxDropTarget);
    // call GetData
    bool returns = (self->GetData());
    // push the result flag
    lua_pushboolean(L, returns);

    return 1;
    }

    static wxLuaArgType s_wxluatypeArray_wxLua_wxDropTarget_delete[] = { &wxluatype_wxDropTarget, NULL };
    static wxLuaBindCFunc s_wxluafunc_wxLua_wxDropTarget_delete[1] = {{ wxlua_userdata_delete, WXLUAMETHOD_METHOD|WXLUAMETHOD_DELETE, 1, 1, s_wxluatypeArray_wxLua_wxDropTarget_delete }};

    // Map Lua Class Methods to C Binding Functions
    wxLuaBindMethod wxDropTarget_methods[] = {
    { "GetData", WXLUAMETHOD_METHOD, s_wxluafunc_wxLua_wxDropTarget_GetData, 1, NULL },

    { "delete", WXLUAMETHOD_METHOD|WXLUAMETHOD_DELETE, s_wxluafunc_wxLua_wxDropTarget_delete, 1, NULL },

    { 0, 0, 0, 0 },
    };

    int wxDropTarget_methodCount = sizeof(wxDropTarget_methods)/sizeof(wxLuaBindMethod) - 1;

    #endif // wxLUA_USE_wxDragDrop && wxUSE_DRAG_AND_DROP

    #if wxLUA_USE_wxDragDrop && wxUSE_DRAG_AND_DROP
    // ---------------------------------------------------------------------------
    // Bind class wxLuaDropTarget
    // ---------------------------------------------------------------------------

    // Lua MetaTable Tag for Class 'wxLuaDropTarget'
    int wxluatype_wxLuaDropTarget = WXLUA_TUNKNOWN;

    static wxLuaArgType s_wxluatypeArray_wxLua_wxLuaDropTarget_OnData[] = { &wxluatype_wxLuaDropTarget, &wxluatype_TNUMBER, &wxluatype_TNUMBER, NULL };
    static int LUACALL wxLua_wxLuaDropTarget_OnData(lua_State *L);
    static wxLuaBindCFunc s_wxluafunc_wxLua_wxLuaDropTarget_OnData[1] = {{ wxLua_wxLuaDropTarget_OnData, WXLUAMETHOD_METHOD, 4, 4, g_wxluaargtypeArray_None }};
    //virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def);
    static int LUACALL wxLua_wxLuaDropTarget_OnData(lua_State *L)
    {
    // wxDragResult res
    wxDragResult res = (wxDragResult)(int)wxlua_getnumbertype(L, 4);
    // int y
    wxCoord y = (wxCoord)(int)wxlua_getnumbertype(L, 3);
    // int x
    wxCoord x = (wxCoord)(int)wxlua_getnumbertype(L, 2);

    // get this
    wxLuaDropTarget * self = (wxLuaDropTarget *)wxluaT_getuserdatatype(L, 1, wxluatype_wxLuaDropTarget);
    // call OnData
    bool returns = (self->OnData(x,y,res));
    // push the result flag
    lua_pushnumber(L, returns);

    return 1;
    }

    static wxLuaArgType s_wxluatypeArray_wxLua_wxLuaDropTarget_delete[] = { &wxluatype_wxLuaDropTarget, NULL };
    static wxLuaBindCFunc s_wxluafunc_wxLua_wxLuaDropTarget_delete[1] = {{ wxlua_userdata_delete, WXLUAMETHOD_METHOD|WXLUAMETHOD_DELETE, 1, 1, s_wxluatypeArray_wxLua_wxLuaDropTarget_delete }};

    static wxLuaArgType s_wxluatypeArray_wxLua_wxLuaDropTarget_constructor[] = { &wxluatype_wxDataObject, NULL };
    static int LUACALL wxLua_wxLuaDropTarget_constructor(lua_State *L);
    static wxLuaBindCFunc s_wxluafunc_wxLua_wxLuaDropTarget_constructor[1] = {{ wxLua_wxLuaDropTarget_constructor, WXLUAMETHOD_CONSTRUCTOR, 0, 1, s_wxluatypeArray_wxLua_wxLuaDropTarget_constructor }};
    //wxLuaDropTarget(wxDataObject *dataObject = NULL);
    static int LUACALL wxLua_wxLuaDropTarget_constructor(lua_State *L)
    {
    // get number of arguments
    int argCount = lua_gettop(L);
    //ignores the parameter
    wxDataObject *dataObject = (argCount >= 1 ? (wxDataObject *)wxluaT_getuserdatatype(L, 1, wxluatype_wxDataObject) : NULL);

    if (dataObject)
    {
    //the wxLuaDropTarget will take ownership of the dataObject
    if (wxluaO_isgcobject(L, dataObject)) wxluaO_undeletegcobject(L, dataObject);
    }

    wxLuaDropTarget* returns = new wxLuaDropTarget(L,dataObject);
    // add to tracked memory list
    wxluaO_addgcobject(L, (void*)returns, new wxLua_wxObject_wxLuaDropTarget((wxLuaDropTarget*)returns));
    // push the constructed class pointer
    wxluaT_pushuserdatatype(L, returns, wxluatype_wxLuaDropTarget);

    return 1;
    }

    // Map Lua Class Methods to C Binding Functions
    wxLuaBindMethod wxLuaDropTarget_methods[] = {
    { "OnData", WXLUAMETHOD_METHOD, s_wxluafunc_wxLua_wxLuaDropTarget_OnData, 1, NULL },

    { "wxLuaDropTarget", WXLUAMETHOD_CONSTRUCTOR, s_wxluafunc_wxLua_wxLuaDropTarget_constructor, 1, NULL },

    { "delete", WXLUAMETHOD_METHOD|WXLUAMETHOD_DELETE, s_wxluafunc_wxLua_wxLuaDropTarget_delete, 1, NULL },

    { 0, 0, 0, 0 },
    };

    int wxLuaDropTarget_methodCount = sizeof(wxLuaDropTarget_methods)/sizeof(wxLuaBindMethod) - 1;

    #endif // wxLUA_USE_wxDragDrop && wxUSE_DRAG_AND_DROP

    ------------------------------------------------------
    lua script:

    -- target setup
    local dropTarget = nil
    local dataObject = nil

    textDataObject = wx.wxTextDataObject()
    dropTarget = wx.wxLuaDropTarget(textDataObject)

    function dropTarget:OnData(x,y,result)
    d3dsetcolor()
    d3dwindow:Refresh()
    return result
    end

    d3dwindow:SetDropTarget(dropTarget)

    -- source setup:
    local control = wx.wxListCtrl(parent, wx.wxID_ANY,
    wx.wxDefaultPosition, wx.wxSize(200, 200),
    wx.wxLC_ICON)

    control:Connect(wx.wxEVT_COMMAND_LIST_BEGIN_DRAG,
    function(event)
    local data = wx.wxTextDataObject("This text will be dragged.")
    local dropsource = wx.wxDropSource(data,control)
    dropsource:DoDragDrop(1)
    end)

     
  • Anonymous

    Anonymous - 2010-09-09

    if someone needs the source or a true patch let me know, beside what I have poster, there are few small functions and objects declarations here and there, but nothing major. the drag work works like a charm for me now.
    Cedric

     
  • John Labenski

    John Labenski - 2012-04-07
    • assigned_to: nobody --> jrl1
    • status: open --> closed-fixed
     
  • John Labenski

    John Labenski - 2012-04-07

    The appropriate fix was to unrem out wxDropSource's
    virtual wxDragResult DoDragDrop(int flags = wxDrag_CopyOnly)
    function in bindings/wxwidgets/wxcore_clipdrag.i
    and regenerate the bindings. It had been mistakenly remmed out since I didn't think it was needed.

    Thanks, fixed in SVN.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.