From 61f4aec8687db426ec7100dda9fa27ff77833143 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Jun 2021 15:28:59 +0200 Subject: [PATCH 01/15] Added PushDisabled(), PopDisabled() currently only exposed in imgui_internal.h (#211) --- imgui.cpp | 22 ++++++++++++++++++++++ imgui.h | 2 +- imgui_internal.h | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 25c779f6..c4568d17 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6575,6 +6575,28 @@ void ImGui::PopItemFlag() g.CurrentItemFlags = g.ItemFlagsStack.back(); } +// PushDisabled()/PopDisabled() +// - Those are not yet exposed in imgui.h because we are unsure of how to alter the style in a way that works for everyone. +// We may rework this. Hypothetically, a future styling system may set a flag which make widgets use different colors. +// - Feedback welcome at https://github.com/ocornut/imgui/issues/211 +// - You may trivially implement your own variation of this if needed. +// Here we test (CurrentItemFlags & ImGuiItemFlags_Disabled) to allow nested PushDisabled() calls. +void ImGui::PushDisabled() +{ + ImGuiContext& g = *GImGui; + if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) + PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.6f); + PushItemFlag(ImGuiItemFlags_Disabled, true); +} + +void ImGui::PopDisabled() +{ + ImGuiContext& g = *GImGui; + PopItemFlag(); + if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) + PopStyleVar(); +} + // FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) { diff --git a/imgui.h b/imgui.h index 8058012b..7e2e75bd 100644 --- a/imgui.h +++ b/imgui.h @@ -61,7 +61,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.84 WIP" -#define IMGUI_VERSION_NUM 18305 +#define IMGUI_VERSION_NUM 18306 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE diff --git a/imgui_internal.h b/imgui_internal.h index d379ef0a..2554eeda 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2379,6 +2379,8 @@ namespace ImGui IMGUI_API void PushMultiItemsWidths(int components, float width_full); IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); + IMGUI_API void PushDisabled(); + IMGUI_API void PopDisabled(); IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); From d0c6dd9bafcfb0845153080fe00d74e62ad28c86 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Jun 2021 16:57:35 +0200 Subject: [PATCH 02/15] ImVector: added clear_delete(), clear_destruct() helpers. --- imgui.cpp | 15 ++++----------- imgui.h | 9 ++++++--- imgui_draw.cpp | 9 +++------ misc/freetype/imgui_freetype.cpp | 3 +-- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c4568d17..7aa91ceb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2927,8 +2927,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) @@ -4189,9 +4188,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; @@ -4207,18 +4204,14 @@ void ImGui::Shutdown(ImGuiContext* context) g.OpenPopupStack.clear(); g.BeginPopupStack.clear(); - 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(); diff --git a/imgui.h b/imgui.h index 7e2e75bd..7465559c 100644 --- a/imgui.h +++ b/imgui.h @@ -61,7 +61,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.84 WIP" -#define IMGUI_VERSION_NUM 18306 +#define IMGUI_VERSION_NUM 18307 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE @@ -1667,7 +1667,11 @@ struct ImVector inline ImVector() { Size = Capacity = 0; Data = NULL; } inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } - inline ~ImVector() { if (Data) IM_FREE(Data); } + inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything + + inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything + inline void clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); } // Important: never called automatically! always explicit. + inline void clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); } // Important: never called automatically! always explicit. inline bool empty() const { return Size == 0; } inline int size() const { return Size; } @@ -1677,7 +1681,6 @@ struct ImVector inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } - inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } inline T* begin() { return Data; } inline const T* begin() const { return Data; } inline T* end() { return Data + Size; } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 190c4c7b..ca435bb5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2006,9 +2006,7 @@ void ImFontAtlas::ClearTexData() void ImFontAtlas::ClearFonts() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - for (int i = 0; i < Fonts.Size; i++) - IM_DELETE(Fonts[i]); - Fonts.clear(); + Fonts.clear_delete(); } void ImFontAtlas::Clear() @@ -2568,9 +2566,8 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) } } - // Cleanup temporary (ImVector doesn't honor destructor) - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - src_tmp_array[src_i].~ImFontBuildSrcData(); + // Cleanup + src_tmp_array.clear_destruct(); ImFontAtlasBuildFinish(atlas); return true; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index db6ec946..e6221f4b 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -688,8 +688,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // Cleanup for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++) IM_FREE(buf_bitmap_buffers[buf_i]); - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - src_tmp_array[src_i].~ImFontBuildSrcDataFT(); + src_tmp_array.clear_destruct(); ImFontAtlasBuildFinish(atlas); From 98a6292165f0f8f12f8b0a7631b73a362664a418 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Jun 2021 17:43:20 +0200 Subject: [PATCH 03/15] Backends: DX12: Fix texture casting crash on 32-bit systems (introduced on 2021/05/19 and v1.83) + added comments about building on 32-bit systems. (#4225) --- backends/imgui_impl_dx12.cpp | 17 ++++++++++++++--- docs/CHANGELOG.txt | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 63071b89..fc88b8c9 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -7,9 +7,13 @@ // Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. // This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. -// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file. +// To build this on 32-bit systems: +// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file) +// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like. +// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!) +// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file) -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs @@ -242,7 +246,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL if (r.right > r.left && r.bottom > r.top) { D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {}; - texture_handle.ptr = (UINT64)(intptr_t)pcmd->GetTexID(); + texture_handle.ptr = (UINT64)pcmd->GetTexID(); ctx->SetGraphicsRootDescriptorTable(1, texture_handle); ctx->RSSetScissorRects(1, &r); ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); @@ -399,6 +403,13 @@ static void ImGui_ImplDX12_CreateFontsTexture() } // Store our identifier + // READ THIS IF THE STATIC_ASSERT() TRIGGERS: + // - Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. + // - This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. + // [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file) + // [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like. + // [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!) + // [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file) static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); io.Fonts->SetTexID((ImTextureID)g_hFontSrvGpuDescHandle.ptr); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index eab19eb1..e03c4a31 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Other Changes: - Backends: Win32: Rework to handle certains Windows 8.1/10 features without a manifest. (#4200, #4191) - ImGui_ImplWin32_GetDpiScaleForMonitor() will handle per-monitor DPI on Windows 10 without a manifest. - ImGui_ImplWin32_EnableDpiAwareness() will call SetProcessDpiAwareness() fallback on Windows 8.1 without a manifest. +- Backends: DX12: Fix texture casting crash on 32-bit systems (introduced on 2021/05/19 and v1.83) + added comments + about building on 32-bit systems. (#4225) [@kingofthebongo2008] - Backends: OpenGL3: Handle GL_CLIP_ORIGIN on <4.5 contexts if "GL_ARB_clip_control" extension is detected. (#4170, #3998) - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg. - Examples: SDL2: Accomodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. From 0cca0d1617f5513a0bff4898c5a7c26cc6887012 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Jun 2021 15:16:39 +0200 Subject: [PATCH 04/15] Internals/experimental: BeginComboPreview(), EndComboPreview(). (#4168, #1658) (amended) --- docs/TODO.txt | 2 +- imgui.h | 1 + imgui_demo.cpp | 6 +++-- imgui_draw.cpp | 12 ++++++++++ imgui_internal.h | 22 +++++++++++++++++ imgui_widgets.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 3 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 146f6970..268b9b8e 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -184,7 +184,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - combo: use clipper: make it easier to disable clipper with a single flag. - combo: flag for BeginCombo to not return true when unchanged (#1182) - - combo: a way/helper to customize the combo preview (#1658) + - combo: a way/helper to customize the combo preview (#1658) -> exeperimental BeginComboPreview() - combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203) - listbox: multiple selection. - listbox: unselect option (#1208) diff --git a/imgui.h b/imgui.h index 7465559c..10ffcb6d 100644 --- a/imgui.h +++ b/imgui.h @@ -2463,6 +2463,7 @@ struct ImDrawList IMGUI_API void _ResetForNewFrame(); IMGUI_API void _ClearFreeMemory(); IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _TryMergeDrawCmds(); IMGUI_API void _OnChangedClipRect(); IMGUI_API void _OnChangedTextureID(); IMGUI_API void _OnChangedVtxOffset(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0c9b92b1..513ba661 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1026,8 +1026,8 @@ static void ShowDemoWindowWidgets() // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; static int item_current_idx = 0; // Here we store our selection data as an index. - const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically it could be anything) - if (ImGui::BeginCombo("combo 1", combo_label, flags)) + const char* combo_preview_value = items[item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything) + if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { @@ -1043,10 +1043,12 @@ static void ShowDemoWindowWidgets() } // Simplified one-liner Combo() API, using values packed in a single constant string + // This is a convenience for when the selection set is small and known at compile-time. static int item_current_2 = 0; ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); // Simplified one-liner Combo() using an array of const char* + // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ca435bb5..15d738df 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -491,6 +491,18 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) #define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset #define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset +// Try to merge two last draw commands +void ImDrawList::_TryMergeDrawCmds() +{ + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) + { + prev_cmd->ElemCount += curr_cmd->ElemCount; + CmdBuffer.pop_back(); + } +} + // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. void ImDrawList::_OnChangedClipRect() diff --git a/imgui_internal.h b/imgui_internal.h index 2554eeda..9caf5940 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -808,6 +808,12 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease }; +// Extend ImGuiComboFlags_ +enum ImGuiComboFlagsPrivate_ +{ + ImGuiComboFlags_CustomPreview = 1 << 20 // enable BeginComboPreview() +}; + // Extend ImGuiSliderFlags_ enum ImGuiSliderFlagsPrivate_ { @@ -996,6 +1002,19 @@ struct ImGuiStyleMod ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } }; +// Storage data for BeginComboPreview()/EndComboPreview() +struct IMGUI_API ImGuiComboPreviewData +{ + ImRect PreviewRect; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec2 BackupCursorPosPrevLine; + float BackupPrevLineTextBaseOffset; + ImGuiLayoutType BackupLayout; + + ImGuiComboPreviewData() { memset(this, 0, sizeof(*this)); } +}; + // Stacked storage data for BeginGroup()/EndGroup() struct IMGUI_API ImGuiGroupData { @@ -1552,6 +1571,7 @@ struct ImGuiContext float ColorEditLastSat; // Backup of last Saturation associated to LastColor[3], so we can restore Saturation in lossy RGB<>HSV round trips float ColorEditLastColor[3]; ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. + ImGuiComboPreviewData ComboPreviewData; float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? bool DragCurrentAccumDirty; @@ -2416,6 +2436,8 @@ namespace ImGui // Combos IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); + IMGUI_API bool BeginComboPreview(); + IMGUI_API void EndComboPreview(); // Gamepad/Keyboard Navigation IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5e7b1c81..593c8ef0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1541,6 +1541,8 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc // - BeginCombo() // - BeginComboPopup() [Internal] // - EndCombo() +// - BeginComboPreview() [Internal] +// - EndComboPreview() [Internal] // - Combo() //------------------------------------------------------------------------- @@ -1602,6 +1604,14 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF } RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); + // Custom preview + if (flags & ImGuiComboFlags_CustomPreview) + { + g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y); + IM_ASSERT(preview_value == NULL || preview_value[0] == 0); + preview_value = NULL; + } + // Render preview and label if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) { @@ -1683,6 +1693,57 @@ void ImGui::EndCombo() EndPopup(); } +// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements +// (Experimental, see GitHub issues: #1658, #4168) +bool ImGui::BeginComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + if (window->SkipItems || !window->ClipRect.Overlaps(window->DC.LastItemRect)) // FIXME: Because we don't have a ImGuiItemStatusFlags_Visible flag to test last ItemAdd() result + return false; + IM_ASSERT(window->DC.LastItemRect.Min.x == preview_data->PreviewRect.Min.x && window->DC.LastItemRect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? + if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional) + return false; + + // FIXME: This could be contained in a PushWorkRect() api + preview_data->BackupCursorPos = window->DC.CursorPos; + preview_data->BackupCursorMaxPos = window->DC.CursorMaxPos; + preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine; + preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + preview_data->BackupLayout = window->DC.LayoutType; + window->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + PushClipRect(preview_data->PreviewRect.Min, preview_data->PreviewRect.Max, true); + + return true; +} + +void ImGui::EndComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + // FIXME: Using CursorMaxPos approximation instead of correct AABB which we will store in ImDrawCmd in the future + ImDrawList* draw_list = window->DrawList; + if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y) + if (draw_list->CmdBuffer.Size > 1) // Unlikely case that the PushClipRect() didn't create a command + { + draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect; + draw_list->_TryMergeDrawCmds(); + } + PopClipRect(); + window->DC.CursorPos = preview_data->BackupCursorPos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); + window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine; + window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset; + window->DC.LayoutType = preview_data->BackupLayout; + preview_data->PreviewRect = ImRect(); +} + // Getter for the old Combo() API: const char*[] static bool Items_ArrayGetter(void* data, int idx, const char** out_text) { From dc676236f0c3c19159d3e0a5cd1e5c0c4cc5613d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Jun 2021 17:02:02 +0200 Subject: [PATCH 05/15] Minor optimization, removing do/while(0) patterns in some cases as they translate to runtime (e.g. translate to xor + test + jne in VS x84, unnecessary) --- imgui_draw.cpp | 7 ++++--- imgui_internal.h | 6 +----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 15d738df..ea559bdf 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -705,10 +705,11 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c } // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. -// Those macros expects l-values. -#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) +// - Those macros expects l-values and need to be used as their own statement. +// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0 #define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) -#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } while (0) +#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0 // TODO: Thickness anti-aliased lines cap are missing their AA fringe. // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. diff --git a/imgui_internal.h b/imgui_internal.h index 9caf5940..d064b9dd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2709,11 +2709,7 @@ extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, #define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA)); #define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2)); #else -#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) do { } while (0) -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) do { } while (0) -#define IMGUI_TEST_ENGINE_LOG(_FMT,...) do { } while (0) -#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) do { } while (0) -#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) do { } while (0) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)0) #endif //----------------------------------------------------------------------------- From d5828cd988db525f27128edeadb1a689cd2d7461 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Wed, 16 Jun 2021 15:42:21 +0200 Subject: [PATCH 06/15] SplitterBehavior: fix using IsItemHovered() after SplitterBehavior() --- imgui_widgets.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 593c8ef0..1a75efed 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1444,6 +1444,8 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float ImRect bb_interact = bb; bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + if (hovered) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb if (g.ActiveId != id) SetItemAllowOverlap(); From 7c44d067e8d1662549db73f80099e01a9c1a5f46 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Jun 2021 15:18:11 +0200 Subject: [PATCH 07/15] Tables: Fix invalid data in TableGetSortSpecs() when SpecsDirty flag is unset. (#4233) Amend 4ce6bd8cf, but with usage of ImPool<> bug existed even before 4ce6bd8c. Would only materialize if user called (ableGetSortSpecs and used data without checking SpecsDirty. --- docs/CHANGELOG.txt | 1 + imgui_internal.h | 5 ++--- imgui_tables.cpp | 26 ++++++++++++++------------ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e03c4a31..6fb4f098 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,7 @@ Other Changes: - Tables: Added ImGuiTableColumnFlags_NoHeaderLabel to request TableHeadersRow() to not submit label for a column. Convenient for some small columns. Name will still appear in context menu. (#4206). - Tables: Fix columns order on TableSetupScrollFreeze() if previous data got frozen columns out of their section. +- Tables: Fix invalid data in TableGetSortSpecs() when SpecsDirty flag is unset. (#4233) - Fixed printf-style format checks on non-MinGW flavors. (#4183, #3592) - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid diff --git a/imgui_internal.h b/imgui_internal.h index d064b9dd..09dc408c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2188,6 +2188,8 @@ struct ImGuiTable ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window) ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() ImGuiTableColumnIdx SortSpecsCount; ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) @@ -2237,7 +2239,6 @@ struct ImGuiTable // Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table). // - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. // - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. -// FIXME-TABLE: more transient data could be stored here: DrawSplitter, incoming RowData? struct ImGuiTableTempData { int TableIndex; // Index in g.Tables.Buf[] pool @@ -2245,8 +2246,6 @@ struct ImGuiTableTempData ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() ImDrawListSplitter DrawSplitter; - ImGuiTableColumnSortSpecs SortSpecsSingle; - ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable() diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 71ee70d5..74c7cd12 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2613,8 +2613,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() if (!table->IsLayoutLocked) TableUpdateLayout(table); - if (table->IsSortSpecsDirty) - TableSortSpecsBuild(table); + TableSortSpecsBuild(table); return &table->SortSpecs; } @@ -2753,14 +2752,18 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table) void ImGui::TableSortSpecsBuild(ImGuiTable* table) { - IM_ASSERT(table->IsSortSpecsDirty); - TableSortSpecsSanitize(table); + bool dirty = table->IsSortSpecsDirty; + if (dirty) + { + TableSortSpecsSanitize(table); + table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + table->SortSpecs.SpecsDirty = true; // Mark as dirty for user + table->IsSortSpecsDirty = false; // Mark as not dirty for us + } // Write output - ImGuiTableTempData* temp_data = table->TempData; - temp_data->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); - ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &temp_data->SortSpecsSingle : temp_data->SortSpecsMulti.Data; - if (sort_specs != NULL) + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; + if (dirty && sort_specs != NULL) for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; @@ -2773,10 +2776,9 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table) sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; sort_spec->SortDirection = column->SortDirection; } + table->SortSpecs.Specs = sort_specs; table->SortSpecs.SpecsCount = table->SortSpecsCount; - table->SortSpecs.SpecsDirty = true; // Mark as dirty for user - table->IsSortSpecsDirty = false; // Mark as not dirty for us } //------------------------------------------------------------------------- @@ -3465,7 +3467,8 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) ImGuiContext& g = *GImGui; IM_ASSERT(table->MemoryCompacted == false); table->SortSpecs.Specs = NULL; - table->IsSortSpecsDirty = true; + table->SortSpecsMulti.clear(); + table->IsSortSpecsDirty = true; // FIXME: shouldn't have to leak into user performing a sort table->ColumnsNames.clear(); table->MemoryCompacted = true; for (int n = 0; n < table->ColumnsCount; n++) @@ -3476,7 +3479,6 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) { temp_data->DrawSplitter.ClearFreeMemory(); - temp_data->SortSpecsMulti.clear(); temp_data->LastTimeActive = -1.0f; } From 0905439c31bfa21046b025a54706e7257eb51226 Mon Sep 17 00:00:00 2001 From: Ivan Sokolov Date: Sat, 19 Jun 2021 21:04:16 +0300 Subject: [PATCH 08/15] Backends: OpenGL3: Destroy shader objects right away (#4244) In OpenGL, after a shader program has been linked, shader objects don't need to be kept neither attached to the program nor in existence --- backends/imgui_impl_opengl3.cpp | 35 ++++++++++++++++++--------------- docs/CHANGELOG.txt | 1 + 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 712de9b2..2048603c 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -7,13 +7,14 @@ // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader. // 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version. // 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater. @@ -155,7 +156,7 @@ using namespace gl; static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. static GLuint g_FontTexture = 0; -static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; +static GLuint g_ShaderHandle = 0; static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; @@ -693,23 +694,29 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() // Create shaders const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; - g_VertHandle = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); - glCompileShader(g_VertHandle); - CheckShader(g_VertHandle, "vertex shader"); + GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vert_handle, 2, vertex_shader_with_version, NULL); + glCompileShader(vert_handle); + CheckShader(vert_handle, "vertex shader"); const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader }; - g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); - glCompileShader(g_FragHandle); - CheckShader(g_FragHandle, "fragment shader"); + GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(frag_handle, 2, fragment_shader_with_version, NULL); + glCompileShader(frag_handle); + CheckShader(frag_handle, "fragment shader"); + // Link g_ShaderHandle = glCreateProgram(); - glAttachShader(g_ShaderHandle, g_VertHandle); - glAttachShader(g_ShaderHandle, g_FragHandle); + glAttachShader(g_ShaderHandle, vert_handle); + glAttachShader(g_ShaderHandle, frag_handle); glLinkProgram(g_ShaderHandle); CheckProgram(g_ShaderHandle, "shader program"); + glDetachShader(g_ShaderHandle, vert_handle); + glDetachShader(g_ShaderHandle, frag_handle); + glDeleteShader(vert_handle); + glDeleteShader(frag_handle); + g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position"); @@ -736,10 +743,6 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects() { if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; } if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; } - if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); } - if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); } - if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; } - if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; } if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; } ImGui_ImplOpenGL3_DestroyFontsTexture(); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6fb4f098..c4ba4781 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,7 @@ Other Changes: - Backends: DX12: Fix texture casting crash on 32-bit systems (introduced on 2021/05/19 and v1.83) + added comments about building on 32-bit systems. (#4225) [@kingofthebongo2008] - Backends: OpenGL3: Handle GL_CLIP_ORIGIN on <4.5 contexts if "GL_ARB_clip_control" extension is detected. (#4170, #3998) +- Backends: OpenGL3: Destroy vertex/fragment shader objects right after they are linked into main shader. (#4244) [@Crowbarous] - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg. - Examples: SDL2: Accomodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. From 98876b4dc233d4b2cea22cc9a6d3e49a6ac2d59d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Jun 2021 14:52:01 +0200 Subject: [PATCH 09/15] Added IMGUI_DISABLE_SSE (#4250, #4091) --- imconfig.h | 1 + imgui_internal.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/imconfig.h b/imconfig.h index e0a2155a..769e7391 100644 --- a/imconfig.h +++ b/imconfig.h @@ -45,6 +45,7 @@ //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). +//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Include imgui_user.h at the end of imgui.h as a convenience //#define IMGUI_INCLUDE_IMGUI_USER_H diff --git a/imgui_internal.h b/imgui_internal.h index 09dc408c..6755adea 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -52,7 +52,7 @@ Index of this file: #include // INT_MIN, INT_MAX // Enable SSE intrinsics if available -#if defined __SSE__ || defined __x86_64__ || defined _M_X64 +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64) && !defined(IMGUI_DISABLE_SSE) #define IMGUI_ENABLE_SSE #include #endif From a15c42d5bd16c2fe49ffb0ac383e4236034e7ef5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Jun 2021 16:58:38 +0200 Subject: [PATCH 10/15] Nav: moved RenderNavHighlight() calls of TreeNode and Selectable out of if (hovered || selected) tests. Should make no difference as NavId currently returns hovered. (#1861, #4242) --- imgui_demo.cpp | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 513ba661..04858d0b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1115,7 +1115,7 @@ static void ShowDemoWindowWidgets() static bool selection[5] = { false, true, false, false, false }; ImGui::Selectable("1. I am selectable", &selection[0]); ImGui::Selectable("2. I am selectable", &selection[1]); - ImGui::Text("3. I am not selectable"); + ImGui::Text("(I am not selectable)"); ImGui::Selectable("4. I am selectable", &selection[3]); if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) if (ImGui::IsMouseDoubleClicked(0)) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 74c7cd12..1c7fbcf4 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2921,7 +2921,6 @@ void ImGui::TableHeader(const char* label) const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); //RenderFrame(bb.Min, bb.Max, col, false, 0.0f); TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); } else { @@ -2929,6 +2928,7 @@ void ImGui::TableHeader(const char* label) if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); if (held) table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1a75efed..e0806945 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5943,8 +5943,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); - RenderNavHighlight(frame_bb, id, nav_highlight_flags); } + RenderNavHighlight(frame_bb, id, nav_highlight_flags); if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) @@ -6207,8 +6207,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl { const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb.Min, bb.Max, col, false, 0.0f); - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); if (span_all_columns && window->DC.CurrentColumns) PopColumnsBackground(); From f0c4d609a6186b0b6db5022eb07a75656b8f399d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Jun 2021 17:37:37 +0200 Subject: [PATCH 11/15] Default window focus scope not 0. Added ImGuiSelectableFlags_SelectOnNav with comments and caveats. (#1861, #4242,) Focus scope default value: amend 7ee623d9 a5041c88 2ebe08be --- imgui.cpp | 2 +- imgui.h | 2 +- imgui_demo.cpp | 1 + imgui_internal.h | 13 +++++++------ imgui_widgets.cpp | 11 +++++++++++ 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7aa91ceb..0988fb7e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6309,7 +6309,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 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); diff --git a/imgui.h b/imgui.h index 10ffcb6d..b954f29c 100644 --- a/imgui.h +++ b/imgui.h @@ -61,7 +61,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.84 WIP" -#define IMGUI_VERSION_NUM 18307 +#define IMGUI_VERSION_NUM 18308 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 04858d0b..ecceed84 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6702,6 +6702,7 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::BeginChild("left pane", ImVec2(150, 0), true); for (int i = 0; i < 100; i++) { + // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav char label[128]; sprintf(label, "MyObject %d", i); if (ImGui::Selectable(label, selected == i)) diff --git a/imgui_internal.h b/imgui_internal.h index 6755adea..7fe1ab3f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -826,12 +826,13 @@ enum ImGuiSelectableFlagsPrivate_ { // NB: need to be in sync with last value of ImGuiSelectableFlags_ ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, - ImGuiSelectableFlags_SelectOnClick = 1 << 21, // Override button behavior to react on Click (default is Click+Release) - ImGuiSelectableFlags_SelectOnRelease = 1 << 22, // Override button behavior to react on Release (default is Click+Release) - ImGuiSelectableFlags_SpanAvailWidth = 1 << 23, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) - ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 24, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. - ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, // Set Nav/Focus ID on mouse hover (used by MenuItem) - ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26 // Disable padding each side with ItemSpacing * 0.5f + ImGuiSelectableFlags_SelectOnNav = 1 << 21, // (WIP) Auto-select when moved into. This is not exposed in public API as to handle multi-select and modifiers we will need user to explicitly control focus scope. May be replaced with a BeginSelection() API. + ImGuiSelectableFlags_SelectOnClick = 1 << 22, // Override button behavior to react on Click (default is Click+Release) + ImGuiSelectableFlags_SelectOnRelease = 1 << 23, // Override button behavior to react on Release (default is Click+Release) + ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) + ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 25, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 26, // Set Nav/Focus ID on mouse hover (used by MenuItem) + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 27 // Disable padding each side with ItemSpacing * 0.5f }; // Extend ImGuiTreeNodeFlags_ diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e0806945..994f8a43 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6181,6 +6181,17 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + // Auto-select when moved into + // - This will be more fully fleshed in the range-select branch + // - This is not exposed as it won't nicely work with some user side handling of shift/control + // - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons + // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) + // - (2) usage will fail with clipped items + // The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. + if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == window->DC.NavFocusScopeIdCurrent) + if (g.NavJustMovedToId == id) + selected = pressed = true; + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { From 0b8a2470743f89d19ab2d5920606434b604b529e Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Wed, 23 Jun 2021 15:15:22 +0300 Subject: [PATCH 12/15] Backends: OSX: Added a fix for shortcuts using CTRL key instead of CMD key. (#4253) --- backends/imgui_impl_osx.mm | 7 ++++--- docs/CHANGELOG.txt | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 81fc1982..2fcb7124 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -8,7 +8,7 @@ // Issues: // [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters].. -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs @@ -19,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key. // 2021-04-19: Inputs: Added a fix for keys remaining stuck in pressed state when CMD-tabbing into different application. // 2021-01-27: Inputs: Added a fix for mouse position not being reported when mouse buttons other than left one are down. // 2020-10-28: Inputs: Added a fix for handling keypad-enter key. @@ -303,12 +304,12 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) for (NSUInteger i = 0; i < len; i++) { int c = [str characterAtIndex:i]; - if (!io.KeyCtrl && !(c >= 0xF700 && c <= 0xFFFF) && c != 127) + if (!io.KeySuper && !(c >= 0xF700 && c <= 0xFFFF) && c != 127) io.AddInputCharacter((unsigned int)c); // We must reset in case we're pressing a sequence of special keys while keeping the command pressed int key = mapCharacterToKey(c); - if (key != -1 && key < 256 && !io.KeyCtrl) + if (key != -1 && key < 256 && !io.KeySuper) resetKeys(); if (key != -1) io.KeysDown[key] = true; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c4ba4781..81ec3c22 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -55,6 +55,7 @@ Other Changes: about building on 32-bit systems. (#4225) [@kingofthebongo2008] - Backends: OpenGL3: Handle GL_CLIP_ORIGIN on <4.5 contexts if "GL_ARB_clip_control" extension is detected. (#4170, #3998) - Backends: OpenGL3: Destroy vertex/fragment shader objects right after they are linked into main shader. (#4244) [@Crowbarous] +- Backends: OSX: Added a fix for shortcuts using CTRL key instead of CMD key. (#4253) [@rokups] - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg. - Examples: SDL2: Accomodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. From 1965f38e9e5dd515f6a75b62911f7ef2d0be4d80 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Jun 2021 14:30:32 +0200 Subject: [PATCH 13/15] ImGuiWindowFlags_UnsavedDocument/ImGuiTabItmeFlags_UnsavedDocument display a dot instead of a '*'. --- docs/CHANGELOG.txt | 5 ++++- imgui.cpp | 20 ++++++++++++-------- imgui.h | 4 ++-- imgui_demo.cpp | 13 +++++++++++++ imgui_widgets.cpp | 34 +++++++++++++++++++++------------- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 81ec3c22..274de61e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,7 +36,9 @@ HOW TO UPDATE? ----------------------------------------------------------------------- Other Changes: -- TabBar: Fixed using more than 32 KB-worth of tab names. (#4176) +- Windows: ImGuiWindowFlags_UnsavedDocument/ImGuiTabItmeFlags_UnsavedDocument display a dot instead of a '*' so it + is independent from font style. When in a tab, the dot is displayed at the same position as the close button. + Added extra comments to clarify the purpose of this flag in the context of docked windows. - Tables: Added ImGuiTableColumnFlags_Disabled acting a master disable over (hidden from user/context menu). (#3935) - Tables: Clarified that TableSetColumnEnabled() requires the table to use the ImGuiTableFlags_Hideable flag, because it manipulates the user-accessible show/hide state. (#3935) @@ -44,6 +46,7 @@ Other Changes: Convenient for some small columns. Name will still appear in context menu. (#4206). - Tables: Fix columns order on TableSetupScrollFreeze() if previous data got frozen columns out of their section. - Tables: Fix invalid data in TableGetSortSpecs() when SpecsDirty flag is unset. (#4233) +- TabBar: Fixed using more than 32 KB-worth of tab names. (#4176) - Fixed printf-style format checks on non-MinGW flavors. (#4183, #3592) - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid diff --git a/imgui.cpp b/imgui.cpp index 0988fb7e..f381c673 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5666,8 +5666,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, @@ -5686,15 +5685,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 (flags & ImGuiWindowFlags_UnsavedDocument) + { + 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); - 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); - } } void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) diff --git a/imgui.h b/imgui.h index b954f29c..2166d659 100644 --- a/imgui.h +++ b/imgui.h @@ -932,7 +932,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) - ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker. + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, @@ -1070,7 +1070,7 @@ enum ImGuiTabBarFlags_ enum ImGuiTabItemFlags_ { ImGuiTabItemFlags_None = 0, - ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker. + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Display a dot next to the title + tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ecceed84..fe257c7d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -317,6 +317,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool no_nav = false; static bool no_background = false; static bool no_bring_to_front = false; + static bool unsaved_document = false; ImGuiWindowFlags window_flags = 0; if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; @@ -328,6 +329,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument; if (no_close) p_open = NULL; // Don't pass our bool* to Begin // We specify a default position/size in case there's no data in the .ini file. @@ -509,6 +511,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); + ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document); ImGui::EndTable(); } } @@ -7476,6 +7479,16 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::Separator(); + // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags. + // They have multiple effects: + // - Display a dot next to the title. + // - Tab is selected when clicking the X close button. + // - Closure is not assumed (will wait for user to stop submitting the tab). + // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty + // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window. + // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. + // Submit Tab Bar and Tabs { ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 994f8a43..ce20b369 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8077,14 +8077,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, #endif // Render text label (with clipping + alpha gradient) + unsaved marker - const char* TAB_UNSAVED_MARKER = "*"; ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); - if (flags & ImGuiTabItemFlags_UnsavedDocument) - { - text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; - ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + IM_FLOOR(-g.FontSize * 0.25f)); - RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL); - } ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; // Return clipped state ignoring the close button @@ -8094,7 +8087,10 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); } - // Close Button + const float button_sz = g.FontSize; + const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x * 2.0f - button_sz), bb.Min.y); + + // Close Button & Unsaved Marker // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() // 'hovered' will be true when hovering the Tab but NOT when hovering the close button // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button @@ -8102,15 +8098,16 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, bool close_button_pressed = false; bool close_button_visible = false; if (close_button_id != 0) - if (is_contents_visible || bb.GetWidth() >= g.Style.TabMinWidthForCloseButton) + if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton)) if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id) close_button_visible = true; + bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x); + if (close_button_visible) { ImGuiLastItemDataBackup last_item_backup; - const float close_button_sz = g.FontSize; PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); - if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x * 2.0f - close_button_sz, bb.Min.y))) + if (CloseButton(close_button_id, button_pos)) close_button_pressed = true; PopStyleVar(); last_item_backup.Restore(); @@ -8118,12 +8115,23 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // Close with middle mouse button if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) close_button_pressed = true; - - text_pixel_clip_bb.Max.x -= close_button_sz; + } + else if (unsaved_marker_visible) + { + const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz) + g.Style.FramePadding * 2.0f); + RenderBullet(bullet_bb.GetCenter()); } + // This is all rather complicated + // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + if (close_button_visible || unsaved_marker_visible) + { + text_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); + text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; + ellipsis_max_x = text_pixel_clip_bb.Max.x; + } RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); #if 0 From 20d415e939081502b5c42da2ea5c1a06d6d8c530 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Jun 2021 15:13:21 +0200 Subject: [PATCH 14/15] FIx static analysers warnings and disable false positives. --- .github/workflows/static-analysis.yml | 2 +- backends/imgui_impl_dx9.cpp | 8 ++++---- backends/imgui_impl_win32.cpp | 2 ++ imgui_widgets.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 13 ++++++++----- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index d3b7d50b..f3e6b2d1 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -43,7 +43,7 @@ jobs: cd examples/example_null pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1 pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log - plog-converter -a 'GA:1,2;OP:1' -t errorfile -w pvs-studio.log + plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log Discord-CI: runs-on: ubuntu-18.04 diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index c874516c..fd20e6b6 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -5,7 +5,7 @@ // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs @@ -278,8 +278,8 @@ static bool ImGui_ImplDX9_CreateFontsTexture() #ifndef IMGUI_USE_BGRA_PACKED_COLOR if (io.Fonts->TexPixelsUseColors) { - ImU32* dst_start = (ImU32*)ImGui::MemAlloc(width * height * bytes_per_pixel); - for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + width * height; dst < dst_end; src++, dst++) + ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); + for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) *dst = IMGUI_COL_TO_DX9_ARGB(*src); pixels = (unsigned char*)dst_start; } @@ -293,7 +293,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) return false; for (int y = 0; y < height; y++) - memcpy((unsigned char*)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel)); + memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); g_FontTexture->UnlockRect(0); // Store our identifier diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index f2425f06..bd4eddfd 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -420,6 +420,8 @@ static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) if (RtlVerifyVersionInfoFn == NULL) if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll")) RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo"); + if (RtlVerifyVersionInfoFn == NULL) + return FALSE; RTL_OSVERSIONINFOEXW versionInfo = { }; ULONGLONG conditionMask = 0; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ce20b369..aee3242b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8119,7 +8119,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, else if (unsaved_marker_visible) { const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz) + g.Style.FramePadding * 2.0f); - RenderBullet(bullet_bb.GetCenter()); + RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); } // This is all rather complicated diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index e6221f4b..2538f20a 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -41,7 +41,8 @@ #include FT_SYNTHESIS_H // #ifdef _MSC_VER -#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #endif #if defined(__GNUC__) @@ -600,13 +601,15 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); if (src_load_color) { - atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight * 4); - memset(atlas->TexPixelsRGBA32, 0, atlas->TexWidth * atlas->TexHeight * 4); + size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4; + atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size); + memset(atlas->TexPixelsRGBA32, 0, tex_size); } else { - atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); - memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1; + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size); + memset(atlas->TexPixelsAlpha8, 0, tex_size); } // 8. Copy rasterized font characters back into the main texture From e534c564857153df8ce1223ab92ada69a816fcfc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Jun 2021 15:57:41 +0200 Subject: [PATCH 15/15] Fonts: Functions with a 'float size_pixels' parameter can accept zero if it is set in ImFontSize::SizePixels. --- docs/CHANGELOG.txt | 1 + imgui_draw.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 32 ++++++++++++++++---------------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 274de61e..fb6304db 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,7 @@ Other Changes: - Tables: Fix invalid data in TableGetSortSpecs() when SpecsDirty flag is unset. (#4233) - TabBar: Fixed using more than 32 KB-worth of tab names. (#4176) - Fixed printf-style format checks on non-MinGW flavors. (#4183, #3592) +- Fonts: Functions with a 'float size_pixels' parameter can accept zero if it is set in ImFontSize::SizePixels. - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid implying that the file is required. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ea559bdf..a026ce4b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2167,7 +2167,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float si IM_ASSERT(font_cfg.FontData == NULL); font_cfg.FontData = ttf_data; font_cfg.FontDataSize = ttf_size; - font_cfg.SizePixels = size_pixels; + font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels; if (glyph_ranges) font_cfg.GlyphRanges = glyph_ranges; return AddFont(&font_cfg); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 2538f20a..71a18870 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -648,6 +648,22 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u const int tx = pack_rect.x + padding; const int ty = pack_rect.y + padding; + // Register glyph + float x0 = info.OffsetX + font_off_x; + float y0 = info.OffsetY + font_off_y; + float x1 = x0 + info.Width; + float y1 = y0 + info.Height; + float u0 = (tx) / (float)atlas->TexWidth; + float v0 = (ty) / (float)atlas->TexHeight; + float u1 = (tx + info.Width) / (float)atlas->TexWidth; + float v1 = (ty + info.Height) / (float)atlas->TexHeight; + dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX); + + ImFontGlyph* dst_glyph = &dst_font->Glyphs.back(); + IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint); + if (src_glyph.Info.IsColored) + dst_glyph->Colored = tex_use_colors = true; + // Blit from temporary buffer to final texture size_t blit_src_stride = (size_t)src_glyph.Info.Width; size_t blit_dst_stride = (size_t)atlas->TexWidth; @@ -666,22 +682,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (int x = 0; x < info.Width; x++) blit_dst[x] = blit_src[x]; } - - // Register glyph - float x0 = info.OffsetX + font_off_x; - float y0 = info.OffsetY + font_off_y; - float x1 = x0 + info.Width; - float y1 = y0 + info.Height; - float u0 = (tx) / (float)atlas->TexWidth; - float v0 = (ty) / (float)atlas->TexHeight; - float u1 = (tx + info.Width) / (float)atlas->TexWidth; - float v1 = (ty + info.Height) / (float)atlas->TexHeight; - dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX); - - ImFontGlyph* dst_glyph = &dst_font->Glyphs.back(); - IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint); - if (src_glyph.Info.IsColored) - dst_glyph->Colored = tex_use_colors = true; } src_tmp.Rects = NULL;