|
|
@@ -214,8 +214,8 @@
|
|
|
Also read releases logs https://github.com/ocornut/imgui/releases for more details.
|
|
|
|
|
|
- 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
|
|
|
- - 2017/12/13 (1.53) - marked IsRootWindowFocused() as obsolete in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
|
|
|
- - marked IsRootWindowOrAnyChildFocused() as obsolete in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
|
|
|
+ - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
|
|
|
+ - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
|
|
|
- 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
|
|
|
- 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
|
|
|
- 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
|
|
|
@@ -224,7 +224,7 @@
|
|
|
- 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
|
|
|
- 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
|
|
|
- 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
|
|
|
- - 2017/11/02 (1.53) - marked IsRootWindowOrAnyChildHovered() as obsolete is favor of using IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows);
|
|
|
+ - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
|
|
|
- 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
|
|
|
- 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
|
|
|
- 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
|
|
|
@@ -632,8 +632,6 @@
|
|
|
// Forward Declarations
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
-static float GetDraggedColumnOffset(int column_index);
|
|
|
-
|
|
|
static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
|
|
|
|
|
|
static ImFont* GetDefaultFont();
|
|
|
@@ -1749,8 +1747,8 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
|
|
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
|
|
|
window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
|
|
|
- if (window->DC.ColumnsCount > 1)
|
|
|
- window->DC.ColumnsCellMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
|
|
|
+ if (window->DC.ColumnsSet)
|
|
|
+ window->DC.ColumnsSet->CellMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
|
|
|
}
|
|
|
|
|
|
// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
|
|
|
@@ -1830,7 +1828,6 @@ ImGuiWindow::ImGuiWindow(const char* name)
|
|
|
ID = ImHash(name, 0);
|
|
|
IDStack.push_back(ID);
|
|
|
Flags = 0;
|
|
|
- OrderWithinParent = 0;
|
|
|
PosFloat = Pos = ImVec2(0.0f, 0.0f);
|
|
|
Size = SizeFull = ImVec2(0.0f, 0.0f);
|
|
|
SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
|
|
|
@@ -1849,6 +1846,8 @@ ImGuiWindow::ImGuiWindow(const char* name)
|
|
|
SkipItems = false;
|
|
|
Appearing = false;
|
|
|
CloseButton = false;
|
|
|
+ BeginOrderWithinParent = -1;
|
|
|
+ BeginOrderWithinContext = -1;
|
|
|
BeginCount = 0;
|
|
|
PopupId = 0;
|
|
|
AutoFitFramesX = AutoFitFramesY = -1;
|
|
|
@@ -1906,6 +1905,16 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
|
|
|
return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
|
|
|
}
|
|
|
|
|
|
+// 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();
|
|
|
+ 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
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -2265,7 +2274,7 @@ void ImGui::NewFrame()
|
|
|
|
|
|
// Initialize on first frame
|
|
|
if (!g.Initialized)
|
|
|
- ImGui::Initialize();
|
|
|
+ Initialize();
|
|
|
|
|
|
SetCurrentFont(GetDefaultFont());
|
|
|
IM_ASSERT(g.Font->IsLoaded());
|
|
|
@@ -2273,6 +2282,7 @@ void ImGui::NewFrame()
|
|
|
g.Time += g.IO.DeltaTime;
|
|
|
g.FrameCount += 1;
|
|
|
g.TooltipOverrideCount = 0;
|
|
|
+ g.WindowsActiveCount = 0;
|
|
|
g.OverlayDrawList.Clear();
|
|
|
g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID);
|
|
|
g.OverlayDrawList.PushClipRectFullScreen();
|
|
|
@@ -2298,6 +2308,17 @@ 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)
|
|
|
+ {
|
|
|
+ ClearDragDrop();
|
|
|
+ g.DragDropPayloadBufHeap.clear();
|
|
|
+ memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
|
|
|
+ }
|
|
|
+ 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));
|
|
|
for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
|
|
|
@@ -2392,10 +2413,7 @@ void ImGui::NewFrame()
|
|
|
if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow())
|
|
|
{
|
|
|
g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f);
|
|
|
- ImGuiWindow* window = g.HoveredRootWindow;
|
|
|
- while (window && window != modal_window)
|
|
|
- window = window->ParentWindow;
|
|
|
- if (!window)
|
|
|
+ if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
|
|
|
g.HoveredRootWindow = g.HoveredWindow = NULL;
|
|
|
}
|
|
|
else
|
|
|
@@ -2483,8 +2501,8 @@ void ImGui::NewFrame()
|
|
|
|
|
|
// Create implicit window - we will only render it if the user has added something to it.
|
|
|
// We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
|
|
|
- ImGui::SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver);
|
|
|
- ImGui::Begin("Debug##Default");
|
|
|
+ SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver);
|
|
|
+ Begin("Debug##Default");
|
|
|
}
|
|
|
|
|
|
static void* SettingsHandlerWindow_ReadOpen(ImGuiContext&, const char* name)
|
|
|
@@ -2771,7 +2789,7 @@ static int ChildWindowComparer(const void* lhs, const void* rhs)
|
|
|
return d;
|
|
|
if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
|
|
|
return d;
|
|
|
- return (a->OrderWithinParent - b->OrderWithinParent);
|
|
|
+ return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
|
|
|
}
|
|
|
|
|
|
static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>& out_sorted_windows, ImGuiWindow* window)
|
|
|
@@ -3345,7 +3363,7 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
|
|
|
static ImGuiWindow* FindHoveredWindow(ImVec2 pos)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- for (int i = g.Windows.Size-1; i >= 0; i--)
|
|
|
+ for (int i = g.Windows.Size - 1; i >= 0; i--)
|
|
|
{
|
|
|
ImGuiWindow* window = g.Windows[i];
|
|
|
if (!window->Active)
|
|
|
@@ -3385,6 +3403,12 @@ bool ImGui::IsAnyWindowHovered()
|
|
|
return g.HoveredWindow != NULL;
|
|
|
}
|
|
|
|
|
|
+bool ImGui::IsAnyWindowFocused()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.NavWindow != NULL;
|
|
|
+}
|
|
|
+
|
|
|
static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
|
|
|
{
|
|
|
const int key_index = GImGui->IO.KeyMap[key];
|
|
|
@@ -3578,7 +3602,8 @@ bool ImGui::IsItemClicked(int mouse_button)
|
|
|
|
|
|
bool ImGui::IsAnyItemHovered()
|
|
|
{
|
|
|
- return GImGui->HoveredId != 0 || GImGui->HoveredIdPreviousFrame != 0;
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
|
|
|
}
|
|
|
|
|
|
bool ImGui::IsAnyItemActive()
|
|
|
@@ -3894,8 +3919,9 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
|
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
|
|
|
IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
|
|
|
- if (IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
|
|
|
- OpenPopupEx(id, true);
|
|
|
+ if (IsMouseClicked(mouse_button))
|
|
|
+ if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
|
|
|
+ OpenPopupEx(id, true);
|
|
|
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize);
|
|
|
}
|
|
|
|
|
|
@@ -3932,9 +3958,9 @@ static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
|
|
|
ImVec2 size = ImFloor(size_arg);
|
|
|
const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
|
|
|
if (size.x <= 0.0f)
|
|
|
- size.x = ImMax(content_avail.x, 4.0f) - fabsf(size.x); // Arbitrary minimum zero-ish child size of 4.0f (0.0f causing too much issues)
|
|
|
+ size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
|
|
|
if (size.y <= 0.0f)
|
|
|
- size.y = ImMax(content_avail.y, 4.0f) - fabsf(size.y);
|
|
|
+ size.y = ImMax(content_avail.y + size.y, 4.0f);
|
|
|
|
|
|
const float backup_border_size = g.Style.ChildBorderSize;
|
|
|
if (!border)
|
|
|
@@ -4346,7 +4372,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
|
|
|
|
|
|
// Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
|
|
|
- ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & ImGuiWindowFlags_ChildWindow) && !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL) : window->ParentWindow;
|
|
|
+ ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
|
|
|
+ ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
|
|
|
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
|
|
|
|
|
|
// Add to stack
|
|
|
@@ -4417,14 +4444,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
// Initialize
|
|
|
window->ParentWindow = parent_window;
|
|
|
- window->RootWindow = ((flags & ImGuiWindowFlags_ChildWindow) && parent_window) ? parent_window->RootWindow : window;
|
|
|
- window->RootNonPopupWindow = !(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) || (flags & ImGuiWindowFlags_Modal) || (parent_window == NULL) ? window : parent_window->RootNonPopupWindow; // Used to display TitleBgActive color and for selecting which window to use for NavWindowing
|
|
|
+ window->RootWindow = window->RootNonPopupWindow = window;
|
|
|
+ if (parent_window && (flags & ImGuiWindowFlags_ChildWindow))
|
|
|
+ window->RootWindow = parent_window->RootWindow;
|
|
|
+ if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
|
|
|
+ window->RootNonPopupWindow = parent_window->RootNonPopupWindow;
|
|
|
//window->RootNavWindow = window;
|
|
|
//while (window->RootNavWindow->Flags & ImGuiWindowFlags_NavFlattened)
|
|
|
// window->RootNavWindow = window->RootNavWindow->ParentWindow;
|
|
|
|
|
|
window->Active = true;
|
|
|
- window->OrderWithinParent = 0;
|
|
|
+ window->BeginOrderWithinParent = 0;
|
|
|
+ window->BeginOrderWithinContext = g.WindowsActiveCount++;
|
|
|
window->BeginCount = 0;
|
|
|
window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
|
|
|
window->LastFrameActive = current_frame;
|
|
|
@@ -4546,7 +4577,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
// Position child window
|
|
|
if (flags & ImGuiWindowFlags_ChildWindow)
|
|
|
{
|
|
|
- window->OrderWithinParent = parent_window->DC.ChildWindows.Size;
|
|
|
+ window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size;
|
|
|
parent_window->DC.ChildWindows.push_back(window);
|
|
|
}
|
|
|
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api)
|
|
|
@@ -4564,7 +4595,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
// This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
|
|
|
IM_ASSERT(window_pos_set_by_api);
|
|
|
float horizontal_overlap = style.ItemSpacing.x; // We want some overlap to convey the relative depth of each popup (currently the amount of overlap it is hard-coded to style.ItemSpacing.x, may need to introduce another style value).
|
|
|
- ImGuiWindow* parent_menu = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
|
|
|
+ ImGuiWindow* parent_menu = parent_window_in_stack;
|
|
|
ImRect rect_to_avoid;
|
|
|
if (parent_menu->DC.MenuBarAppending)
|
|
|
rect_to_avoid = ImRect(-FLT_MAX, parent_menu->Pos.y + parent_menu->TitleBarHeight(), FLT_MAX, parent_menu->Pos.y + parent_menu->TitleBarHeight() + parent_menu->MenuBarHeight());
|
|
|
@@ -4805,11 +4836,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->DC.ItemFlagsStack.resize(0);
|
|
|
window->DC.ItemWidthStack.resize(0);
|
|
|
window->DC.TextWrapPosStack.resize(0);
|
|
|
- window->DC.ColumnsCurrent = 0;
|
|
|
- window->DC.ColumnsCount = 1;
|
|
|
- window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
|
|
|
- window->DC.ColumnsStartMaxPosX = window->DC.CursorMaxPos.x;
|
|
|
- window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.ColumnsStartPosY;
|
|
|
+ window->DC.ColumnsSet = NULL;
|
|
|
window->DC.TreeDepth = 0;
|
|
|
window->DC.StateStorage = &window->StateStorage;
|
|
|
window->DC.GroupStack.resize(0);
|
|
|
@@ -4962,7 +4989,7 @@ void ImGui::End()
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
|
|
- if (window->DC.ColumnsCount != 1) // close columns set if any is open
|
|
|
+ if (window->DC.ColumnsSet != NULL)
|
|
|
EndColumns();
|
|
|
PopClipRect(); // inner window clip rectangle
|
|
|
|
|
|
@@ -4999,8 +5026,10 @@ void ImGui::Scrollbar(ImGuiLayoutType direction)
|
|
|
const ImRect window_rect = window->Rect();
|
|
|
const float border_size = window->WindowBorderSize;
|
|
|
ImRect bb = horizontal
|
|
|
- ? ImRect(window->InnerRect.Min.x, window_rect.Max.y - style.ScrollbarSize, window->InnerRect.Max.x, window_rect.Max.y - border_size)
|
|
|
- : ImRect(window_rect.Max.x - style.ScrollbarSize, window->InnerRect.Min.y, window_rect.Max.x - border_size, window->InnerRect.Max.y);
|
|
|
+ ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size)
|
|
|
+ : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size);
|
|
|
+ if (!horizontal)
|
|
|
+ bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
|
|
|
if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f)
|
|
|
return;
|
|
|
|
|
|
@@ -5438,6 +5467,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";
|
|
|
@@ -5493,13 +5523,13 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End()
|
|
|
|
|
|
- switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
|
|
|
+ switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
|
|
|
{
|
|
|
- case ImGuiFocusedFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
|
|
|
+ case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
|
|
|
return g.NavWindow && g.CurrentWindow->RootWindow == g.NavWindow->RootWindow;
|
|
|
case ImGuiFocusedFlags_RootWindow:
|
|
|
return g.CurrentWindow->RootWindow == g.NavWindow;
|
|
|
- case ImGuiHoveredFlags_ChildWindows:
|
|
|
+ case ImGuiFocusedFlags_ChildWindows:
|
|
|
return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
|
|
|
default:
|
|
|
return g.CurrentWindow == g.NavWindow;
|
|
|
@@ -5708,8 +5738,8 @@ ImVec2 ImGui::GetContentRegionMax()
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
ImVec2 mx = window->ContentsRegionRect.Max;
|
|
|
- if (window->DC.ColumnsCount != 1)
|
|
|
- mx.x = GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x;
|
|
|
+ if (window->DC.ColumnsSet)
|
|
|
+ mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x;
|
|
|
return mx;
|
|
|
}
|
|
|
|
|
|
@@ -6183,6 +6213,19 @@ 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 && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
|
|
|
+ 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;
|
|
|
+ FocusWindow(window);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
|
|
|
g.HoveredWindow = backup_hovered_window;
|
|
|
|
|
|
@@ -6244,7 +6287,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();
|
|
|
}
|
|
|
}
|
|
|
@@ -6644,8 +6688,10 @@ 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_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 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);
|
|
|
if (pressed && !(flags & ImGuiTreeNodeFlags_Leaf))
|
|
|
{
|
|
|
@@ -6654,6 +6700,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) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
|
|
|
+ toggled = false;
|
|
|
if (toggled)
|
|
|
{
|
|
|
is_open = !is_open;
|
|
|
@@ -6733,7 +6781,6 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
float button_sz = g.FontSize * 0.5f;
|
|
|
ImGuiItemHoveredDataBackup last_item_backup;
|
|
|
- last_item_backup.Backup();
|
|
|
if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz))
|
|
|
*p_open = false;
|
|
|
last_item_backup.Restore();
|
|
|
@@ -9302,7 +9349,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
const ImGuiStyle& style = g.Style;
|
|
|
|
|
|
- if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1) // FIXME-OPT: Avoid if vertically clipped.
|
|
|
+ if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped.
|
|
|
PopClipRect();
|
|
|
|
|
|
ImGuiID id = window->GetID(label);
|
|
|
@@ -9333,7 +9380,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|
|
bb_with_spacing.Max.y += spacing_D;
|
|
|
if (!ItemAdd(bb_with_spacing, id))
|
|
|
{
|
|
|
- if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
|
|
|
+ if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
|
|
|
PushColumnClipRect();
|
|
|
return false;
|
|
|
}
|
|
|
@@ -9355,7 +9402,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|
|
RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
|
|
|
}
|
|
|
|
|
|
- if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
|
|
|
+ if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
|
|
|
{
|
|
|
PushColumnClipRect();
|
|
|
bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x);
|
|
|
@@ -9853,7 +9900,22 @@ 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))
|
|
|
+ // Drag and Drop Source
|
|
|
+ if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization
|
|
|
+ {
|
|
|
+ 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");
|
|
|
+ EndDragDropSource();
|
|
|
+ hovered = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Tooltip
|
|
|
+ if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
|
|
|
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
|
|
|
|
|
|
return pressed;
|
|
|
@@ -10129,6 +10191,22 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
|
|
PopID();
|
|
|
EndGroup();
|
|
|
|
|
|
+ // Drag and Drop Target
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ memcpy((float*)col, payload->Data, sizeof(float) * components);
|
|
|
+ value_changed = true;
|
|
|
+ }
|
|
|
+ EndDragDropTarget();
|
|
|
+ }
|
|
|
+
|
|
|
// When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().
|
|
|
if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
|
|
|
window->DC.LastItemId = g.ActiveId;
|
|
|
@@ -10476,7 +10554,7 @@ void ImGui::Separator()
|
|
|
}
|
|
|
|
|
|
// Horizontal Separator
|
|
|
- if (window->DC.ColumnsCount > 1)
|
|
|
+ if (window->DC.ColumnsSet)
|
|
|
PopClipRect();
|
|
|
|
|
|
float x1 = window->Pos.x;
|
|
|
@@ -10488,7 +10566,7 @@ void ImGui::Separator()
|
|
|
ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout.
|
|
|
if (!ItemAdd(bb, 0))
|
|
|
{
|
|
|
- if (window->DC.ColumnsCount > 1)
|
|
|
+ if (window->DC.ColumnsSet)
|
|
|
PushColumnClipRect();
|
|
|
return;
|
|
|
}
|
|
|
@@ -10498,10 +10576,10 @@ void ImGui::Separator()
|
|
|
if (g.LogEnabled)
|
|
|
LogRenderedText(NULL, IM_NEWLINE "--------------------------------");
|
|
|
|
|
|
- if (window->DC.ColumnsCount > 1)
|
|
|
+ if (window->DC.ColumnsSet)
|
|
|
{
|
|
|
PushColumnClipRect();
|
|
|
- window->DC.ColumnsCellMinY = window->DC.CursorPos.y;
|
|
|
+ window->DC.ColumnsSet->CellMinY = window->DC.CursorPos.y;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -10714,29 +10792,30 @@ void ImGui::NewLine()
|
|
|
void ImGui::NextColumn()
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
- if (window->SkipItems || window->DC.ColumnsCount <= 1)
|
|
|
+ if (window->SkipItems || window->DC.ColumnsSet == NULL)
|
|
|
return;
|
|
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
PopItemWidth();
|
|
|
PopClipRect();
|
|
|
|
|
|
- window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
|
|
|
- if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount)
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
+ columns->CellMaxY = ImMax(columns->CellMaxY, window->DC.CursorPos.y);
|
|
|
+ if (++columns->Current < columns->Count)
|
|
|
{
|
|
|
// Columns 1+ cancel out IndentX
|
|
|
- window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x;
|
|
|
- window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
|
|
|
+ window->DC.ColumnsOffsetX = GetColumnOffset(columns->Current) - window->DC.IndentX + g.Style.ItemSpacing.x;
|
|
|
+ window->DrawList->ChannelsSetCurrent(columns->Current);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- window->DC.ColumnsCurrent = 0;
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
- window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY;
|
|
|
+ columns->Current = 0;
|
|
|
+ columns->CellMinY = columns->CellMaxY;
|
|
|
window->DrawList->ChannelsSetCurrent(0);
|
|
|
}
|
|
|
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
- window->DC.CursorPos.y = window->DC.ColumnsCellMinY;
|
|
|
+ window->DC.CursorPos.y = columns->CellMinY;
|
|
|
window->DC.CurrentLineHeight = 0.0f;
|
|
|
window->DC.CurrentLineTextBaseOffset = 0.0f;
|
|
|
|
|
|
@@ -10747,38 +10826,38 @@ void ImGui::NextColumn()
|
|
|
int ImGui::GetColumnIndex()
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.ColumnsCurrent;
|
|
|
+ return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0;
|
|
|
}
|
|
|
|
|
|
int ImGui::GetColumnsCount()
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.ColumnsCount;
|
|
|
+ return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1;
|
|
|
}
|
|
|
|
|
|
-static float OffsetNormToPixels(ImGuiWindow* window, float offset_norm)
|
|
|
+static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm)
|
|
|
{
|
|
|
- return offset_norm * (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
|
|
|
+ return offset_norm * (columns->MaxX - columns->MinX);
|
|
|
}
|
|
|
|
|
|
-static float PixelsToOffsetNorm(ImGuiWindow* window, float offset)
|
|
|
+static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset)
|
|
|
{
|
|
|
- return (offset - window->DC.ColumnsMinX) / (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
|
|
|
+ return (offset - columns->MinX) / (columns->MaxX - columns->MinX);
|
|
|
}
|
|
|
|
|
|
-static float GetDraggedColumnOffset(int column_index)
|
|
|
+static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
|
|
|
{
|
|
|
// Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
|
|
|
// window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets.
|
|
|
- IM_ASSERT(g.ActiveId == window->DC.ColumnsSetId + ImGuiID(column_index));
|
|
|
+ IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
|
|
|
|
|
|
float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x;
|
|
|
- x = ImMax(x, ImGui::GetColumnOffset(column_index-1) + g.Style.ColumnsMinSpacing);
|
|
|
- if ((window->DC.ColumnsFlags & ImGuiColumnsFlags_NoPreserveWidths))
|
|
|
- x = ImMin(x, ImGui::GetColumnOffset(column_index+1) - g.Style.ColumnsMinSpacing);
|
|
|
+ x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
|
|
|
+ if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
|
|
|
+ x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
|
|
|
|
|
|
return x;
|
|
|
}
|
|
|
@@ -10786,128 +10865,174 @@ static float GetDraggedColumnOffset(int column_index)
|
|
|
float ImGui::GetColumnOffset(int column_index)
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
+ IM_ASSERT(columns != NULL);
|
|
|
+
|
|
|
if (column_index < 0)
|
|
|
- column_index = window->DC.ColumnsCurrent;
|
|
|
+ column_index = columns->Current;
|
|
|
+ IM_ASSERT(column_index < columns->Columns.Size);
|
|
|
|
|
|
/*
|
|
|
if (g.ActiveId)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
+ const ImGuiID column_id = columns->ColumnsSetId + ImGuiID(column_index);
|
|
|
if (g.ActiveId == column_id)
|
|
|
- return GetDraggedColumnOffset(column_index);
|
|
|
+ return GetDraggedColumnOffset(columns, column_index);
|
|
|
}
|
|
|
*/
|
|
|
|
|
|
- IM_ASSERT(column_index < window->DC.ColumnsData.Size);
|
|
|
- const float t = window->DC.ColumnsData[column_index].OffsetNorm;
|
|
|
- const float x_offset = ImLerp(window->DC.ColumnsMinX, window->DC.ColumnsMaxX, t);
|
|
|
+ const float t = columns->Columns[column_index].OffsetNorm;
|
|
|
+ const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
|
|
|
return x_offset;
|
|
|
}
|
|
|
|
|
|
-void ImGui::SetColumnOffset(int column_index, float offset)
|
|
|
+static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false)
|
|
|
{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
if (column_index < 0)
|
|
|
- column_index = window->DC.ColumnsCurrent;
|
|
|
+ column_index = columns->Current;
|
|
|
+
|
|
|
+ float offset_norm;
|
|
|
+ if (before_resize)
|
|
|
+ offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
|
|
|
+ else
|
|
|
+ offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
|
|
|
+ return OffsetNormToPixels(columns, offset_norm);
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetColumnWidth(int column_index)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
+ IM_ASSERT(columns != NULL);
|
|
|
+
|
|
|
+ if (column_index < 0)
|
|
|
+ column_index = columns->Current;
|
|
|
+ return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
|
|
|
+}
|
|
|
|
|
|
- IM_ASSERT(column_index < window->DC.ColumnsData.Size);
|
|
|
+void ImGui::SetColumnOffset(int column_index, float offset)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
+ IM_ASSERT(columns != NULL);
|
|
|
|
|
|
- const bool preserve_width = !(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < window->DC.ColumnsCount-1);
|
|
|
- const float width = preserve_width ? GetColumnWidth(column_index) : 0.0f;
|
|
|
+ if (column_index < 0)
|
|
|
+ column_index = columns->Current;
|
|
|
+ IM_ASSERT(column_index < columns->Columns.Size);
|
|
|
|
|
|
- if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoForceWithinWindow))
|
|
|
- offset = ImMin(offset, window->DC.ColumnsMaxX - g.Style.ColumnsMinSpacing * (window->DC.ColumnsCount - column_index));
|
|
|
- const float offset_norm = PixelsToOffsetNorm(window, offset);
|
|
|
+ const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
|
|
|
+ const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
|
|
|
|
|
|
- const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
- window->DC.StateStorage->SetFloat(column_id, offset_norm);
|
|
|
- window->DC.ColumnsData[column_index].OffsetNorm = offset_norm;
|
|
|
+ if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
|
|
|
+ offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
|
|
|
+ columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset);
|
|
|
|
|
|
if (preserve_width)
|
|
|
SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
|
|
|
}
|
|
|
|
|
|
-float ImGui::GetColumnWidth(int column_index)
|
|
|
+void ImGui::SetColumnWidth(int column_index, float width)
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- if (column_index < 0)
|
|
|
- column_index = window->DC.ColumnsCurrent;
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
+ IM_ASSERT(columns != NULL);
|
|
|
|
|
|
- return OffsetNormToPixels(window, window->DC.ColumnsData[column_index+1].OffsetNorm - window->DC.ColumnsData[column_index].OffsetNorm);
|
|
|
+ if (column_index < 0)
|
|
|
+ column_index = columns->Current;
|
|
|
+ SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
|
|
|
}
|
|
|
|
|
|
-void ImGui::SetColumnWidth(int column_index, float width)
|
|
|
+void ImGui::PushColumnClipRect(int column_index)
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
if (column_index < 0)
|
|
|
- column_index = window->DC.ColumnsCurrent;
|
|
|
+ column_index = columns->Current;
|
|
|
|
|
|
- SetColumnOffset(column_index+1, GetColumnOffset(column_index) + width);
|
|
|
+ PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false);
|
|
|
}
|
|
|
|
|
|
-void ImGui::PushColumnClipRect(int column_index)
|
|
|
+static ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id)
|
|
|
{
|
|
|
- ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- if (column_index < 0)
|
|
|
- column_index = window->DC.ColumnsCurrent;
|
|
|
+ for (int n = 0; n < window->ColumnsStorage.Size; n++)
|
|
|
+ if (window->ColumnsStorage[n].ID == id)
|
|
|
+ return &window->ColumnsStorage[n];
|
|
|
|
|
|
- PushClipRect(window->DC.ColumnsData[column_index].ClipRect.Min, window->DC.ColumnsData[column_index].ClipRect.Max, false);
|
|
|
+ window->ColumnsStorage.push_back(ImGuiColumnsSet());
|
|
|
+ ImGuiColumnsSet* columns = &window->ColumnsStorage.back();
|
|
|
+ columns->ID = id;
|
|
|
+ return columns;
|
|
|
}
|
|
|
|
|
|
-void ImGui::BeginColumns(const char* id, int columns_count, ImGuiColumnsFlags flags)
|
|
|
+void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
|
IM_ASSERT(columns_count > 1);
|
|
|
- IM_ASSERT(window->DC.ColumnsCount == 1); // Nested columns are currently not supported
|
|
|
+ IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported
|
|
|
|
|
|
// Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
|
|
|
// In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
|
|
|
- PushID(0x11223347 + (id ? 0 : columns_count));
|
|
|
- window->DC.ColumnsSetId = window->GetID(id ? id : "columns");
|
|
|
+ PushID(0x11223347 + (str_id ? 0 : columns_count));
|
|
|
+ ImGuiID id = window->GetID(str_id ? str_id : "columns");
|
|
|
PopID();
|
|
|
|
|
|
- // Set state for first column
|
|
|
- window->DC.ColumnsCurrent = 0;
|
|
|
- window->DC.ColumnsCount = columns_count;
|
|
|
- window->DC.ColumnsFlags = flags;
|
|
|
+ // Acquire storage for the columns set
|
|
|
+ ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id);
|
|
|
+ IM_ASSERT(columns->ID == id);
|
|
|
+ columns->Current = 0;
|
|
|
+ columns->Count = columns_count;
|
|
|
+ columns->Flags = flags;
|
|
|
+ window->DC.ColumnsSet = columns;
|
|
|
|
|
|
+ // Set state for first column
|
|
|
const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->Size.x -window->ScrollbarSizes.x);
|
|
|
- window->DC.ColumnsMinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
|
|
|
- //window->DC.ColumnsMaxX = content_region_width - window->Scroll.x -((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
|
|
|
- window->DC.ColumnsMaxX = content_region_width - window->Scroll.x;
|
|
|
- window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
|
|
|
- window->DC.ColumnsStartMaxPosX = window->DC.CursorMaxPos.x;
|
|
|
- window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.CursorPos.y;
|
|
|
+ columns->MinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
|
|
|
+ //column->ColumnsMaxX = content_region_width - window->Scroll.x -((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
|
|
|
+ columns->MaxX = content_region_width - window->Scroll.x;
|
|
|
+ columns->StartPosY = window->DC.CursorPos.y;
|
|
|
+ columns->StartMaxPosX = window->DC.CursorMaxPos.x;
|
|
|
+ columns->CellMinY = columns->CellMaxY = window->DC.CursorPos.y;
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
|
|
|
- // Cache column offsets
|
|
|
- window->DC.ColumnsData.resize(columns_count + 1);
|
|
|
- for (int column_index = 0; column_index < columns_count + 1; column_index++)
|
|
|
+ // Initialize defaults
|
|
|
+ columns->IsFirstFrame = (columns->Columns.Size == 0);
|
|
|
+ if (columns->Columns.Size == 0)
|
|
|
{
|
|
|
- const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
- KeepAliveID(column_id);
|
|
|
- const float default_t = column_index / (float)window->DC.ColumnsCount;
|
|
|
- float t = window->DC.StateStorage->GetFloat(column_id, default_t);
|
|
|
- if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoForceWithinWindow))
|
|
|
- t = ImMin(t, PixelsToOffsetNorm(window, window->DC.ColumnsMaxX - g.Style.ColumnsMinSpacing * (window->DC.ColumnsCount - column_index)));
|
|
|
- window->DC.ColumnsData[column_index].OffsetNorm = t;
|
|
|
+ columns->Columns.reserve(columns_count + 1);
|
|
|
+ for (int n = 0; n < columns_count + 1; n++)
|
|
|
+ {
|
|
|
+ ImGuiColumnData column;
|
|
|
+ column.OffsetNorm = n / (float)columns_count;
|
|
|
+ columns->Columns.push_back(column);
|
|
|
+ }
|
|
|
}
|
|
|
+ IM_ASSERT(columns->Columns.Size == columns_count + 1);
|
|
|
|
|
|
- // Cache clipping rectangles
|
|
|
- for (int column_index = 0; column_index < columns_count; column_index++)
|
|
|
+ for (int n = 0; n < columns_count + 1; n++)
|
|
|
{
|
|
|
- float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(column_index) - 1.0f);
|
|
|
- float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(column_index + 1) - 1.0f);
|
|
|
- window->DC.ColumnsData[column_index].ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
|
|
|
- window->DC.ColumnsData[column_index].ClipRect.ClipWith(window->ClipRect);
|
|
|
+ // Clamp
|
|
|
+ ImGuiColumnData* column = &columns->Columns[n];
|
|
|
+ float t = column->OffsetNorm;
|
|
|
+ if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
|
|
|
+ t = ImMin(t, PixelsToOffsetNorm(columns, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - n)));
|
|
|
+ column->OffsetNorm = t;
|
|
|
+
|
|
|
+ if (n == columns_count)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ // Compute clipping rectangles
|
|
|
+ float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f);
|
|
|
+ float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
|
|
|
+ column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
|
|
|
+ column->ClipRect.ClipWith(window->ClipRect);
|
|
|
}
|
|
|
|
|
|
- window->DrawList->ChannelsSplit(window->DC.ColumnsCount);
|
|
|
+ window->DrawList->ChannelsSplit(columns->Count);
|
|
|
PushColumnClipRect();
|
|
|
PushItemWidth(GetColumnWidth() * 0.65f);
|
|
|
}
|
|
|
@@ -10916,34 +11041,37 @@ void ImGui::EndColumns()
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
- IM_ASSERT(window->DC.ColumnsCount > 1);
|
|
|
+ ImGuiColumnsSet* columns = window->DC.ColumnsSet;
|
|
|
+ IM_ASSERT(columns != NULL);
|
|
|
|
|
|
PopItemWidth();
|
|
|
PopClipRect();
|
|
|
window->DrawList->ChannelsMerge();
|
|
|
|
|
|
- window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
|
|
|
- window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;
|
|
|
- if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_GrowParentContentsSize))
|
|
|
- window->DC.CursorMaxPos.x = ImMax(window->DC.ColumnsStartMaxPosX, window->DC.ColumnsMaxX); // Restore cursor max pos, as columns don't grow parent
|
|
|
+ columns->CellMaxY = ImMax(columns->CellMaxY, window->DC.CursorPos.y);
|
|
|
+ window->DC.CursorPos.y = columns->CellMaxY;
|
|
|
+ if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize))
|
|
|
+ window->DC.CursorMaxPos.x = ImMax(columns->StartMaxPosX, columns->MaxX); // Restore cursor max pos, as columns don't grow parent
|
|
|
|
|
|
// Draw columns borders and handle resize
|
|
|
- if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
|
|
|
+ bool is_being_resized = false;
|
|
|
+ if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
|
|
|
{
|
|
|
- const float y1 = window->DC.ColumnsStartPosY;
|
|
|
+ const float y1 = columns->StartPosY;
|
|
|
const float y2 = window->DC.CursorPos.y;
|
|
|
int dragging_column = -1;
|
|
|
- for (int i = 1; i < window->DC.ColumnsCount; i++)
|
|
|
+ for (int n = 1; n < columns->Count; n++)
|
|
|
{
|
|
|
- float x = window->Pos.x + GetColumnOffset(i);
|
|
|
- const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(i);
|
|
|
+ float x = window->Pos.x + GetColumnOffset(n);
|
|
|
+ const ImGuiID column_id = columns->ID + ImGuiID(n);
|
|
|
const float column_hw = 4.0f; // Half-width for interaction
|
|
|
const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2));
|
|
|
+ KeepAliveID(column_id);
|
|
|
if (IsClippedEx(column_rect, column_id, false))
|
|
|
continue;
|
|
|
|
|
|
bool hovered = false, held = false;
|
|
|
- if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoResize))
|
|
|
+ if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
|
|
|
{
|
|
|
ButtonBehavior(column_rect, column_id, &hovered, &held);
|
|
|
if (hovered || held)
|
|
|
@@ -10951,11 +11079,10 @@ void ImGui::EndColumns()
|
|
|
if (held && g.ActiveIdIsJustActivated)
|
|
|
g.ActiveIdClickOffset.x -= column_hw; // Store from center of column line (we used a 8 wide rect for columns clicking). This is used by GetDraggedColumnOffset().
|
|
|
if (held)
|
|
|
- dragging_column = i;
|
|
|
+ dragging_column = n;
|
|
|
}
|
|
|
|
|
|
- // Draw column
|
|
|
- // We clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.
|
|
|
+ // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.)
|
|
|
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
|
|
|
const float xi = (float)(int)x;
|
|
|
window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col);
|
|
|
@@ -10964,27 +11091,27 @@ void ImGui::EndColumns()
|
|
|
// Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
|
|
|
if (dragging_column != -1)
|
|
|
{
|
|
|
- float x = GetDraggedColumnOffset(dragging_column);
|
|
|
+ if (!columns->IsBeingResized)
|
|
|
+ for (int n = 0; n < columns->Count + 1; n++)
|
|
|
+ columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
|
|
|
+ columns->IsBeingResized = is_being_resized = true;
|
|
|
+ float x = GetDraggedColumnOffset(columns, dragging_column);
|
|
|
SetColumnOffset(dragging_column, x);
|
|
|
}
|
|
|
}
|
|
|
+ columns->IsBeingResized = is_being_resized;
|
|
|
|
|
|
- window->DC.ColumnsSetId = 0;
|
|
|
- window->DC.ColumnsCurrent = 0;
|
|
|
- window->DC.ColumnsCount = 1;
|
|
|
- window->DC.ColumnsFlags = 0;
|
|
|
- window->DC.ColumnsData.resize(0);
|
|
|
+ window->DC.ColumnsSet = NULL;
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
}
|
|
|
|
|
|
-// [2017/08: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
|
|
|
+// [2017/12: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
|
|
|
void ImGui::Columns(int columns_count, const char* id, bool border)
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
IM_ASSERT(columns_count >= 1);
|
|
|
-
|
|
|
- if (window->DC.ColumnsCount != columns_count && window->DC.ColumnsCount != 1)
|
|
|
+ if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count != columns_count)
|
|
|
EndColumns();
|
|
|
|
|
|
ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
|
|
|
@@ -11070,6 +11197,253 @@ void ImGui::Value(const char* prefix, float v, const char* float_format)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// DRAG AND DROP
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImGui::ClearDragDrop()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ g.DragDropActive = false;
|
|
|
+ g.DragDropPayload.Clear();
|
|
|
+ g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
|
|
|
+ g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
|
|
|
+ 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)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ if (g.IO.MouseDown[mouse_button] == false)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ 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.
|
|
|
+ // 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);
|
|
|
+ ClearDragDrop();
|
|
|
+ ImGuiPayload& payload = g.DragDropPayload;
|
|
|
+ payload.SourceId = id;
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover))
|
|
|
+ window->DC.LastItemRectHoveredRect = false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::EndDragDropSource()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(g.DragDropActive);
|
|
|
+
|
|
|
+ if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoAutoTooltip))
|
|
|
+ {
|
|
|
+ EndTooltip();
|
|
|
+ PopStyleColor();
|
|
|
+ //PopStyleVar();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Discard the drag if have not called SetDragDropPayload()
|
|
|
+ if (g.DragDropPayload.DataFrameCount == -1)
|
|
|
+ ClearDragDrop();
|
|
|
+}
|
|
|
+
|
|
|
+// 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;
|
|
|
+ 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) || (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 (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;
|
|
|
+ IM_ASSERT(id != 0);
|
|
|
+ if (!IsMouseHoveringRect(bb.Min, bb.Max) || (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) 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()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ if (!g.DragDropActive)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ 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 = id;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool ImGui::IsDragDropPayloadBeingAccepted()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
|
|
|
+}
|
|
|
+
|
|
|
+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(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ?
|
|
|
+ if (type != NULL && !payload.IsDataType(type))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
|
|
|
+ // 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 = g.DragDropTargetId;
|
|
|
+ g.DragDropAcceptIdCurrRectSurface = r_surface;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Render default drop visuals
|
|
|
+ payload.Preview = was_accepted_previously;
|
|
|
+ if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
|
|
|
+ {
|
|
|
+ // 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->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 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))
|
|
|
+ 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
|
|
|
//-----------------------------------------------------------------------------
|