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)
View and moderate all "feature-requests Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Feature Requests"
btw, wxDropTarget is missing some functions too. I'll post more details after some more testing.
View and moderate all "feature-requests Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Feature Requests"
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
View and moderate all "feature-requests Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Feature Requests"
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)
View and moderate all "feature-requests Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Feature Requests"
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
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.