Using IntPtr (For example, with SetDragDropPayload)
Hi there! I have a bit of a newbie question to ask since I'm having a hard time finding how people approach this: How should I go about using ImGui.NET methods that take an IntPtr?
For example, ImGui.SetDragDropPayload takes a type string, an IntPtr, and a size. When I ImGui.GetDragDropPayload() I don't seem to be able to just grab the type that I set (I can only query if it is a certain type)... And I'm not sure how to use IntPtr to represent an object in my game engine.
I feel like there is a fundamental paradigm that I'm not understanding here, as using IntPtr to hold game data seems like a common thing in ImGui.NET. I've done some looking into how to represent objects as IntPtr in .Net, but this seems to point me to creating IntPtr for use in WinApi functions and I haven't been able to get anything working yet or understand how I should be approaching this...
As you can probably tell, I'm also entirely unfamiliar with the C++ Dear ImGui, so this makes things even trickier for me to get my head around. Any thoughts would be appreciated!
Thanks, Allen
Edit:
Here's an example of how I'm using it right now. As I mentioned, I don't know how to use the payload propertly, so I'm just using a separate static object to represent what's currently being dragged. Then checking to see if the payload's NativePtr is null or not. It seems to work, I think, but is obviously not ideal:
private static unsafe void SubmitTestWindow()
{
ImGui.Begin("Test");
string[] items = new string[] { "hello", "world", "how", "are", "you?" };
for (int i = 0; i < items.Length; i++)
{
ImGui.Button(items[i]);
if (ImGui.BeginDragDropSource())
{
ImGui.Text(items[i]);
ImGui.SetDragDropPayload(typeof(string).FullName, IntPtr.Zero, 0);
draggedItem = items[i];
ImGui.EndDragDropSource();
}
if (ImGui.BeginDragDropTarget())
{
var payload = ImGui.AcceptDragDropPayload(typeof(string).FullName);
if (payload.NativePtr != null)
{
Console.WriteLine("Dropped " + draggedItem + " onto " + items[i]);
draggedItem = null;
}
ImGui.EndDragDropTarget();
}
}
ImGui.End();
}
In this case of the drag and drop API, is easier to just use the item index, as your data is already in a list.
If you do need to marshal data, you could use the fixed statement to get a pointer to your data:
fixed (Data* dataPtr = data) { // or &obj.Data
ImGui.SetDragDropPayload(..., (IntPtr)dataPtr, sizeof(Data));
}
If data is a local variable, (IntPtr)&data is enough.
For functions that use the pointer for longer than the fixed block, you will need to allocate and free memory like this:
var dataPtr = (Data*)Marshal.AllocHGlobal(sizeof(Data));
*dataPtr = data; // or dataPtr[0] = data;
Foo((IntPtr)dataPtr, sizeof(Data));
Marshal.FreeHGlobal((IntPtr)dataPtr);
In any case, Data must be a blittable struct.
Edit: You can also use GCHandles for managed objects.
@Rafiuth You said that you could just use the item index, can you demonstrate that? I can't seem to get dragdrop working at all. I keep getting "attempted to read or write protected memory" errors
@Thraka I'm a bit rusty on ImGui, but I think you can just pass the variable address as the data parameter, like in the example below:
string[] dragItems = { "Apple", "Banana", "Orange", "Mango" };
private unsafe void DragDropSample()
{
for (int i = 0; i < dragItems.Length; i++) {
ImGui.Button(dragItems[i]);
if (ImGui.BeginDragDropSource()) {
ImGui.Text(dragItems[i]);
ImGui.SetDragDropPayload("ItemIndex", (IntPtr)(&i), sizeof(int));
ImGui.EndDragDropSource();
}
if (ImGui.BeginDragDropTarget()) {
var payload = ImGui.AcceptDragDropPayload("ItemIndex");
if (payload.NativePtr != null) {
var dataPtr = (int*)payload.Data;
int srcIndex = dataPtr[0];
var srcItem = dragItems[srcIndex];
dragItems[srcIndex] = dragItems[i];
dragItems[i] = srcItem;
}
ImGui.EndDragDropTarget();
}
}
}
Thanks! I'll take a look.
I also have this problem data cannot be written SetDragDropPayload return false
void DrawLogicTick()
{
if (ImGui::IsItemVisible() && ShowDragSpace)
{
if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey::ImGuiKey_MouseLeft))
{
DrawWidgetRect();
SelectWidget = this;
}
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
{
this->DrawIconForControlPanel();
ImGui::Text(WidgetName.c_str());
//ImGui::SetDragDropPayload("DragWidget", &i, sizeof(int));
if (!ImGui::SetDragDropPayload("DragWidget", this, sizeof(HWidget*)))//sizeof(HWidget*));
std::cout << "\n Set DrawWidget False";
ImGui::EndDragDropSource();
}
if (ImGui::BeginDragDropTarget())
{
B = true;
ImGui::EndDragDropTarget();
}
if (B)
{
ImVec2 WidgetSize = ImGui::GetItemRectSize();
ImVec2 WidgetPos = ImGui::GetCursorPos();
ImVec2 SaveVec = ImGui::GetCursorScreenPos();
//WidgetPos.y -= WidgetSize.y + 5;
HRect RootChildRect;
RootChildRect.top = WidgetPos.y - WidgetSize.y * 1.6;
RootChildRect.left = WidgetPos.x - WidgetSize.x * 0.25;
RootChildRect.right = WidgetPos.x + WidgetSize.x;
RootChildRect.below = (WidgetPos.y - 5);
ImGui::SetCursorPos(ImVec2(RootChildRect.left, RootChildRect.top));
ImGui::BeginChild(2 + (int)this, ImVec2(WidgetSize.x * 1.5, WidgetSize.y * 2));
ImGui::EndChild();
if (ImGui::BeginDragDropTarget())
{
ImGui::EndDragDropTarget();
}
else
{
B = false;
}
// Create Right Box
ImGui::SetCursorPos(ImVec2(RootChildRect.right, WidgetPos.y - WidgetSize.y - 5));
ImGui::BeginChild((int)this, ImVec2(WidgetSize.x * 0.25, WidgetSize.y), true);
ImGui::EndChild();
if (ImGui::BeginDragDropTarget())
{
ImDrawList* DL = ImGui::GetForegroundDrawList();
DL->AddLine(ImVec2(SaveVec.x + WidgetSize.x + 10, SaveVec.y - (WidgetSize.y + 5)), ImVec2(SaveVec.x + WidgetSize.x + 10, SaveVec.y), ImColor(255, 255, 255), 2);
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DragWidget"))
{
HWidget* SaveWidget = (HWidget*)payload->Data;
//if (SaveWidget->AvailableFlags & HWidgetFlag_TurnRight)
//{
Subclass = SaveWidget->CreateSelfClass();
Subclass->Flag = HWidgetFlag_TurnRight;
Subclass->Father = this;
//}
}
ImGui::EndDragDropTarget();
}
// Create Below Box
ImGui::SetCursorPosY(RootChildRect.below);//可能之后有问题
ImGui::BeginChild(1 + (int)this, ImVec2(WidgetSize.x, WidgetSize.y * 0.6), true);
ImGui::EndChild();
if (ImGui::BeginDragDropTarget())
{
ImDrawList* DL = ImGui::GetForegroundDrawList();
DL->AddLine(ImVec2(SaveVec.x, SaveVec.y + 5), ImVec2(SaveVec.x + WidgetSize.x, SaveVec.y + 5), ImColor(255, 255, 255), 2);
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DragWidget"))
{
HWidget* SaveWidget = (HWidget*)payload->Data;
std::cout << "\n SaveWidget " << SaveWidget;
//if (!SaveWidget->Father || !SelectWidget)
//{
// SaveWidget= SaveWidget->CreateSelfClass();
//}
//else
//{
// SaveWidget = SelectWidget;
//}
if (false)//SaveWidget->Father != NULL)
{
//if (SaveWidget->Subclass)
//{
// SaveWidget->Father->Subclass = SaveWidget->Subclass;
// SaveWidget->Subclass->Father = SaveWidget->Father;
// SaveWidget->Subclass->Flag = SaveWidget->Flag;
//}
//else
//{
// SaveWidget->Father->Subclass = NULL;
//}
//Subclass = SaveWidget;
//SaveWidget->Father = this;
}
else
{
if(SelectWidget)
std::cout << "\n Select Widget" << SelectWidget;
std::cout << "\n SaveWidget " << SaveWidget;
if (SaveWidget == SelectWidget)
{
}
else
{
std::cout << "\n Add Widget";
SaveWidget = SaveWidget->CreateSelfClass();
}
if (Subclass)
{
SaveWidget->Subclass = Subclass;
SaveWidget->Father = this;
Subclass->Father = SaveWidget;
Subclass = SaveWidget;
}
else
{
SaveWidget->Father = this;
Subclass = SaveWidget;
}
}
}
ImGui::EndDragDropTarget();
}
// Create Top Box
ImGui::SetCursorPosY(RootChildRect.top);
ImGui::BeginChild(3 + (int)this, ImVec2(WidgetSize.x, WidgetSize.y * 0.6), true);
ImGui::EndChild();
ImGui::SetCursorPos(ImVec2(RootChildRect.left, WidgetPos.y - WidgetSize.y - 5));
ImGui::BeginChild(4 + (int)this, ImVec2(WidgetSize.x * 0.25, WidgetSize.y), true);
ImGui::EndChild();
}
}
ImGui::EndGroup();
if (SelectWidget == this)
DrawWidgetRect();
if (Subclass)
{
Subclass->Draw();
}
}
I did it in less than 20 lines. (NOTE: this code is inside the BeginTabBar -> for loop.
if (ImGui.BeginDragDropSource())
{
this.ruleIndexToSwap = i;
ImGui.SetDragDropPayload("RuleIndex", IntPtr.Zero, 0);
ImGui.Text(currRule.Name);
ImGui.EndDragDropSource();
}
if (ImGui.BeginDragDropTarget())
{
ImGui.AcceptDragDropPayload("RuleIndex");
if (ImGui.IsMouseReleased(ImGuiMouseButton.Left))
{
this.SwapRules(this.ruleIndexToSwap, i);
}
ImGui.EndDragDropTarget();
}