mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-11-04 01:34:32 +00:00 
			
		
		
		
	Drag and drop API experiment
This commit is contained in:
		
							
								
								
									
										172
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								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 <on release>
 | 
			
		||||
                    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
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -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<unsigned char> 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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user