From 22b36bef9e6ec315f16eff98d11d2b853bf31f80 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Jun 2024 14:59:00 +0200 Subject: [PATCH 01/10] Examples: undo adding SDL3 example to Visual Studio sln. --- examples/imgui_examples.sln | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index cf1e7d75f..071bcbd63 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -29,8 +29,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_opengl3", "ex EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_sdlrenderer2", "example_sdl2_sdlrenderer2\example_sdl2_sdlrenderer2.vcxproj", "{0C0B2BEA-311F-473C-9652-87923EF639E3}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", "example_sdl3_sdlrenderer3\example_sdl3_sdlrenderer3.vcxproj", "{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -143,14 +141,6 @@ Global {0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|Win32.Build.0 = Release|Win32 {0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|x64.ActiveCfg = Release|x64 {0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|x64.Build.0 = Release|x64 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|Win32.ActiveCfg = Debug|Win32 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|Win32.Build.0 = Debug|Win32 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|x64.ActiveCfg = Debug|x64 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|x64.Build.0 = Debug|x64 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|Win32.ActiveCfg = Release|Win32 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|Win32.Build.0 = Release|Win32 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.ActiveCfg = Release|x64 - {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 0c2650e8339213398c28625f3d1d91fc9bf6db6b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Jun 2024 16:23:27 +0200 Subject: [PATCH 02/10] Backends: OSX: build fix. Amend 32f9dfc --- backends/imgui_impl_osx.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 14cdd85cd..fdd407f3e 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -80,6 +80,7 @@ struct ImGui_ImplOSX_Data KeyEventResponder* KeyEventResponder; NSTextInputContext* InputContext; id Monitor; + NSWindow* Window; ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); } }; @@ -402,6 +403,7 @@ bool ImGui_ImplOSX_Init(NSView* view) //io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bd->Observer = [ImGuiObserver new]; + bd->Window = view.window ?: NSApp.orderedWindows.firstObject; ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (__bridge_retained void*)bd->Window; From dbffb702f836f4c9bcbac97ab7e80fcb63b2e123 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Jun 2024 18:57:14 +0200 Subject: [PATCH 03/10] ImGuiStorage: tweak impl for BuildSortByKey(). --- imgui.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0fe364f6a..520590206 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2542,20 +2542,18 @@ ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_ return in_p; } +static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs) +{ + // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. + ImGuiID lhs_v = ((const ImGuiStoragePair*)lhs)->key; + ImGuiID rhs_v = ((const ImGuiStoragePair*)rhs)->key; + return (lhs_v > rhs_v ? +1 : lhs_v < rhs_v ? -1 : 0); +} + // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. void ImGuiStorage::BuildSortByKey() { - struct StaticFunc - { - static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs) - { - // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. - if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; - if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1; - return 0; - } - }; - ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID); + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), PairComparerByID); } int ImGuiStorage::GetInt(ImGuiID key, int default_val) const From fbb903e15808d6a36034d65649e10b6976d0cdb9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Jun 2024 16:37:33 +0200 Subject: [PATCH 04/10] Inputs: fixed using Shortcut() or SetNextItemShortcut() within a disabled block bypassing the disabled state. (#7726) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 9 ++++++++- imgui.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index eba73bb2b..85bcfbb13 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,8 @@ Other changes: on third-party backends to set ImGuiBackendFlags_HasMouseCursors and honor changes of ImGui::GetMouseCursor() value. (#1495) - IO: Added io.ClearInputMouse() to clear mouse state. (#4921) +- Inputs: fixed using Shortcut() or SetNextItemShortcut() within a disabled block bypassing + the disabled state. (#7726) - TabBar, Style: added ImGuiTabBarFlags_DrawSelectedOverline option to draw an horizontal line over selected tabs to increase visibility. This is used by docking. Added corresponding ImGuiCol_TabSelectedOverline and ImGuiCol_TabDimmedSelectedOverline colors. diff --git a/imgui.cpp b/imgui.cpp index 520590206..72f1f1871 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4214,6 +4214,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag } // Display shortcut (only works with mouse) + // (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip) if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut)) if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal)) SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut)); @@ -9793,12 +9794,15 @@ void ImGui::SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags) g.NextItemData.ShortcutFlags = flags; } +// Called from within ItemAdd: at this point we can read from NextItemData and write to LastItemData void ImGui::ItemHandleShortcut(ImGuiID id) { ImGuiContext& g = *GImGui; ImGuiInputFlags flags = g.NextItemData.ShortcutFlags; IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetNextItemShortcut) == 0); // Passing flags not supported by SetNextItemShortcut()! + if (g.LastItemData.InFlags & ImGuiItemFlags_Disabled) + return; if (flags & ImGuiInputFlags_Tooltip) { g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasShortcut; @@ -9822,7 +9826,7 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags) bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID owner_id) { - //ImGuiContext& g = *GImGui; + ImGuiContext& g = *GImGui; //IMGUI_DEBUG_LOG("Shortcut(%s, flags=%X, owner_id=0x%08X)\n", GetKeyChordName(key_chord, g.TempBuffer.Data, g.TempBuffer.Size), flags, owner_id); // When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any. @@ -9834,6 +9838,9 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own if (owner_id == ImGuiKeyOwner_Any || owner_id == ImGuiKeyOwner_NoOwner) owner_id = GetRoutingIdFromOwnerId(owner_id); + if (g.CurrentItemFlags & ImGuiItemFlags_Disabled) + return false; + // Submit route if (!SetShortcutRouting(key_chord, flags, owner_id)) return false; diff --git a/imgui.h b/imgui.h index 95506954b..7617addc4 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.90.9 WIP" -#define IMGUI_VERSION_NUM 19083 +#define IMGUI_VERSION_NUM 19084 #define IMGUI_HAS_TABLE /* From 953d40c929fc56ad719845ad1788aa046ef9ee33 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Jun 2024 17:17:54 +0200 Subject: [PATCH 05/10] Tables: moved TableGetHoveredColumn() to public API. (#7715, #3740) --- docs/CHANGELOG.txt | 2 ++ imgui.h | 3 ++- imgui_internal.h | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 85bcfbb13..acb2f3202 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other changes: - TabBar, Style: added ImGuiTabBarFlags_DrawSelectedOverline option to draw an horizontal line over selected tabs to increase visibility. This is used by docking. Added corresponding ImGuiCol_TabSelectedOverline and ImGuiCol_TabDimmedSelectedOverline colors. +- Tables: added TableGetHoveredColumn() to public API, as an alternative to testing for + 'TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered' on each column. (#3740) - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern sets active id so a multi-frame extern source doesn't interfere with hovered widgets. (#143) - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern does not assume diff --git a/imgui.h b/imgui.h index 7617addc4..ff8778c03 100644 --- a/imgui.h +++ b/imgui.h @@ -779,7 +779,7 @@ namespace ImGui // - TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row! // - TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! // - 5. Call EndTable() - IMGUI_API bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); + IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible. @@ -812,6 +812,7 @@ namespace ImGui IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column. IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column. IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) + IMGUI_API int TableGetHoveredColumn(); // return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. Can also use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details. // Legacy Columns API (prefer using Tables!) diff --git a/imgui_internal.h b/imgui_internal.h index a02f01b85..9bbbc5eca 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3332,7 +3332,6 @@ namespace ImGui IMGUI_API void TableOpenContextMenu(int column_n = -1); IMGUI_API void TableSetColumnWidth(int column_n, float width); IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); - IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. IMGUI_API float TableGetHeaderRowHeight(); IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); From 77d582fa37b4958a284421432aec18ba84f138bc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Jun 2024 18:04:24 +0200 Subject: [PATCH 06/10] Windows: BeginChild(): fixed a glitch when during a resize of a child window which is tightly close to the boundaries of its parent. (#7706) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index acb2f3202..4b9b12c79 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,9 @@ Other changes: - IO: Added io.ClearInputMouse() to clear mouse state. (#4921) - Inputs: fixed using Shortcut() or SetNextItemShortcut() within a disabled block bypassing the disabled state. (#7726) +- Windows: BeginChild(): fixed a glitch when during a resize of a child window which is + tightly close to the boundaries of its parent (e.g. with zero WindowPadding), the child + position could have temporarily be moved around by erroneous padding application. (#7706) - TabBar, Style: added ImGuiTabBarFlags_DrawSelectedOverline option to draw an horizontal line over selected tabs to increase visibility. This is used by docking. Added corresponding ImGuiCol_TabSelectedOverline and ImGuiCol_TabDimmedSelectedOverline colors. diff --git a/imgui.cpp b/imgui.cpp index 72f1f1871..114aeee25 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6140,12 +6140,13 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si border_target = ImClamp(border_target, clamp_min, clamp_max); if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent { - ImGuiWindowFlags parent_flags = window->ParentWindow->Flags; - ImRect border_limit_rect = window->ParentWindow->InnerRect; - border_limit_rect.Expand(ImVec2(-ImMax(window->WindowPadding.x, window->WindowBorderSize), -ImMax(window->WindowPadding.y, window->WindowBorderSize))); - if ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar)) + ImGuiWindow* parent_window = window->ParentWindow; + ImGuiWindowFlags parent_flags = parent_window->Flags; + ImRect border_limit_rect = parent_window->InnerRect; + border_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize))); + if ((axis == ImGuiAxis_X) && ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar))) border_target.x = ImClamp(border_target.x, border_limit_rect.Min.x, border_limit_rect.Max.x); - if (parent_flags & ImGuiWindowFlags_NoScrollbar) + if ((axis == ImGuiAxis_Y) && (parent_flags & ImGuiWindowFlags_NoScrollbar)) border_target.y = ImClamp(border_target.y, border_limit_rect.Min.y, border_limit_rect.Max.y); } if (!ignore_resize) From 0582f7678a4447d9d36e3f2385d990f4885d44e1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Jun 2024 19:05:47 +0200 Subject: [PATCH 07/10] Nav: store NavJustMovedToIsTabbing + shuffle a few nav related fields. (for usage by multi-select) --- imgui.cpp | 5 +++++ imgui_internal.h | 26 ++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 114aeee25..25423664a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12393,6 +12393,8 @@ void ImGui::NavInitRequestApplyResult() g.NavJustMovedToId = result->ID; g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = 0; + g.NavJustMovedToIsTabbing = false; + g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0; } // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) @@ -12649,6 +12651,9 @@ void ImGui::NavMoveRequestApplyResult() g.NavJustMovedToId = result->ID; g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = g.NavMoveKeyMods; + g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0; + g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0; + //IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId); } // Apply new NavID/Focus diff --git a/imgui_internal.h b/imgui_internal.h index 9bbbc5eca..b75f9a324 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1599,7 +1599,7 @@ struct ImGuiNavItemData float DistBox; // Move // Best candidate box distance to current NavId float DistCenter; // Move // Best candidate center distance to current NavId float DistAxial; // Move // Best candidate axial distance to current NavId - ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value. + ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (InFlags & ImGuiItemFlags_HasSelectionUserData) ImGuiNavItemData() { Clear(); } void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } @@ -2044,6 +2044,7 @@ struct ImGuiContext ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavId; // Focused item for navigation ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope) + ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer) ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) @@ -2051,13 +2052,9 @@ struct ImGuiContext ImVector NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain. ImGuiID NavHighlightActivatedId; float NavHighlightActivatedTimer; - ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). - ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). - ImGuiKeyChord NavJustMovedToKeyMods; ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. ImGuiActivateFlags NavNextActivateFlags; ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse - ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) @@ -2088,6 +2085,14 @@ struct ImGuiContext ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy + // Navigation: record of last move request + ImGuiID NavJustMovedFromFocusScopeId; // Just navigated from this focus scope id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). + ImGuiKeyChord NavJustMovedToKeyMods; + bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags. + bool NavJustMovedToHasSelectionData; // Copy of move result's InFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. + // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiKey_Tab on OS X). For reconfiguration (see #4828) ImGuiKeyChord ConfigNavWindowingKeyPrev; // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab on OS X) @@ -2324,18 +2329,18 @@ struct ImGuiContext NavWindow = NULL; NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; - NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; + NavLayer = ImGuiNavLayer_Main; + NavNextActivateId = 0; NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; NavHighlightActivatedId = 0; NavHighlightActivatedTimer = 0.0f; - NavJustMovedToKeyMods = ImGuiMod_None; NavInputSource = ImGuiInputSource_Keyboard; - NavLayer = ImGuiNavLayer_Main; NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; NavIdIsAlive = false; NavMousePosDirty = false; NavDisableHighlight = true; NavDisableMouseHover = false; + NavAnyRequest = false; NavInitRequest = false; NavInitRequestFromMove = false; @@ -2350,6 +2355,11 @@ struct ImGuiContext NavTabbingDir = 0; NavTabbingCounter = 0; + NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0; + NavJustMovedToKeyMods = ImGuiMod_None; + NavJustMovedToIsTabbing = false; + NavJustMovedToHasSelectionData = false; + // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac... // FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this.. ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab); From 404af57004917e4b7cb763d416a78f2acf990055 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 28 Jun 2024 15:04:52 +0200 Subject: [PATCH 08/10] Backends: OpenGL2, OpenGL3: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748) Analogous to change to Vulkan backend in 1.90. --- backends/imgui_impl_opengl2.cpp | 3 +++ backends/imgui_impl_opengl3.cpp | 3 +++ docs/CHANGELOG.txt | 2 ++ 3 files changed, 8 insertions(+) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 3eb092afd..7f1ea325a 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-12-08: OpenGL: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). @@ -113,6 +114,8 @@ void ImGui_ImplOpenGL2_NewFrame() if (!bd->FontTexture) ImGui_ImplOpenGL2_CreateDeviceObjects(); + if (!bd->FontTexture) + ImGui_ImplOpenGL2_CreateFontsTexture(); } static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 58603a047..bbe96c420 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-06-28: OpenGL: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748) // 2024-05-07: OpenGL: Update loader for Linux to support EGL/GLVND. (#7562) // 2024-04-16: OpenGL: Detect ES3 contexts on desktop based on version string, to e.g. avoid calling glPolygonMode() on them. (#7447) // 2024-01-09: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" and variants, fixing regression on distros missing a symlink. @@ -402,6 +403,8 @@ void ImGui_ImplOpenGL3_NewFrame() if (!bd->ShaderHandle) ImGui_ImplOpenGL3_CreateDeviceObjects(); + if (!bd->FontTexture) + ImGui_ImplOpenGL3_CreateFontsTexture(); } static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4b9b12c79..18871c060 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -90,6 +90,8 @@ Other changes: - Debug Tools: Metrics/Debugger: Browsing a Storage perform hover lookup on identifier. - Viewports: Backported 'void* ImGuiViewport::PlatformHandle' from docking branch for use by backends. +- Backends: OpenGL2, OpenGL3: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it + has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748) [@mlauss2] - Backends: SDL3: Update for API removal of keysym field in SDL_KeyboardEvent. (#7728) - Backends: SDL3: Update for SDL_StartTextInput()/SDL_StopTextInput() API changes. (#7735) - Backends: Vulkan: Remove Volk/ from volk.h #include directives. (#7722, #6582, #4854) From c7df9c71214a16790eaa2d202a5fd7b9f164578f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 28 Jun 2024 15:48:08 +0200 Subject: [PATCH 09/10] Backends: Win32: Fixed warning with old MinGW/GCC versions. --- backends/imgui_impl_win32.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index b0f694057..9241f8edb 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -98,6 +98,7 @@ typedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*); #endif #if defined(__GNUC__) #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader) #endif From 0403096a9d3574d6c07eda91daf79d45e3fbf927 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 28 Jun 2024 15:54:40 +0200 Subject: [PATCH 10/10] Drags: added ImGuisliderFlags_WrapAround flag for DragInt(), DragFloat() etc. (#7749) --- docs/CHANGELOG.txt | 1 + imgui.h | 5 +++-- imgui_demo.cpp | 12 ++++++++---- imgui_widgets.cpp | 37 +++++++++++++++++++++++++------------ 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 18871c060..d3f328494 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,7 @@ Other changes: Added corresponding ImGuiCol_TabSelectedOverline and ImGuiCol_TabDimmedSelectedOverline colors. - Tables: added TableGetHoveredColumn() to public API, as an alternative to testing for 'TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered' on each column. (#3740) +- Drags: added ImGuisliderFlags_WrapAround flag for DragInt(), DragFloat() etc. (#7749) - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern sets active id so a multi-frame extern source doesn't interfere with hovered widgets. (#143) - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern does not assume diff --git a/imgui.h b/imgui.h index ff8778c03..1ba242aa0 100644 --- a/imgui.h +++ b/imgui.h @@ -1732,8 +1732,9 @@ enum ImGuiSliderFlags_ ImGuiSliderFlags_None = 0, ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. - ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) - ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits). + ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget. + ImGuisliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions for now. ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. // Obsolete names diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7bc4281cf..745258617 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -720,18 +720,19 @@ static void ShowDemoWindowWidgets() { IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); - static int i1 = 50, i2 = 42; + static int i1 = 50, i2 = 42, i3 = 128; ImGui::DragInt("drag int", &i1, 1); ImGui::SameLine(); HelpMarker( "Click and drag to edit value.\n" "Hold SHIFT/ALT for faster/slower edit.\n" "Double-click or CTRL+click to input value."); - ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuisliderFlags_WrapAround); static float f1 = 1.00f, f2 = 0.0067f; ImGui::DragFloat("drag float", &f1, 0.005f); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuisliderFlags_WrapAround); } ImGui::SeparatorText("Sliders"); @@ -2145,6 +2146,8 @@ static void ShowDemoWindowWidgets() ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); + ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuisliderFlags_WrapAround); + ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); // Drags static float drag_f = 0.5f; @@ -2159,9 +2162,10 @@ static void ShowDemoWindowWidgets() // Sliders static float slider_f = 0.5f; static int slider_i = 50; + const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuisliderFlags_WrapAround; ImGui::Text("Underlying float value: %f", slider_f); - ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags); - ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags); + ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders); + ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders); ImGui::TreePop(); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 927cb2b98..41a14bf3d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2305,12 +2305,13 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const { ImGuiContext& g = *GImGui; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_clamped = (v_min < v_max); + const bool is_bounded = (v_min < v_max); + const bool is_wrapped = is_bounded && (flags & ImGuisliderFlags_WrapAround); const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); // Default tweak speed - if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) + if (v_speed == 0.0f && is_bounded && (v_max - v_min < FLT_MAX)) v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings @@ -2344,8 +2345,8 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const // Clear current value on activation // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. - bool is_just_activated = g.ActiveIdIsJustActivated; - bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + const bool is_just_activated = g.ActiveIdIsJustActivated; + const bool is_already_past_limits_and_pushing_outward = is_bounded && !is_wrapped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); if (is_just_activated || is_already_past_limits_and_pushing_outward) { g.DragCurrentAccum = 0.0f; @@ -2403,13 +2404,24 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (v_cur == (TYPE)-0) v_cur = (TYPE)0; - // Clamp values (+ handle overflow/wrap-around for integer types) - if (*v != v_cur && is_clamped) + if (*v != v_cur && is_bounded) { - if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point)) - v_cur = v_min; - if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point)) - v_cur = v_max; + if (is_wrapped) + { + // Wrap values + if (v_cur < v_min) + v_cur += v_max - v_min + (is_floating_point ? 0 : 1); + if (v_cur > v_max) + v_cur -= v_max - v_min + (is_floating_point ? 0 : 1); + } + else + { + // Clamp values + handle overflow/wrap-around for integer types. + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point)) + v_cur = v_max; + } } // Apply result @@ -2422,7 +2434,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. - IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); ImGuiContext& g = *GImGui; if (g.ActiveId == id) @@ -3015,7 +3027,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) { // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. - IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + IM_ASSERT((flags & ImGuisliderFlags_WrapAround) == 0); // Not supported by SliderXXX(), only by DragXXX() switch (data_type) {