Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_sdlrenderer.cpp
#	backends/imgui_impl_sdlrenderer.h
#	imgui.cpp
#	imgui_widgets.cpp
This commit is contained in:
ocornut
2021-12-01 15:37:40 +01:00
20 changed files with 255 additions and 167 deletions

144
imgui.cpp
View File

@ -1982,7 +1982,7 @@ void ImGuiStorage::BuildSortByKey()
{
struct StaticFunc
{
static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
{
// We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
@ -1990,8 +1990,7 @@ void ImGuiStorage::BuildSortByKey()
return 0;
}
};
if (Data.Size > 1)
ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID);
}
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
@ -3169,7 +3168,7 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
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) };
ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
ImGui::KeepAliveID(id);
return id;
@ -3332,42 +3331,46 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
{
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
return IsItemFocused();
if (!IsItemFocused())
return false;
}
else
{
// Test for bounding box overlap, as updated as ItemAdd()
ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
return false;
IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
// Test if we are hovering the right window (our window could be behind another window)
// [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
// [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
// to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
// the test that has been running for a long while.
if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
return false;
// Test if another item is active (e.g. being dragged)
if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
return false;
// Test if interactions on this window are blocked by an active popup or modal.
// The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
if (!IsWindowContentHoverable(window, flags))
return false;
// Test if the item is disabled
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
// Special handling for calling after Begin() which represent the title bar or tab.
// When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
if ((g.LastItemData.ID == window->ID || g.LastItemData.ID == window->MoveId) && window->WriteAccessed)
return false;
}
// Test for bounding box overlap, as updated as ItemAdd()
ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
return false;
IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
// Test if we are hovering the right window (our window could be behind another window)
// [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
// [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
// to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
// the test that has been running for a long while.
if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
return false;
// Test if another item is active (e.g. being dragged)
if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
return false;
// Test if interactions on this window are blocked by an active popup or modal.
// The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
if (!IsWindowContentHoverable(window, flags))
return false;
// Test if the item is disabled
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
// Special handling for calling after Begin() which represent the title bar or tab.
// When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
if ((g.LastItemData.ID == window->ID || g.LastItemData.ID == window->MoveId) && window->WriteAccessed)
return false;
return true;
}
@ -4474,8 +4477,7 @@ static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, Im
if (window->Active)
{
int count = window->DC.ChildWindows.Size;
if (count > 1)
ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
for (int i = 0; i < count; i++)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
@ -6276,7 +6278,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Update ->RootWindow and others pointers (before any possible call to FocusWindow)
if (first_begin_of_the_frame)
{
UpdateWindowParentAndRootLinks(window, flags, parent_window);
window->ParentWindowInBeginStack = parent_window_in_stack;
}
// Process SetNextWindow***() calls
// (FIXME: Consider splitting the HasXXX flags into X/Y components
@ -8562,7 +8567,7 @@ void ImGui::EndGroup()
window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
ItemSize(group_bb.GetSize());
ItemAdd(group_bb, 0);
ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop);
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
@ -8851,10 +8856,10 @@ void ImGui::SetScrollHereY(float center_y_ratio)
void ImGui::BeginTooltip()
{
BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None);
}
void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
void ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)
{
ImGuiContext& g = *GImGui;
@ -8883,7 +8888,7 @@ void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags toolt
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
}
ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking;
Begin(window_name, NULL, flags | extra_flags);
Begin(window_name, NULL, flags | extra_window_flags);
}
void ImGui::EndTooltip()
@ -8894,7 +8899,7 @@ void ImGui::EndTooltip()
void ImGui::SetTooltipV(const char* fmt, va_list args)
{
BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None);
TextV(fmt, args);
EndTooltip();
}
@ -10930,16 +10935,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
return false;
// 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.
// A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag.
if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
{
IM_ASSERT(0);
return false;
}
// Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
// Magic fallback 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.
// THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG 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.
// Rely on keeping other window->LastItemXXX fields intact.
source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
@ -16659,6 +16664,7 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
// - DebugNodeWindow() [Internal]
// - DebugNodeWindowSettings() [Internal]
// - DebugNodeWindowsList() [Internal]
// - DebugNodeWindowsListByBeginStackParent() [Internal]
//-----------------------------------------------------------------------------
#ifndef IMGUI_DISABLE_METRICS_WINDOW
@ -16890,8 +16896,27 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
// Windows
DebugNodeWindowsList(&g.Windows, "Windows");
//DebugNodeWindowsList(&g.WindowsFocusOrder, "WindowsFocusOrder");
if (TreeNode("Windows", "Windows (%d)", g.Windows.Size))
{
//SetNextItemOpen(true, ImGuiCond_Once);
DebugNodeWindowsList(&g.Windows, "By display order");
DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)");
if (TreeNode("By submission order (begin stack)"))
{
// Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!
ImVector<ImGuiWindow*>& temp_buffer = g.WindowsTempSortBuffer;
temp_buffer.resize(0);
for (int i = 0; i < g.Windows.Size; i++)
if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount)
temp_buffer.push_back(g.Windows[i]);
struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };
ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);
DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);
TreePop();
}
TreePop();
}
// DrawLists
int drawlist_count = 0;
@ -17704,7 +17729,6 @@ void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* la
{
if (!TreeNode(label, "%s (%d)", label, windows->Size))
return;
Text("(In front-to-back order:)");
for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back
{
PushID((*windows)[i]);
@ -17714,6 +17738,24 @@ void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* la
TreePop();
}
// FIXME-OPT: This is technically suboptimal, but it is simpler this way.
void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack)
{
for (int i = 0; i < windows_size; i++)
{
ImGuiWindow* window = windows[i];
if (window->ParentWindowInBeginStack != parent_in_begin_stack)
continue;
char buf[20];
ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext);
//BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name);
DebugNodeWindow(window, buf);
Indent();
DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window);
Unindent();
}
}
//-----------------------------------------------------------------------------
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
//-----------------------------------------------------------------------------