diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index 2c485841a..34b262dff 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -114,7 +114,7 @@ extern "C" { #define GLAPI extern #endif /* glcorearb.h is for use with OpenGL core profile implementations. -** It should should be placed in the same directory as gl.h and +** It should be placed in the same directory as gl.h and ** included as . ** ** glcorearb.h includes only APIs in the latest OpenGL core profile diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0f89ffd96..bc158639f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,12 +68,17 @@ Other Changes: - Using <> scrolling buttons while the selected Tab is at either end of the section mid-section but not fully visible always makes it fully visible (before eventually selecting a Tab in the leading/trailing section) +- Tables: + - Fixed a bug restoring correct .ini columns order when table use is Sortable + but had no user changes. (regression from 1.92.9). (#9519, #9108) - Selectable: - Fixed `ImGuiSelectableFlags_SelectOnNav` triggering during NavInit. - Fonts: - Reworked `AddFontDefault()` to use `io.DisplayFrameBufferScale` as part of the heuristic to select `AddFontDefaultVector()` by default, effectively using ProggyForever instead of ProggyClean on most Apple/Retina setups by default. + - imgui_freetype: Fixed blurryness rendering `AddFontDefaultVector()`. Caused by a + non-pixel aligned offset caused by `ExtraSizeScale`. (#9348, #9233) [@redpartizan, @RDMCz] - ColorEdit: - ColorButton, ColorEdit, ColorPicker: cancel-out alpha caused by BeginDisabled() so disabled color buttons have the same color as non-disabled oness. (#9511) @@ -83,6 +88,8 @@ Other Changes: - Amended context menu right-click opening code to check that the right-click hasn't been owned by another items. This is more correct and also necessary to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534) + - Reworked `GetMousePosOnOpeningCurrentPopup()` to be legal to call within the + BeginPopup/EndPopup scope of a popup which was just closed. (#9551) [@jkunstwald] - ImGuiTextFilter: - Added support for space as an "and" filter, which is the standard. (#2435, #30) e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data. @@ -119,6 +126,7 @@ Other Changes: - Added optional `platform_io.DrawCallback_SetSamplerFromTex` standard backend-agnostic draw callback for requesting to use the sampler associated already associated to a texture. Currently only supported by the OpenGL2/3 and SDLRenderer3 backend. (#9378) + - Fixed dangling ImDrawList::_OwnerName when using animated label. (#9552) [@ubi-dcastonguay] - Demo: - Added `Widgets->Mixed Values` section. (#5518, #5677, #6865) - Style Editor: fixed style/colors combo box applying style when opening Combo. @@ -139,7 +147,7 @@ Other Changes: don't have the equivalent of `SDL_SetTextureScaleMode()` and the callback won't work with them. - Vulkan: added for support for multiple Vulkan contexts with custom loaders. (#6616) [@lstalmir] - WebGPU: fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport()` - when when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU] + when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU] - WebGPU: update to build with wgpu-native 29.0+. (#9377, #9532, #9530) [@lucascompython, @ivan-enzhaev] - Examples: - MSVC: disabled /JMC in Visual Studio projects (unnecessary overhead). @@ -1941,7 +1949,7 @@ Non-breaking Fonts/Textures related changes: - Fonts: ImFontAtlas::AddFontXXX() can fail more gracefully if error handling is configured to not assert (this will be better exposed via future font flags). - Fonts: added style.FontScaleBase scaling factor (previously called io.FontGlobalScale). -- Fonts: added style.FontScaleDpi scaling factor. This is designed to be be changed on +- Fonts: added style.FontScaleDpi scaling factor. This is designed to be changed on per-monitor/per-viewport basis, which `io.ConfigDpiScaleFonts` does automatically. (which is why it is separate from FontScaleBase). - Fonts: added optional font_size parameter to ImGui::PushFont() function. @@ -3213,7 +3221,7 @@ Other changes: - Backends: Vulkan: Remove Volk/ from volk.h #include directives. (#7722, #6582, #4854) [@martin-ejdestig] - Examples: SDL3: Remove use of SDL_HINT_IME_NATIVE_UI since new SDL_HINT_IME_IMPLEMENTED_UI - values has a more suitable default for our case case. + values has a more suitable default for our case. - Examples: GLFW+Vulkan, SDL+Vulkan: handle swap chain resize even without Vulkan returning VK_SUBOPTIMAL_KHR, which doesn't seem to happen on Wayland. (#7671) [@AndreiNego, @ocornut] @@ -5421,7 +5429,7 @@ Other Changes: - ColorPicker4: Fixed picker being unable to select exact 1.0f color when dragging toward the edges of the SV square (previously picked 0.999989986f). (#3517) [@rokups] - Menus: Fixed vertical alignments of MenuItem() calls within a menu bar (broken in 1.84). (#4538) -- Menus: Improve closing logic when moving diagonally in empty between between parent and child menus to +- Menus: Improve closing logic when moving diagonally in empty space between parent and child menus to accommodate for varying font size and dpi. - Menus: Fixed crash when navigating left inside a child window inside a sub-menu. (#4510). - Menus: Fixed an assertion happening in some situations when closing nested menus (broken in 1.83). (#4640) diff --git a/imgui.cpp b/imgui.cpp index 661962441..16d33fa68 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -231,7 +231,7 @@ CODE This is to increase compatibility, increase maintainability and facilitate use from other languages. - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. - We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. + We can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (so don't use ImVector in your code or at our own risk!). - Building: We don't use nor mandate a build system for the main library. @@ -3190,7 +3190,7 @@ void ImGuiTextFilter::Build() const char* buf_e = InputBuf + ImStrlen(InputBuf); const char* word_e; - int seq_incl_start_idx = -1; + int seq_start_idx = -1; for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1) { // Trim blanks @@ -3224,21 +3224,21 @@ void ImGuiTextFilter::Build() { _Items.insert(_Items.Data + _CountExclude, ImGuiTextFilterItem(word_b, word_e)); _CountExclude++; - if (seq_incl_start_idx != -1) - seq_incl_start_idx++; + if (seq_start_idx != -1) + seq_start_idx++; } else { - if (seq_incl_start_idx == -1) - seq_incl_start_idx = _Items.Size; + if (seq_start_idx == -1) + seq_start_idx = _Items.Size; _Items.insert(_Items.Data + _Items.Size, ImGuiTextFilterItem(word_b, word_e)); - _Items.Data[seq_incl_start_idx].CountInclude++; + _Items.Data[seq_start_idx].CountInclude++; } } // Next sequence if (word_e[0] == ',') - seq_incl_start_idx = -1; + seq_start_idx = -1; } } @@ -3258,19 +3258,19 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const return false; // Process includes - ImGuiTextFilterItem* seq_incl_end = _Items.Data + _Items.Size; - if (seq == seq_incl_end) // When no inclusion are specified (only exclusions) we implicitly pass + ImGuiTextFilterItem* seq_end = _Items.Data + _Items.Size; + if (seq == seq_end) // When no inclusion are specified (only exclusions) we implicitly pass return true; - while (seq < seq_incl_end) + while (seq < seq_end) { - ImGuiTextFilterItem* seq_next = seq + seq->CountInclude; - IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_next <= seq_incl_end); - for (; seq < seq_next; seq++) + ImGuiTextFilterItem* seq_incl_end = seq + seq->CountInclude; + IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_incl_end <= seq_end); + for (; seq < seq_incl_end; seq++) if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) == NULL) break; - if (seq == seq_next) // All matched + if (seq == seq_incl_end) // All matched return true; - seq = seq_next; // Try next + seq = seq_incl_end; // Try next } return false; } @@ -8195,6 +8195,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) size_t buf_len = (size_t)window->NameBufLen; window->Name = ImStrdupcpy(window->Name, &buf_len, name); window->NameBufLen = (int)buf_len; + window->DrawList->_OwnerName = window->Name; } // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS @@ -10891,12 +10892,11 @@ void ImGui::TeleportMousePos(const ImVec2& pos) //IMGUI_DEBUG_LOG_IO("TeleportMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); } -// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() { ImGuiContext& g = *GImGui; if (g.BeginPopupStack.Size > 0) - return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.BeginPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; return g.IO.MousePos; } @@ -12759,7 +12759,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) } scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); } - scroll[axis] = ImRound64(ImMax(scroll[axis], 0.0f)); + scroll[axis] = ImRoundPositive64(ImMax(scroll[axis], 0.0f)); if (!window->Collapsed && !window->SkipItems) scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); } @@ -13539,7 +13539,7 @@ bool ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags // This is a helper to handle the simplest case of associating one named popup to one given widget. // - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. // - To create a popup with a specific identifier, pass it in str_id. -// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. // - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. // - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). // This is essentially the same as: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8415b49b9..bce46bcd5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4782,6 +4782,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); baked->Descent = ImFloor(unscaled_descent * scale_for_layout); + // FIXME: round to rasterizer density? (#9348) } return true; } diff --git a/imgui_internal.h b/imgui_internal.h index ec74884f1..0b782b6f3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -548,8 +548,9 @@ inline ImVec2 ImTrunc(const ImVec2& v) { return inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } inline float ImTrunc64(float f) { return (float)(ImS64)(f); } -inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } // FIXME: Positive values only. -inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the the bit-hack version (search for "0x1p120f"). +inline float ImRoundPositive64(float f) { return (float)(ImS64)(f + 0.5f); } // Positive values only. +inline float ImRoundSigned64(float f) { return (float)(ImS64)(f >= 0.0f ? f + 0.5f : f - 0.5f); } +inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the bit-hack version (search for "0x1p120f"). inline int ImModPositive(int a, int b) { return (a + b) % b; } inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } @@ -851,10 +852,11 @@ struct ImGuiTextIndex // [Internal] Types struct ImGuiTextFilterItem { - const char* Begin; - int Len; - int CountInclude; // >0 when beginning of an AND chain. - ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; } + const char* Begin; // Pointer within parent's buffer + int Len; // Length of text (non-zero terminated) + short CountInclude; // Number of consecutive items forming an end chain. >0 when beginning of an AND chain, =0 otherwise. + unsigned short MatchIncludesMask; // Storage for multi-sources versions of PassFilter(). Unused by core library. + ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; MatchIncludesMask = 0; } }; // Helper: ImGuiPackedDate (sizeof() == 2) @@ -915,7 +917,7 @@ struct IMGUI_API ImDrawListSharedData const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->TexUvLines) ImFontAtlas* FontAtlas; // Current font atlas ImFont* Font; // Current font (used for simplified AddText overload) - float FontSize; // Current font size (used for for simplified AddText overload) + float FontSize; // Current font size (used for simplified AddText overload) float FontScale; // Current font scale (== FontSize / Font->FontSize) float CurveTessellationMaxError; // Tessellation tolerance when using PathBezierCurveTo() float CircleTessellationMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc @@ -3370,9 +3372,9 @@ struct IMGUI_API ImGuiTable ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly ImGuiTableInstanceData InstanceDataFirst; ImVector InstanceDataExtra; // FIXME-OPT: Using a small-vector pattern would be good. - 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() + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableColumnSortSpecs SortSpecsSingle; ImGuiTableColumnIdx SortSpecsCount; ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns using fixed width (<= ColumnsCount) @@ -3404,6 +3406,7 @@ struct IMGUI_API ImGuiTable ImS8 NavLayer; // ImGuiNavLayer at the time of BeginTable(). bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). + bool IsNewTable; bool IsInitializing; bool IsReconcileMode; bool IsSortSpecsDirty; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index fb1b998d0..b3e0458eb 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -375,7 +375,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG const int previous_frame_active = table->LastFrameActive; const int instance_no = (previous_frame_active != g.FrameCount) ? 0 : table->InstanceCurrent + 1; const ImGuiTableFlags previous_flags = table->Flags; - const bool is_new_table = (previous_frame_active == -1); table->ID = id; table->Flags = flags; table->LastFrameActive = g.FrameCount; @@ -384,6 +383,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->IsLayoutLocked = false; table->InnerWidth = inner_width; table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent; + table->IsNewTable = (previous_frame_active == -1); temp_data->UserOuterSize = outer_size; // Instance data (for instance 0, TableID == TableInstanceID) @@ -585,7 +585,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG if (table->IsInitializing) { // Initialize - if (is_new_table) + if (table->IsNewTable) { table->SettingsOffset = -1; table->IsSettingsRequestLoad = true; @@ -1756,7 +1756,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo ImGuiTableColumn* column = &table->Columns[column_idx]; // If topology change goes into reconcile mode - if (table->IsReconcileMode == false && column->ID != column_id) + if (table->IsReconcileMode == false && column->ID != column_id && !table->IsNewTable) { table->IsReconcileMode = true; table->TempData->ReconcileColumnsRequests.reserve(table->ColumnsCount - column_idx); @@ -3970,12 +3970,10 @@ void ImGui::TableSaveSettings(ImGuiTable* table) if (column->DisplayOrder != n) settings->SaveFlags |= ImGuiTableFlags_Reorderable; if (column->SortOrder != -1) - settings->SaveFlags |= ImGuiTableFlags_Sortable; + settings->SaveFlags |= ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable; // Because SortOrder saving itself is gated, make sure every column is saved (#9519) if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0)) settings->SaveFlags |= ImGuiTableFlags_Hideable; } - if (table->Flags & ImGuiTableFlags_Sortable) - settings->SaveFlags |= ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable; settings->SaveFlags &= table->Flags; settings->RefScale = save_ref_scale ? table->RefScale : 0.0f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2a768bf05..d7f4186e5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4802,7 +4802,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(buf != NULL && buf_size >= 0); IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) - IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline does not not work with left-trimming + IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline does not work with left-trimming IM_ASSERT((flags & ImGuiInputTextFlags_WordWrap) == 0 || (flags & ImGuiInputTextFlags_Password) == 0); // WordWrap does not work with Password mode. IM_ASSERT((flags & ImGuiInputTextFlags_WordWrap) == 0 || (flags & ImGuiInputTextFlags_Multiline) != 0); // WordWrap does not work in single-line mode. diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 79dff8bfb..2e2e78f7d 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -7,6 +7,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026/09/25: fixed handling of ExtraSizeScale. // 2025/06/11: refactored for the new ImFontLoader architecture, and ImGuiBackendFlags_RendererHasTextures support. // 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. @@ -463,11 +464,13 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; const float scale = 1.0f / (rasterizer_density * src->ExtraSizeScale); - baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). - baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). + baked->Ascent = ((float)metrics.ascender / FT_SCALEFACTOR) * scale; // The pixel extents above the baseline in pixels (typically positive). + baked->Descent = ((float)metrics.descender / FT_SCALEFACTOR) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font. + baked->Ascent = ImRoundSigned64(baked->Ascent * rasterizer_density) / rasterizer_density; + baked->Descent = ImRoundSigned64(baked->Descent * rasterizer_density) / rasterizer_density; } return true; }