Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/wolfpld/tracy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Taudul <wolf@nereid.pl>2021-08-21 01:52:30 +0300
committerBartosz Taudul <wolf@nereid.pl>2021-08-21 01:52:30 +0300
commit30445b656fe94c9f8f26480fc79cf021c9ad67ac (patch)
tree1c0c935fc3e657d2d2a8622813e28920e24dabdf /imgui/imgui.cpp
parentc82bf3915bae272cb36b5846545ed250627302f3 (diff)
Update ImGui to 1.84.1 + docking.
Diffstat (limited to 'imgui/imgui.cpp')
-rw-r--r--imgui/imgui.cpp1001
1 files changed, 659 insertions, 342 deletions
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index aad29c78..bc1616e4 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.83
+// dear imgui, v1.84
// (main code and documentation)
// Help:
@@ -11,7 +11,7 @@
// - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases
-// - Gallery https://github.com/ocornut/imgui/issues/3793 (please post your screenshots/video there!)
+// - Gallery https://github.com/ocornut/imgui/issues/4451 (please post your screenshots/video there!)
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues
@@ -386,6 +386,9 @@ CODE
- 2021/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
+ - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
+ - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
+ - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder
- 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
- if you are using official backends from the source tree: you have nothing to do.
- if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
@@ -406,7 +409,7 @@ CODE
- ImGui::SetScrollHere() -> use ImGui::SetScrollHereY()
- 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing.
- 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future.
- - 2021/02/22 (1.82) - win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.
+ - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.
- 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.
- 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
- removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
@@ -795,6 +798,11 @@ CODE
#include <stdint.h> // intptr_t
#endif
+// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled
+#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
+#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
+#endif
+
// [Windows] OS specific includes (optional)
#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#define IMGUI_DISABLE_WIN32_FUNCTIONS
@@ -946,7 +954,8 @@ const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbi
static ImGuiViewportP* AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& platform_pos, const ImVec2& size, ImGuiViewportFlags flags);
static void UpdateViewportsNewFrame();
static void UpdateViewportsEndFrame();
-static void UpdateSelectWindowViewport(ImGuiWindow* window);
+static void WindowSelectViewport(ImGuiWindow* window);
+static void WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack);
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window);
static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
@@ -1004,7 +1013,8 @@ static void* GImAllocatorUserData = NULL;
ImGuiStyle::ImGuiStyle()
{
- Alpha = 1.0f; // Global alpha applies to everything in ImGui
+ Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui.
+ DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
WindowPadding = ImVec2(8,8); // Padding within a window
WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
@@ -1089,7 +1099,7 @@ ImGuiIO::ImGuiIO()
DisplaySize = ImVec2(-1.0f, -1.0f);
DeltaTime = 1.0f / 60.0f;
IniSavingRate = 5.0f;
- IniFilename = "imgui.ini";
+ IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables).
LogFilename = "imgui_log.txt";
MouseDoubleClickTime = 0.30f;
MouseDoubleClickMaxDist = 6.0f;
@@ -1205,6 +1215,24 @@ void ImGuiIO::ClearInputCharacters()
InputQueueCharacters.resize(0);
}
+void ImGuiIO::ClearInputKeys()
+{
+ memset(KeysDown, 0, sizeof(KeysDown));
+ for (int n = 0; n < IM_ARRAYSIZE(KeysDownDuration); n++)
+ KeysDownDuration[n] = KeysDownDurationPrev[n] = -1.0f;
+ KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
+ KeyMods = KeyModsPrev = ImGuiKeyModFlags_None;
+ for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++)
+ NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f;
+}
+
+void ImGuiIO::AddFocusEvent(bool focused)
+{
+ // We intentionally overwrite this and process in NewFrame(), in order to give a chance
+ // to multi-viewports backends to queue AddFocusEvent(false),AddFocusEvent(true) in same frame.
+ AppFocusLost = !focused;
+}
+
//-----------------------------------------------------------------------------
// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
//-----------------------------------------------------------------------------
@@ -1734,7 +1762,7 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
}
// Based on stb_to_utf8() from github.com/nothings/stb/
-static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
+static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c)
{
if (c < 0x80)
{
@@ -1769,6 +1797,13 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
return 0;
}
+const char* ImTextCharToUtf8(char out_buf[5], unsigned int c)
+{
+ int count = ImTextCharToUtf8_inline(out_buf, 5, c);
+ out_buf[count] = 0;
+ return out_buf;
+}
+
// Not optimal but we very rarely use this function.
int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
{
@@ -1785,20 +1820,20 @@ static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
return 3;
}
-int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
+int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
{
- char* buf_out = buf;
- const char* buf_end = buf + buf_size;
- while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
+ char* buf_p = out_buf;
+ const char* buf_end = out_buf + out_buf_size;
+ while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
{
unsigned int c = (unsigned int)(*in_text++);
if (c < 0x80)
- *buf_out++ = (char)c;
+ *buf_p++ = (char)c;
else
- buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
+ buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c);
}
- *buf_out = 0;
- return (int)(buf_out - buf);
+ *buf_p = 0;
+ return (int)(buf_p - out_buf);
}
int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
@@ -2540,6 +2575,7 @@ static const ImGuiCol GWindowDockStyleColors[ImGuiWindowDockStyleCol_COUNT] =
static const ImGuiStyleVarInfo GStyleVarInfo[] =
{
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
+ { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
@@ -2819,7 +2855,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
int ellipsis_char_count = 1;
if (ellipsis_char == (ImWchar)-1)
{
- ellipsis_char = (ImWchar)'.';
+ ellipsis_char = font->DotChar;
ellipsis_char_count = 3;
}
const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
@@ -2964,8 +3000,7 @@ ImGuiWindow::~ImGuiWindow()
{
IM_ASSERT(DrawList == &DrawListInst);
IM_DELETE(Name);
- for (int i = 0; i != ColumnsStorage.Size; i++)
- ColumnsStorage[i].~ImGuiOldColumns();
+ ColumnsStorage.clear_destruct();
}
ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
@@ -3165,7 +3200,7 @@ void ImGui::MarkItemEdited(ImGuiID id)
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.ActiveIdHasBeenEditedThisFrame = true;
g.ActiveIdHasBeenEditedBefore = true;
- g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
}
static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
@@ -3201,10 +3236,14 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.NavDisableMouseHover && !g.NavDisableHighlight)
+ {
+ if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
+ return false;
return IsItemFocused();
+ }
// Test for bounding box overlap, as updated as ItemAdd()
- ImGuiItemStatusFlags status_flags = window->DC.LastItemStatusFlags;
+ ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
return false;
IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
@@ -3220,7 +3259,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
// Test if another item is active (e.g. being dragged)
if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
- if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
+ 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.
@@ -3229,12 +3268,12 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false;
// Test if the item is disabled
- if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
+ 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 ((window->DC.LastItemId == window->ID || window->DC.LastItemId == window->MoveId) && window->WriteAccessed)
+ if ((g.LastItemData.ID == window->ID || g.LastItemData.ID == window->MoveId) && window->WriteAccessed)
return false;
return true;
}
@@ -3255,7 +3294,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
return false;
if (g.NavDisableMouseHover)
return false;
- if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (g.CurrentItemFlags & ImGuiItemFlags_Disabled))
+ if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
{
g.HoveredIdDisabled = true;
return false;
@@ -3264,9 +3303,21 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
// We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
// hover test in widgets code. We could also decide to split this function is two.
if (id != 0)
- {
SetHoveredID(id);
+ // When disabled we'll return false but still set HoveredId
+ ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);
+ if (item_flags & ImGuiItemFlags_Disabled)
+ {
+ // Release active id if turning disabled
+ if (g.ActiveId == id)
+ ClearActiveID();
+ g.HoveredIdDisabled = true;
+ return false;
+ }
+
+ if (id != 0)
+ {
// [DEBUG] Item Picker tool!
// We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
// the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
@@ -3294,22 +3345,25 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged
// This is also inlined in ItemAdd()
// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect!
-void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
+void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
{
- window->DC.LastItemId = item_id;
- window->DC.LastItemStatusFlags = item_flags;
- window->DC.LastItemRect = 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;
}
+// Called by ItemAdd()
// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(id != 0 && id == window->DC.LastItemId);
+ IM_ASSERT(id != 0 && id == g.LastItemData.ID);
// Increment counters
// FIXME: ImGuiItemFlags_Disabled should disable more.
- const bool is_tab_stop = (g.CurrentItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
+ const bool is_tab_stop = (g.LastItemData.InFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
window->DC.FocusCounterRegular++;
if (is_tab_stop)
{
@@ -3331,13 +3385,13 @@ void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{
if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular)
{
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
return;
}
if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
{
g.NavJustTabbedId = id;
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
return;
}
@@ -3576,8 +3630,9 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
FocusWindow(window);
SetActiveID(window->MoveId, window);
g.NavDisableHighlight = true;
- g.ActiveIdNoClearOnFocusLoss = true;
g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindowDockTree->Pos;
+ g.ActiveIdNoClearOnFocusLoss = true;
+ SetActiveIdUsingNavAndKeys();
bool can_move_window = true;
if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoMove))
@@ -3659,8 +3714,8 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
// Clear the NoInput window flag set by the Viewport system
moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs; // FIXME-VIEWPORT: Test engine managed to crash here because Viewport was NULL.
- ClearActiveID();
g.MovingWindow = NULL;
+ ClearActiveID();
}
}
else
@@ -3739,8 +3794,6 @@ static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
window->DC.CursorPos += delta;
window->DC.CursorStartPos += delta;
window->DC.CursorMaxPos += delta;
- window->DC.LastItemRect.Translate(delta);
- window->DC.LastItemDisplayRect.Translate(delta);
}
static void ScaleWindow(ImGuiWindow* window, float scale)
@@ -4138,6 +4191,14 @@ void ImGui::NewFrame()
g.DragDropWithinTarget = false;
g.DragDropHoldJustPressedId = 0;
+ // Clear buttons state when focus is lost
+ // (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle)
+ if (g.IO.AppFocusLost)
+ {
+ g.IO.ClearInputKeys();
+ g.IO.AppFocusLost = false;
+ }
+
// Update keyboard input state
// Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
g.IO.KeyMods = GetMergedKeyModFlags();
@@ -4217,7 +4278,6 @@ void ImGui::NewFrame()
g.ItemFlagsStack.resize(0);
g.ItemFlagsStack.push_back(ImGuiItemFlags_None);
g.GroupStack.resize(0);
- ClosePopupsOverWindow(g.NavWindow, false);
// Docking
DockContextNewFrameUpdateDocking(&g);
@@ -4336,9 +4396,7 @@ void ImGui::Shutdown(ImGuiContext* context)
CallContextHooks(&g, ImGuiContextHookType_Shutdown);
// Clear everything else
- for (int i = 0; i < g.Windows.Size; i++)
- IM_DELETE(g.Windows[i]);
- g.Windows.clear();
+ g.Windows.clear_delete();
g.WindowsFocusOrder.clear();
g.WindowsTempSortBuffer.clear();
g.CurrentWindow = NULL;
@@ -4355,18 +4413,14 @@ void ImGui::Shutdown(ImGuiContext* context)
g.BeginPopupStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
- for (int i = 0; i < g.Viewports.Size; i++)
- IM_DELETE(g.Viewports[i]);
- g.Viewports.clear();
+ g.Viewports.clear_delete();
g.TabBars.Clear();
g.CurrentTabBarStack.clear();
g.ShrinkWidthBuffer.clear();
g.Tables.Clear();
- for (int i = 0; i < g.TablesTempDataStack.Size; i++)
- g.TablesTempDataStack[i].~ImGuiTableTempData();
- g.TablesTempDataStack.clear();
+ g.TablesTempDataStack.clear_destruct();
g.DrawChannelsTempMergeBuffer.clear();
g.ClipboardHandlerData.clear();
@@ -4691,11 +4745,15 @@ void ImGui::EndFrame()
// Clear Input data for next frame
g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
g.IO.InputQueueCharacters.resize(0);
+ g.IO.KeyModsPrev = g.IO.KeyMods; // doing it here is better than in NewFrame() as we'll tolerate backend writing to KeyMods. If we want to firmly disallow it we should detect it.
memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
CallContextHooks(&g, ImGuiContextHookType_EndFramePost);
}
+// Prepare the data for rendering so you can call GetDrawData()
+// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all:
+// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend)
void ImGui::Render()
{
ImGuiContext& g = *GImGui;
@@ -5091,10 +5149,7 @@ bool ImGui::IsItemActive()
{
ImGuiContext& g = *GImGui;
if (g.ActiveId)
- {
- ImGuiWindow* window = g.CurrentWindow;
- return g.ActiveId == window->DC.LastItemId;
- }
+ return g.ActiveId == g.LastItemData.ID;
return false;
}
@@ -5102,21 +5157,17 @@ bool ImGui::IsItemActivated()
{
ImGuiContext& g = *GImGui;
if (g.ActiveId)
- {
- ImGuiWindow* window = g.CurrentWindow;
- if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
+ if (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID)
return true;
- }
return false;
}
bool ImGui::IsItemDeactivated()
{
ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
- return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
- return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
+ if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated)
+ return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
+ return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID);
}
bool ImGui::IsItemDeactivatedAfterEdit()
@@ -5129,14 +5180,13 @@ bool ImGui::IsItemDeactivatedAfterEdit()
bool ImGui::IsItemFocused()
{
ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
-
- if (g.NavId != window->DC.LastItemId || g.NavId == 0)
+ if (g.NavId != g.LastItemData.ID || g.NavId == 0)
return false;
// Special handling for the dummy item 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 (window->DC.LastItemId == window->ID && window->WriteAccessed)
+ ImGuiWindow* window = g.CurrentWindow;
+ if (g.LastItemData.ID == window->ID && window->WriteAccessed)
return false;
return true;
@@ -5152,13 +5202,13 @@ bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
bool ImGui::IsItemToggledOpen()
{
ImGuiContext& g = *GImGui;
- return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
+ return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
}
bool ImGui::IsItemToggledSelection()
{
ImGuiContext& g = *GImGui;
- return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
+ return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
}
bool ImGui::IsAnyItemHovered()
@@ -5181,14 +5231,14 @@ bool ImGui::IsAnyItemFocused()
bool ImGui::IsItemVisible()
{
- ImGuiWindow* window = GetCurrentWindowRead();
- return window->ClipRect.Overlaps(window->DC.LastItemRect);
+ ImGuiContext& g = *GImGui;
+ return g.CurrentWindow->ClipRect.Overlaps(g.LastItemData.Rect);
}
bool ImGui::IsItemEdited()
{
- ImGuiWindow* window = GetCurrentWindowRead();
- return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
+ ImGuiContext& g = *GImGui;
+ return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0;
}
// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
@@ -5196,7 +5246,7 @@ bool ImGui::IsItemEdited()
void ImGui::SetItemAllowOverlap()
{
ImGuiContext& g = *GImGui;
- ImGuiID id = g.CurrentWindow->DC.LastItemId;
+ ImGuiID id = g.LastItemData.ID;
if (g.HoveredId == id)
g.HoveredIdAllowOverlap = true;
if (g.ActiveId == id)
@@ -5206,29 +5256,39 @@ void ImGui::SetItemAllowOverlap()
void ImGui::SetItemUsingMouseWheel()
{
ImGuiContext& g = *GImGui;
- ImGuiID id = g.CurrentWindow->DC.LastItemId;
+ ImGuiID id = g.LastItemData.ID;
if (g.HoveredId == id)
g.HoveredIdUsingMouseWheel = true;
if (g.ActiveId == id)
g.ActiveIdUsingMouseWheel = true;
}
+void ImGui::SetActiveIdUsingNavAndKeys()
+{
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(g.ActiveId != 0);
+ g.ActiveIdUsingNavDirMask = ~(ImU32)0;
+ g.ActiveIdUsingNavInputMask = ~(ImU32)0;
+ g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
+ NavMoveRequestCancel();
+}
+
ImVec2 ImGui::GetItemRectMin()
{
- ImGuiWindow* window = GetCurrentWindowRead();
- return window->DC.LastItemRect.Min;
+ ImGuiContext& g = *GImGui;
+ return g.LastItemData.Rect.Min;
}
ImVec2 ImGui::GetItemRectMax()
{
- ImGuiWindow* window = GetCurrentWindowRead();
- return window->DC.LastItemRect.Max;
+ ImGuiContext& g = *GImGui;
+ return g.LastItemData.Rect.Max;
}
ImVec2 ImGui::GetItemRectSize()
{
- ImGuiWindow* window = GetCurrentWindowRead();
- return window->DC.LastItemRect.GetSize();
+ ImGuiContext& g = *GImGui;
+ return g.LastItemData.Rect.GetSize();
}
bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
@@ -5333,7 +5393,7 @@ void ImGui::EndChild()
ItemAdd(bb, 0);
}
if (g.HoveredWindow == window)
- parent_window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
}
g.WithinEndChild = false;
g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
@@ -6011,8 +6071,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
// Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
// FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
- const char* UNSAVED_DOCUMENT_MARKER = "*";
- const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
+ const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f;
const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
// As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
@@ -6031,15 +6090,20 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y);
- //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
- //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
- RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
if (flags & ImGuiWindowFlags_UnsavedDocument)
{
- ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
- ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
- RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
+ ImVec2 marker_pos;
+ marker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x);
+ marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f;
+ if (marker_pos.x > layout_r.Min.x)
+ {
+ RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text));
+ clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f));
+ }
}
+ //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
+ //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
+ RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
}
void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
@@ -6093,21 +6157,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
- // Update the Appearing flag
- bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
+ // Update the Appearing flag (note: the BeginDocked() path may also set this to true later)
+ bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
if (flags & ImGuiWindowFlags_Popup)
{
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
window_just_activated_by_user |= (window != popup_ref.Window);
}
- window->Appearing = window_just_activated_by_user;
- if (window->Appearing)
- SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
// Update Flags, LastFrameActive, BeginOrderXXX fields
+ const bool window_was_appearing = window->Appearing;
if (first_begin_of_the_frame)
{
+ window->Appearing = window_just_activated_by_user;
+ if (window->Appearing)
+ SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
+
window->FlagsPreviousFrame = window->Flags;
window->Flags = (ImGuiWindowFlags)flags;
window->LastFrameActive = current_frame;
@@ -6129,6 +6195,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
bool has_dock_node = (window->DockId != 0 || window->DockNode != NULL);
bool new_auto_dock_node = !has_dock_node && GetWindowAlwaysWantOwnTabBar(window);
+ bool dock_node_was_visible = window->DockNodeIsVisible;
+ bool dock_tab_was_visible = window->DockTabIsVisible;
if (has_dock_node || new_auto_dock_node)
{
BeginDocked(window, p_open);
@@ -6138,11 +6206,22 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Docking currently override constraints
g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint;
+
+ // Amend the Appearing flag
+ if (window->DockTabIsVisible && !dock_tab_was_visible && dock_node_was_visible && !window->Appearing && !window_was_appearing)
+ {
+ window->Appearing = true;
+ SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
+ }
+ }
+ else
+ {
+ window->DockIsActive = window->DockNodeIsVisible = window->DockTabIsVisible = false;
}
}
// 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_in_stack = window->DockIsActive ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
+ ImGuiWindow* parent_window_in_stack = window->DockIsActive ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
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));
@@ -6152,7 +6231,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Add to stack
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
- g.CurrentWindowStack.push_back(window);
+ ImGuiWindowStackData window_stack_data;
+ window_stack_data.Window = window;
+ window_stack_data.ParentLastItemDataBackup = g.LastItemData;
+ g.CurrentWindowStack.push_back(window_stack_data);
g.CurrentWindow = window;
window->DC.StackSizesOnBegin.SetToCurrentState();
g.CurrentWindow = NULL;
@@ -6289,7 +6371,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// SELECT VIEWPORT
// We need to do this before using any style/font sizes, as viewport with a different DPI may affect font sizes.
- UpdateSelectWindowViewport(window);
+ WindowSelectViewport(window);
SetCurrentViewport(window, window->Viewport);
window->FontDpiScale = (g.IO.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ? window->Viewport->DpiScale : 1.0f;
SetCurrentWindow(window);
@@ -6421,85 +6503,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetCurrentWindow(window);
}
- bool viewport_rect_changed = false;
if (window->ViewportOwned)
- {
- // Synchronize window --> viewport in most situations
- // Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM
- if (window->Viewport->PlatformRequestMove)
- {
- window->Pos = window->Viewport->Pos;
- MarkIniSettingsDirty(window);
- }
- else if (memcmp(&window->Viewport->Pos, &window->Pos, sizeof(window->Pos)) != 0)
- {
- viewport_rect_changed = true;
- window->Viewport->Pos = window->Pos;
- }
-
- if (window->Viewport->PlatformRequestResize)
- {
- window->Size = window->SizeFull = window->Viewport->Size;
- MarkIniSettingsDirty(window);
- }
- else if (memcmp(&window->Viewport->Size, &window->Size, sizeof(window->Size)) != 0)
- {
- viewport_rect_changed = true;
- window->Viewport->Size = window->Size;
- }
- window->Viewport->UpdateWorkRect();
-
- // The viewport may have changed monitor since the global update in UpdateViewportsNewFrame()
- // Either a SetNextWindowPos() call in the current frame or a SetWindowPos() call in the previous frame may have this effect.
- if (viewport_rect_changed)
- UpdateViewportPlatformMonitor(window->Viewport);
-
- // Update common viewport flags
- const ImGuiViewportFlags viewport_flags_to_clear = ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoRendererClear;
- ImGuiViewportFlags viewport_flags = window->Viewport->Flags & ~viewport_flags_to_clear;
- const bool is_modal = (flags & ImGuiWindowFlags_Modal) != 0;
- const bool is_short_lived_floating_window = (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0;
- if (flags & ImGuiWindowFlags_Tooltip)
- viewport_flags |= ImGuiViewportFlags_TopMost;
- if ((g.IO.ConfigViewportsNoTaskBarIcon || is_short_lived_floating_window) && !is_modal)
- viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon;
- if (g.IO.ConfigViewportsNoDecoration || is_short_lived_floating_window)
- viewport_flags |= ImGuiViewportFlags_NoDecoration;
-
- // Not correct to set modal as topmost because:
- // - Because other popups can be stacked above a modal (e.g. combo box in a modal)
- // - ImGuiViewportFlags_TopMost is currently handled different in backends: in Win32 it is "appear top most" whereas in GLFW and SDL it is "stay topmost"
- //if (flags & ImGuiWindowFlags_Modal)
- // viewport_flags |= ImGuiViewportFlags_TopMost;
-
- // For popups and menus that may be protruding out of their parent viewport, we enable _NoFocusOnClick so that clicking on them
- // won't steal the OS focus away from their parent window (which may be reflected in OS the title bar decoration).
- // Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app,
- // but it shouldn't be much of a problem considering those are already popups that are closed when clicking elsewhere.
- if (is_short_lived_floating_window && !is_modal)
- viewport_flags |= ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoFocusOnClick;
-
- // We can overwrite viewport flags using ImGuiWindowClass (advanced users)
- // We don't default to the main viewport because.
- if (window->WindowClass.ParentViewportId)
- window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId;
- else if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && parent_window_in_stack)
- window->Viewport->ParentViewportId = parent_window_in_stack->Viewport->ID;
- else
- window->Viewport->ParentViewportId = g.IO.ConfigViewportsNoDefaultParent ? 0 : IMGUI_VIEWPORT_DEFAULT_ID;
- if (window->WindowClass.ViewportFlagsOverrideSet)
- viewport_flags |= window->WindowClass.ViewportFlagsOverrideSet;
- if (window->WindowClass.ViewportFlagsOverrideClear)
- viewport_flags &= ~window->WindowClass.ViewportFlagsOverrideClear;
-
- // We can also tell the backend that clearing the platform window won't be necessary,
- // as our window background is filling the viewport and we have disabled BgAlpha.
- // FIXME: Work on support for per-viewport transparency (#2766)
- if (!(flags & ImGuiWindowFlags_NoBackground))
- viewport_flags |= ImGuiViewportFlags_NoRendererClear;
-
- window->Viewport->Flags = viewport_flags;
- }
+ WindowSyncOwnedViewport(window, parent_window_in_stack);
// Calculate the range of allowed position for that window (to be movable and visible past safe area padding)
// When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.
@@ -6766,7 +6771,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
window->DC.MenuBarAppending = false;
- window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
+ window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user);
window->DC.TreeDepth = 0;
window->DC.TreeJumpToParentOnPopMask = 0x00;
window->DC.ChildWindows.resize(0);
@@ -6840,13 +6845,13 @@ 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.
if (window->DockIsActive)
- SetLastItemData(window, window->ID, window->DockTabItemStatusFlags, window->DockTabItemRect);
+ SetLastItemData(window->ID, g.CurrentItemFlags, window->DockTabItemStatusFlags, window->DockTabItemRect);
else
- SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, 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))
- IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId);
+ IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID);
#endif
}
else
@@ -6857,8 +6862,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Pull/inherit current state
- g.CurrentItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
- window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // Inherit from parent only // -V595
+ window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : window->GetID("#FOCUSSCOPE"); // Inherit from parent only // -V595
if (!(flags & ImGuiWindowFlags_DockNodeHost))
PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
@@ -6920,6 +6924,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
skip_items = true;
window->SkipItems = skip_items;
+
+ // Sanity check: there are two spots which can set Appearing = true
+ // - when 'window_just_activated_by_user' is set -> HiddenFramesCannotSkipItems is set -> SkipItems always false
+ // - in BeginDocked() path when DockNodeIsVisible == DockTabIsVisible == true -> hidden _should_ be all zero // FIXME: Not formally proven, hence the assert.
+ if (window->SkipItems && !window->Appearing)
+ IM_ASSERT(window->Appearing == false); // Please report on GitHub if this triggers: https://github.com/ocornut/imgui/issues/4177
}
return !window->SkipItems;
@@ -6958,11 +6968,12 @@ void ImGui::End()
host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding;
// Pop from window stack
+ g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;
g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back();
window->DC.StackSizesOnBegin.CompareWithCurrentState();
- SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
+ SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
if (g.CurrentWindow)
SetCurrentViewport(g.CurrentWindow, g.CurrentWindow->Viewport);
}
@@ -7150,6 +7161,35 @@ void ImGui::PopItemFlag()
g.CurrentItemFlags = g.ItemFlagsStack.back();
}
+// BeginDisabled()/EndDisabled()
+// - Those can be nested but this cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep things disabled)
+// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.
+// - Feedback welcome at https://github.com/ocornut/imgui/issues/211
+// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
+// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag()
+void ImGui::BeginDisabled(bool disabled)
+{
+ ImGuiContext& g = *GImGui;
+ bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
+ g.DisabledAlphaBackup = g.Style.Alpha;
+ if (!was_disabled && disabled)
+ g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha);
+ if (was_disabled || disabled)
+ g.CurrentItemFlags |= ImGuiItemFlags_Disabled;
+ g.ItemFlagsStack.push_back(g.CurrentItemFlags);
+}
+
+void ImGui::EndDisabled()
+{
+ ImGuiContext& g = *GImGui;
+ bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
+ //PopItemFlag();
+ g.ItemFlagsStack.pop_back();
+ g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled;
+ if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0)
+ g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
+}
+
// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
{
@@ -7185,6 +7225,7 @@ void ImGui::PopTextWrapPos()
window->DC.TextWrapPosStack.pop_back();
}
+// FIXME: We are exposing the docking hierarchy to end-user here (via IsWindowHovered, IsWindowFocused) which is unusual.
bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
{
if (window->RootWindowDockTree == potential_parent)
@@ -7626,8 +7667,8 @@ void ImGui::SetItemDefaultFocus()
if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
{
g.NavInitRequest = false;
- g.NavInitResultId = window->DC.LastItemId;
- g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
+ g.NavInitResultId = g.LastItemData.ID;
+ g.NavInitResultRectRel = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
NavUpdateAnyRequestFlag();
if (!IsItemVisible())
SetScrollHereY();
@@ -7778,8 +7819,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!");
IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!");
- IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?");
- IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?");
+ IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()");
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations
@@ -8063,9 +8103,16 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+ // Set item data
+ g.LastItemData.ID = id;
+ g.LastItemData.Rect = bb;
+ g.LastItemData.InFlags = g.CurrentItemFlags;
+ g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None;
+
+ // Directional navigation processing
if (id != 0)
{
- // Navigation processing runs prior to clipping early-out
+ // Runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
@@ -8089,11 +8136,6 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
}
#endif
}
-
- // Equivalent to calling SetLastItemData()
- window->DC.LastItemId = id;
- window->DC.LastItemRect = bb;
- window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
#ifdef IMGUI_ENABLE_TEST_ENGINE
@@ -8114,7 +8156,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
if (IsMouseHoveringRect(bb.Min, bb.Max))
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
return true;
}
@@ -8446,24 +8488,24 @@ void ImGui::EndGroup()
const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
if (group_contains_curr_active_id)
- window->DC.LastItemId = g.ActiveId;
+ g.LastItemData.ID = g.ActiveId;
else if (group_contains_prev_active_id)
- window->DC.LastItemId = g.ActiveIdPreviousFrame;
- window->DC.LastItemRect = group_bb;
+ g.LastItemData.ID = g.ActiveIdPreviousFrame;
+ g.LastItemData.Rect = group_bb;
// Forward Hovered flag
const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
if (group_contains_curr_hovered_id)
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
// Forward Edited flag
if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
// Forward Deactivated flag
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated;
g.GroupStack.pop_back();
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
@@ -8652,7 +8694,7 @@ void ImGui::SetScrollHereX(float center_x_ratio)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);
- float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
+ float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio);
SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
// Tweak: snap on edges when aiming at an item very close to the edge
@@ -9048,12 +9090,13 @@ void ImGui::EndPopup()
// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
{
- 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); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
+ ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // 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); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
OpenPopupEx(id, popup_flags);
}
}
@@ -9076,11 +9119,12 @@ void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags
// The main difference being that this is tweaked to avoid computing the ID twice.
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
return false;
- 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); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
+ ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // 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); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
OpenPopupEx(id, popup_flags);
@@ -9089,7 +9133,8 @@ bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag
bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
if (!str_id)
str_id = "window_context";
ImGuiID id = window->GetID(str_id);
@@ -9102,7 +9147,8 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_fl
bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
if (!str_id)
str_id = "void_context";
ImGuiID id = window->GetID(str_id);
@@ -9193,7 +9239,7 @@ ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& s
}
// Note that this is used for popups, which can overlap the non work-area of individual viewports.
-ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
+ImRect ImGui::GetPopupAllowedExtentRect(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
ImRect r_screen;
@@ -9218,7 +9264,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
- ImRect r_outer = GetWindowAllowedExtentRect(window);
+ ImRect r_outer = GetPopupAllowedExtentRect(window);
if (window->Flags & ImGuiWindowFlags_ChildMenu)
{
// Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
@@ -9287,8 +9333,8 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
g.NavLayer = nav_layer;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
window->NavLastIds[nav_layer] = id;
- if (window->DC.LastItemId == id)
- window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
+ if (g.LastItemData.ID == id)
+ window->NavRectRel[nav_layer] = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
if (g.ActiveIdSource == ImGuiInputSource_Nav)
g.NavDisableMouseHover = true;
@@ -9385,7 +9431,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
else
{
// Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
- quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
+ quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
}
#if IMGUI_DEBUG_NAV_SCORING
@@ -9473,19 +9519,20 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
//if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
// return;
- const ImGuiItemFlags item_flags = g.CurrentItemFlags;
+ const ImGuiItemFlags item_flags = g.LastItemData.InFlags;
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
// Process Init Request
if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
{
// Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
- if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
+ const bool candidate_for_nav_default_focus = (item_flags & (ImGuiItemFlags_NoNavDefaultFocus | ImGuiItemFlags_Disabled)) == 0;
+ if (candidate_for_nav_default_focus || g.NavInitResultId == 0)
{
g.NavInitResultId = id;
g.NavInitResultRectRel = nav_bb_rel;
}
- if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
+ if (candidate_for_nav_default_focus)
{
g.NavInitRequest = false; // Found a match, clear request
NavUpdateAnyRequestFlag();
@@ -9741,16 +9788,6 @@ static void ImGui::NavUpdate()
io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (io.KeyShift)
io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
-
- // AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl)
- // But also even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
- if (io.KeyAlt && !io.KeyCtrl)
- io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
-
- // We automatically cancel toggling nav layer when any text has been typed while holding Alt. (See #370)
- if (io.KeyAlt && !io.KeyCtrl && g.NavWindowingToggleLayer && io.InputQueueCharacters.Size > 0)
- g.NavWindowingToggleLayer = false;
-
#undef NAV_MAP_KEY
}
memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
@@ -10243,6 +10280,8 @@ static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
static void ImGui::NavUpdateWindowing()
{
ImGuiContext& g = *GImGui;
+ ImGuiIO& io = g.IO;
+
ImGuiWindow* apply_focus_window = NULL;
bool apply_toggle_layer = false;
@@ -10254,25 +10293,25 @@ static void ImGui::NavUpdateWindowing()
// Fade out
if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
{
- g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
+ g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0f, 0.0f);
if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
g.NavWindowingTargetAnim = NULL;
}
// Start CTRL-TAB or Square+L/R window selection
bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
- bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
+ bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && io.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
{
g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow;
g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
- g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
+ g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer
g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad;
}
// Gamepad update
- g.NavWindowingTimer += g.IO.DeltaTime;
+ g.NavWindowingTimer += io.DeltaTime;
if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad)
{
// Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise
@@ -10304,31 +10343,49 @@ static void ImGui::NavUpdateWindowing()
// Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
if (IsKeyPressedMap(ImGuiKey_Tab, true))
- NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
- if (!g.IO.KeyCtrl)
+ NavUpdateWindowingHighlightWindow(io.KeyShift ? +1 : -1);
+ if (!io.KeyCtrl)
apply_focus_window = g.NavWindowingTarget;
}
// Keyboard: Press and Release ALT to toggle menu layer
- // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of backend clearing releases all keys on ALT-TAB
- if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
+ // - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer.
+ // - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
+ if (io.KeyMods == ImGuiKeyModFlags_Alt && (io.KeyModsPrev & ImGuiKeyModFlags_Alt) == 0)
+ {
g.NavWindowingToggleLayer = true;
- if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
- if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
- apply_toggle_layer = true;
+ g.NavInputSource = ImGuiInputSource_Keyboard;
+ }
+ if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard)
+ {
+ // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370)
+ // We cancel toggling nav layer when other modifiers are pressed. (See #4439)
+ if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper)
+ g.NavWindowingToggleLayer = false;
+
+ // Apply layer toggle on release
+ // Important: we don't assume that Alt was previously held in order to handle loss of focus when backend calls io.AddFocusEvent(false)
+ // Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss.
+ if (!(io.KeyMods & ImGuiKeyModFlags_Alt) && (io.KeyModsPrev & ImGuiKeyModFlags_Alt) && g.NavWindowingToggleLayer)
+ if (g.ActiveId == 0 || g.ActiveIdAllowOverlap)
+ if (IsMousePosValid(&io.MousePos) == IsMousePosValid(&io.MousePosPrev))
+ apply_toggle_layer = true;
+ if (!io.KeyAlt)
+ g.NavWindowingToggleLayer = false;
+ }
// Move window
if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
{
ImVec2 move_delta;
- if (g.NavInputSource == ImGuiInputSource_Keyboard && !g.IO.KeyShift)
+ if (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift)
move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
if (g.NavInputSource == ImGuiInputSource_Gamepad)
move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
if (move_delta.x != 0.0f || move_delta.y != 0.0f)
{
const float NAV_MOVE_SPEED = 800.0f;
- const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well
+ const float move_speed = ImFloor(NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well
ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindowDockTree;
SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always);
MarkIniSettingsDirty(moving_window);
@@ -10479,7 +10536,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
ImGuiID source_parent_id = 0;
if (!(flags & ImGuiDragDropFlags_SourceExtern))
{
- source_id = window->DC.LastItemId;
+ source_id = g.LastItemData.ID;
if (source_id != 0)
{
// Common path: items with ID
@@ -10506,15 +10563,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
}
// Early out
- if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
+ if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
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.
- source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
- bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
+ // Rely on keeping other window->LastItemXXX fields intact.
+ source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
+ bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id);
if (is_hovered && g.IO.MouseClicked[mouse_button])
{
SetActiveID(source_id, window);
@@ -10528,10 +10586,8 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
source_parent_id = window->IDStack.back();
source_drag_active = IsMouseDragging(mouse_button);
- // Disable navigation and key inputs while dragging
- g.ActiveIdUsingNavDirMask = ~(ImU32)0;
- g.ActiveIdUsingNavInputMask = ~(ImU32)0;
- g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
+ // Disable navigation and key inputs while dragging + cancel existing request if any
+ SetActiveIdUsingNavAndKeys();
}
else
{
@@ -10566,13 +10622,13 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
{
ImGuiWindow* tooltip_window = g.CurrentWindow;
- tooltip_window->SkipItems = true;
+ tooltip_window->Hidden = tooltip_window->SkipItems = true;
tooltip_window->HiddenFramesCanSkipItems = 1;
}
}
if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
- window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
+ g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
return true;
}
@@ -10672,14 +10728,14 @@ bool ImGui::BeginDragDropTarget()
return false;
ImGuiWindow* window = g.CurrentWindow;
- if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
+ if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect))
return false;
ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree)
return false;
- const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
- ImGuiID id = window->DC.LastItemId;
+ const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect;
+ ImGuiID id = g.LastItemData.ID;
if (id == 0)
id = window->GetIDFromRectangle(display_rect);
if (g.DragDropPayload.SourceId == id)
@@ -10721,17 +10777,11 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
}
// Render default drop visuals
+ // FIXME-DRAGDROP: Settle on a proper default visuals for drop target.
payload.Preview = was_accepted_previously;
flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
- {
- // FIXME-DRAGDROP: 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->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1));
- window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);
- if (push_clip_rect) window->DrawList->PopClipRect();
- }
+ window->DrawList->AddRect(r.Min - ImVec2(3.5f,3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);
g.DragDropAcceptFrameCount = g.FrameCount;
payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
@@ -11357,7 +11407,8 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
// - UpdateViewportsNewFrame() [Internal]
// - UpdateViewportsEndFrame() [Internal]
// - AddUpdateViewport() [Internal]
-// - UpdateSelectWindowViewport() [Internal]
+// - WindowSelectViewport() [Internal]
+// - WindowSyncOwnedViewport() [Internal]
// - UpdatePlatformWindows()
// - RenderPlatformWindowsDefault()
// - FindPlatformMonitorForPos() [Internal]
@@ -11373,6 +11424,7 @@ ImGuiViewport* ImGui::GetMainViewport()
return g.Viewports[0];
}
+// FIXME: This leaks access to viewports not listed in PlatformIO.Viewports[]. Problematic? (#4236)
ImGuiViewport* ImGui::FindViewportByID(ImGuiID id)
{
ImGuiContext& g = *GImGui;
@@ -11804,7 +11856,7 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
}
// FIXME-VIEWPORT: This is all super messy and ought to be clarified or rewritten.
-static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
+static void ImGui::WindowSelectViewport(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
ImGuiWindowFlags flags = window->Flags;
@@ -11829,7 +11881,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasViewport) == 0)
{
// By default inherit from parent window
- if (window->Viewport == NULL && window->ParentWindow && !window->ParentWindow->IsFallbackWindow)
+ if (window->Viewport == NULL && window->ParentWindow && (!window->ParentWindow->IsFallbackWindow || window->ParentWindow->WasActive))
window->Viewport = window->ParentWindow->Viewport;
// Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file
@@ -11931,6 +11983,92 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
// window->Flags |= ImGuiWindowFlags_NoTitleBar;
}
+void ImGui::WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack)
+{
+ ImGuiContext& g = *GImGui;
+
+ bool viewport_rect_changed = false;
+
+ // Synchronize window --> viewport in most situations
+ // Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM
+ if (window->Viewport->PlatformRequestMove)
+ {
+ window->Pos = window->Viewport->Pos;
+ MarkIniSettingsDirty(window);
+ }
+ else if (memcmp(&window->Viewport->Pos, &window->Pos, sizeof(window->Pos)) != 0)
+ {
+ viewport_rect_changed = true;
+ window->Viewport->Pos = window->Pos;
+ }
+
+ if (window->Viewport->PlatformRequestResize)
+ {
+ window->Size = window->SizeFull = window->Viewport->Size;
+ MarkIniSettingsDirty(window);
+ }
+ else if (memcmp(&window->Viewport->Size, &window->Size, sizeof(window->Size)) != 0)
+ {
+ viewport_rect_changed = true;
+ window->Viewport->Size = window->Size;
+ }
+ window->Viewport->UpdateWorkRect();
+
+ // The viewport may have changed monitor since the global update in UpdateViewportsNewFrame()
+ // Either a SetNextWindowPos() call in the current frame or a SetWindowPos() call in the previous frame may have this effect.
+ if (viewport_rect_changed)
+ UpdateViewportPlatformMonitor(window->Viewport);
+
+ // Update common viewport flags
+ const ImGuiViewportFlags viewport_flags_to_clear = ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoRendererClear;
+ ImGuiViewportFlags viewport_flags = window->Viewport->Flags & ~viewport_flags_to_clear;
+ ImGuiWindowFlags window_flags = window->Flags;
+ const bool is_modal = (window_flags & ImGuiWindowFlags_Modal) != 0;
+ const bool is_short_lived_floating_window = (window_flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0;
+ if (window_flags & ImGuiWindowFlags_Tooltip)
+ viewport_flags |= ImGuiViewportFlags_TopMost;
+ if ((g.IO.ConfigViewportsNoTaskBarIcon || is_short_lived_floating_window) && !is_modal)
+ viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon;
+ if (g.IO.ConfigViewportsNoDecoration || is_short_lived_floating_window)
+ viewport_flags |= ImGuiViewportFlags_NoDecoration;
+
+ // Not correct to set modal as topmost because:
+ // - Because other popups can be stacked above a modal (e.g. combo box in a modal)
+ // - ImGuiViewportFlags_TopMost is currently handled different in backends: in Win32 it is "appear top most" whereas in GLFW and SDL it is "stay topmost"
+ //if (flags & ImGuiWindowFlags_Modal)
+ // viewport_flags |= ImGuiViewportFlags_TopMost;
+
+ // For popups and menus that may be protruding out of their parent viewport, we enable _NoFocusOnClick so that clicking on them
+ // won't steal the OS focus away from their parent window (which may be reflected in OS the title bar decoration).
+ // Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app,
+ // but it shouldn't be much of a problem considering those are already popups that are closed when clicking elsewhere.
+ if (is_short_lived_floating_window && !is_modal)
+ viewport_flags |= ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoFocusOnClick;
+
+ // We can overwrite viewport flags using ImGuiWindowClass (advanced users)
+ if (window->WindowClass.ViewportFlagsOverrideSet)
+ viewport_flags |= window->WindowClass.ViewportFlagsOverrideSet;
+ if (window->WindowClass.ViewportFlagsOverrideClear)
+ viewport_flags &= ~window->WindowClass.ViewportFlagsOverrideClear;
+
+ // We can also tell the backend that clearing the platform window won't be necessary,
+ // as our window background is filling the viewport and we have disabled BgAlpha.
+ // FIXME: Work on support for per-viewport transparency (#2766)
+ if (!(window_flags & ImGuiWindowFlags_NoBackground))
+ viewport_flags |= ImGuiViewportFlags_NoRendererClear;
+
+ window->Viewport->Flags = viewport_flags;
+
+ // Update parent viewport ID
+ // (the !IsFallbackWindow test mimic the one done in WindowSelectViewport())
+ if (window->WindowClass.ParentViewportId)
+ window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId;
+ else if ((window_flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && parent_window_in_stack && (!parent_window_in_stack->IsFallbackWindow || parent_window_in_stack->WasActive))
+ window->Viewport->ParentViewportId = parent_window_in_stack->Viewport->ID;
+ else
+ window->Viewport->ParentViewportId = g.IO.ConfigViewportsNoDefaultParent ? 0 : IMGUI_VIEWPORT_DEFAULT_ID;
+}
+
// Called by user at the end of the main loop, after EndFrame()
// This will handle the creation/update of all OS windows via function defined in the ImGuiPlatformIO api.
void ImGui::UpdatePlatformWindows()
@@ -12546,7 +12684,8 @@ static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID
ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx)
{
// Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used)
- // FIXME-OPT FIXME-DOCK: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster.
+ // FIXME-OPT FIXME-DOCK: This is suboptimal, even if the node count is small enough not to be a worry.0
+ // We should poke in ctx->Nodes to find a suitable ID faster. Even more so trivial that ctx->Nodes lookup is already sorted.
ImGuiID id = 0x0001;
while (DockContextFindNodeByID(ctx, id) != NULL)
id++;
@@ -12699,7 +12838,7 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc
node->ParentNode->ChildNodes[1] = node;
node->SelectedTabId = settings->SelectedTabId;
node->SplitAxis = (ImGuiAxis)settings->SplitAxis;
- node->LocalFlags |= (settings->Flags & ImGuiDockNodeFlags_SavedFlagsMask_);
+ node->SetLocalFlags(settings->Flags & ImGuiDockNodeFlags_SavedFlagsMask_);
// Bind host window immediately if it already exist (in case of a rebuild)
// This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set.
@@ -12841,7 +12980,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
new_node->HostWindow = node->HostWindow;
node = new_node;
}
- node->LocalFlags &= ~ImGuiDockNodeFlags_HiddenTabBar;
+ node->SetLocalFlags(node->LocalFlags & ~ImGuiDockNodeFlags_HiddenTabBar);
if (node != payload_node)
{
@@ -12879,8 +13018,8 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
IM_ASSERT(last_focused_node != NULL);
ImGuiDockNode* last_focused_root_node = DockNodeGetRootNode(last_focused_node);
IM_ASSERT(last_focused_root_node == DockNodeGetRootNode(payload_node));
- last_focused_node->LocalFlags |= ImGuiDockNodeFlags_CentralNode;
- node->LocalFlags &= ~ImGuiDockNodeFlags_CentralNode;
+ last_focused_node->SetLocalFlags(last_focused_node->LocalFlags |= ImGuiDockNodeFlags_CentralNode);
+ node->SetLocalFlags(node->LocalFlags & ~ImGuiDockNodeFlags_CentralNode);
last_focused_root_node->CentralNode = last_focused_node;
}
@@ -12950,7 +13089,7 @@ void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* windo
window->DockId = 0;
window->Collapsed = false;
window->DockIsActive = false;
- window->DockTabIsVisible = false;
+ window->DockNodeIsVisible = window->DockTabIsVisible = false;
window->Size = window->SizeFull = FixLargeWindowsWhenUndocking(window->SizeFull, window->Viewport);
MarkIniSettingsDirty();
@@ -13041,7 +13180,7 @@ bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode*
ImGuiDockNode::ImGuiDockNode(ImGuiID id)
{
ID = id;
- SharedFlags = LocalFlags = ImGuiDockNodeFlags_None;
+ SharedFlags = LocalFlags = LocalFlagsInWindows = MergedFlags = ImGuiDockNodeFlags_None;
ParentNode = ChildNodes[0] = ChildNodes[1] = NULL;
TabBar = NULL;
SplitAxis = ImGuiAxis_None;
@@ -13345,6 +13484,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
// Remove inactive windows
// Merge node flags overrides stored in windows
+ node->LocalFlagsInWindows = ImGuiDockNodeFlags_None;
for (int window_n = 0; window_n < node->Windows.Size; window_n++)
{
ImGuiWindow* window = node->Windows[window_n];
@@ -13371,13 +13511,14 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
else
{
// FIXME-DOCKING: Missing policies for conflict resolution, hence the "Experimental" tag on this.
- node->LocalFlags &= ~window->WindowClass.DockNodeFlagsOverrideClear;
- node->LocalFlags |= window->WindowClass.DockNodeFlagsOverrideSet;
+ //node->LocalFlagsInWindow &= ~window->WindowClass.DockNodeFlagsOverrideClear;
+ node->LocalFlagsInWindows |= window->WindowClass.DockNodeFlagsOverrideSet;
}
}
+ node->UpdateMergedFlags();
// Auto-hide tab bar option
- ImGuiDockNodeFlags node_flags = node->GetMergedFlags();
+ ImGuiDockNodeFlags node_flags = node->MergedFlags;
if (node->WantHiddenTabBarUpdate && node->Windows.Size == 1 && (node_flags & ImGuiDockNodeFlags_AutoHideTabBar) && !node->IsHiddenTabBar())
node->WantHiddenTabBarToggle = true;
node->WantHiddenTabBarUpdate = false;
@@ -13388,9 +13529,9 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
// Apply toggles at a single point of the frame (here!)
if (node->Windows.Size > 1)
- node->LocalFlags &= ~ImGuiDockNodeFlags_HiddenTabBar;
+ node->SetLocalFlags(node->LocalFlags & ~ImGuiDockNodeFlags_HiddenTabBar);
else if (node->WantHiddenTabBarToggle)
- node->LocalFlags ^= ImGuiDockNodeFlags_HiddenTabBar;
+ node->SetLocalFlags(node->LocalFlags ^ ImGuiDockNodeFlags_HiddenTabBar);
node->WantHiddenTabBarToggle = false;
DockNodeUpdateVisibleFlag(node);
@@ -13446,6 +13587,20 @@ static void ImGui::DockNodeUpdateForRootNode(ImGuiDockNode* node)
}
}
+static void DockNodeSetupHostWindow(ImGuiDockNode* node, ImGuiWindow* host_window)
+{
+ // Remove ourselves from any previous different host window
+ // This can happen if a user mistakenly does (see #4295 for details):
+ // - N+0: DockBuilderAddNode(id, 0) // missing ImGuiDockNodeFlags_DockSpace
+ // - N+1: NewFrame() // will create floating host window for that node
+ // - N+1: DockSpace(id) // requalify node as dockspace, moving host window
+ if (node->HostWindow && node->HostWindow != host_window && node->HostWindow->DockNodeAsHost == node)
+ node->HostWindow->DockNodeAsHost = NULL;
+
+ host_window->DockNodeAsHost = node;
+ node->HostWindow = host_window;
+}
+
static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
{
ImGuiContext& g = *GImGui;
@@ -13528,7 +13683,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
}
}
- const ImGuiDockNodeFlags node_flags = node->GetMergedFlags();
+ const ImGuiDockNodeFlags node_flags = node->MergedFlags;
// Decide if the node will have a close button and a window menu button
node->HasWindowMenuButton = (node->Windows.Size > 0) && (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0;
@@ -13594,8 +13749,8 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
PopStyleVar();
beginned_into_host_window = true;
- node->HostWindow = host_window = g.CurrentWindow;
- host_window->DockNodeAsHost = node;
+ host_window = g.CurrentWindow;
+ DockNodeSetupHostWindow(node, host_window);
host_window->DC.CursorPos = host_window->Pos;
node->Pos = host_window->Pos;
node->Size = host_window->Size;
@@ -13780,7 +13935,7 @@ bool ImGui::DockNodeBeginAmendTabBar(ImGuiDockNode* node)
{
if (node->TabBar == NULL || node->HostWindow == NULL)
return false;
- if (node->SharedFlags & ImGuiDockNodeFlags_KeepAliveOnly)
+ if (node->MergedFlags & ImGuiDockNodeFlags_KeepAliveOnly)
return false;
Begin(node->HostWindow->Name);
PushOverrideID(node->ID);
@@ -13858,7 +14013,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
ImGuiID focus_tab_id = 0;
node->IsFocused = is_focused;
- const ImGuiDockNodeFlags node_flags = node->GetMergedFlags();
+ const ImGuiDockNodeFlags node_flags = node->MergedFlags;
const bool has_window_menu_button = (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0 && (style.WindowMenuButtonPosition != ImGuiDir_None);
// In a dock node, the Collapse Button turns into the Window Menu button.
@@ -13968,8 +14123,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
node->VisibleWindow = window;
// Store last item data so it can be queried with IsItemXXX functions after the user Begin() call
- window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags;
- window->DockTabItemRect = host_window->DC.LastItemRect;
+ window->DockTabItemStatusFlags = g.LastItemData.StatusFlags;
+ window->DockTabItemRect = g.LastItemData.Rect;
// Update navigation ID on menu layer
if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
@@ -13999,11 +14154,11 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] * ImVec4(1.0f,1.0f,1.0f,0.4f));
}
if (CloseButton(host_window->GetID("#CLOSE"), close_button_pos))
- if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->VisibleTabId))
- {
- node->WantCloseTabId = tab->ID;
- TabBarCloseTab(tab_bar, tab);
- }
+ {
+ node->WantCloseAll = true;
+ for (int n = 0; n < tab_bar->Tabs.Size; n++)
+ TabBarCloseTab(tab_bar, &tab_bar->Tabs[n]);
+ }
//if (IsItemActive())
// focus_tab_id = tab_bar->SelectedTabId;
if (!close_button_is_enabled)
@@ -14024,7 +14179,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
{
// ImGuiButtonFlags_AllowItemOverlap + SetItemAllowOverlap() required for appending into dock node tab bar,
// otherwise dragging window will steal HoveredId and amended tabs cannot get them.
- host_window->DC.LastItemId = title_bar_id;
+ g.LastItemData.ID = title_bar_id;
SetItemAllowOverlap();
}
if (held)
@@ -14252,8 +14407,8 @@ static void ImGui::DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockN
IM_ASSERT(ref_node_for_rect->IsVisible);
// Filter, figure out where we are allowed to dock
- ImGuiDockNodeFlags src_node_flags = root_payload_as_host ? root_payload_as_host->GetMergedFlags() : root_payload->WindowClass.DockNodeFlagsOverrideSet;
- ImGuiDockNodeFlags dst_node_flags = host_node ? host_node->GetMergedFlags() : host_window->WindowClass.DockNodeFlagsOverrideSet;
+ ImGuiDockNodeFlags src_node_flags = root_payload_as_host ? root_payload_as_host->MergedFlags : root_payload->WindowClass.DockNodeFlagsOverrideSet;
+ ImGuiDockNodeFlags dst_node_flags = host_node ? host_node->MergedFlags : host_window->WindowClass.DockNodeFlagsOverrideSet;
data->IsCenterAvailable = true;
if (is_outer_docking)
data->IsCenterAvailable = false;
@@ -14263,7 +14418,11 @@ static void ImGui::DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockN
data->IsCenterAvailable = false;
else if ((!host_node || !host_node->IsEmpty()) && root_payload_as_host && root_payload_as_host->IsSplitNode() && (root_payload_as_host->OnlyNodeWithWindows == NULL)) // Is _visibly_ split?
data->IsCenterAvailable = false;
- else if ((dst_node_flags & ImGuiDockNodeFlags_NoDockingOverMe) || (src_node_flags & ImGuiDockNodeFlags_NoDockingOverOther))
+ else if (dst_node_flags & ImGuiDockNodeFlags_NoDockingOverMe)
+ data->IsCenterAvailable = false;
+ else if ((src_node_flags & ImGuiDockNodeFlags_NoDockingOverOther) && (!host_node || !host_node->IsEmpty()))
+ data->IsCenterAvailable = false;
+ else if ((src_node_flags & ImGuiDockNodeFlags_NoDockingOverEmpty) && host_node && host_node->IsEmpty())
data->IsCenterAvailable = false;
data->IsSidesAvailable = true;
@@ -14433,7 +14592,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
}
// Stop after ImGuiDir_None
- if ((host_node && (host_node->GetMergedFlags() & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit)
+ if ((host_node && (host_node->MergedFlags & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit)
return;
}
}
@@ -14486,6 +14645,9 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
child_1->SharedFlags = parent_node->SharedFlags & ImGuiDockNodeFlags_SharedFlagsInheritMask_;
child_inheritor->LocalFlags = parent_node->LocalFlags & ImGuiDockNodeFlags_LocalFlagsTransferMask_;
parent_node->LocalFlags &= ~ImGuiDockNodeFlags_LocalFlagsTransferMask_;
+ child_0->UpdateMergedFlags();
+ child_1->UpdateMergedFlags();
+ parent_node->UpdateMergedFlags();
if (child_inheritor->IsCentralNode())
DockNodeGetRootNode(parent_node)->CentralNode = child_inheritor;
}
@@ -14525,6 +14687,8 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
parent_node->LocalFlags &= ~ImGuiDockNodeFlags_LocalFlagsTransferMask_; // Preserve Dockspace flag
parent_node->LocalFlags |= (child_0 ? child_0->LocalFlags : 0) & ImGuiDockNodeFlags_LocalFlagsTransferMask_;
parent_node->LocalFlags |= (child_1 ? child_1->LocalFlags : 0) & ImGuiDockNodeFlags_LocalFlagsTransferMask_;
+ parent_node->LocalFlagsInWindows = (child_0 ? child_0->LocalFlagsInWindows : 0) | (child_1 ? child_1->LocalFlagsInWindows : 0); // FIXME: Would be more consistent to update from actual windows
+ parent_node->UpdateMergedFlags();
if (child_0)
{
@@ -14656,7 +14820,7 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node)
bb.Max[axis ^ 1] += child_1->Size[axis ^ 1];
//if (g.IO.KeyCtrl) GetForegroundDrawList(g.CurrentWindow->Viewport)->AddRect(bb.Min, bb.Max, IM_COL32(255,0,255,255));
- const ImGuiDockNodeFlags merged_flags = child_0->GetMergedFlags() | child_1->GetMergedFlags();
+ const ImGuiDockNodeFlags merged_flags = child_0->MergedFlags | child_1->MergedFlags; // Merged flags for BOTH childs
const ImGuiDockNodeFlags no_resize_axis_flag = (axis == ImGuiAxis_X) ? ImGuiDockNodeFlags_NoResizeX : ImGuiDockNodeFlags_NoResizeY;
if ((merged_flags & ImGuiDockNodeFlags_NoResize) || (merged_flags & no_resize_axis_flag))
{
@@ -14850,7 +15014,7 @@ ImGuiID ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags
{
IMGUI_DEBUG_LOG_DOCKING("DockSpace: dockspace node 0x%08X created\n", id);
node = DockContextAddNode(ctx, id);
- node->LocalFlags |= ImGuiDockNodeFlags_CentralNode;
+ node->SetLocalFlags(ImGuiDockNodeFlags_CentralNode);
}
if (window_class && window_class->ClassId != node->WindowClass.ClassId)
IMGUI_DEBUG_LOG_DOCKING("DockSpace: dockspace node 0x%08X: setup WindowClass 0x%08X -> 0x%08X\n", id, node->WindowClass.ClassId, window_class->ClassId);
@@ -14862,10 +15026,10 @@ ImGuiID ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags
if (node->LastFrameActive == g.FrameCount && !(flags & ImGuiDockNodeFlags_KeepAliveOnly))
{
IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID");
- node->LocalFlags |= ImGuiDockNodeFlags_DockSpace;
+ node->SetLocalFlags(node->LocalFlags | ImGuiDockNodeFlags_DockSpace);
return id;
}
- node->LocalFlags |= ImGuiDockNodeFlags_DockSpace;
+ node->SetLocalFlags(node->LocalFlags | ImGuiDockNodeFlags_DockSpace);
// Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible
if (flags & ImGuiDockNodeFlags_KeepAliveOnly)
@@ -14903,9 +15067,8 @@ ImGuiID ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags
PopStyleVar();
ImGuiWindow* host_window = g.CurrentWindow;
- host_window->DockNodeAsHost = node;
+ DockNodeSetupHostWindow(node, host_window);
host_window->ChildId = window->GetID(title);
- node->HostWindow = host_window;
node->OnlyNodeWithWindows = NULL;
IM_ASSERT(node->IsRootNode());
@@ -14917,7 +15080,7 @@ ImGuiID ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags
// The specific sub-property of _CentralNode we are interested in recovering here is the "Don't delete when empty" property,
// as it doesn't make sense for an empty dockspace to not have this property.
if (node->IsLeafNode() && !node->IsCentralNode())
- node->LocalFlags |= ImGuiDockNodeFlags_CentralNode;
+ node->SetLocalFlags(node->LocalFlags | ImGuiDockNodeFlags_CentralNode);
// Update the node
DockNodeUpdate(node);
@@ -15043,11 +15206,11 @@ void ImGui::DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size)
ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags)
{
ImGuiContext* ctx = GImGui;
- ImGuiDockNode* node = NULL;
if (id != 0)
DockBuilderRemoveNode(id);
+ ImGuiDockNode* node = NULL;
if (flags & ImGuiDockNodeFlags_DockSpace)
{
DockSpace(id, ImVec2(0, 0), (flags & ~ImGuiDockNodeFlags_DockSpace) | ImGuiDockNodeFlags_KeepAliveOnly);
@@ -15056,7 +15219,7 @@ ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags)
else
{
node = DockContextAddNode(ctx, id);
- node->LocalFlags = flags;
+ node->SetLocalFlags(flags);
}
node->LastFrameAlive = ctx->FrameCount; // Set this otherwise BeginDocked will undock during the same frame.
return node->ID;
@@ -15070,8 +15233,12 @@ void ImGui::DockBuilderRemoveNode(ImGuiID node_id)
return;
DockBuilderRemoveNodeDockedWindows(node_id, true);
DockBuilderRemoveNodeChildNodes(node_id);
+ // Node may have moved or deleted if e.g. any merge happened
+ node = DockContextFindNodeByID(ctx, node_id);
+ if (node == NULL)
+ return;
if (node->IsCentralNode() && node->ParentNode)
- node->ParentNode->LocalFlags |= ImGuiDockNodeFlags_CentralNode;
+ node->ParentNode->SetLocalFlags(node->ParentNode->LocalFlags | ImGuiDockNodeFlags_CentralNode);
DockContextRemoveNode(ctx, node, true);
}
@@ -15141,8 +15308,8 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id)
}
else if (has_central_node)
{
- root_node->LocalFlags |= ImGuiDockNodeFlags_CentralNode;
root_node->CentralNode = root_node;
+ root_node->SetLocalFlags(root_node->LocalFlags | ImGuiDockNodeFlags_CentralNode);
}
}
@@ -15224,10 +15391,12 @@ static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID ds
ImGuiDockNode* dst_node = ImGui::DockContextAddNode(ctx, dst_node_id_if_known);
dst_node->SharedFlags = src_node->SharedFlags;
dst_node->LocalFlags = src_node->LocalFlags;
+ dst_node->LocalFlagsInWindows = ImGuiDockNodeFlags_None;
dst_node->Pos = src_node->Pos;
dst_node->Size = src_node->Size;
dst_node->SizeRef = src_node->SizeRef;
dst_node->SplitAxis = src_node->SplitAxis;
+ dst_node->UpdateMergedFlags();
out_node_remap_pairs->push_back(src_node->ID);
out_node_remap_pairs->push_back(dst_node->ID);
@@ -15250,11 +15419,12 @@ void ImGui::DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVect
IM_ASSERT(dst_node_id != 0);
IM_ASSERT(out_node_remap_pairs != NULL);
+ DockBuilderRemoveNode(dst_node_id);
+
ImGuiDockNode* src_node = DockContextFindNodeByID(ctx, src_node_id);
IM_ASSERT(src_node != NULL);
out_node_remap_pairs->clear();
- DockBuilderRemoveNode(dst_node_id);
DockBuilderCopyNodeRec(src_node, dst_node_id, out_node_remap_pairs);
IM_ASSERT((out_node_remap_pairs->Size % 2) == 0);
@@ -15441,6 +15611,9 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
ImGuiContext* ctx = GImGui;
ImGuiContext& g = *ctx;
+ // Clear fields ahead so most early-out paths don't have to do it
+ window->DockIsActive = window->DockNodeIsVisible = window->DockTabIsVisible = false;
+
const bool auto_dock_node = GetWindowAlwaysWantOwnTabBar(window);
if (auto_dock_node)
{
@@ -15490,14 +15663,9 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
// If the window has been orphaned, transition the docknode to an implicit node processed in DockContextNewFrameUpdateDocking()
ImGuiDockNode* root_node = DockNodeGetRootNode(node);
if (root_node->LastFrameAlive < g.FrameCount)
- {
DockContextProcessUndockWindow(ctx, window);
- }
else
- {
window->DockIsActive = true;
- window->DockTabIsVisible = false;
- }
return;
}
@@ -15510,8 +15678,8 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
// FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test)
if (node->HostWindow == NULL)
{
- window->DockIsActive = (node->State == ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing);
- window->DockTabIsVisible = false;
+ if (node->State == ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing)
+ window->DockIsActive = true;
if (node->Windows.Size > 1)
DockNodeHideWindowDuringHostWindowCreation(window);
return;
@@ -15535,8 +15703,9 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
SetNextWindowSize(node->Size);
g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos()
window->DockIsActive = true;
+ window->DockNodeIsVisible = true;
window->DockTabIsVisible = false;
- if (node->SharedFlags & ImGuiDockNodeFlags_KeepAliveOnly)
+ if (node->MergedFlags & ImGuiDockNodeFlags_KeepAliveOnly)
return;
// When the window is selected we mark it as visible.
@@ -15569,8 +15738,9 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
ImGuiContext& g = *GImGui;
IM_ASSERT(g.ActiveId == window->MoveId);
IM_ASSERT(g.MovingWindow == window);
+ IM_ASSERT(g.CurrentWindow == window);
- window->DC.LastItemId = window->MoveId;
+ g.LastItemData.ID = window->MoveId;
window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
bool is_drag_docking = ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); // FIXME-DOCKING: Need to make this stateful and explicit
@@ -16222,10 +16392,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);
if (cfg->ShowTablesRects && g.NavWindow != NULL)
{
- for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
+ for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
{
- ImGuiTable* table = g.Tables.GetByIndex(table_n);
- if (table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
+ ImGuiTable* table = g.Tables.TryGetMapData(table_n);
+ if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
continue;
BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
@@ -16342,23 +16512,24 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
// Details for TabBars
- if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
+ if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount()))
{
- for (int n = 0; n < g.TabBars.GetSize(); n++)
- {
- ImGuiTabBar* tab_bar = g.TabBars.GetByIndex(n);
- PushID(tab_bar);
- DebugNodeTabBar(tab_bar, "TabBar");
- PopID();
- }
+ for (int n = 0; n < g.TabBars.GetMapSize(); n++)
+ if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n))
+ {
+ PushID(tab_bar);
+ DebugNodeTabBar(tab_bar, "TabBar");
+ PopID();
+ }
TreePop();
}
// Details for Tables
- if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
+ if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount()))
{
- for (int n = 0; n < g.Tables.GetSize(); n++)
- DebugNodeTable(g.Tables.GetByIndex(n));
+ for (int n = 0; n < g.Tables.GetMapSize(); n++)
+ if (ImGuiTable* table = g.Tables.TryGetMapData(n))
+ DebugNodeTable(table);
TreePop();
}
@@ -16481,7 +16652,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Indent();
Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]);
Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
- Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
+ Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInputMask: %llX", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.ActiveIdUsingNavInputMask, g.ActiveIdUsingKeyInputMask);
+ Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame
Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
Unindent();
@@ -16528,10 +16700,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Overlay: Display Tables Rectangles
if (cfg->ShowTablesRects)
{
- for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
+ for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
{
- ImGuiTable* table = g.Tables.GetByIndex(table_n);
- if (table->LastFrameActive < g.FrameCount - 1)
+ ImGuiTable* table = g.Tables.TryGetMapData(table_n);
+ if (table == NULL || table->LastFrameActive < g.FrameCount - 1)
continue;
ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);
if (cfg->ShowTablesRectsType >= TRT_ColumnsRect)
@@ -16575,6 +16747,25 @@ void ImGui::ShowMetricsWindow(bool* p_open)
End();
}
+// [DEBUG] List fonts in a font atlas and display its texture
+void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
+{
+ for (int i = 0; i < atlas->Fonts.Size; i++)
+ {
+ ImFont* font = atlas->Fonts[i];
+ PushID(font);
+ DebugNodeFont(font);
+ PopID();
+ }
+ if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
+ {
+ ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
+ ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
+ Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
+ TreePop();
+ }
+}
+
// [DEBUG] Display contents of Columns
void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
{
@@ -16586,6 +16777,34 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
TreePop();
}
+static void DebugNodeDockNodeFlags(ImGuiDockNodeFlags* p_flags, const char* label, bool enabled)
+{
+ using namespace ImGui;
+ PushID(label);
+ PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
+ Text("%s:", label);
+ if (!enabled)
+ BeginDisabled();
+ CheckboxFlags("NoSplit", p_flags, ImGuiDockNodeFlags_NoSplit);
+ CheckboxFlags("NoResize", p_flags, ImGuiDockNodeFlags_NoResize);
+ CheckboxFlags("NoResizeX", p_flags, ImGuiDockNodeFlags_NoResizeX);
+ CheckboxFlags("NoResizeY",p_flags, ImGuiDockNodeFlags_NoResizeY);
+ CheckboxFlags("NoTabBar", p_flags, ImGuiDockNodeFlags_NoTabBar);
+ CheckboxFlags("HiddenTabBar", p_flags, ImGuiDockNodeFlags_HiddenTabBar);
+ CheckboxFlags("NoWindowMenuButton", p_flags, ImGuiDockNodeFlags_NoWindowMenuButton);
+ CheckboxFlags("NoCloseButton", p_flags, ImGuiDockNodeFlags_NoCloseButton);
+ CheckboxFlags("NoDocking", p_flags, ImGuiDockNodeFlags_NoDocking);
+ CheckboxFlags("NoDockingSplitMe", p_flags, ImGuiDockNodeFlags_NoDockingSplitMe);
+ CheckboxFlags("NoDockingSplitOther", p_flags, ImGuiDockNodeFlags_NoDockingSplitOther);
+ CheckboxFlags("NoDockingOverMe", p_flags, ImGuiDockNodeFlags_NoDockingOverMe);
+ CheckboxFlags("NoDockingOverOther", p_flags, ImGuiDockNodeFlags_NoDockingOverOther);
+ CheckboxFlags("NoDockingOverEmpty", p_flags, ImGuiDockNodeFlags_NoDockingOverEmpty);
+ if (!enabled)
+ EndDisabled();
+ PopStyleVar();
+ PopID();
+}
+
// [DEBUG] Display contents of ImDockNode
void ImGui::DebugNodeDockNode(ImGuiDockNode* node, const char* label)
{
@@ -16616,17 +16835,16 @@ void ImGui::DebugNodeDockNode(ImGuiDockNode* node, const char* label)
node->IsCentralNode() ? " IsCentralNode" : "",
is_alive ? " IsAlive" : "", is_active ? " IsActive" : "",
node->WantLockSizeOnce ? " WantLockSizeOnce" : "");
- if (TreeNode("flags", "LocalFlags: 0x%04X SharedFlags: 0x%04X", node->LocalFlags, node->SharedFlags))
+ if (TreeNode("flags", "Flags Merged: 0x%04X, Local: 0x%04X, InWindows: 0x%04X, Shared: 0x%04X", node->MergedFlags, node->LocalFlags, node->LocalFlagsInWindows, node->SharedFlags))
{
- CheckboxFlags("LocalFlags: NoDocking", &node->LocalFlags, ImGuiDockNodeFlags_NoDocking);
- CheckboxFlags("LocalFlags: NoSplit", &node->LocalFlags, ImGuiDockNodeFlags_NoSplit);
- CheckboxFlags("LocalFlags: NoResize", &node->LocalFlags, ImGuiDockNodeFlags_NoResize);
- CheckboxFlags("LocalFlags: NoResizeX", &node->LocalFlags, ImGuiDockNodeFlags_NoResizeX);
- CheckboxFlags("LocalFlags: NoResizeY", &node->LocalFlags, ImGuiDockNodeFlags_NoResizeY);
- CheckboxFlags("LocalFlags: NoTabBar", &node->LocalFlags, ImGuiDockNodeFlags_NoTabBar);
- CheckboxFlags("LocalFlags: HiddenTabBar", &node->LocalFlags, ImGuiDockNodeFlags_HiddenTabBar);
- CheckboxFlags("LocalFlags: NoWindowMenuButton", &node->LocalFlags, ImGuiDockNodeFlags_NoWindowMenuButton);
- CheckboxFlags("LocalFlags: NoCloseButton", &node->LocalFlags, ImGuiDockNodeFlags_NoCloseButton);
+ if (BeginTable("flags", 4))
+ {
+ TableNextColumn(); DebugNodeDockNodeFlags(&node->MergedFlags, "MergedFlags", false);
+ TableNextColumn(); DebugNodeDockNodeFlags(&node->LocalFlags, "LocalFlags", true);
+ TableNextColumn(); DebugNodeDockNodeFlags(&node->LocalFlagsInWindows, "LocalFlagsInWindows", false);
+ TableNextColumn(); DebugNodeDockNodeFlags(&node->SharedFlags, "SharedFlags", true);
+ EndTable();
+ }
TreePop();
}
if (node->ParentNode)
@@ -16740,16 +16958,17 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb)
{
IM_ASSERT(show_mesh || show_aabb);
- ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
- ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;
// Draw wire-frame version of all triangles
ImRect clip_rect = draw_cmd->ClipRect;
ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
ImDrawListFlags backup_flags = out_draw_list->Flags;
out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
- for (unsigned int idx_n = draw_cmd->IdxOffset; idx_n < draw_cmd->IdxOffset + draw_cmd->ElemCount; )
+ for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; )
{
+ ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list
+ ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;
+
ImVec2 triangle[3];
for (int n = 0; n < 3; n++, idx_n++)
vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));
@@ -16765,6 +16984,102 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co
out_draw_list->Flags = backup_flags;
}
+// [DEBUG] Display details for a single font, called by ShowStyleEditor().
+void ImGui::DebugNodeFont(ImFont* font)
+{
+ bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)",
+ font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
+ SameLine();
+ if (SmallButton("Set as default"))
+ GetIO().FontDefault = font;
+ if (!opened)
+ return;
+
+ // Display preview text
+ PushFont(font);
+ Text("The quick brown fox jumps over the lazy dog");
+ PopFont();
+
+ // Display details
+ SetNextItemWidth(GetFontSize() * 8);
+ DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");
+ SameLine(); MetricsHelpMarker(
+ "Note than the default embedded font is NOT meant to be scaled.\n\n"
+ "Font are currently rendered into bitmaps at a given size at the time of building the atlas. "
+ "You may oversample them to get some flexibility with scaling. "
+ "You can also render at multiple sizes and select which one to use at runtime.\n\n"
+ "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
+ Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
+ char c_str[5];
+ Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
+ Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
+ const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface);
+ Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
+ for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
+ if (font->ConfigData)
+ if (const ImFontConfig* cfg = &font->ConfigData[config_i])
+ BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
+ config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
+
+ // Display all glyphs of the fonts in separate pages of 256 characters
+ if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
+ {
+ ImDrawList* draw_list = GetWindowDrawList();
+ const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
+ const float cell_size = font->FontSize * 1;
+ const float cell_spacing = GetStyle().ItemSpacing.y;
+ for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
+ {
+ // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
+ // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
+ // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
+ if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
+ {
+ base += 4096 - 256;
+ continue;
+ }
+
+ int count = 0;
+ for (unsigned int n = 0; n < 256; n++)
+ if (font->FindGlyphNoFallback((ImWchar)(base + n)))
+ count++;
+ if (count <= 0)
+ continue;
+ if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
+ continue;
+
+ // Draw a 16x16 grid of glyphs
+ ImVec2 base_pos = GetCursorScreenPos();
+ for (unsigned int n = 0; n < 256; n++)
+ {
+ // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
+ // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
+ ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
+ ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
+ const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
+ draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
+ if (glyph)
+ font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
+ if (glyph && IsMouseHoveringRect(cell_p1, cell_p2))
+ {
+ BeginTooltip();
+ Text("Codepoint: U+%04X", base + n);
+ Separator();
+ Text("Visible: %d", glyph->Visible);
+ Text("AdvanceX: %.1f", glyph->AdvanceX);
+ Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
+ Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
+ EndTooltip();
+ }
+ }
+ Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
+ TreePop();
+ }
+ TreePop();
+ }
+ TreePop();
+}
+
// [DEBUG] Display contents of ImGuiStorage
void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{
@@ -16943,9 +17258,11 @@ void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* la
#else
void ImGui::ShowMetricsWindow(bool*) {}
+void ImGui::ShowFontAtlas(ImFontAtlas*) {}
void ImGui::DebugNodeColumns(ImGuiOldColumns*) {}
void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {}
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}
+void ImGui::DebugNodeFont(ImFont*) {}
void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}