From c5536e49efb61d786ea7f5a07031eeca34e00ec1 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Oct 2017 21:15:02 +0100 Subject: [PATCH 01/25] Drag and drop API experiment --- imgui.cpp | 172 ++++++++++++++++++++++++++++++++++++++++++++++- imgui_internal.h | 53 +++++++++++++++ 2 files changed, 223 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0c2e72a5..ad4a1895 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2231,6 +2231,15 @@ void ImGui::NewFrame() if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) g.ScalarAsInputTextId = 0; + // Elapse drag & drop payload + if (g.DragDropActive && g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) + { + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropPayloadBufHeap.clear(); + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + } + // Update keyboard input state memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) @@ -5868,7 +5877,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease)) if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps - pressed = true; + if (!g.DragDropActive) + pressed = true; ClearActiveID(); } } @@ -9426,7 +9436,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl else window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border - if (hovered && !(flags & ImGuiColorEditFlags_NoTooltip)) + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); return pressed; @@ -10584,6 +10594,164 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) } } +//----------------------------------------------------------------------------- +// DRAG AND DROP +//----------------------------------------------------------------------------- + +// Call when current ID is active. +// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.IO.MouseDown[mouse_button] == false) + return false; + if (g.ActiveId != window->DC.LastItemId) + return false; + + if (IsMouseDragging(mouse_button)) + { + if (!g.DragDropActive) + { + ImGuiPayload& payload = g.DragDropPayload; + payload.Clear(); + payload.SourceId = g.ActiveId; + payload.SourceParentId = window->IDStack.back(); + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + } + + if (!(flags & ImGuiDragDropFlags_SourceNoAutoTooltip)) + { + // FIXME-DRAG + //SetNextWindowPos(g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding); + //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This is better but e.g ColorButton with checkboard has issue with transparent colors :( + SetNextWindowPos(g.IO.MousePos); + PushStyleColor(ImGuiCol_PopupBg, GetStyleColorVec4(ImGuiCol_PopupBg) * ImVec4(1.0f, 1.0f, 1.0f, 0.6f)); + BeginTooltipEx(ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_ShowBorders); + } + return true; + } + return false; +} + +void ImGui::EndDragDropSource() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropPayload.DataFrameCount != -1); // Forgot to call SetDragDropSourcePayload(), at least once on the first frame of a successful BeginDragDropSource() + + if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoAutoTooltip)) + { + EndTooltip(); + PopStyleColor(); + //PopStyleVar(); + } +} + +// Use 'cond' to choose to submit paypload on drag start or every frame +bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + ImGuiPayload& payload = g.DragDropPayload; + if (cond == 0) + cond = ImGuiCond_Always; + + IM_ASSERT(type != NULL); + IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType)); // Payload type can be at most 8 characters longs + IM_ASSERT(data != NULL && data_size > 0); + IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); + IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() + + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + { + // Copy payload + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) + { + // Store in heap + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy((void*)payload.Data, data, data_size); + } + else if (data_size > 0) + { + // Store locally + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + payload.Data = g.DragDropPayloadBufLocal; + memcpy((void*)payload.Data, data, data_size); + } + else + { + payload.Data = NULL; + } + payload.DataSize = (int)data_size; + } + payload.DataFrameCount = g.FrameCount; + + return (payload.AcceptFrameCount == g.FrameCount) || (payload.AcceptFrameCount == g.FrameCount - 1); +} + +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + //if (!window->DC.LastItemRectHoveredRect || (g.ActiveId == g.DragDropPayload.SourceId || g.ActiveIdPreviousFrame == g.DragDropPayload.SourceId)) + if (!window->DC.LastItemRectHoveredRect || (window->DC.LastItemId && window->DC.LastItemId == g.DragDropPayload.SourceId)) + return false; + if (window->RootWindow != g.HoveredWindow->RootWindow) + return false; + + return true; +} + +const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiPayload& payload = g.DragDropPayload; + 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); // Internal/usage error, please report! + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + if (payload.AcceptId == 0) + payload.AcceptId = window->DC.LastItemId; + + bool was_accepted_previously = (payload.AcceptFrameCount == g.FrameCount - 1); + if (payload.AcceptFrameCount != g.FrameCount) + { + // Render drop visuals + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) + { + ImRect r = window->DC.LastItemRect; + r.Expand(4.0f); + window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.0f); // FIXME-DRAG FIXME-STYLE + window->DrawList->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); // FIXME-DRAG FIXME-STYLE + } + payload.AcceptFrameCount = g.FrameCount; + } + + payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton); + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + return &payload; +} + +// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. +void ImGui::EndDragDropTarget() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); +} + //----------------------------------------------------------------------------- // PLATFORM DEPENDENT HELPERS //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 1cb723ca..5c82ea1d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -43,9 +43,11 @@ struct ImGuiIniData; struct ImGuiMouseCursorData; struct ImGuiPopupRef; struct ImGuiWindow; +struct ImGuiPayload; // User data payload for drag and drop operations typedef int ImGuiLayoutType; // enum: horizontal or vertical // enum ImGuiLayoutType_ typedef int ImGuiButtonFlags; // flags: for ButtonEx(), ButtonBehavior() // enum ImGuiButtonFlags_ +typedef int ImGuiDragDropFlags; // flags: for *DragDrop*() // enum ImGuiDragDropFlags_ typedef int ImGuiItemFlags; // flags: for PushItemFlag() // enum ImGuiItemFlags_ typedef int ImGuiSeparatorFlags; // flags: for Separator() - internal // enum ImGuiSeparatorFlags_ typedef int ImGuiSliderFlags; // flags: for SliderBehavior() // enum ImGuiSliderFlags_ @@ -215,6 +217,15 @@ enum ImGuiSeparatorFlags_ ImGuiSeparatorFlags_Vertical = 1 << 1 }; +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +enum ImGuiDragDropFlags_ +{ + ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 1, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 2, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. +}; + // FIXME: this is in development, not exposed/functional as a generic feature yet. enum ImGuiLayoutType_ { @@ -404,6 +415,28 @@ struct ImGuiPopupRef ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupId = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } }; +// Data payload for Drag and Drop operations +struct ImGuiPayload +{ + // Members + const void* Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size + + // [Internal] + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + ImGuiID AcceptId; // Target item id (set at the time of accepting the payload) + int AcceptFrameCount; // Last time a target expressed a desire to accept the source + int DataFrameCount; // Data timestamp + char DataType[8 + 1]; // Data type tag (short user-supplied string) + bool Delivery; // Set when AcceptDragDropPayload() was called and the mouse button is released over the target item + + ImGuiPayload() { Clear(); } + void Clear() { SourceId = SourceParentId = AcceptId = 0; AcceptFrameCount = -1; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } + bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsDelivery() const { return Delivery; } +}; + // Main state for ImGui struct ImGuiContext { @@ -472,6 +505,14 @@ struct ImGuiContext ImGuiMouseCursor MouseCursor; ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]; + // Drag and Drop + bool DragDropActive; + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly + unsigned char DragDropPayloadBufLocal[8]; + // Widget state ImGuiTextEditState InputTextState; ImFont InputTextPasswordFont; @@ -547,6 +588,10 @@ struct ImGuiContext SetNextTreeNodeOpenVal = false; SetNextTreeNodeOpenCond = 0; + DragDropActive = false; + DragDropSourceFlags = 0; + DragDropMouseButton = -1; + ScalarAsInputTextId = 0; ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; DragCurrentValue = 0.0f; @@ -810,6 +855,14 @@ namespace ImGui 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. + // FIXME-WIP: New Drag and Drop API + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0, int mouse_button = 0); // Call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond = 0); // Type is a user defined string of maximum 8 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + IMGUI_API void EndDragDropSource(); + IMGUI_API bool BeginDragDropTarget(); // Call after submitting an item that may receive an item. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // Accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. + IMGUI_API void EndDragDropTarget(); + // 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 EndColumns(); // close columns From b5f714e9f9d222f8e10ef641b2dabbcbf76fcfed Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Oct 2017 21:31:49 +0100 Subject: [PATCH 02/25] Drag and Drop: made BeginDragDropSource() clear the IsItemHovered() by default, added a flag to keep it. --- imgui.cpp | 4 ++++ imgui_internal.h | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ad4a1895..b11a28d7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10631,6 +10631,10 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) PushStyleColor(ImGuiCol_PopupBg, GetStyleColorVec4(ImGuiCol_PopupBg) * ImVec4(1.0f, 1.0f, 1.0f, 0.6f)); BeginTooltipEx(ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_ShowBorders); } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover)) + window->DC.LastItemRectHoveredRect = false; + return true; } return false; diff --git a/imgui_internal.h b/imgui_internal.h index 5c82ea1d..d8dfca1c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -220,9 +220,12 @@ enum ImGuiSeparatorFlags_ // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() enum ImGuiDragDropFlags_ { + // BeginDragDropSource() flags ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, - ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 1, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. - ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 2, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. + // BeginDragDropTarget() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. }; From acf78da74288ba03875d387f502f8faf05ec6b76 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Oct 2017 21:37:14 +0100 Subject: [PATCH 03/25] Drag and drop: moved to imgui.h --- imgui.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ imgui_internal.h | 45 +-------------------------------------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/imgui.h b/imgui.h index 995b3980..7f1baa9c 100644 --- a/imgui.h +++ b/imgui.h @@ -64,6 +64,7 @@ struct ImGuiTextBuffer; // Text buffer for logging/accumulating text struct ImGuiTextEditCallbackData; // Shared state of ImGui::InputText() when using custom ImGuiTextEditCallback (rare/advanced use) struct ImGuiSizeConstraintCallbackData;// Structure used to constraint window size in custom ways when using custom ImGuiSizeConstraintCallback (rare/advanced use) struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiPayload; // User data payload for drag and drop operations struct ImGuiContext; // ImGui context (opaque) // Typedefs and Enumerations (declared as int for compatibility and to not pollute the top of this file) @@ -77,6 +78,7 @@ typedef int ImGuiKey; // enum: a key identifier (ImGui-side enum) typedef int ImGuiMouseCursor; // enum: a mouse cursor identifier // enum ImGuiMouseCursor_ typedef int ImGuiCond; // enum: a condition for Set*() // enum ImGuiCond_ typedef int ImGuiColorEditFlags; // flags: color edit flags for Color*() // enum ImGuiColorEditFlags_ +typedef int ImGuiDragDropFlags; // flags: for *DragDrop*() // enum ImGuiDragDropFlags_ typedef int ImGuiWindowFlags; // flags: window flags for Begin*() // enum ImGuiWindowFlags_ typedef int ImGuiColumnsFlags; // flags: for *Columns*() // enum ImGuiColumnsFlags_ typedef int ImGuiInputTextFlags; // flags: for InputText*() // enum ImGuiInputTextFlags_ @@ -410,6 +412,14 @@ namespace ImGui IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + // Drag and Drop + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0, int mouse_button = 0); // Call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond = 0); // Type is a user defined string of maximum 8 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + IMGUI_API void EndDragDropSource(); + IMGUI_API bool BeginDragDropTarget(); // Call after submitting an item that may receive an item. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // Accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. + IMGUI_API void EndDragDropTarget(); + // Clipping IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); IMGUI_API void PopClipRect(); @@ -583,6 +593,18 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped }; +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +enum ImGuiDragDropFlags_ +{ + // BeginDragDropSource() flags + ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. + // BeginDragDropTarget() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. +}; + // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array enum ImGuiKey_ { @@ -1118,6 +1140,28 @@ struct ImGuiSizeConstraintCallbackData ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. }; +// Data payload for Drag and Drop operations +struct ImGuiPayload +{ + // Members + const void* Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size + + // [Internal] + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + ImGuiID AcceptId; // Target item id (set at the time of accepting the payload) + int AcceptFrameCount; // Last time a target expressed a desire to accept the source + int DataFrameCount; // Data timestamp + char DataType[8 + 1]; // Data type tag (short user-supplied string) + bool Delivery; // Set when AcceptDragDropPayload() was called and the mouse button is released over the target item + + ImGuiPayload() { Clear(); } + void Clear() { SourceId = SourceParentId = AcceptId = 0; AcceptFrameCount = -1; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } + bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsDelivery() const { return Delivery; } +}; + // Helpers macros to generate 32-bits encoded colors #ifdef IMGUI_USE_BGRA_PACKED_COLOR #define IM_COL32_R_SHIFT 16 diff --git a/imgui_internal.h b/imgui_internal.h index d8dfca1c..666b4491 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -43,11 +43,9 @@ struct ImGuiIniData; struct ImGuiMouseCursorData; struct ImGuiPopupRef; struct ImGuiWindow; -struct ImGuiPayload; // User data payload for drag and drop operations typedef int ImGuiLayoutType; // enum: horizontal or vertical // enum ImGuiLayoutType_ typedef int ImGuiButtonFlags; // flags: for ButtonEx(), ButtonBehavior() // enum ImGuiButtonFlags_ -typedef int ImGuiDragDropFlags; // flags: for *DragDrop*() // enum ImGuiDragDropFlags_ typedef int ImGuiItemFlags; // flags: for PushItemFlag() // enum ImGuiItemFlags_ typedef int ImGuiSeparatorFlags; // flags: for Separator() - internal // enum ImGuiSeparatorFlags_ typedef int ImGuiSliderFlags; // flags: for SliderBehavior() // enum ImGuiSliderFlags_ @@ -217,18 +215,6 @@ enum ImGuiSeparatorFlags_ ImGuiSeparatorFlags_Vertical = 1 << 1 }; -// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() -enum ImGuiDragDropFlags_ -{ - // BeginDragDropSource() flags - ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, - ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. - // BeginDragDropTarget() flags - ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. - ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. - ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. -}; - // FIXME: this is in development, not exposed/functional as a generic feature yet. enum ImGuiLayoutType_ { @@ -418,28 +404,6 @@ struct ImGuiPopupRef ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupId = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } }; -// Data payload for Drag and Drop operations -struct ImGuiPayload -{ - // Members - const void* Data; // Data (copied and owned by dear imgui) - int DataSize; // Data size - - // [Internal] - ImGuiID SourceId; // Source item id - ImGuiID SourceParentId; // Source parent id (if available) - ImGuiID AcceptId; // Target item id (set at the time of accepting the payload) - int AcceptFrameCount; // Last time a target expressed a desire to accept the source - int DataFrameCount; // Data timestamp - char DataType[8 + 1]; // Data type tag (short user-supplied string) - bool Delivery; // Set when AcceptDragDropPayload() was called and the mouse button is released over the target item - - ImGuiPayload() { Clear(); } - void Clear() { SourceId = SourceParentId = AcceptId = 0; AcceptFrameCount = -1; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } - bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } - bool IsDelivery() const { return Delivery; } -}; - // Main state for ImGui struct ImGuiContext { @@ -594,6 +558,7 @@ struct ImGuiContext DragDropActive = false; DragDropSourceFlags = 0; DragDropMouseButton = -1; + memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); ScalarAsInputTextId = 0; ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; @@ -858,14 +823,6 @@ namespace ImGui 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. - // FIXME-WIP: New Drag and Drop API - IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0, int mouse_button = 0); // Call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() - IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond = 0); // Type is a user defined string of maximum 8 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. - IMGUI_API void EndDragDropSource(); - IMGUI_API bool BeginDragDropTarget(); // Call after submitting an item that may receive an item. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() - IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // Accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. - IMGUI_API void EndDragDropTarget(); - // 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 EndColumns(); // close columns From 0e775807b4be21405817df60c53889ab0a1ce230 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Oct 2017 23:10:44 +0100 Subject: [PATCH 04/25] Drag and Drop: Added a mechanism to allow widgets with no identifiers (such as Text/Image) to be used with BeginDragDropSource() given the explicit ImGuiDragDropFlags_SourceAllowNullID flag. --- imgui.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++-- imgui.h | 1 + imgui_internal.h | 1 + 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b11a28d7..de89f4f6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1860,6 +1860,16 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) return ImHash(str, str_end ? (int)(str_end - str) : 0, seed); } +// This is particularly dodgy and used in extremely rare situation. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; + ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed); + ImGui::KeepAliveID(id); + return id; +} + //----------------------------------------------------------------------------- // Internal API exposed in imgui_internal.h //----------------------------------------------------------------------------- @@ -10606,16 +10616,48 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) ImGuiWindow* window = g.CurrentWindow; if (g.IO.MouseDown[mouse_button] == false) return false; - if (g.ActiveId != window->DC.LastItemId) + + ImGuiID id = window->DC.LastItemId; + if (id == 0) + { + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image(). + // We build a throwaway ID based on current ID stack + relative AABB of items in window. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // If you want fail-proof dragging, + // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. + bool is_hovered = window->DC.LastItemRectHoveredRect; + if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); + if (is_hovered) + SetHoveredID(id); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(id, window); + FocusWindow(window); + } + if (g.ActiveId == id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. + g.ActiveIdAllowOverlap = is_hovered; + } + if (g.ActiveId != id) return false; if (IsMouseDragging(mouse_button)) { if (!g.DragDropActive) { + IM_ASSERT(id != 0); ImGuiPayload& payload = g.DragDropPayload; payload.Clear(); - payload.SourceId = g.ActiveId; + payload.SourceId = id; payload.SourceParentId = window->IDStack.back(); g.DragDropActive = true; g.DragDropSourceFlags = flags; diff --git a/imgui.h b/imgui.h index 7f1baa9c..25a9c5a6 100644 --- a/imgui.h +++ b/imgui.h @@ -599,6 +599,7 @@ enum ImGuiDragDropFlags_ // BeginDragDropSource() flags ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. + ImGuiDragDropFlags_SourceAllowNullID = 1 << 2, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. // BeginDragDropTarget() flags ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. diff --git a/imgui_internal.h b/imgui_internal.h index 666b4491..dafb3aef 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -754,6 +754,7 @@ public: ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const void* ptr); ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); + ImGuiID GetIDFromRectangle(const ImRect& r_abs); ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } From d46772b429df1a157b4c2d4ebc11509d3d726cac Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Oct 2017 23:14:17 +0100 Subject: [PATCH 05/25] Comments --- imgui.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index de89f4f6..709ebdff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1860,7 +1860,7 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) return ImHash(str, str_end ? (int)(str_end - str) : 0, seed); } -// This is particularly dodgy and used in extremely rare situation. +// This is only used in rare/specific situations to manufacture an ID out of nowhere. ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) { ImGuiID seed = IDStack.back(); @@ -10628,10 +10628,9 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) return false; } - // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image(). + // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() // We build a throwaway ID based on current ID stack + relative AABB of items in window. // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. - // If you want fail-proof dragging, // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. bool is_hovered = window->DC.LastItemRectHoveredRect; if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window)) From a81061955568973e72ebea5d7a3f7035368bd50c Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 30 Oct 2017 00:03:04 +0100 Subject: [PATCH 06/25] Drag and Drop: Added support for drag and drop hold-long-to-open for CollapsingHeader() and TreeNode(). Open only! --- imgui.cpp | 13 +++++++++++++ imgui_internal.h | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 8e7225fc..383b012e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5841,6 +5841,16 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool bool pressed = false; bool hovered = ItemHoverable(bb, id); + // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button + if ((flags & ImGuiButtonFlags_PressedOnDragDropHold) && g.DragDropActive && !hovered) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + hovered = true; + SetHoveredID(id); + if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy + pressed = true; + } + if ((flags & ImGuiButtonFlags_FlattenChilds) && g.HoveredRootWindow == window) g.HoveredWindow = backup_hovered_window; @@ -6271,6 +6281,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // - OpenOnArrow .................... single-click on arrow to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowOverlapMode : 0); + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); @@ -6281,6 +6292,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)); if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) toggled |= g.IO.MouseDoubleClicked[0]; + if (g.DragDropActive && is_open) // We don't nodes to be highlighted when holding ever after the node has been opened, but don't close them! + toggled = false; if (toggled) { is_open = !is_open; diff --git a/imgui_internal.h b/imgui_internal.h index 6e69c676..53af4b37 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -183,7 +183,8 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_AlignTextBaseLine = 1 << 8, // vertically align button to match text baseline (ButtonEx() only) ImGuiButtonFlags_NoKeyModifiers = 1 << 9, // disable interaction if a key modifier is held ImGuiButtonFlags_AllowOverlapMode = 1 << 10, // require previous frame HoveredId to either match id or be null before being usable - ImGuiButtonFlags_NoHoldingActiveID = 1 << 11 // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12 // press when held into while we are drag and dropping another item }; enum ImGuiSliderFlags_ From 5956fff7e2959574e4273ca1b5cc540fd0dff0d5 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 30 Oct 2017 00:10:05 +0100 Subject: [PATCH 07/25] Drag and Drop: ImGuiButtonFlags_PressedOnDragDropHold focuses the target window. --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 383b012e..6603d3f9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5848,7 +5848,10 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool hovered = true; SetHoveredID(id); if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy + { pressed = true; + FocusWindow(window); + } } if ((flags & ImGuiButtonFlags_FlattenChilds) && g.HoveredRootWindow == window) From 66f42324ad6203560de5631753644ce4d8e81bc8 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 1 Nov 2017 17:24:17 +0100 Subject: [PATCH 08/25] Drag and Drop: Added ImGuiDragDropFlags_SourceNoHoldToOpenOthers flag. --- imgui.cpp | 2 +- imgui.h | 15 ++++++++------- imgui_internal.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6603d3f9..19223865 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5842,7 +5842,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool bool hovered = ItemHoverable(bb, id); // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button - if ((flags & ImGuiButtonFlags_PressedOnDragDropHold) && g.DragDropActive && !hovered) + if ((flags & ImGuiButtonFlags_PressedOnDragDropHold) && g.DragDropActive && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) { hovered = true; diff --git a/imgui.h b/imgui.h index 25a9c5a6..12ea6e2a 100644 --- a/imgui.h +++ b/imgui.h @@ -597,13 +597,14 @@ enum ImGuiHoveredFlags_ enum ImGuiDragDropFlags_ { // BeginDragDropSource() flags - ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, - ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. - ImGuiDragDropFlags_SourceAllowNullID = 1 << 2, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. - // BeginDragDropTarget() flags - ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. - ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. - ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. + ImGuiDragDropFlags_SourceNoAutoTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the dragged contents. This flag disable this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. + // AcceptDragDropPayload() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. }; // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array diff --git a/imgui_internal.h b/imgui_internal.h index 53af4b37..5e80c6ee 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -184,7 +184,7 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_NoKeyModifiers = 1 << 9, // disable interaction if a key modifier is held ImGuiButtonFlags_AllowOverlapMode = 1 << 10, // require previous frame HoveredId to either match id or be null before being usable ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) - ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12 // press when held into while we are drag and dropping another item + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12 // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) }; enum ImGuiSliderFlags_ From 553bdeedf78126b9b91289a64dce6efe2e8b741e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 2 Nov 2017 18:30:46 +0100 Subject: [PATCH 09/25] Drag and Drop: Made it legal to not call SetDragDropPayload() between BeginDragDropSource() and EndDragDropSource(). (#143) --- imgui.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e3481db8..73456b35 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10706,7 +10706,6 @@ void ImGui::EndDragDropSource() { ImGuiContext& g = *GImGui; IM_ASSERT(g.DragDropActive); - IM_ASSERT(g.DragDropPayload.DataFrameCount != -1); // Forgot to call SetDragDropSourcePayload(), at least once on the first frame of a successful BeginDragDropSource() if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoAutoTooltip)) { @@ -10714,9 +10713,16 @@ void ImGui::EndDragDropSource() PopStyleColor(); //PopStyleVar(); } + + // Discard the drag if have not called SetDragDropPayload() + if (g.DragDropPayload.DataFrameCount == -1) + { + g.DragDropActive = false; + g.DragDropPayload.Clear(); + } } -// Use 'cond' to choose to submit paypload on drag start or every frame +// Use 'cond' to choose to submit payload on drag start or every frame bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) { ImGuiContext& g = *GImGui; @@ -10783,7 +10789,7 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop ImGuiPayload& payload = g.DragDropPayload; 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); // Internal/usage error, please report! + IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? if (type != NULL && !payload.IsDataType(type)) return NULL; From 8b725c94cbab321d7bc1b4ee7d1efbf131c4f41d Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 6 Nov 2017 19:39:23 +0100 Subject: [PATCH 10/25] Drag and Drop: Rework internal to allow overlapping targets (#143) --- imgui.cpp | 30 ++++++++++++++---------------- imgui.h | 7 ++++--- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 73456b35..8c52e469 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2250,6 +2250,8 @@ void ImGui::NewFrame() g.ScalarAsInputTextId = 0; // Elapse drag & drop payload + g.DragDropPayload.AcceptIdPrev = g.DragDropPayload.AcceptIdCurr; + g.DragDropPayload.AcceptIdCurr = 0; if (g.DragDropActive && g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) { g.DragDropActive = false; @@ -10773,7 +10775,6 @@ bool ImGui::BeginDragDropTarget() return false; ImGuiWindow* window = g.CurrentWindow; - //if (!window->DC.LastItemRectHoveredRect || (g.ActiveId == g.DragDropPayload.SourceId || g.ActiveIdPreviousFrame == g.DragDropPayload.SourceId)) if (!window->DC.LastItemRectHoveredRect || (window->DC.LastItemId && window->DC.LastItemId == g.DragDropPayload.SourceId)) return false; if (window->RootWindow != g.HoveredWindow->RootWindow) @@ -10793,23 +10794,20 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop if (type != NULL && !payload.IsDataType(type)) return NULL; - if (payload.AcceptId == 0) - payload.AcceptId = window->DC.LastItemId; - - bool was_accepted_previously = (payload.AcceptFrameCount == g.FrameCount - 1); - if (payload.AcceptFrameCount != g.FrameCount) + // NB: We currently accept NULL id however, overlapping targets required unique ID to function + const bool was_accepted_previously = (payload.AcceptIdPrev == window->DC.LastItemId); + //if (window->DC.LastItemId) + payload.AcceptIdCurr = window->DC.LastItemId; + + // Render drop visuals + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) { - // Render drop visuals - if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) - { - ImRect r = window->DC.LastItemRect; - r.Expand(4.0f); - window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.0f); // FIXME-DRAG FIXME-STYLE - window->DrawList->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); // FIXME-DRAG FIXME-STYLE - } - payload.AcceptFrameCount = g.FrameCount; + ImRect r = window->DC.LastItemRect; + r.Expand(4.0f); + window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.0f); // FIXME-DRAG FIXME-STYLE + window->DrawList->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); // FIXME-DRAG FIXME-STYLE } - + payload.AcceptFrameCount = g.FrameCount; payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton); if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) return NULL; diff --git a/imgui.h b/imgui.h index 6191f099..849d7864 100644 --- a/imgui.h +++ b/imgui.h @@ -587,7 +587,7 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_Default = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 0, // Return true even if a popup window is normally blocking access to this item/window //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 1, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. - ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 2, // Return true even if an active item is blocking access to this item/window + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 2, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 3, // Return true even if the position is overlapped by another window ImGuiHoveredFlags_FlattenChilds = 1 << 4, // Treat all child windows as the same window (for IsWindowHovered()) ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped @@ -1153,14 +1153,15 @@ struct ImGuiPayload // [Internal] ImGuiID SourceId; // Source item id ImGuiID SourceParentId; // Source parent id (if available) - ImGuiID AcceptId; // Target item id (set at the time of accepting the payload) + ImGuiID AcceptIdCurr; // Target item id (set at the time of accepting the payload) + ImGuiID AcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) int AcceptFrameCount; // Last time a target expressed a desire to accept the source int DataFrameCount; // Data timestamp char DataType[8 + 1]; // Data type tag (short user-supplied string) bool Delivery; // Set when AcceptDragDropPayload() was called and the mouse button is released over the target item ImGuiPayload() { Clear(); } - void Clear() { SourceId = SourceParentId = AcceptId = 0; AcceptFrameCount = -1; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } + void Clear() { SourceId = SourceParentId = AcceptIdCurr = AcceptIdPrev = 0; AcceptFrameCount = -1; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } bool IsDelivery() const { return Delivery; } }; From de1e7dc088952f484cd905e815449519641d0e81 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 6 Nov 2017 20:02:56 +0100 Subject: [PATCH 11/25] Drag and Drop: Moved internal fields out of public sight. (#143) --- imgui.cpp | 33 +++++++++++++++++++-------------- imgui.h | 5 +---- imgui_internal.h | 5 +++++ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8c52e469..999b373f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -662,6 +662,7 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* ini namespace ImGui { +static void ClearDragDrop(); static void FocusPreviousWindow(); } @@ -2250,15 +2251,14 @@ void ImGui::NewFrame() g.ScalarAsInputTextId = 0; // Elapse drag & drop payload - g.DragDropPayload.AcceptIdPrev = g.DragDropPayload.AcceptIdCurr; - g.DragDropPayload.AcceptIdCurr = 0; if (g.DragDropActive && g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) { - g.DragDropActive = false; - g.DragDropPayload.Clear(); + ClearDragDrop(); g.DragDropPayloadBufHeap.clear(); memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); } + g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; + g.DragDropAcceptIdCurr = 0; // Update keyboard input state memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); @@ -10631,6 +10631,15 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) // DRAG AND DROP //----------------------------------------------------------------------------- +static void ImGui::ClearDragDrop() +{ + ImGuiContext& g = *GImGui; + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptFrameCount = -1; +} + // Call when current ID is active. // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) @@ -10677,8 +10686,8 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) if (!g.DragDropActive) { IM_ASSERT(id != 0); + ClearDragDrop(); ImGuiPayload& payload = g.DragDropPayload; - payload.Clear(); payload.SourceId = id; payload.SourceParentId = window->IDStack.back(); g.DragDropActive = true; @@ -10718,10 +10727,7 @@ void ImGui::EndDragDropSource() // Discard the drag if have not called SetDragDropPayload() if (g.DragDropPayload.DataFrameCount == -1) - { - g.DragDropActive = false; - g.DragDropPayload.Clear(); - } + ClearDragDrop(); } // Use 'cond' to choose to submit payload on drag start or every frame @@ -10765,7 +10771,7 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s } payload.DataFrameCount = g.FrameCount; - return (payload.AcceptFrameCount == g.FrameCount) || (payload.AcceptFrameCount == g.FrameCount - 1); + return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); } bool ImGui::BeginDragDropTarget() @@ -10795,9 +10801,8 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop return NULL; // NB: We currently accept NULL id however, overlapping targets required unique ID to function - const bool was_accepted_previously = (payload.AcceptIdPrev == window->DC.LastItemId); - //if (window->DC.LastItemId) - payload.AcceptIdCurr = window->DC.LastItemId; + const bool was_accepted_previously = (g.DragDropAcceptIdPrev == window->DC.LastItemId); + g.DragDropAcceptIdCurr = window->DC.LastItemId; // Render drop visuals if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) @@ -10807,7 +10812,7 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.0f); // FIXME-DRAG FIXME-STYLE window->DrawList->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); // FIXME-DRAG FIXME-STYLE } - payload.AcceptFrameCount = g.FrameCount; + g.DragDropAcceptFrameCount = g.FrameCount; payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton); if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) return NULL; diff --git a/imgui.h b/imgui.h index 849d7864..1624e317 100644 --- a/imgui.h +++ b/imgui.h @@ -1153,15 +1153,12 @@ struct ImGuiPayload // [Internal] ImGuiID SourceId; // Source item id ImGuiID SourceParentId; // Source parent id (if available) - ImGuiID AcceptIdCurr; // Target item id (set at the time of accepting the payload) - ImGuiID AcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) - int AcceptFrameCount; // Last time a target expressed a desire to accept the source int DataFrameCount; // Data timestamp char DataType[8 + 1]; // Data type tag (short user-supplied string) bool Delivery; // Set when AcceptDragDropPayload() was called and the mouse button is released over the target item ImGuiPayload() { Clear(); } - void Clear() { SourceId = SourceParentId = AcceptIdCurr = AcceptIdPrev = 0; AcceptFrameCount = -1; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } + void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } bool IsDelivery() const { return Delivery; } }; diff --git a/imgui_internal.h b/imgui_internal.h index 5e80c6ee..5c3b24c8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -480,6 +480,9 @@ struct ImGuiContext ImGuiDragDropFlags DragDropSourceFlags; int DragDropMouseButton; ImGuiPayload DragDropPayload; + 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) + int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly unsigned char DragDropPayloadBufLocal[8]; @@ -563,6 +566,8 @@ struct ImGuiContext DragDropActive = false; DragDropSourceFlags = 0; DragDropMouseButton = -1; + DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; + DragDropAcceptFrameCount = -1; memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); ScalarAsInputTextId = 0; From b6504b8eee930cca4a98d36603273c407a69c135 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 8 Nov 2017 15:47:52 +0100 Subject: [PATCH 12/25] Drag and drop: Handle overlapping drag target priorities given their surface, which appears to make most sense for drag and drop operations. --- imgui.cpp | 14 ++++++++++++-- imgui_internal.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 999b373f..a5e9d37a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2259,6 +2259,7 @@ void ImGui::NewFrame() } g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; g.DragDropAcceptIdCurr = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; // Update keyboard input state memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); @@ -10637,6 +10638,7 @@ static void ImGui::ClearDragDrop() g.DragDropActive = false; g.DragDropPayload.Clear(); g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; g.DragDropAcceptFrameCount = -1; } @@ -10800,14 +10802,22 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop if (type != NULL && !payload.IsDataType(type)) return NULL; - // NB: We currently accept NULL id however, overlapping targets required unique ID to function + // 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. + ImRect r = window->DC.LastItemRect; + float r_surface = r.GetWidth() * r.GetHeight(); + if (r_surface < g.DragDropAcceptIdCurrRectSurface) + { + g.DragDropAcceptIdCurr = window->DC.LastItemId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + } + // Render drop visuals if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) { - ImRect r = window->DC.LastItemRect; r.Expand(4.0f); window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.0f); // FIXME-DRAG FIXME-STYLE window->DrawList->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); // FIXME-DRAG FIXME-STYLE diff --git a/imgui_internal.h b/imgui_internal.h index 5c3b24c8..c93faf7f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -480,6 +480,7 @@ struct ImGuiContext ImGuiDragDropFlags DragDropSourceFlags; int DragDropMouseButton; ImGuiPayload DragDropPayload; + float DragDropAcceptIdCurrRectSurface; 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) int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source From b1653cd361aa2acd632877829c6d55a859e39d20 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 Nov 2017 20:09:09 +0100 Subject: [PATCH 13/25] Drag and Drop: Allow NULL payload (since type only can be useful). (#143) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a5e9d37a..2ead2edf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10742,7 +10742,7 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s IM_ASSERT(type != NULL); IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType)); // Payload type can be at most 8 characters longs - IM_ASSERT(data != NULL && data_size > 0); + IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() From 4b94738c7e64a7a912a72b373063b42a407ec1bd Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 Nov 2017 20:17:10 +0100 Subject: [PATCH 14/25] Drag and Drop: Drop target rectangle goes out of clipping range (#143) --- imgui.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2ead2edf..cdb02542 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10818,9 +10818,13 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop // Render drop visuals if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) { - r.Expand(4.0f); - window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.0f); // FIXME-DRAG FIXME-STYLE - window->DrawList->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); // FIXME-DRAG FIXME-STYLE + // FIXME-DRAG FIXME-STYLE: Settle on a proper default visuals for drop target, w/ ImGuiCol enum value probably. + r.Expand(5.0f); + bool push_clip_rect = !window->ClipRect.Contains(r); + if (push_clip_rect) window->DrawList->PushClipRectFullScreen(); + window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.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(); } g.DragDropAcceptFrameCount = g.FrameCount; payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton); From 7908cce25f01c2e2dffe01732a7efc8a01055140 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 10 Nov 2017 13:13:28 +0100 Subject: [PATCH 15/25] Drag and Drop: Added internal BeginDragDropTargetCustom() convenient to avoid submitting dummy ItemAdd. (#143) --- imgui.cpp | 39 ++++++++++++++++++++++++++++++--------- imgui_internal.h | 5 +++++ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cdb02542..b43295e8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -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); } +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() { ImGuiContext& g = *GImGui; @@ -10785,9 +10806,11 @@ bool ImGui::BeginDragDropTarget() ImGuiWindow* window = g.CurrentWindow; if (!window->DC.LastItemRectHoveredRect || (window->DC.LastItemId && window->DC.LastItemId == g.DragDropPayload.SourceId)) return false; - if (window->RootWindow != g.HoveredWindow->RootWindow) + if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) return false; + g.DragDropTargetRect = window->DC.LastItemRect; + g.DragDropTargetId = window->DC.LastItemId; return true; } @@ -10797,25 +10820,22 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop ImGuiWindow* window = g.CurrentWindow; ImGuiPayload& payload = g.DragDropPayload; 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() ? if (type != NULL && !payload.IsDataType(type)) 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. - 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(); if (r_surface < g.DragDropAcceptIdCurrRectSurface) { - g.DragDropAcceptIdCurr = window->DC.LastItemId; + g.DragDropAcceptIdCurr = g.DragDropTargetId; g.DragDropAcceptIdCurrRectSurface = r_surface; } - // Render drop visuals + // Render default drop visuals 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. @@ -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); if (push_clip_rect) window->DrawList->PopClipRect(); } + g.DragDropAcceptFrameCount = g.FrameCount; payload.Delivery = was_accepted_previously && IsMouseReleased(g.DragDropMouseButton); if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) diff --git a/imgui_internal.h b/imgui_internal.h index c93faf7f..849ab612 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -480,6 +480,8 @@ struct ImGuiContext ImGuiDragDropFlags DragDropSourceFlags; int DragDropMouseButton; ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; + ImGuiID DragDropTargetId; float DragDropAcceptIdCurrRectSurface; 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) @@ -567,6 +569,7 @@ struct ImGuiContext DragDropActive = false; DragDropSourceFlags = 0; DragDropMouseButton = -1; + DragDropTargetId = 0; DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; DragDropAcceptFrameCount = -1; memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); @@ -835,6 +838,8 @@ namespace ImGui 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 bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); + // 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 EndColumns(); // close columns From ffad688fc8d5b957716cb873c1bfbd5c12839bbf Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 14 Nov 2017 22:11:43 +0100 Subject: [PATCH 16/25] Drag and Drop: Added payload->IsPreview() to user can render their custom preview while handling overlapping drop targets. (#143) --- imgui.cpp | 3 ++- imgui.h | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b43295e8..3eecc73a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10836,7 +10836,8 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop } // Render default drop visuals - if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && was_accepted_previously) + payload.Preview = was_accepted_previously; + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) { // FIXME-DRAG FIXME-STYLE: Settle on a proper default visuals for drop target, w/ ImGuiCol enum value probably. r.Expand(5.0f); diff --git a/imgui.h b/imgui.h index 1624e317..7959d0e7 100644 --- a/imgui.h +++ b/imgui.h @@ -1155,11 +1155,13 @@ struct ImGuiPayload ImGuiID SourceParentId; // Source parent id (if available) int DataFrameCount; // Data timestamp char DataType[8 + 1]; // Data type tag (short user-supplied string) - bool Delivery; // Set when AcceptDragDropPayload() was called and the mouse button is released over the target item + bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) + bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. ImGuiPayload() { Clear(); } - void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Delivery = false; } + void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsPreview() const { return Preview; } bool IsDelivery() const { return Delivery; } }; From 5027311e7fc8f7e1d5d00ed68449d2010d351628 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 17:59:12 +0100 Subject: [PATCH 17/25] Drag and drop: Standardizing payload types as defines. (#143) --- imgui_internal.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 1980e45b..45bbedeb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -167,6 +167,10 @@ inline void operator delete(void*, ImPlacementNewDummy, void*) {} // Types //----------------------------------------------------------------------------- +// Drag and Drop payload types. String starting with '_' are managed by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4] // Standard type for colors. User code may use this type. Build a float[4] out of a float[3] if you don't have alpha. +#define IMGUI_PAYLOAD_TYPE_DOCKABLE "_IMDOCK" // ImGuiWindow* // [Internal] Docking/tabs + enum ImGuiButtonFlags_ { ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat @@ -239,7 +243,8 @@ enum ImGuiDir ImGuiDir_Left = 0, ImGuiDir_Right = 1, ImGuiDir_Up = 2, - ImGuiDir_Down = 3 + ImGuiDir_Down = 3, + ImGuiDir_Count_ }; enum ImGuiCorner From dc2768503f91b5d11e6cbb76fde873a53e3ccf7f Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 19 Nov 2017 16:24:17 +0100 Subject: [PATCH 18/25] Fix for drag and drop branch. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 2510fb70..978277d6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10796,7 +10796,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags, int mouse_button) //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This is better but e.g ColorButton with checkboard has issue with transparent colors :( SetNextWindowPos(g.IO.MousePos); PushStyleColor(ImGuiCol_PopupBg, GetStyleColorVec4(ImGuiCol_PopupBg) * ImVec4(1.0f, 1.0f, 1.0f, 0.6f)); - BeginTooltipEx(ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_ShowBorders); + BeginTooltipEx(ImGuiWindowFlags_NoInputs); } if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover)) From 6ea744d8f42cd8b5bd89562126712ddd79700721 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 30 Nov 2017 16:54:39 +0100 Subject: [PATCH 19/25] Drag and Drop: Added DragSource from color square. Added DragTarget on ColorEdit4 widget. (#143) --- imgui.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index a21cba8b..280a2438 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9671,6 +9671,16 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl else window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization + { + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col, sizeof(col), ImGuiCond_Once); + ColorButton(desc_id, col, flags); + SameLine(); + TextUnformatted("Color"); + EndDragDropSource(); + hovered = false; + } + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); @@ -9947,6 +9957,17 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag PopID(); EndGroup(); + if (window->DC.LastItemRectHoveredRect && BeginDragDropTarget()) // NB: The LastItemRectHoveredRect test is merely an optional micro-optimization + { + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + { + IM_ASSERT(payload->DataSize == sizeof(ImVec4)); + memcpy((float*)col, payload->Data, sizeof(ImVec4)); + value_changed = true; + } + EndDragDropTarget(); + } + return value_changed; } From 7bf85db6c451163133a1197457a7a1dd7ff6fbdb Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 8 Dec 2017 12:48:53 +0100 Subject: [PATCH 20/25] Drag and drop: Added COL3F payload for color without alpha overwrite. Exposed standard color payload types in imgui.h (#143) --- imgui.cpp | 13 ++++++++++--- imgui.h | 4 ++++ imgui_internal.h | 3 +-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 950addd7..c64a8339 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9677,7 +9677,10 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization { - SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col, sizeof(col), ImGuiCond_Once); + if (flags & ImGuiColorEditFlags_NoAlpha) + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col, sizeof(float) * 3, ImGuiCond_Once); + else + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col, sizeof(float) * 4, ImGuiCond_Once); ColorButton(desc_id, col, flags); SameLine(); TextUnformatted("Color"); @@ -9963,10 +9966,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (window->DC.LastItemRectHoveredRect && BeginDragDropTarget()) // NB: The LastItemRectHoveredRect test is merely an optional micro-optimization { + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * 3); + value_changed = true; + } if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) { - IM_ASSERT(payload->DataSize == sizeof(ImVec4)); - memcpy((float*)col, payload->Data, sizeof(ImVec4)); + memcpy((float*)col, payload->Data, sizeof(float) * components); value_changed = true; } EndDragDropTarget(); diff --git a/imgui.h b/imgui.h index 0bc00310..294f6695 100644 --- a/imgui.h +++ b/imgui.h @@ -610,6 +610,10 @@ enum ImGuiDragDropFlags_ ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. }; +// Standard Drag and Drop payload types. Types starting with '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3] // Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4] // Standard type for colors. User code may use this type. + // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array enum ImGuiKey_ { diff --git a/imgui_internal.h b/imgui_internal.h index 92d98876..1bf61084 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -169,8 +169,7 @@ inline void operator delete(void*, ImPlacementNewDummy, void*) {} // Types //----------------------------------------------------------------------------- -// Drag and Drop payload types. String starting with '_' are managed by Dear ImGui. -#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4] // Standard type for colors. User code may use this type. Build a float[4] out of a float[3] if you don't have alpha. +// Internal Drag and Drop payload types. String starting with '_' are reserved for Dear ImGui. #define IMGUI_PAYLOAD_TYPE_DOCKABLE "_IMDOCK" // ImGuiWindow* // [Internal] Docking/tabs enum ImGuiButtonFlags_ From a4863e8084e4b80a38e2b76a9dd724c971ee5e7d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 8 Dec 2017 12:49:35 +0100 Subject: [PATCH 21/25] Demo: Picker with palette demo supports drag and drop. (#143, #346) --- imgui_demo.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6b0fed76..c74df600 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -775,12 +775,19 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); ImGui::Text("Color button with Custom Picker Popup:"); + + // Generate a dummy palette static bool saved_palette_inited = false; static ImVec4 saved_palette[32]; - static ImVec4 backup_color; if (!saved_palette_inited) for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + saved_palette[n].w = 1.0f; // Alpha + } + saved_palette_inited = true; + + static ImVec4 backup_color; bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); ImGui::SameLine(); open_popup |= ImGui::Button("Palette"); @@ -809,8 +816,18 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::PushID(n); if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); - if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) + if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + EndDragDropTarget(); + } + ImGui::PopID(); } ImGui::EndGroup(); From 7ec934f43910ff917239942aed36169996bfdadc Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Dec 2017 15:33:26 +0100 Subject: [PATCH 22/25] Drag and Drop: Comments --- imgui.cpp | 4 +++- imgui.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 24d60b72..39290f60 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6685,7 +6685,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)); if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) toggled |= g.IO.MouseDoubleClicked[0]; - if (g.DragDropActive && is_open) // We don't nodes to be highlighted when holding ever after the node has been opened, but don't close them! + if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. toggled = false; if (toggled) { @@ -9886,6 +9886,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl else window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + // Drag and Drop Source if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization { if (flags & ImGuiColorEditFlags_NoAlpha) @@ -9899,6 +9900,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl hovered = false; } + // Tooltip if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); diff --git a/imgui.h b/imgui.h index 3cdec027..3622dfc8 100644 --- a/imgui.h +++ b/imgui.h @@ -421,6 +421,7 @@ namespace ImGui IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) // Drag and Drop + // [BETA API] Missing Demo code. API may evolve. IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0, int mouse_button = 0); // Call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond = 0); // Type is a user defined string of maximum 8 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. IMGUI_API void EndDragDropSource(); From e98df91dc47b8fc17cb2c0963ed9e85d9fc5ce0a Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Dec 2017 15:44:22 +0100 Subject: [PATCH 23/25] Drag and Drop: Added ImGuiCol_DragDropTarget (#143, #707) --- imgui.cpp | 8 ++++---- imgui.h | 1 + imgui_draw.cpp | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 39290f60..9e632e54 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5454,6 +5454,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening"; + case ImGuiCol_DragDropTarget: return "DragDropTarget"; } IM_ASSERT(0); return "Unknown"; @@ -11345,12 +11346,11 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop payload.Preview = was_accepted_previously; if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) { - // FIXME-DRAG FIXME-STYLE: Settle on a proper default visuals for drop target, w/ ImGuiCol enum value probably. - r.Expand(5.0f); + // FIXME-DRAG: Settle on a proper default visuals for drop target. + r.Expand(3.5f); bool push_clip_rect = !window->ClipRect.Contains(r); if (push_clip_rect) window->DrawList->PushClipRectFullScreen(); - window->DrawList->AddRectFilled(r.Min, r.Max, IM_COL32(255, 255, 0, 20), 0.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); + window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); if (push_clip_rect) window->DrawList->PopClipRect(); } diff --git a/imgui.h b/imgui.h index 3622dfc8..5f749316 100644 --- a/imgui.h +++ b/imgui.h @@ -719,6 +719,7 @@ enum ImGuiCol_ ImGuiCol_PlotHistogramHovered, ImGuiCol_TextSelectedBg, ImGuiCol_ModalWindowDarkening, // darken entire screen when a modal window is active + ImGuiCol_DragDropTarget, ImGuiCol_COUNT // Obsolete names (will be removed) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7a5bb2de..69e93689 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -171,6 +171,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); } void ImGui::StyleColorsDark(ImGuiStyle* dst) @@ -220,6 +221,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); } void ImGui::StyleColorsLight(ImGuiStyle* dst) @@ -271,9 +273,9 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); } - //----------------------------------------------------------------------------- // ImDrawList //----------------------------------------------------------------------------- From d561a43a4d81259f32822a19b2a30e3883e48923 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Dec 2017 18:17:18 +0100 Subject: [PATCH 24/25] Drag and Drop: Drop target infer a fallback ID from the rectangle. Avoid Preview being accepted on drop frame when drop target has no ID. (#143) --- imgui.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9e632e54..033b1e51 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11292,7 +11292,8 @@ bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) 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)) + IM_ASSERT(id != 0); + if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) return false; g.DragDropTargetRect = bb; @@ -11301,7 +11302,7 @@ bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) } // 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. +// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. // 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() @@ -11311,13 +11312,19 @@ bool ImGui::BeginDragDropTarget() return false; ImGuiWindow* window = g.CurrentWindow; - if (!window->DC.LastItemRectHoveredRect || (window->DC.LastItemId && window->DC.LastItemId == g.DragDropPayload.SourceId)) + if (!window->DC.LastItemRectHoveredRect) return false; if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) return false; + ImGuiID id = window->DC.LastItemId; + if (id == 0) + id = window->GetIDFromRectangle(window->DC.LastItemRect); + if (g.DragDropPayload.SourceId == id) + return false; + g.DragDropTargetRect = window->DC.LastItemRect; - g.DragDropTargetId = window->DC.LastItemId; + g.DragDropTargetId = id; return true; } From ab049c6fc02d68ba0741cb9789612a8a06d0164d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Dec 2017 20:34:16 +0100 Subject: [PATCH 25/25] Drag and Drop: Fix merge for IMGUI_DISABLE_OBSOLETE_FUNCTIONS --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 033b1e51..11b8dcbc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6674,7 +6674,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // - OpenOnDoubleClick .............. double-click anywhere to open // - OpenOnArrow .................... single-click on arrow to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open - ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowItemOverlap : 0); + ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0); button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0);