Drag and Drop: Added internal BeginDragDropTargetCustom() convenient to avoid submitting dummy ItemAdd. (#143)

This commit is contained in:
omar 2017-11-10 13:13:28 +01:00
parent 4b94738c7e
commit 7908cce25f
2 changed files with 35 additions and 9 deletions

View File

@ -10776,6 +10776,27 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s
return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
} }
bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
{
ImGuiContext& g = *GImGui;
if (!g.DragDropActive)
return false;
ImGuiWindow* window = g.CurrentWindow;
if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
return false;
if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id && id == g.DragDropPayload.SourceId))
return false;
g.DragDropTargetRect = bb;
g.DragDropTargetId = id;
return true;
}
// We don't use BeginDragDropTargetCustom() and duplicate its code because:
// 1) LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle it.
// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
bool ImGui::BeginDragDropTarget() bool ImGui::BeginDragDropTarget()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -10785,9 +10806,11 @@ bool ImGui::BeginDragDropTarget()
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (!window->DC.LastItemRectHoveredRect || (window->DC.LastItemId && window->DC.LastItemId == g.DragDropPayload.SourceId)) if (!window->DC.LastItemRectHoveredRect || (window->DC.LastItemId && window->DC.LastItemId == g.DragDropPayload.SourceId))
return false; return false;
if (window->RootWindow != g.HoveredWindow->RootWindow) if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
return false; return false;
g.DragDropTargetRect = window->DC.LastItemRect;
g.DragDropTargetId = window->DC.LastItemId;
return true; return true;
} }
@ -10797,25 +10820,22 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
ImGuiPayload& payload = g.DragDropPayload; ImGuiPayload& payload = g.DragDropPayload;
IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
IM_ASSERT(window->DC.LastItemRectHoveredRect); // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ?
if (type != NULL && !payload.IsDataType(type)) if (type != NULL && !payload.IsDataType(type))
return NULL; return NULL;
// NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
const bool was_accepted_previously = (g.DragDropAcceptIdPrev == window->DC.LastItemId);
g.DragDropAcceptIdCurr = window->DC.LastItemId;
// Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
ImRect r = window->DC.LastItemRect; // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
ImRect r = g.DragDropTargetRect;
float r_surface = r.GetWidth() * r.GetHeight(); float r_surface = r.GetWidth() * r.GetHeight();
if (r_surface < g.DragDropAcceptIdCurrRectSurface) if (r_surface < g.DragDropAcceptIdCurrRectSurface)
{ {
g.DragDropAcceptIdCurr = window->DC.LastItemId; g.DragDropAcceptIdCurr = g.DragDropTargetId;
g.DragDropAcceptIdCurrRectSurface = r_surface; g.DragDropAcceptIdCurrRectSurface = r_surface;
} }
// Render drop visuals // Render default drop visuals
if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously)
{ {
// FIXME-DRAG FIXME-STYLE: Settle on a proper default visuals for drop target, w/ ImGuiCol enum value probably. // FIXME-DRAG FIXME-STYLE: Settle on a proper default visuals for drop target, w/ ImGuiCol enum value probably.
@ -10826,6 +10846,7 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
window->DrawList->AddRect(r.Min + ImVec2(1.5f,1.5f), r.Max - ImVec2(1.5f,1.5f), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); window->DrawList->AddRect(r.Min + ImVec2(1.5f,1.5f), r.Max - ImVec2(1.5f,1.5f), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f);
if (push_clip_rect) window->DrawList->PopClipRect(); if (push_clip_rect) window->DrawList->PopClipRect();
} }
g.DragDropAcceptFrameCount = g.FrameCount; g.DragDropAcceptFrameCount = g.FrameCount;
payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton); payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton);
if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))

View File

@ -480,6 +480,8 @@ struct ImGuiContext
ImGuiDragDropFlags DragDropSourceFlags; ImGuiDragDropFlags DragDropSourceFlags;
int DragDropMouseButton; int DragDropMouseButton;
ImGuiPayload DragDropPayload; ImGuiPayload DragDropPayload;
ImRect DragDropTargetRect;
ImGuiID DragDropTargetId;
float DragDropAcceptIdCurrRectSurface; float DragDropAcceptIdCurrRectSurface;
ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload)
ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets)
@ -567,6 +569,7 @@ struct ImGuiContext
DragDropActive = false; DragDropActive = false;
DragDropSourceFlags = 0; DragDropSourceFlags = 0;
DragDropMouseButton = -1; DragDropMouseButton = -1;
DragDropTargetId = 0;
DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0;
DragDropAcceptFrameCount = -1; DragDropAcceptFrameCount = -1;
memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));
@ -835,6 +838,8 @@ namespace ImGui
IMGUI_API void Scrollbar(ImGuiLayoutType direction); IMGUI_API void Scrollbar(ImGuiLayoutType direction);
IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). not exposed because it is misleading what it doesn't have an effect on regular layout. IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). not exposed because it is misleading what it doesn't have an effect on regular layout.
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
// FIXME-WIP: New Columns API // FIXME-WIP: New Columns API
IMGUI_API void BeginColumns(const char* id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). IMGUI_API void BeginColumns(const char* id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
IMGUI_API void EndColumns(); // close columns IMGUI_API void EndColumns(); // close columns