|
|
@@ -1,4 +1,4 @@
|
|
|
-// dear imgui, v1.86 WIP
|
|
|
+// dear imgui, v1.86
|
|
|
// (main code and documentation)
|
|
|
|
|
|
// Help:
|
|
|
@@ -380,6 +380,7 @@ CODE
|
|
|
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
|
|
|
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
|
|
|
|
|
+ - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings
|
|
|
- 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function.
|
|
|
- 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful.
|
|
|
- 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
|
|
|
@@ -948,6 +949,9 @@ static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVe
|
|
|
static void RenderWindowOuterBorders(ImGuiWindow* window);
|
|
|
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
|
|
|
static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
|
|
|
+static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
|
|
|
+static void RenderDimmedBackgrounds();
|
|
|
+static ImGuiWindow* FindBlockingModal(ImGuiWindow* window);
|
|
|
|
|
|
// Viewports
|
|
|
static void UpdateViewportsNewFrame();
|
|
|
@@ -1948,7 +1952,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;
|
|
|
@@ -1956,8 +1960,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
|
|
|
@@ -2349,8 +2352,9 @@ static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_
|
|
|
static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n)
|
|
|
{
|
|
|
// StartPosY starts from ItemsFrozen hence the subtraction
|
|
|
+ // Perform the add and multiply with double to allow seeking through larger ranges
|
|
|
ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;
|
|
|
- float pos_y = clipper->StartPosY + (item_n - data->ItemsFrozen) * clipper->ItemsHeight;
|
|
|
+ float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight);
|
|
|
ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight);
|
|
|
}
|
|
|
|
|
|
@@ -2388,6 +2392,7 @@ void ImGuiListClipper::Begin(int items_count, float items_height)
|
|
|
g.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData());
|
|
|
ImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
|
|
|
data->Reset(this);
|
|
|
+ data->LossynessOffset = window->DC.CursorStartPosLossyness.y;
|
|
|
TempData = data;
|
|
|
}
|
|
|
|
|
|
@@ -2434,10 +2439,7 @@ bool ImGuiListClipper::Step()
|
|
|
|
|
|
// No items
|
|
|
if (ItemsCount == 0 || GetSkipItemForListClipping())
|
|
|
- {
|
|
|
- End();
|
|
|
- return false;
|
|
|
- }
|
|
|
+ return (void)End(), false;
|
|
|
|
|
|
// While we are in frozen row state, keep displaying items one by one, unclipped
|
|
|
// FIXME: Could be stored as a table-agnostic state.
|
|
|
@@ -2445,6 +2447,8 @@ bool ImGuiListClipper::Step()
|
|
|
{
|
|
|
DisplayStart = data->ItemsFrozen;
|
|
|
DisplayEnd = data->ItemsFrozen + 1;
|
|
|
+ if (DisplayStart >= ItemsCount)
|
|
|
+ return (void)End(), false;
|
|
|
data->ItemsFrozen++;
|
|
|
return true;
|
|
|
}
|
|
|
@@ -2460,6 +2464,8 @@ bool ImGuiListClipper::Step()
|
|
|
data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1));
|
|
|
DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen);
|
|
|
DisplayEnd = ImMin(data->Ranges[0].Max, ItemsCount);
|
|
|
+ if (DisplayStart == DisplayEnd)
|
|
|
+ return (void)End(), false;
|
|
|
data->StepNo = 1;
|
|
|
return true;
|
|
|
}
|
|
|
@@ -2471,16 +2477,13 @@ bool ImGuiListClipper::Step()
|
|
|
{
|
|
|
IM_ASSERT(data->StepNo == 1);
|
|
|
if (table)
|
|
|
- {
|
|
|
- const float pos_y1 = table->RowPosY1; // Using RowPosY1 instead of StartPosY to handle clipper straddling the frozen row
|
|
|
- const float pos_y2 = table->RowPosY2; // Using RowPosY2 instead of CursorPos.y to take account of tallest cell.
|
|
|
- ItemsHeight = pos_y2 - pos_y1;
|
|
|
- window->DC.CursorPos.y = pos_y2;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ItemsHeight = (window->DC.CursorPos.y - StartPosY) / (float)(DisplayEnd - DisplayStart);
|
|
|
- }
|
|
|
+ IM_ASSERT(table->RowPosY1 == StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
|
|
|
+
|
|
|
+ ItemsHeight = (window->DC.CursorPos.y - StartPosY) / (float)(DisplayEnd - DisplayStart);
|
|
|
+ bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
|
|
|
+ if (affected_by_floating_point_precision)
|
|
|
+ ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries.
|
|
|
+
|
|
|
IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
|
|
|
calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
|
|
|
}
|
|
|
@@ -2521,8 +2524,10 @@ bool ImGuiListClipper::Step()
|
|
|
for (int i = 0; i < data->Ranges.Size; i++)
|
|
|
if (data->Ranges[i].PosToIndexConvert)
|
|
|
{
|
|
|
- data->Ranges[i].Min = ImClamp(already_submitted + (int)ImFloor((data->Ranges[i].Min - window->DC.CursorPos.y) / ItemsHeight) + data->Ranges[i].PosToIndexOffsetMin, already_submitted, ItemsCount - 1);
|
|
|
- data->Ranges[i].Max = ImClamp(already_submitted + (int)ImCeil((data->Ranges[i].Max - window->DC.CursorPos.y) / ItemsHeight) + 0 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, ItemsCount);
|
|
|
+ int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / ItemsHeight);
|
|
|
+ int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / ItemsHeight) + 0.999999f);
|
|
|
+ data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, ItemsCount - 1);
|
|
|
+ data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, ItemsCount);
|
|
|
data->Ranges[i].PosToIndexConvert = false;
|
|
|
}
|
|
|
ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);
|
|
|
@@ -3388,6 +3393,17 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+// This is also inlined in ItemAdd()
|
|
|
+// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect!
|
|
|
+void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ g.LastItemData.ID = item_id;
|
|
|
+ g.LastItemData.InFlags = in_flags;
|
|
|
+ g.LastItemData.StatusFlags = item_flags;
|
|
|
+ g.LastItemData.Rect = item_rect;
|
|
|
+}
|
|
|
+
|
|
|
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
|
|
|
{
|
|
|
if (wrap_pos_x < 0.0f)
|
|
|
@@ -3898,7 +3914,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
|
|
|
|
|
// Modal windows prevents mouse from hovering behind them.
|
|
|
ImGuiWindow* modal_window = GetTopMostPopupModal();
|
|
|
- if (modal_window && g.HoveredWindow && !IsWindowChildOf(g.HoveredWindow->RootWindow, modal_window, true))
|
|
|
+ if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window))
|
|
|
clear_hovered_windows = true;
|
|
|
|
|
|
// Disabled mouse?
|
|
|
@@ -4306,8 +4322,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];
|
|
|
@@ -4434,6 +4449,84 @@ void ImGui::PopClipRect()
|
|
|
window->ClipRect = window->DrawList->_ClipRectStack.back();
|
|
|
}
|
|
|
|
|
|
+static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col)
|
|
|
+{
|
|
|
+ if ((col & IM_COL32_A_MASK) == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport();
|
|
|
+ ImRect viewport_rect = viewport->GetMainRect();
|
|
|
+
|
|
|
+ // Draw behind window by moving the draw command at the FRONT of the draw list
|
|
|
+ {
|
|
|
+ // We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows,
|
|
|
+ // and draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
|
|
|
+ ImDrawList* draw_list = window->RootWindow->DrawList;
|
|
|
+ if (draw_list->CmdBuffer.Size == 0)
|
|
|
+ draw_list->AddDrawCmd();
|
|
|
+ draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged
|
|
|
+ draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
|
|
|
+ ImDrawCmd cmd = draw_list->CmdBuffer.back();
|
|
|
+ IM_ASSERT(cmd.ElemCount == 6);
|
|
|
+ draw_list->CmdBuffer.pop_back();
|
|
|
+ draw_list->CmdBuffer.push_front(cmd);
|
|
|
+ draw_list->PopClipRect();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* parent_window)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* bottom_most_visible_window = parent_window;
|
|
|
+ for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--)
|
|
|
+ {
|
|
|
+ ImGuiWindow* window = g.Windows[i];
|
|
|
+ if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
|
+ continue;
|
|
|
+ if (!IsWindowWithinBeginStackOf(window, parent_window))
|
|
|
+ break;
|
|
|
+ if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window))
|
|
|
+ bottom_most_visible_window = window;
|
|
|
+ }
|
|
|
+ return bottom_most_visible_window;
|
|
|
+}
|
|
|
+
|
|
|
+static void ImGui::RenderDimmedBackgrounds()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal();
|
|
|
+ const bool dim_bg_for_modal = (modal_window != NULL);
|
|
|
+ const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active);
|
|
|
+ if (!dim_bg_for_modal && !dim_bg_for_window_list)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (dim_bg_for_modal)
|
|
|
+ {
|
|
|
+ // Draw dimming behind modal or a begin stack child, whichever comes first in draw order.
|
|
|
+ ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window);
|
|
|
+ RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio));
|
|
|
+ }
|
|
|
+ else if (dim_bg_for_window_list)
|
|
|
+ {
|
|
|
+ // Draw dimming behind CTRL+Tab target window
|
|
|
+ RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
|
|
|
+
|
|
|
+ // Draw border around CTRL+Tab target window
|
|
|
+ ImGuiWindow* window = g.NavWindowingTargetAnim;
|
|
|
+ ImGuiViewport* viewport = GetMainViewport();
|
|
|
+ float distance = g.FontSize;
|
|
|
+ ImRect bb = window->Rect();
|
|
|
+ bb.Expand(distance);
|
|
|
+ if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)
|
|
|
+ bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward
|
|
|
+ if (window->DrawList->CmdBuffer.Size == 0)
|
|
|
+ window->DrawList->AddDrawCmd();
|
|
|
+ window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
|
|
|
+ window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f);
|
|
|
+ window->DrawList->PopClipRect();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
|
|
|
void ImGui::EndFrame()
|
|
|
{
|
|
|
@@ -4528,6 +4621,7 @@ void ImGui::Render()
|
|
|
|
|
|
if (g.FrameCountEnded != g.FrameCount)
|
|
|
EndFrame();
|
|
|
+ const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount);
|
|
|
g.FrameCountRendered = g.FrameCount;
|
|
|
g.IO.MetricsRenderWindows = 0;
|
|
|
|
|
|
@@ -4542,6 +4636,10 @@ void ImGui::Render()
|
|
|
AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
|
|
|
}
|
|
|
|
|
|
+ // Draw modal/window whitening backgrounds
|
|
|
+ if (first_render_of_frame)
|
|
|
+ RenderDimmedBackgrounds();
|
|
|
+
|
|
|
// Add ImDrawList to render
|
|
|
ImGuiWindow* windows_to_render_top_most[2];
|
|
|
windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
|
|
|
@@ -4565,7 +4663,7 @@ void ImGui::Render()
|
|
|
viewport->DrawDataBuilder.FlattenIntoSingleLayer();
|
|
|
|
|
|
// Draw software mouse cursor if requested by io.MouseDrawCursor flag
|
|
|
- if (g.IO.MouseDrawCursor)
|
|
|
+ if (g.IO.MouseDrawCursor && first_render_of_frame)
|
|
|
RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
|
|
|
|
|
|
// Add foreground ImDrawList (for each active viewport)
|
|
|
@@ -4791,11 +4889,11 @@ bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
|
|
|
return g.IO.MouseClickedCount[button] == 2;
|
|
|
}
|
|
|
|
|
|
-bool ImGui::IsMouseTripleClicked(ImGuiMouseButton button)
|
|
|
+int ImGui::GetMouseClickedCount(ImGuiMouseButton button)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
|
- return g.IO.MouseClickedCount[button] == 3;
|
|
|
+ return g.IO.MouseClickedCount[button];
|
|
|
}
|
|
|
|
|
|
// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
|
|
|
@@ -5191,6 +5289,29 @@ static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settin
|
|
|
window->Collapsed = settings->Collapsed;
|
|
|
}
|
|
|
|
|
|
+static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+
|
|
|
+ const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0;
|
|
|
+ const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild;
|
|
|
+ if ((just_created || child_flag_changed) && !new_is_explicit_child)
|
|
|
+ {
|
|
|
+ IM_ASSERT(!g.WindowsFocusOrder.contains(window));
|
|
|
+ g.WindowsFocusOrder.push_back(window);
|
|
|
+ window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
|
|
|
+ }
|
|
|
+ else if (!just_created && child_flag_changed && new_is_explicit_child)
|
|
|
+ {
|
|
|
+ IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window);
|
|
|
+ for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++)
|
|
|
+ g.WindowsFocusOrder[n]->FocusOrder--;
|
|
|
+ g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder);
|
|
|
+ window->FocusOrder = -1;
|
|
|
+ }
|
|
|
+ window->IsExplicitChild = new_is_explicit_child;
|
|
|
+}
|
|
|
+
|
|
|
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
@@ -5230,16 +5351,12 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
|
|
|
window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
|
|
|
}
|
|
|
|
|
|
- if (!(flags & ImGuiWindowFlags_ChildWindow))
|
|
|
- {
|
|
|
- g.WindowsFocusOrder.push_back(window);
|
|
|
- window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
|
|
|
- }
|
|
|
-
|
|
|
if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
|
|
|
g.Windows.push_front(window); // Quite slow but rare and only once
|
|
|
else
|
|
|
g.Windows.push_back(window);
|
|
|
+ UpdateWindowInFocusOrderList(window, true, window->Flags);
|
|
|
+
|
|
|
return window;
|
|
|
}
|
|
|
|
|
|
@@ -5346,11 +5463,11 @@ ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window)
|
|
|
return size_final;
|
|
|
}
|
|
|
|
|
|
-static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
|
|
|
+static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window)
|
|
|
{
|
|
|
- if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
|
|
|
+ if (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
|
|
|
return ImGuiCol_PopupBg;
|
|
|
- if (flags & ImGuiWindowFlags_ChildWindow)
|
|
|
+ if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
|
return ImGuiCol_ChildBg;
|
|
|
return ImGuiCol_WindowBg;
|
|
|
}
|
|
|
@@ -5628,7 +5745,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
|
|
|
// Window background
|
|
|
if (!(flags & ImGuiWindowFlags_NoBackground))
|
|
|
{
|
|
|
- ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
|
|
|
+ ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window));
|
|
|
bool override_alpha = false;
|
|
|
float alpha = 1.0f;
|
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
|
|
|
@@ -5789,6 +5906,36 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing)
|
|
|
+// should be positioned behind that modal window, unless the window was created inside the modal begin-stack.
|
|
|
+// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent.
|
|
|
+// - Window // FindBlockingModal() returns Modal1
|
|
|
+// - Window // .. returns Modal1
|
|
|
+// - Modal1 // .. returns Modal2
|
|
|
+// - Window // .. returns Modal2
|
|
|
+// - Window // .. returns Modal2
|
|
|
+// - Modal2 // .. returns Modal2
|
|
|
+static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ if (g.OpenPopupStack.Size <= 0)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal.
|
|
|
+ for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--)
|
|
|
+ {
|
|
|
+ ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window;
|
|
|
+ if (popup_window == NULL || !popup_window->WasActive || !(popup_window->Flags & ImGuiWindowFlags_Modal)) // Check WasActive, because this code may run before popup renders on current frame.
|
|
|
+ continue;
|
|
|
+ if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed.
|
|
|
+ break;
|
|
|
+ for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow)
|
|
|
+ if (IsWindowWithinBeginStackOf(window, parent))
|
|
|
+ return popup_window; // Place window above its begin stack parent.
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
// Push a new Dear ImGui window to add widgets to.
|
|
|
// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
|
|
|
// - Begin/End can be called multiple times during the frame with the same window name to append content.
|
|
|
@@ -5809,6 +5956,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
const bool window_just_created = (window == NULL);
|
|
|
if (window_just_created)
|
|
|
window = CreateNewWindow(name, flags);
|
|
|
+ else
|
|
|
+ UpdateWindowInFocusOrderList(window, window_just_created, flags);
|
|
|
|
|
|
// Automatically disable manual moving/resizing when NoInputs is set
|
|
|
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
|
|
|
@@ -5865,6 +6014,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window_stack_data.StackSizesOnBegin.SetToCurrentState();
|
|
|
g.CurrentWindowStack.push_back(window_stack_data);
|
|
|
g.CurrentWindow = NULL;
|
|
|
+ if (flags & ImGuiWindowFlags_ChildMenu)
|
|
|
+ g.BeginMenuCount++;
|
|
|
|
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
|
{
|
|
|
@@ -5876,7 +6027,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
|
|
|
@@ -6131,6 +6285,22 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
want_focus = true;
|
|
|
else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
|
|
|
want_focus = true;
|
|
|
+
|
|
|
+ ImGuiWindow* modal = GetTopMostPopupModal();
|
|
|
+ if (modal != NULL && !IsWindowWithinBeginStackOf(window, modal))
|
|
|
+ {
|
|
|
+ // Avoid focusing a window that is created outside of active modal. This will prevent active modal from being closed.
|
|
|
+ // Since window is not focused it would reappear at the same display position like the last time it was visible.
|
|
|
+ // In case of completely new windows it would go to the top (over current modal), but input to such window would still be blocked by modal.
|
|
|
+ // Position window behind a modal that is not a begin-parent of this window.
|
|
|
+ want_focus = false;
|
|
|
+ if (window == window->RootWindow)
|
|
|
+ {
|
|
|
+ ImGuiWindow* blocking_modal = FindBlockingModal(window);
|
|
|
+ IM_ASSERT(blocking_modal != NULL);
|
|
|
+ BringWindowToDisplayBehind(window, blocking_modal);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Handle manual resize: Resize Grips, Borders, Gamepad
|
|
|
@@ -6228,24 +6398,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
|
|
|
PushClipRect(host_rect.Min, host_rect.Max, false);
|
|
|
|
|
|
- // Draw modal window background (darkens what is behind them, all viewports)
|
|
|
- const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
|
|
|
- const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
|
|
|
- if (dim_bg_for_modal || dim_bg_for_window_list)
|
|
|
- {
|
|
|
- const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
|
|
|
- window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
|
|
|
- }
|
|
|
-
|
|
|
- // Draw navigation selection/windowing rectangle background
|
|
|
- if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
|
|
|
- {
|
|
|
- ImRect bb = window->Rect();
|
|
|
- bb.Expand(g.FontSize);
|
|
|
- if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
|
|
|
- window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
|
|
|
- }
|
|
|
-
|
|
|
// Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71)
|
|
|
// When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
|
|
|
// FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493)
|
|
|
@@ -6273,20 +6425,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->DrawList = &window->DrawListInst;
|
|
|
}
|
|
|
|
|
|
- // Draw navigation selection/windowing rectangle border
|
|
|
- if (g.NavWindowingTargetAnim == window)
|
|
|
- {
|
|
|
- float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
|
|
|
- ImRect bb = window->Rect();
|
|
|
- bb.Expand(g.FontSize);
|
|
|
- if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
|
|
|
- {
|
|
|
- bb.Expand(-g.FontSize - 1.0f);
|
|
|
- rounding = window->WindowRounding;
|
|
|
- }
|
|
|
- window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, 0, 3.0f);
|
|
|
- }
|
|
|
-
|
|
|
// UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
|
|
|
|
|
|
// Work rectangle.
|
|
|
@@ -6318,7 +6456,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
|
|
|
window->DC.GroupOffset.x = 0.0f;
|
|
|
window->DC.ColumnsOffset.x = 0.0f;
|
|
|
- window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
|
|
|
+
|
|
|
+ // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount.
|
|
|
+ // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64.
|
|
|
+ double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DC.ColumnsOffset.x;
|
|
|
+ double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + decoration_up_height;
|
|
|
+ window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y);
|
|
|
+ window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y));
|
|
|
window->DC.CursorPos = window->DC.CursorStartPos;
|
|
|
window->DC.CursorPosPrevLine = window->DC.CursorPos;
|
|
|
window->DC.CursorMaxPos = window->DC.CursorStartPos;
|
|
|
@@ -6378,10 +6522,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
|
|
|
// We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
|
|
|
// This is useful to allow creating context menus on title bar only, etc.
|
|
|
- g.LastItemData.ID = window->MoveId;
|
|
|
- g.LastItemData.InFlags = g.CurrentItemFlags;
|
|
|
- g.LastItemData.StatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
|
|
|
- g.LastItemData.Rect = title_bar_rect;
|
|
|
+ SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
|
|
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
|
if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
|
|
|
@@ -6432,7 +6573,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->HiddenFramesCanSkipItems = 1;
|
|
|
|
|
|
// Update the Hidden flag
|
|
|
- window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0);
|
|
|
+ bool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
|
|
|
+ window->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0);
|
|
|
|
|
|
// Disable inputs for requested number of frames
|
|
|
if (window->DisableInputsFrames > 0)
|
|
|
@@ -6443,7 +6585,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
|
|
|
// Update the SkipItems flag, used to early out of all items functions (no layout required)
|
|
|
bool skip_items = false;
|
|
|
- if (window->Collapsed || !window->Active || window->Hidden)
|
|
|
+ if (window->Collapsed || !window->Active || hidden_regular)
|
|
|
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
|
|
|
skip_items = true;
|
|
|
window->SkipItems = skip_items;
|
|
|
@@ -6480,6 +6622,8 @@ void ImGui::End()
|
|
|
|
|
|
// Pop from window stack
|
|
|
g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;
|
|
|
+ if (window->Flags & ImGuiWindowFlags_ChildMenu)
|
|
|
+ g.BeginMenuCount--;
|
|
|
if (window->Flags & ImGuiWindowFlags_Popup)
|
|
|
g.BeginPopupStack.pop_back();
|
|
|
g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithCurrentState();
|
|
|
@@ -6537,6 +6681,34 @@ void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window)
|
|
|
+{
|
|
|
+ IM_ASSERT(window != NULL && behind_window != NULL);
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ window = window->RootWindow;
|
|
|
+ behind_window = behind_window->RootWindow;
|
|
|
+ int pos_wnd = FindWindowDisplayIndex(window);
|
|
|
+ int pos_beh = FindWindowDisplayIndex(behind_window);
|
|
|
+ if (pos_wnd < pos_beh)
|
|
|
+ {
|
|
|
+ size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*);
|
|
|
+ memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes);
|
|
|
+ g.Windows[pos_beh - 1] = window;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*);
|
|
|
+ memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes);
|
|
|
+ g.Windows[pos_beh] = window;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int ImGui::FindWindowDisplayIndex(ImGuiWindow* window)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.Windows.index_from_ptr(g.Windows.find(window));
|
|
|
+}
|
|
|
+
|
|
|
// Moving window to front of display and set focus (which happens to be back of our sorted list)
|
|
|
void ImGui::FocusWindow(ImGuiWindow* window)
|
|
|
{
|
|
|
@@ -6766,6 +6938,19 @@ bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+bool ImGui::IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
|
|
|
+{
|
|
|
+ if (window->RootWindow == potential_parent)
|
|
|
+ return true;
|
|
|
+ while (window != NULL)
|
|
|
+ {
|
|
|
+ if (window == potential_parent)
|
|
|
+ return true;
|
|
|
+ window = window->ParentWindowInBeginStack;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
@@ -6829,8 +7014,8 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
|
|
|
return false;
|
|
|
if (flags & ImGuiFocusedFlags_AnyWindow)
|
|
|
return true;
|
|
|
- IM_ASSERT(cur_window); // Not inside a Begin()/End()
|
|
|
|
|
|
+ IM_ASSERT(cur_window); // Not inside a Begin()/End()
|
|
|
const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0;
|
|
|
if (flags & ImGuiHoveredFlags_RootWindow)
|
|
|
cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy);
|
|
|
@@ -7604,6 +7789,11 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
|
|
|
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
|
|
|
NavProcessItem();
|
|
|
|
|
|
+ // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something".
|
|
|
+ // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something".
|
|
|
+ // READ THE FAQ: https://dearimgui.org/faq
|
|
|
+ IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!");
|
|
|
+
|
|
|
// [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
|
|
|
#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
|
|
if (id == g.DebugItemPickerBreakId)
|
|
|
@@ -7946,7 +8136,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.
|
|
|
@@ -8346,6 +8536,16 @@ ImGuiWindow* ImGui::GetTopMostPopupModal()
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
|
|
|
+ if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
|
|
|
+ if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup))
|
|
|
+ return popup;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
@@ -8438,7 +8638,7 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to
|
|
|
bool ref_window_is_descendent_of_popup = false;
|
|
|
for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
|
|
|
if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
|
|
|
- if (popup_window->RootWindow == ref_window->RootWindow)
|
|
|
+ if (IsWindowWithinBeginStackOf(ref_window, popup_window))
|
|
|
{
|
|
|
ref_window_is_descendent_of_popup = true;
|
|
|
break;
|
|
|
@@ -8511,7 +8711,7 @@ void ImGui::CloseCurrentPopup()
|
|
|
ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
|
|
|
bool close_parent = false;
|
|
|
if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
|
|
|
- if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
|
|
|
+ if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar))
|
|
|
close_parent = true;
|
|
|
if (!close_parent)
|
|
|
break;
|
|
|
@@ -8539,7 +8739,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
|
|
|
|
|
|
char name[20];
|
|
|
if (flags & ImGuiWindowFlags_ChildMenu)
|
|
|
- ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
|
|
|
+ ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth
|
|
|
else
|
|
|
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
|
|
|
|
|
|
@@ -11318,6 +11518,7 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
|
|
|
// - DebugNodeWindow() [Internal]
|
|
|
// - DebugNodeWindowSettings() [Internal]
|
|
|
// - DebugNodeWindowsList() [Internal]
|
|
|
+// - DebugNodeWindowsListByBeginStackParent() [Internal]
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#ifndef IMGUI_DISABLE_METRICS_WINDOW
|
|
|
@@ -11540,8 +11741,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;
|
|
|
@@ -11820,7 +12040,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list,
|
|
|
}
|
|
|
|
|
|
ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
|
|
|
- if (window && IsItemHovered())
|
|
|
+ if (window && IsItemHovered() && fg_draw_list)
|
|
|
fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
|
|
|
if (!node_open)
|
|
|
return;
|
|
|
@@ -12165,7 +12385,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]);
|
|
|
@@ -12175,6 +12394,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)
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -12295,6 +12532,9 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat
|
|
|
// Stack Tool: Display UI
|
|
|
void ImGui::ShowStackToolWindow(bool* p_open)
|
|
|
{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize))
|
|
|
+ SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver);
|
|
|
if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1)
|
|
|
{
|
|
|
End();
|
|
|
@@ -12302,7 +12542,6 @@ void ImGui::ShowStackToolWindow(bool* p_open)
|
|
|
}
|
|
|
|
|
|
// Display hovered/active status
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
|
|
|
const ImGuiID active_id = g.ActiveId;
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|