Skip to content

Commit

Permalink
Drag and Drop: implement simple item reordering API.
Browse files Browse the repository at this point in the history
  • Loading branch information
rokups committed May 5, 2022
1 parent d768b8c commit 713adaa
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
49 changes: 49 additions & 0 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11259,6 +11259,55 @@ void ImGui::EndDragDropTarget()
g.DragDropWithinTarget = false;
}

//-----------------------------------------------------------------------------
// [SECTION] REORDERING
//-----------------------------------------------------------------------------

int ImGui::ItemReorder(ImGuiID id, bool vertical)
{
ImGuiContext& g = *GImGui;

if (!g.IO.MouseDown[0] && g.LastItemData.ID == g.ActiveIdPreviousFrame)
{
g.ReorderScopeId = 0;
g.ReorderResult = 0;
}
else if (g.ActiveId && g.ActiveId == g.LastItemData.ID)
{
g.ActiveIdAllowOverlap = true; // Enable IsItemHovered() while current item is active
g.ReorderScopeId = id;
g.ReorderItemRect = g.LastItemData.Rect;
if (g.ReorderResult != 0)
{
int result = g.ReorderResult;
g.ReorderScopeId = 0;
g.ReorderResult = 0;
return result;
}
}
else if (g.IO.MouseDown[0] && IsItemHovered() && g.ReorderScopeId == id)
{
ImGuiAxis axis = (ImGuiAxis)vertical;
if (g.IO.MousePos[axis] > g.ReorderItemRect.Max[axis])
g.ReorderResult = +1;
else if (g.IO.MousePos[axis] < g.ReorderItemRect.Min[axis])
g.ReorderResult = -1;
}
return 0;
}

int ImGui::ItemReorder(const char* id, bool vertical)
{
ImGuiContext& g = *GImGui;
return ItemReorder(g.CurrentWindow->GetID(id), vertical);
}

int ImGui::ItemReorder(bool vertical)
{
ImGuiContext& g = *GImGui;
return ItemReorder(g.CurrentWindow->IDStack.back(), vertical);
}

//-----------------------------------------------------------------------------
// [SECTION] LOGGING/CAPTURING
//-----------------------------------------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,15 @@ namespace ImGui
IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.

// Reordering
// - Call after each item that can be reordered.
// - Returns -1/+1 if item should be swapped with the previous/next one, or 0 for no action.
// - Only items within current or specified id scope participate in item reorder.
// FIXME: "bool vertical" should be replaced with "ImGuiAxis axis", but ImGuiAxis is in imgui_internal.h
IMGUI_API int ItemReorder(ImGuiID id, bool vertical);
IMGUI_API int ItemReorder(const char* id, bool vertical);
IMGUI_API int ItemReorder(bool vertical);

// Disabling [BETA API]
// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)
// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
Expand Down
48 changes: 48 additions & 0 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2285,6 +2285,54 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}

IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (api)");
if (ImGui::TreeNode("Drag to reorder items (api)"))
{
HelpMarker("Drag items to reorder them.");
static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
static bool vertical = true;
ImGui::Checkbox("Vertical", &vertical);

int swap_n = 0;
int swap_d = 0;
for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
{
const char* item = item_names[n];
if (vertical)
{
ImGui::Selectable(item);
}
else
{
ImGui::Button(item);
if (n + 1 < IM_ARRAYSIZE(item_names))
ImGui::SameLine();
}

// Called after reorderable item. "SomeId" is optional in this simple example, but may be used to
// avoid mixing multiple distinct reorderable lists when they exist in same id scope.
if (int swap_direction = ImGui::ItemReorder("SomeId", vertical))
{
swap_n = n;
swap_d = swap_direction;
}
}

// Defer swap after rendering in order to avoid rendering glitches when items of different length are
// swapped in a horizontal list.
if (swap_d != 0)
{
const char* item = item_names[swap_n];
int next_n = swap_n + swap_d;
if (next_n >= 0 && next_n < IM_ARRAYSIZE(item_names))
{
item_names[swap_n] = item_names[next_n];
item_names[next_n] = item;
}
}
ImGui::TreePop();
}

ImGui::TreePop();
}

Expand Down
5 changes: 5 additions & 0 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,11 @@ struct ImGuiContext
ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size
unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads

// Reorder
ImGuiID ReorderScopeId;
ImRect ReorderItemRect; // Rect of item that initiated reorder operation
int ReorderResult; // Reorder response

// Clipper
int ClipperTempDataStacked;
ImVector<ImGuiListClipperData> ClipperTempData;
Expand Down

0 comments on commit 713adaa

Please sign in to comment.