From 6e8e2c0fa9e9cc5347a3c3962d30515830a89fcf Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 8 Nov 2019 19:00:49 +0100 Subject: [PATCH 1/9] Scrollbar: Fixed an issue where scrollbars wouldn't display on the frame following a frame where all child window contents would be culled. Demo: Fixed a small bug with scrolling demo. Metrics: Tweaks. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 12 +++++++++--- imgui_demo.cpp | 44 +++++++++++++++++++++++++------------------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a45a3b795..80d2229f2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,8 @@ Other Changes: multi-line label and no frame padding, such as: multi-line text, small button, tree node item, etc. The second item was correctly offset to match text baseline, and would interact/display correctly, but it wouldn't push the contents area boundary low enough. +- Scrollbar: Fixed an issue where scrollbars wouldn't display on the frame following a frame where + all child window contents would be culled. - ColorPicker: Fixed SV triangle gradient to block (broken in 1.73). (#2864, #2711). [@lewa-j] - TreeNode: Fixed combination of ImGuiTreeNodeFlags_SpanFullWidth and ImGuiTreeNodeFlags_OpenOnArrow incorrectly locating the arrow hit position to the left of the frame. (#2451, #2438, #1897) diff --git a/imgui.cpp b/imgui.cpp index e21c8a0d9..db6d05a3a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5054,6 +5054,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImGuiStyle& style = g.Style; ImGuiWindowFlags flags = window->Flags; + // Ensure that ScrollBar doesn't read last frame's SkipItems + window->SkipItems = false; + // Draw window + handle manual resize // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. const float window_rounding = window->WindowRounding; @@ -9754,7 +9757,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("%s: NULL", label); return; } - if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window)) + bool open = ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window); + if (ImGui::IsItemHovered() && window->WasActive) + ImGui::GetForegroundDrawList()->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!open) return; ImGuiWindowFlags flags = window->Flags; NodeDrawList(window, window->DrawList, "DrawList"); @@ -9763,7 +9769,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); - ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y); + ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); @@ -9821,7 +9827,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) }; Funcs::NodeWindows(g.Windows, "Windows"); - if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) + if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) { for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b98eb7663..deaf4bc40 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2215,7 +2215,7 @@ static void ShowDemoWindowLayout() ImGui::TextUnformatted(names[i]); ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; - ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); + bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -2225,16 +2225,19 @@ static void ShowDemoWindowLayout() ImGui::SetScrollY(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); - for (int item = 0; item < 100; item++) + if (window_visible) // Avoid calling SetScrollHereY when running with culled items { - if (enable_track && item == track_item) + for (int item = 0; item < 100; item++) { - ImGui::TextColored(ImVec4(1,1,0,1), "Item %d", item); - ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom - } - else - { - ImGui::Text("Item %d", item); + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom + } + else + { + ImGui::Text("Item %d", item); + } } } float scroll_y = ImGui::GetScrollY(); @@ -2253,23 +2256,26 @@ static void ShowDemoWindowLayout() { float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); - ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags); + bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); - for (int item = 0; item < 100; item++) + if (window_visible) // Avoid calling SetScrollHereY when running with culled items { - if (enable_track && item == track_item) + for (int item = 0; item < 100; item++) { - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); - ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + } + else + { + ImGui::Text("Item %d", item); + } + ImGui::SameLine(); } - else - { - ImGui::Text("Item %d", item); - } - ImGui::SameLine(); } float scroll_x = ImGui::GetScrollX(); float scroll_max_x = ImGui::GetScrollMaxX(); From 7c441e37faef9211b0684b6c7a4548b40dcc9507 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 11 Nov 2019 14:47:39 +0100 Subject: [PATCH 2/9] CI: Update jobs to MacOS latest (Catalina) Metrics: Added description to Item Picker. --- .github/workflows/build.yml | 4 ++-- imgui.cpp | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index babd548a8..86f5de6e8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -168,7 +168,7 @@ jobs: run: make -C examples/example_sdl_opengl3 MacOS: - runs-on: macOS-10.14 + runs-on: macOS-latest steps: - uses: actions/checkout@v1 with: @@ -206,7 +206,7 @@ jobs: run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2 iOS: - runs-on: macOS-10.14 + runs-on: macOS-latest steps: - uses: actions/checkout@v1 with: diff --git a/imgui.cpp b/imgui.cpp index db6d05a3a..b3b39711c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -351,7 +351,7 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): Begin() (5 arguments signature), IsRootWindowOrAnyChildHovered(), AlignFirstTextHeightToWidgets(), SetNextWindowPosCenter(), ImFont::Glyph. Grep this log for details and new names, or see how they were implemented until 1.73. + - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): Begin() (5 arguments signature), IsRootWindowOrAnyChildHovered(), AlignFirstTextHeightToWidgets(), SetNextWindowPosCenter(), ImFont::Glyph. See docs/Changelog.txt or grep this log for details and new names, or see how they were implemented until 1.73. - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). @@ -9607,6 +9607,19 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_METRICS_WINDOW +static void HelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + void ImGui::ShowMetricsWindow(bool* p_open) { if (!ImGui::Begin("Dear ImGui Metrics", p_open)) @@ -9890,6 +9903,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. if (ImGui::Button("Item Picker..")) ImGui::DebugStartItemPicker(); + ImGui::SameLine(); + HelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); ImGui::Checkbox("Show windows rectangles", &show_windows_rects); From b138f8cbcd0bce666a9584f37d4616041e91a5f4 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Nov 2019 23:54:22 +0100 Subject: [PATCH 3/9] Internal: Nav rename preparing for nav inputs ownership changes. IsNavInputPressed() -> IsNavInputTest() --- imgui.cpp | 23 ++++++++++++----------- imgui_internal.h | 6 +----- imgui_widgets.cpp | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b3b39711c..9c4f1949b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8169,7 +8169,7 @@ static void ImGui::NavUpdate() g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); // Process NavCancel input (to close a popup, get back to parent, clear focus) - if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) { if (g.ActiveId != 0) { @@ -8213,14 +8213,14 @@ static void ImGui::NavUpdate() if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); - bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); + bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); if (g.ActiveId == 0 && activate_pressed) g.NavActivateId = g.NavId; if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) g.NavActivateDownId = g.NavId; if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) g.NavActivatePressedId = g.NavId; - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) g.NavInputId = g.NavId; } if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) @@ -8241,10 +8241,11 @@ static void ImGui::NavUpdate() g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { - if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Left; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Right; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Up; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Down; } + const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } } g.NavMoveClipDir = g.NavMoveDir; } @@ -8539,7 +8540,7 @@ static void ImGui::NavUpdateWindowing() } // Start CTRL-TAB or Square+L/R window selection - bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); + bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.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)) @@ -8558,7 +8559,7 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // Select window to focus - const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); + const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); if (focus_change_dir != 0) { NavUpdateWindowingHighlightWindow(focus_change_dir); @@ -8590,9 +8591,9 @@ static void ImGui::NavUpdateWindowing() // 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 back-end clearing releases all keys on ALT-TAB - if (IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) + if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) g.NavWindowingToggleLayer = true; - if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) + 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; diff --git a/imgui_internal.h b/imgui_internal.h index 42d296dbe..0d0dda3e0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -956,7 +956,6 @@ struct ImGuiContext bool ActiveIdPreviousFrameIsAlive; bool ActiveIdPreviousFrameHasBeenEditedBefore; ImGuiWindow* ActiveIdPreviousFrameWindow; - ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. @@ -1145,12 +1144,10 @@ struct ImGuiContext ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdWindow = NULL; ActiveIdSource = ImGuiInputSource_None; - ActiveIdPreviousFrame = 0; ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameHasBeenEditedBefore = false; ActiveIdPreviousFrameWindow = NULL; - LastActiveId = 0; LastActiveIdTimer = 0.0f; @@ -1639,8 +1636,7 @@ namespace ImGui IMGUI_API bool IsMouseDragPastThreshold(int button, float lock_threshold = -1.0f); inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } - inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; } - inline bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) { return (GetNavInputAmount(n1, mode) + GetNavInputAmount(n2, mode)) > 0.0f; } + inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } // Drag and Drop IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2757ac6fa..353f97d94 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -549,7 +549,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (g.NavActivateDownId == id) { bool nav_activated_by_code = (g.NavActivateId == id); - bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); if (nav_activated_by_code || nav_activated_by_inputs) pressed = true; if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) From 25eee91542adaef308270fa864fc92b0d9d6eb61 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Nov 2019 21:35:42 +0100 Subject: [PATCH 4/9] Error handling: Assert if user mistakenly calls End() instead of EndChild() on a child window. (#1651) Internals: Moved some error handling code. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 118 ++++++++++++++++++++++++++++----------------- imgui_internal.h | 23 ++++----- 3 files changed, 88 insertions(+), 54 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 80d2229f2..29e869b07 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,7 @@ Other Changes: interactions with custom multi-selections patterns. (#1896, #1861) - DragScalar, SliderScalar, InputScalar: Added p_ prefix to parameter that are pointers to the data to clarify how they are used, and more comments redirecting to the demo code. (#2844) +- Error handling: Assert if user mistakenly calls End() instead of EndChild() on a child window. (#1651) - Misc: Optimized storage of window settings data (reducing allocation count). - Misc: Windows: Do not use _wfopen() if IMGUI_DISABLE_WIN32_FUNCTIONS is defined. (#2815) - Docs: Improved and moved FAQ to docs/FAQ.md so it can be readable on the web. [@ButternCream, @ocornut] diff --git a/imgui.cpp b/imgui.cpp index 9c4f1949b..42b7f4549 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -54,6 +54,7 @@ CODE // [SECTION] ImGuiListClipper // [SECTION] RENDER HELPERS // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] ERROR CHECKING // [SECTION] SCROLLING // [SECTION] TOOLTIPS // [SECTION] POPUPS @@ -838,7 +839,6 @@ static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock static void SetCurrentWindow(ImGuiWindow* window); static void FindHoveredWindow(); static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); -static void CheckStacksSize(ImGuiWindow* window, bool write); static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); @@ -874,6 +874,10 @@ static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_win static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); static int FindWindowFocusIndex(ImGuiWindow* window); +// Error Checking +static void ErrorCheckEndFrame(); +static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); + // Misc static void UpdateMouseInputs(); static void UpdateMouseWheel(); @@ -3539,7 +3543,7 @@ void ImGui::NewFrame() } g.Time += g.IO.DeltaTime; - g.FrameScopeActive = true; + g.WithinFrameScope = true; g.FrameCount += 1; g.TooltipOverrideCount = 0; g.WindowsActiveCount = 0; @@ -3713,7 +3717,7 @@ void ImGui::NewFrame() // This fallback is particularly important as it avoid ImGui:: calls from crashing. SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); Begin("Debug##Default"); - g.FrameScopePushedImplicitWindow = true; + g.WithinFrameScopeWithImplicitWindow = true; #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_PostNewFrame(&g); @@ -3982,7 +3986,7 @@ void ImGui::EndFrame() IM_ASSERT(g.Initialized); if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. return; - IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); + IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) @@ -3991,24 +3995,10 @@ void ImGui::EndFrame() g.PlatformImeLastPos = g.PlatformImePos; } - // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you - // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). - if (g.CurrentWindowStack.Size != 1) - { - if (g.CurrentWindowStack.Size > 1) - { - IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); - while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING - End(); - } - else - { - IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); - } - } + ErrorCheckEndFrame(); // Hide implicit/fallback "Debug" window if it hasn't been used - g.FrameScopePushedImplicitWindow = false; + g.WithinFrameScopeWithImplicitWindow = false; if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) g.CurrentWindow->Active = false; End(); @@ -4035,7 +4025,7 @@ void ImGui::EndFrame() } // End frame - g.FrameScopeActive = false; + g.WithinFrameScope = false; g.FrameCountEnded = g.FrameCount; // Initiate moving window + handle left-click and right-click focus @@ -4602,7 +4592,10 @@ void ImGui::EndChild() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.WithinEndChild == false); IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss + + g.WithinEndChild = true; if (window->BeginCount > 1) { End(); @@ -4634,6 +4627,7 @@ void ImGui::EndChild() ItemAdd(bb, 0); } } + g.WithinEndChild = false; } // Helper to create a child window / scrolling region that looks like a normal widget frame. @@ -4656,22 +4650,6 @@ void ImGui::EndChildFrame() EndChild(); } -// Save and compare stack sizes on Begin()/End() to detect usage errors -static void CheckStacksSize(ImGuiWindow* window, bool write) -{ - // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) - ImGuiContext& g = *GImGui; - short* p_backup = &window->DC.StackSizesBackup[0]; - { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() - { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() - { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() - // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. - { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() - { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() - { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() - IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); -} - static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) { window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); @@ -5238,7 +5216,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required - IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame() + IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame() IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet // Find or create @@ -5300,7 +5278,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // 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); g.CurrentWindow = NULL; - CheckStacksSize(window, true); + ErrorCheckBeginEndCompareStacksSize(window, true); if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; @@ -5839,16 +5817,22 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) void ImGui::End() { ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; - if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow) + // Error checking: verify that user hasn't called End() too many times! + // FIXME-ERRORHANDLING + if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) { IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); - return; // FIXME-ERRORHANDLING + return; } IM_ASSERT(g.CurrentWindowStack.Size > 0); - ImGuiWindow* window = g.CurrentWindow; + // Error checking: verify that user doesn't directly call End() on a child window. + if (window->Flags & ImGuiWindowFlags_ChildWindow) + IM_ASSERT(g.WithinEndChild && "Must call EndChild() and not End()!"); + // Close anything that is open if (window->DC.CurrentColumns) EndColumns(); PopClipRect(); // Inner window clip rectangle @@ -5861,7 +5845,7 @@ void ImGui::End() g.CurrentWindowStack.pop_back(); if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - CheckStacksSize(window, false); + ErrorCheckBeginEndCompareStacksSize(window, false); SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); } @@ -7007,6 +6991,54 @@ void ImGui::Unindent(float indent_w) } +//----------------------------------------------------------------------------- +// [SECTION] ERROR CHECKING +//----------------------------------------------------------------------------- + +static void ImGui::ErrorCheckEndFrame() +{ + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + ImGuiContext& g = *GImGui; + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING + End(); + } + else + { + IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } + +} + +// Save and compare stack sizes on Begin()/End() to detect usage errors +// Begin() calls this with write=true +// End() calls this with write=false +static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write) +{ + ImGuiContext& g = *GImGui; + short* p = &window->DC.StackSizesBackup[0]; + + // Window stacks + // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop() + { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() + + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() + { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() + { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() + { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() + IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); +} + + //----------------------------------------------------------------------------- // [SECTION] SCROLLING //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 0d0dda3e0..3b7ad26e3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -903,9 +903,7 @@ struct ImGuiPtrOrIndex struct ImGuiContext { bool Initialized; - bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame() - bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame() - bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it. + bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; ImGuiStyle Style; ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() @@ -916,19 +914,22 @@ struct ImGuiContext int FrameCount; int FrameCountEnded; int FrameCountRendered; + bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() + bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed + bool WithinEndChild; // Set within EndChild() // Windows state ImVector Windows; // Windows, sorted in display order, back to front ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front ImVector WindowsSortBuffer; ImVector CurrentWindowStack; - ImGuiStorage WindowsById; - int WindowsActiveCount; - ImGuiWindow* CurrentWindow; // Being drawn into + ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* + int WindowsActiveCount; // Number of unique windows submitted by frame + ImGuiWindow* CurrentWindow; // Window being drawn into ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. - ImGuiWindow* WheelingWindow; + ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; float WheelingWindowTimer; @@ -1057,9 +1058,9 @@ struct ImGuiContext ImFont InputTextPasswordFont; ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets - float ColorEditLastHue; + float ColorEditLastHue; // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips float ColorEditLastColor[3]; - ImVec4 ColorPickerRef; + ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. bool DragCurrentAccumDirty; float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio @@ -1082,7 +1083,7 @@ struct ImGuiContext ImVector SettingsHandlers; // List of .ini settings handlers ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries - // Logging + // Capture/Logging bool LogEnabled; ImGuiLogType LogType; FILE* LogFile; // If != NULL log to stdout/ file @@ -1109,7 +1110,6 @@ struct ImGuiContext ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData) { Initialized = false; - FrameScopeActive = FrameScopePushedImplicitWindow = false; Font = NULL; FontSize = FontBaseSize = 0.0f; FontAtlasOwnedByContext = shared_font_atlas ? false : true; @@ -1117,6 +1117,7 @@ struct ImGuiContext Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; WindowsActiveCount = 0; CurrentWindow = NULL; From 03852470deabade6cf2f4c960a480e2c806c94e2 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Nov 2019 21:58:18 +0100 Subject: [PATCH 5/9] Internals: Routing recoverable user errors via IMGUI_USER_ERROR() macro. (#1651) --- imgui.cpp | 11 +++++------ imgui_internal.h | 5 +++++ imgui_widgets.cpp | 8 ++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 42b7f4549..1706086a6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5820,17 +5820,16 @@ void ImGui::End() ImGuiWindow* window = g.CurrentWindow; // Error checking: verify that user hasn't called End() too many times! - // FIXME-ERRORHANDLING if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) { - IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); + IMGUI_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); return; } IM_ASSERT(g.CurrentWindowStack.Size > 0); // Error checking: verify that user doesn't directly call End() on a child window. if (window->Flags & ImGuiWindowFlags_ChildWindow) - IM_ASSERT(g.WithinEndChild && "Must call EndChild() and not End()!"); + IMGUI_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); // Close anything that is open if (window->DC.CurrentColumns) @@ -7004,13 +7003,13 @@ static void ImGui::ErrorCheckEndFrame() { if (g.CurrentWindowStack.Size > 1) { - IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); - while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING + IMGUI_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) End(); } else { - IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + IMGUI_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); } } diff --git a/imgui_internal.h b/imgui_internal.h index 3b7ad26e3..f04d4e429 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -161,6 +161,11 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds #define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // +// Error handling +#ifndef IMGUI_USER_ERROR +#define IMGUI_USER_ERROR(_EXPR, _MSG) IM_ASSERT((_EXPR) && (_MSG)) // Recoverable User Error +#endif + // Debug Logging #ifndef IMGUI_DEBUG_LOG #define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 353f97d94..beeffba65 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6472,8 +6472,8 @@ void ImGui::EndTabBar() ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT(tab_bar != NULL && "Mismatched BeginTabBar()/EndTabBar()!"); - return; // FIXME-ERRORHANDLING + IMGUI_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); + return; } if (tab_bar->WantLayout) TabBarLayout(tab_bar); @@ -6869,8 +6869,8 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT(tab_bar && "Needs to be called between BeginTabBar() and EndTabBar()!"); - return false; // FIXME-ERRORHANDLING + IMGUI_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; } bool ret = TabItemEx(tab_bar, label, p_open, flags); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) From be436e2b0bed33921817ac8c77ea9c44b2abacfe Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Nov 2019 22:04:16 +0100 Subject: [PATCH 6/9] Fix HelpMarker() symbol collision for unity builds (#2893) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1706086a6..fc89ef4c8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9639,7 +9639,8 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_METRICS_WINDOW -static void HelpMarker(const char* desc) +// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. +static void MetricsHelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) @@ -9936,7 +9937,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (ImGui::Button("Item Picker..")) ImGui::DebugStartItemPicker(); ImGui::SameLine(); - HelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); + MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); ImGui::Checkbox("Show windows rectangles", &show_windows_rects); From b23dcab6e13ddf8c973288fbbd1866dbc809dada Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 14 Nov 2019 16:06:39 +0100 Subject: [PATCH 7/9] Fix 25eee91 incorrect assert when ending a child-popup (rarely used but used by sub-nenus) --- imgui.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fc89ef4c8..3e5646686 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7516,13 +7516,19 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla void ImGui::EndPopup() { ImGuiContext& g = *GImGui; - IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls IM_ASSERT(g.BeginPopupStack.Size > 0); // Make all menus and popups wrap around for now, may need to expose that policy. - NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + // Child-popups don't need to be layed out + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; End(); + g.WithinEndChild = false; } bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) From be05e12e21050f91435fdbb027da1206c6b6adab Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 14 Nov 2019 18:02:18 +0100 Subject: [PATCH 8/9] Misc: Using static_assert() when using C++11, instead of our own construct (avoid zealous Clang warnings). --- docs/CHANGELOG.txt | 1 + imgui_internal.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 29e869b07..0531da371 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,7 @@ Other Changes: - Error handling: Assert if user mistakenly calls End() instead of EndChild() on a child window. (#1651) - Misc: Optimized storage of window settings data (reducing allocation count). - Misc: Windows: Do not use _wfopen() if IMGUI_DISABLE_WIN32_FUNCTIONS is defined. (#2815) +- Misc: Using static_assert() when using C++11, instead of our own construct (avoid zealous Clang warnings). - Docs: Improved and moved FAQ to docs/FAQ.md so it can be readable on the web. [@ButternCream, @ocornut] - Docs: Added permanent redirect from https://www.dearimgui.org/faq to FAQ page. - Demo: Added simple item reordering demo in Widgets -> Drag and Drop section. (#2823, #143) [@rokups] diff --git a/imgui_internal.h b/imgui_internal.h index f04d4e429..027d3804b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -155,7 +155,11 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_NEWLINE "\n" #endif #define IM_TABSIZE (4) +#if (__cplusplus >= 201100) +#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") +#else #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] +#endif #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 #define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds From 8f40020ca6e561216f1562898c5961973b36baad Mon Sep 17 00:00:00 2001 From: Tracy Ma <1991md@gmail.com> Date: Fri, 15 Nov 2019 16:51:48 +0800 Subject: [PATCH 9/9] Disable Win32 clipboard and IME functions when build target UWP (#2892, #2895) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0531da371..513cd335a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,7 @@ Other Changes: - Error handling: Assert if user mistakenly calls End() instead of EndChild() on a child window. (#1651) - Misc: Optimized storage of window settings data (reducing allocation count). - Misc: Windows: Do not use _wfopen() if IMGUI_DISABLE_WIN32_FUNCTIONS is defined. (#2815) +- Misc: Windows: Disabled win32 function by default when building with UWP. (#2892, #2895) - Misc: Using static_assert() when using C++11, instead of our own construct (avoid zealous Clang warnings). - Docs: Improved and moved FAQ to docs/FAQ.md so it can be readable on the web. [@ButternCream, @ocornut] - Docs: Added permanent redirect from https://www.dearimgui.org/faq to FAQ page. diff --git a/imgui.cpp b/imgui.cpp index 3e5646686..bfe4b1783 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9483,6 +9483,10 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl #else #include #endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif #elif defined(__APPLE__) #include #endif